summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/vi
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/service/vi')
-rw-r--r--src/core/hle/service/vi/application_display_service.cpp8
-rw-r--r--src/core/hle/service/vi/application_display_service.h9
-rw-r--r--src/core/hle/service/vi/application_root_service.cpp8
-rw-r--r--src/core/hle/service/vi/application_root_service.h5
-rw-r--r--src/core/hle/service/vi/fbshare_buffer_manager.cpp447
-rw-r--r--src/core/hle/service/vi/fbshare_buffer_manager.h83
-rw-r--r--src/core/hle/service/vi/manager_root_service.cpp9
-rw-r--r--src/core/hle/service/vi/manager_root_service.h7
-rw-r--r--src/core/hle/service/vi/service_creator.cpp5
-rw-r--r--src/core/hle/service/vi/service_creator.h4
-rw-r--r--src/core/hle/service/vi/system_display_service.cpp22
-rw-r--r--src/core/hle/service/vi/system_display_service.h10
-rw-r--r--src/core/hle/service/vi/system_root_service.cpp8
-rw-r--r--src/core/hle/service/vi/system_root_service.h5
-rw-r--r--src/core/hle/service/vi/vi.cpp16
15 files changed, 609 insertions, 37 deletions
diff --git a/src/core/hle/service/vi/application_display_service.cpp b/src/core/hle/service/vi/application_display_service.cpp
index a6e04bf60..9c009f902 100644
--- a/src/core/hle/service/vi/application_display_service.cpp
+++ b/src/core/hle/service/vi/application_display_service.cpp
@@ -13,10 +13,12 @@
namespace Service::VI {
IApplicationDisplayService::IApplicationDisplayService(
- Core::System& system_, std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service)
+ Core::System& system_, std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
+ std::shared_ptr<FbshareBufferManager> shared_buffer_manager)
: ServiceFramework{system_, "IApplicationDisplayService"},
m_binder_service{std::move(binder_service)},
- m_surface_flinger{m_binder_service->GetSurfaceFlinger()} {
+ m_surface_flinger{m_binder_service->GetSurfaceFlinger()},
+ m_shared_buffer_manager{std::move(shared_buffer_manager)} {
// clang-format off
static const FunctionInfo functions[] = {
@@ -64,7 +66,7 @@ Result IApplicationDisplayService::GetSystemDisplayService(
Out<SharedPointer<ISystemDisplayService>> out_system_display_service) {
LOG_WARNING(Service_VI, "(STUBBED) called");
*out_system_display_service =
- std::make_shared<ISystemDisplayService>(system, m_surface_flinger);
+ std::make_shared<ISystemDisplayService>(system, m_surface_flinger, m_shared_buffer_manager);
R_SUCCEED();
}
diff --git a/src/core/hle/service/vi/application_display_service.h b/src/core/hle/service/vi/application_display_service.h
index e56490f9f..5022b2f63 100644
--- a/src/core/hle/service/vi/application_display_service.h
+++ b/src/core/hle/service/vi/application_display_service.h
@@ -16,15 +16,21 @@ class IHOSBinderDriver;
namespace Service::VI {
+class FbshareBufferManager;
class IManagerDisplayService;
class ISystemDisplayService;
class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
public:
IApplicationDisplayService(Core::System& system_,
- std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service);
+ std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
+ std::shared_ptr<FbshareBufferManager> shared_buffer_manager);
~IApplicationDisplayService() override;
+ std::shared_ptr<FbshareBufferManager> GetSharedBufferManager() const {
+ return m_shared_buffer_manager;
+ }
+
private:
Result GetRelayService(Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_relay_service);
Result GetSystemDisplayService(
@@ -62,6 +68,7 @@ private:
private:
const std::shared_ptr<Nvnflinger::IHOSBinderDriver> m_binder_service;
const std::shared_ptr<Nvnflinger::Nvnflinger> m_surface_flinger;
+ const std::shared_ptr<FbshareBufferManager> m_shared_buffer_manager;
std::vector<u64> m_stray_layer_ids;
bool m_vsync_event_fetched{false};
};
diff --git a/src/core/hle/service/vi/application_root_service.cpp b/src/core/hle/service/vi/application_root_service.cpp
index 501fbdd6a..ed8c9b1b3 100644
--- a/src/core/hle/service/vi/application_root_service.cpp
+++ b/src/core/hle/service/vi/application_root_service.cpp
@@ -11,8 +11,10 @@
namespace Service::VI {
IApplicationRootService::IApplicationRootService(
- Core::System& system_, std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service)
- : ServiceFramework{system_, "vi:u"}, m_binder_service{std::move(binder_service)} {
+ Core::System& system_, std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
+ std::shared_ptr<FbshareBufferManager> shared_buffer_manager)
+ : ServiceFramework{system_, "vi:u"}, m_binder_service{std::move(binder_service)},
+ m_shared_buffer_manager{std::move(shared_buffer_manager)} {
static const FunctionInfo functions[] = {
{0, C<&IApplicationRootService::GetDisplayService>, "GetDisplayService"},
{1, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -26,7 +28,7 @@ Result IApplicationRootService::GetDisplayService(
Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) {
LOG_DEBUG(Service_VI, "called");
R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_binder_service,
- Permission::User, policy));
+ m_shared_buffer_manager, Permission::User, policy));
}
} // namespace Service::VI
diff --git a/src/core/hle/service/vi/application_root_service.h b/src/core/hle/service/vi/application_root_service.h
index d1f023e9e..5970b6e68 100644
--- a/src/core/hle/service/vi/application_root_service.h
+++ b/src/core/hle/service/vi/application_root_service.h
@@ -16,13 +16,15 @@ class IHOSBinderDriver;
namespace Service::VI {
+class FbshareBufferManager;
class IApplicationDisplayService;
enum class Policy : u32;
class IApplicationRootService final : public ServiceFramework<IApplicationRootService> {
public:
explicit IApplicationRootService(Core::System& system_,
- std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service);
+ std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
+ std::shared_ptr<FbshareBufferManager> shared_buffer_manager);
~IApplicationRootService() override;
private:
@@ -32,6 +34,7 @@ private:
private:
const std::shared_ptr<Nvnflinger::IHOSBinderDriver> m_binder_service;
+ const std::shared_ptr<FbshareBufferManager> m_shared_buffer_manager;
};
} // namespace Service::VI
diff --git a/src/core/hle/service/vi/fbshare_buffer_manager.cpp b/src/core/hle/service/vi/fbshare_buffer_manager.cpp
new file mode 100644
index 000000000..e61c02e1c
--- /dev/null
+++ b/src/core/hle/service/vi/fbshare_buffer_manager.cpp
@@ -0,0 +1,447 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <random>
+
+#include "core/core.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_system_resource.h"
+#include "core/hle/service/nvdrv/devices/nvmap.h"
+#include "core/hle/service/nvdrv/nvdrv.h"
+#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
+#include "core/hle/service/nvnflinger/pixel_format.h"
+#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
+#include "core/hle/service/vi/fbshare_buffer_manager.h"
+#include "core/hle/service/vi/layer/vi_layer.h"
+#include "core/hle/service/vi/vi_results.h"
+#include "video_core/gpu.h"
+#include "video_core/host1x/host1x.h"
+
+namespace Service::VI {
+
+namespace {
+
+Result AllocateSharedBufferMemory(std::unique_ptr<Kernel::KPageGroup>* out_page_group,
+ Core::System& system, u32 size) {
+ using Core::Memory::YUZU_PAGESIZE;
+
+ // Allocate memory for the system shared buffer.
+ auto& kernel = system.Kernel();
+
+ // Hold a temporary page group reference while we try to map it.
+ auto pg = std::make_unique<Kernel::KPageGroup>(
+ kernel, std::addressof(kernel.GetSystemSystemResource().GetBlockInfoManager()));
+
+ // Allocate memory from secure pool.
+ R_TRY(kernel.MemoryManager().AllocateAndOpen(
+ pg.get(), size / YUZU_PAGESIZE,
+ Kernel::KMemoryManager::EncodeOption(Kernel::KMemoryManager::Pool::Secure,
+ Kernel::KMemoryManager::Direction::FromBack)));
+
+ // Fill the output data with red.
+ for (auto& block : *pg) {
+ u32* start = system.DeviceMemory().GetPointer<u32>(block.GetAddress());
+ u32* end = system.DeviceMemory().GetPointer<u32>(block.GetAddress() + block.GetSize());
+
+ for (; start < end; start++) {
+ *start = 0xFF0000FF;
+ }
+ }
+
+ // Return the mapped page group.
+ *out_page_group = std::move(pg);
+
+ // We succeeded.
+ R_SUCCEED();
+}
+
+Result MapSharedBufferIntoProcessAddressSpace(Common::ProcessAddress* out_map_address,
+ std::unique_ptr<Kernel::KPageGroup>& pg,
+ Kernel::KProcess* process, Core::System& system) {
+ using Core::Memory::YUZU_PAGESIZE;
+
+ auto& page_table = process->GetPageTable();
+
+ // Get bounds of where mapping is possible.
+ const VAddr alias_code_begin = GetInteger(page_table.GetAliasCodeRegionStart());
+ const VAddr alias_code_size = page_table.GetAliasCodeRegionSize() / YUZU_PAGESIZE;
+ const auto state = Kernel::KMemoryState::IoMemory;
+ const auto perm = Kernel::KMemoryPermission::UserReadWrite;
+ std::mt19937_64 rng{process->GetRandomEntropy(0)};
+
+ // Retry up to 64 times to map into alias code range.
+ Result res = ResultSuccess;
+ int i;
+ for (i = 0; i < 64; i++) {
+ *out_map_address = alias_code_begin + ((rng() % alias_code_size) * YUZU_PAGESIZE);
+ res = page_table.MapPageGroup(*out_map_address, *pg, state, perm);
+ if (R_SUCCEEDED(res)) {
+ break;
+ }
+ }
+
+ // Return failure, if necessary
+ R_UNLESS(i < 64, res);
+
+ // We succeeded.
+ R_SUCCEED();
+}
+
+Result CreateNvMapHandle(u32* out_nv_map_handle, Nvidia::Devices::nvmap& nvmap, u32 size) {
+ // Create a handle.
+ Nvidia::Devices::nvmap::IocCreateParams create_params{
+ .size = size,
+ .handle = 0,
+ };
+ R_UNLESS(nvmap.IocCreate(create_params) == Nvidia::NvResult::Success,
+ VI::ResultOperationFailed);
+
+ // Assign the output handle.
+ *out_nv_map_handle = create_params.handle;
+
+ // We succeeded.
+ R_SUCCEED();
+}
+
+Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Nvidia::DeviceFD nvmap_fd) {
+ // Free the handle.
+ Nvidia::Devices::nvmap::IocFreeParams free_params{
+ .handle = handle,
+ };
+ R_UNLESS(nvmap.IocFree(free_params, nvmap_fd) == Nvidia::NvResult::Success,
+ VI::ResultOperationFailed);
+
+ // We succeeded.
+ R_SUCCEED();
+}
+
+Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::ProcessAddress buffer,
+ u32 size, Nvidia::DeviceFD nvmap_fd) {
+ // Assign the allocated memory to the handle.
+ Nvidia::Devices::nvmap::IocAllocParams alloc_params{
+ .handle = handle,
+ .heap_mask = 0,
+ .flags = {},
+ .align = 0,
+ .kind = 0,
+ .address = GetInteger(buffer),
+ };
+ R_UNLESS(nvmap.IocAlloc(alloc_params, nvmap_fd) == Nvidia::NvResult::Success,
+ VI::ResultOperationFailed);
+
+ // We succeeded.
+ R_SUCCEED();
+}
+
+Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, Nvidia::DeviceFD nvmap_fd,
+ Common::ProcessAddress buffer, u32 size) {
+ // Get the nvmap device.
+ auto nvmap = nvdrv.GetDevice<Nvidia::Devices::nvmap>(nvmap_fd);
+ ASSERT(nvmap != nullptr);
+
+ // Create a handle.
+ R_TRY(CreateNvMapHandle(out_handle, *nvmap, size));
+
+ // Ensure we maintain a clean state on failure.
+ ON_RESULT_FAILURE {
+ R_ASSERT(FreeNvMapHandle(*nvmap, *out_handle, nvmap_fd));
+ };
+
+ // Assign the allocated memory to the handle.
+ R_RETURN(AllocNvMapHandle(*nvmap, *out_handle, buffer, size, nvmap_fd));
+}
+
+void FreeHandle(u32 handle, Nvidia::Module& nvdrv, Nvidia::DeviceFD nvmap_fd) {
+ auto nvmap = nvdrv.GetDevice<Nvidia::Devices::nvmap>(nvmap_fd);
+ ASSERT(nvmap != nullptr);
+
+ R_ASSERT(FreeNvMapHandle(*nvmap, handle, nvmap_fd));
+}
+
+constexpr auto SharedBufferBlockLinearFormat = android::PixelFormat::Rgba8888;
+constexpr u32 SharedBufferBlockLinearBpp = 4;
+
+constexpr u32 SharedBufferBlockLinearWidth = 1280;
+constexpr u32 SharedBufferBlockLinearHeight = 768;
+constexpr u32 SharedBufferBlockLinearStride =
+ SharedBufferBlockLinearWidth * SharedBufferBlockLinearBpp;
+constexpr u32 SharedBufferNumSlots = 7;
+
+constexpr u32 SharedBufferWidth = 1280;
+constexpr u32 SharedBufferHeight = 720;
+constexpr u32 SharedBufferAsync = false;
+
+constexpr u32 SharedBufferSlotSize =
+ SharedBufferBlockLinearWidth * SharedBufferBlockLinearHeight * SharedBufferBlockLinearBpp;
+constexpr u32 SharedBufferSize = SharedBufferSlotSize * SharedBufferNumSlots;
+
+constexpr SharedMemoryPoolLayout SharedBufferPoolLayout = [] {
+ SharedMemoryPoolLayout layout{};
+ layout.num_slots = SharedBufferNumSlots;
+
+ for (u32 i = 0; i < SharedBufferNumSlots; i++) {
+ layout.slots[i].buffer_offset = i * SharedBufferSlotSize;
+ layout.slots[i].size = SharedBufferSlotSize;
+ layout.slots[i].width = SharedBufferWidth;
+ layout.slots[i].height = SharedBufferHeight;
+ }
+
+ return layout;
+}();
+
+void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 handle) {
+ auto buffer = std::make_shared<android::NvGraphicBuffer>();
+ buffer->width = SharedBufferWidth;
+ buffer->height = SharedBufferHeight;
+ buffer->stride = SharedBufferBlockLinearStride;
+ buffer->format = SharedBufferBlockLinearFormat;
+ buffer->external_format = SharedBufferBlockLinearFormat;
+ buffer->buffer_id = handle;
+ buffer->offset = slot * SharedBufferSlotSize;
+ ASSERT(producer.SetPreallocatedBuffer(slot, buffer) == android::Status::NoError);
+}
+
+} // namespace
+
+FbshareBufferManager::FbshareBufferManager(Core::System& system,
+ std::shared_ptr<Nvnflinger::Nvnflinger> surface_flinger,
+ std::shared_ptr<Nvidia::Module> nvdrv)
+ : m_system(system), m_surface_flinger(std::move(surface_flinger)), m_nvdrv(std::move(nvdrv)) {}
+
+FbshareBufferManager::~FbshareBufferManager() = default;
+
+Result FbshareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id,
+ u64* out_layer_handle, u64 display_id,
+ Nvnflinger::LayerBlending blending) {
+ std::scoped_lock lk{m_guard};
+
+ // Ensure we haven't already created.
+ const u64 aruid = owner_process->GetProcessId();
+ R_UNLESS(!m_sessions.contains(aruid), VI::ResultPermissionDenied);
+
+ // Allocate memory for the shared buffer if needed.
+ if (!m_buffer_page_group) {
+ R_TRY(AllocateSharedBufferMemory(std::addressof(m_buffer_page_group), m_system,
+ SharedBufferSize));
+
+ // Record buffer id.
+ m_buffer_id = m_next_buffer_id++;
+
+ // Record display id.
+ m_display_id = display_id;
+ }
+
+ // Map into process.
+ Common::ProcessAddress map_address{};
+ R_TRY(MapSharedBufferIntoProcessAddressSpace(std::addressof(map_address), m_buffer_page_group,
+ owner_process, m_system));
+
+ // Create new session.
+ auto [it, was_emplaced] = m_sessions.emplace(aruid, FbshareSession{});
+ auto& session = it->second;
+
+ auto& container = m_nvdrv->GetContainer();
+ session.session_id = container.OpenSession(owner_process);
+ session.nvmap_fd = m_nvdrv->Open("/dev/nvmap", session.session_id);
+
+ // Create an nvmap handle for the buffer and assign the memory to it.
+ R_TRY(AllocateHandleForBuffer(std::addressof(session.buffer_nvmap_handle), *m_nvdrv,
+ session.nvmap_fd, map_address, SharedBufferSize));
+
+ // Create and open a layer for the display.
+ session.layer_id = m_surface_flinger->CreateLayer(m_display_id, blending).value();
+ m_surface_flinger->OpenLayer(session.layer_id);
+
+ // Get the layer.
+ VI::Layer* layer = m_surface_flinger->FindLayer(m_display_id, session.layer_id);
+ ASSERT(layer != nullptr);
+
+ // Get the producer and set preallocated buffers.
+ auto& producer = layer->GetBufferQueue();
+ MakeGraphicBuffer(producer, 0, session.buffer_nvmap_handle);
+ MakeGraphicBuffer(producer, 1, session.buffer_nvmap_handle);
+
+ // Assign outputs.
+ *out_buffer_id = m_buffer_id;
+ *out_layer_handle = session.layer_id;
+
+ // We succeeded.
+ R_SUCCEED();
+}
+
+void FbshareBufferManager::Finalize(Kernel::KProcess* owner_process) {
+ std::scoped_lock lk{m_guard};
+
+ if (m_buffer_id == 0) {
+ return;
+ }
+
+ const u64 aruid = owner_process->GetProcessId();
+ const auto it = m_sessions.find(aruid);
+ if (it == m_sessions.end()) {
+ return;
+ }
+
+ auto& session = it->second;
+
+ // Destroy the layer.
+ m_surface_flinger->DestroyLayer(session.layer_id);
+
+ // Close nvmap handle.
+ FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd);
+
+ // Close nvmap device.
+ m_nvdrv->Close(session.nvmap_fd);
+
+ // Close session.
+ auto& container = m_nvdrv->GetContainer();
+ container.CloseSession(session.session_id);
+
+ // Erase.
+ m_sessions.erase(it);
+}
+
+Result FbshareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size,
+ s32* out_nvmap_handle,
+ SharedMemoryPoolLayout* out_pool_layout,
+ u64 buffer_id,
+ u64 applet_resource_user_id) {
+ std::scoped_lock lk{m_guard};
+
+ R_UNLESS(m_buffer_id > 0, VI::ResultNotFound);
+ R_UNLESS(buffer_id == m_buffer_id, VI::ResultNotFound);
+ R_UNLESS(m_sessions.contains(applet_resource_user_id), VI::ResultNotFound);
+
+ *out_pool_layout = SharedBufferPoolLayout;
+ *out_buffer_size = SharedBufferSize;
+ *out_nvmap_handle = m_sessions[applet_resource_user_id].buffer_nvmap_handle;
+
+ R_SUCCEED();
+}
+
+Result FbshareBufferManager::GetLayerFromId(VI::Layer** out_layer, u64 layer_id) {
+ // Ensure the layer id is valid.
+ R_UNLESS(layer_id > 0, VI::ResultNotFound);
+
+ // Get the layer.
+ VI::Layer* layer = m_surface_flinger->FindLayer(m_display_id, layer_id);
+ R_UNLESS(layer != nullptr, VI::ResultNotFound);
+
+ // We succeeded.
+ *out_layer = layer;
+ R_SUCCEED();
+}
+
+Result FbshareBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence,
+ std::array<s32, 4>& out_slot_indexes,
+ s64* out_target_slot, u64 layer_id) {
+ std::scoped_lock lk{m_guard};
+
+ // Get the layer.
+ VI::Layer* layer;
+ R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id));
+
+ // Get the producer.
+ auto& producer = layer->GetBufferQueue();
+
+ // Get the next buffer from the producer.
+ s32 slot;
+ R_UNLESS(producer.DequeueBuffer(std::addressof(slot), out_fence, SharedBufferAsync != 0,
+ SharedBufferWidth, SharedBufferHeight,
+ SharedBufferBlockLinearFormat, 0) == android::Status::NoError,
+ VI::ResultOperationFailed);
+
+ // Assign remaining outputs.
+ *out_target_slot = slot;
+ out_slot_indexes = {0, 1, -1, -1};
+
+ // We succeeded.
+ R_SUCCEED();
+}
+
+Result FbshareBufferManager::PresentSharedFrameBuffer(android::Fence fence,
+ Common::Rectangle<s32> crop_region,
+ u32 transform, s32 swap_interval,
+ u64 layer_id, s64 slot) {
+ std::scoped_lock lk{m_guard};
+
+ // Get the layer.
+ VI::Layer* layer;
+ R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id));
+
+ // Get the producer.
+ auto& producer = layer->GetBufferQueue();
+
+ // Request to queue the buffer.
+ std::shared_ptr<android::GraphicBuffer> buffer;
+ R_UNLESS(producer.RequestBuffer(static_cast<s32>(slot), std::addressof(buffer)) ==
+ android::Status::NoError,
+ VI::ResultOperationFailed);
+
+ ON_RESULT_FAILURE {
+ producer.CancelBuffer(static_cast<s32>(slot), fence);
+ };
+
+ // Queue the buffer to the producer.
+ android::QueueBufferInput input{};
+ android::QueueBufferOutput output{};
+ input.crop = crop_region;
+ input.fence = fence;
+ input.transform = static_cast<android::NativeWindowTransform>(transform);
+ input.swap_interval = swap_interval;
+ R_UNLESS(producer.QueueBuffer(static_cast<s32>(slot), input, std::addressof(output)) ==
+ android::Status::NoError,
+ VI::ResultOperationFailed);
+
+ // We succeeded.
+ R_SUCCEED();
+}
+
+Result FbshareBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event,
+ u64 layer_id) {
+ std::scoped_lock lk{m_guard};
+
+ // Get the layer.
+ VI::Layer* layer;
+ R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id));
+
+ // Get the producer.
+ auto& producer = layer->GetBufferQueue();
+
+ // Set the event.
+ *out_event = std::addressof(producer.GetNativeHandle());
+
+ // We succeeded.
+ R_SUCCEED();
+}
+
+Result FbshareBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) {
+ std::vector<u8> capture_buffer(m_system.GPU().GetAppletCaptureBuffer());
+ Common::ScratchBuffer<u32> scratch;
+
+ // TODO: this could be optimized
+ s64 e = -1280 * 768 * 4;
+ for (auto& block : *m_buffer_page_group) {
+ u8* start = m_system.DeviceMemory().GetPointer<u8>(block.GetAddress());
+ u8* end = m_system.DeviceMemory().GetPointer<u8>(block.GetAddress() + block.GetSize());
+
+ for (; start < end; start++) {
+ *start = 0;
+
+ if (e >= 0 && e < static_cast<s64>(capture_buffer.size())) {
+ *start = capture_buffer[e];
+ }
+ e++;
+ }
+
+ m_system.GPU().Host1x().MemoryManager().ApplyOpOnPointer(start, scratch, [&](DAddr addr) {
+ m_system.GPU().InvalidateRegion(addr, end - start);
+ });
+ }
+
+ *out_was_written = true;
+ *out_layer_index = 1;
+ R_SUCCEED();
+}
+
+} // namespace Service::VI
diff --git a/src/core/hle/service/vi/fbshare_buffer_manager.h b/src/core/hle/service/vi/fbshare_buffer_manager.h
new file mode 100644
index 000000000..b9e99e61f
--- /dev/null
+++ b/src/core/hle/service/vi/fbshare_buffer_manager.h
@@ -0,0 +1,83 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <map>
+
+#include "common/math_util.h"
+#include "core/hle/service/nvdrv/core/container.h"
+#include "core/hle/service/nvdrv/nvdata.h"
+#include "core/hle/service/nvnflinger/hwc_layer.h"
+#include "core/hle/service/nvnflinger/nvnflinger.h"
+#include "core/hle/service/nvnflinger/ui/fence.h"
+
+namespace Kernel {
+class KPageGroup;
+}
+
+namespace Service::VI {
+
+struct SharedMemorySlot {
+ u64 buffer_offset;
+ u64 size;
+ s32 width;
+ s32 height;
+};
+static_assert(sizeof(SharedMemorySlot) == 0x18, "SharedMemorySlot has wrong size");
+
+struct SharedMemoryPoolLayout {
+ s32 num_slots;
+ std::array<SharedMemorySlot, 0x10> slots;
+};
+static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size");
+
+struct FbshareSession;
+
+class FbshareBufferManager final {
+public:
+ explicit FbshareBufferManager(Core::System& system,
+ std::shared_ptr<Nvnflinger::Nvnflinger> surface_flinger,
+ std::shared_ptr<Nvidia::Module> nvdrv);
+ ~FbshareBufferManager();
+
+ Result Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id, u64* out_layer_handle,
+ u64 display_id, Nvnflinger::LayerBlending blending);
+ void Finalize(Kernel::KProcess* owner_process);
+
+ Result GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle,
+ SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id,
+ u64 applet_resource_user_id);
+ Result AcquireSharedFrameBuffer(android::Fence* out_fence, std::array<s32, 4>& out_slots,
+ s64* out_target_slot, u64 layer_id);
+ Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region,
+ u32 transform, s32 swap_interval, u64 layer_id, s64 slot);
+ Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id);
+
+ Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index);
+
+private:
+ Result GetLayerFromId(VI::Layer** out_layer, u64 layer_id);
+
+private:
+ u64 m_next_buffer_id = 1;
+ u64 m_display_id = 0;
+ u64 m_buffer_id = 0;
+ SharedMemoryPoolLayout m_pool_layout = {};
+ std::map<u64, FbshareSession> m_sessions;
+ std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group;
+
+ std::mutex m_guard;
+ Core::System& m_system;
+ const std::shared_ptr<Nvnflinger::Nvnflinger> m_surface_flinger;
+ const std::shared_ptr<Nvidia::Module> m_nvdrv;
+};
+
+struct FbshareSession {
+ Nvidia::DeviceFD nvmap_fd = {};
+ Nvidia::NvCore::SessionId session_id = {};
+ u64 layer_id = {};
+ u32 buffer_nvmap_handle = 0;
+};
+
+} // namespace Service::VI
diff --git a/src/core/hle/service/vi/manager_root_service.cpp b/src/core/hle/service/vi/manager_root_service.cpp
index 36b84909a..b61f0ecb6 100644
--- a/src/core/hle/service/vi/manager_root_service.cpp
+++ b/src/core/hle/service/vi/manager_root_service.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/nvnflinger/hos_binder_driver.h"
#include "core/hle/service/vi/application_display_service.h"
#include "core/hle/service/vi/manager_root_service.h"
#include "core/hle/service/vi/service_creator.h"
@@ -11,8 +12,10 @@
namespace Service::VI {
IManagerRootService::IManagerRootService(
- Core::System& system_, std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service)
- : ServiceFramework{system_, "vi:m"}, m_binder_service{std::move(binder_service)} {
+ Core::System& system_, std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
+ std::shared_ptr<FbshareBufferManager> shared_buffer_manager)
+ : ServiceFramework{system_, "vi:m"}, m_binder_service{std::move(binder_service)},
+ m_shared_buffer_manager{std::move(shared_buffer_manager)} {
static const FunctionInfo functions[] = {
{2, C<&IManagerRootService::GetDisplayService>, "GetDisplayService"},
{3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -30,7 +33,7 @@ Result IManagerRootService::GetDisplayService(
Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) {
LOG_DEBUG(Service_VI, "called");
R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_binder_service,
- Permission::Manager, policy));
+ m_shared_buffer_manager, Permission::Manager, policy));
}
} // namespace Service::VI
diff --git a/src/core/hle/service/vi/manager_root_service.h b/src/core/hle/service/vi/manager_root_service.h
index 26aa95a88..509445b7b 100644
--- a/src/core/hle/service/vi/manager_root_service.h
+++ b/src/core/hle/service/vi/manager_root_service.h
@@ -16,21 +16,24 @@ class IHOSBinderDriver;
namespace Service::VI {
+class FbshareBufferManager;
class IApplicationDisplayService;
enum class Policy : u32;
class IManagerRootService final : public ServiceFramework<IManagerRootService> {
public:
explicit IManagerRootService(Core::System& system_,
- std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service);
+ std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
+ std::shared_ptr<FbshareBufferManager> shared_buffer_manager);
~IManagerRootService() override;
-private:
Result GetDisplayService(
Out<SharedPointer<IApplicationDisplayService>> out_application_display_service,
Policy policy);
+private:
const std::shared_ptr<Nvnflinger::IHOSBinderDriver> m_binder_service;
+ const std::shared_ptr<FbshareBufferManager> m_shared_buffer_manager;
};
} // namespace Service::VI
diff --git a/src/core/hle/service/vi/service_creator.cpp b/src/core/hle/service/vi/service_creator.cpp
index 594e57398..414bd6655 100644
--- a/src/core/hle/service/vi/service_creator.cpp
+++ b/src/core/hle/service/vi/service_creator.cpp
@@ -23,7 +23,8 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) {
Result GetApplicationDisplayService(
std::shared_ptr<IApplicationDisplayService>* out_application_display_service,
Core::System& system, std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
- Permission permission, Policy policy) {
+ std::shared_ptr<FbshareBufferManager> shared_buffer_manager, Permission permission,
+ Policy policy) {
if (!IsValidServiceAccess(permission, policy)) {
LOG_ERROR(Service_VI, "Permission denied for policy {}", policy);
@@ -31,7 +32,7 @@ Result GetApplicationDisplayService(
}
*out_application_display_service =
- std::make_shared<IApplicationDisplayService>(system, binder_service);
+ std::make_shared<IApplicationDisplayService>(system, binder_service, shared_buffer_manager);
R_SUCCEED();
}
diff --git a/src/core/hle/service/vi/service_creator.h b/src/core/hle/service/vi/service_creator.h
index bdfac8a08..6691f25c0 100644
--- a/src/core/hle/service/vi/service_creator.h
+++ b/src/core/hle/service/vi/service_creator.h
@@ -19,6 +19,7 @@ union Result;
namespace Service::VI {
+class FbshareBufferManager;
class IApplicationDisplayService;
enum class Permission;
enum class Policy : u32;
@@ -26,6 +27,7 @@ enum class Policy : u32;
Result GetApplicationDisplayService(
std::shared_ptr<IApplicationDisplayService>* out_application_display_service,
Core::System& system, std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
- Permission permission, Policy policy);
+ std::shared_ptr<FbshareBufferManager> shared_buffer_manager, Permission permission,
+ Policy policy);
} // namespace Service::VI
diff --git a/src/core/hle/service/vi/system_display_service.cpp b/src/core/hle/service/vi/system_display_service.cpp
index 8d6c3f04c..4670cf4cc 100644
--- a/src/core/hle/service/vi/system_display_service.cpp
+++ b/src/core/hle/service/vi/system_display_service.cpp
@@ -3,16 +3,17 @@
#include "common/settings.h"
#include "core/hle/service/cmif_serialization.h"
-#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
#include "core/hle/service/vi/system_display_service.h"
#include "core/hle/service/vi/vi_types.h"
namespace Service::VI {
ISystemDisplayService::ISystemDisplayService(
- Core::System& system_, std::shared_ptr<Nvnflinger::Nvnflinger> surface_flinger)
+ Core::System& system_, std::shared_ptr<Nvnflinger::Nvnflinger> surface_flinger,
+ std::shared_ptr<FbshareBufferManager> shared_buffer_manager)
: ServiceFramework{system_, "ISystemDisplayService"},
- m_surface_flinger{std::move(surface_flinger)} {
+ m_surface_flinger{std::move(surface_flinger)},
+ m_shared_buffer_manager{std::move(shared_buffer_manager)} {
// clang-format off
static const FunctionInfo functions[] = {
{1200, nullptr, "GetZOrderCountMin"},
@@ -101,11 +102,11 @@ Result ISystemDisplayService::GetDisplayMode(Out<u32> out_width, Out<u32> out_he
Result ISystemDisplayService::GetSharedBufferMemoryHandleId(
Out<s32> out_nvmap_handle, Out<u64> out_size,
- OutLargeData<Nvnflinger::SharedMemoryPoolLayout, BufferAttr_HipcMapAlias> out_pool_layout,
- u64 buffer_id, ClientAppletResourceUserId aruid) {
+ OutLargeData<SharedMemoryPoolLayout, BufferAttr_HipcMapAlias> out_pool_layout, u64 buffer_id,
+ ClientAppletResourceUserId aruid) {
LOG_INFO(Service_VI, "called. buffer_id={}, aruid={:#x}", buffer_id, aruid.pid);
- R_RETURN(m_surface_flinger->GetSystemBufferManager().GetSharedBufferMemoryHandleId(
+ R_RETURN(m_shared_buffer_manager->GetSharedBufferMemoryHandleId(
out_size, out_nvmap_handle, out_pool_layout, buffer_id, aruid.pid));
}
@@ -123,8 +124,8 @@ Result ISystemDisplayService::AcquireSharedFrameBuffer(Out<android::Fence> out_f
Out<std::array<s32, 4>> out_slots,
Out<s64> out_target_slot, u64 layer_id) {
LOG_DEBUG(Service_VI, "called");
- R_RETURN(m_surface_flinger->GetSystemBufferManager().AcquireSharedFrameBuffer(
- out_fence, *out_slots, out_target_slot, layer_id));
+ R_RETURN(m_shared_buffer_manager->AcquireSharedFrameBuffer(out_fence, *out_slots,
+ out_target_slot, layer_id));
}
Result ISystemDisplayService::PresentSharedFrameBuffer(android::Fence fence,
@@ -132,15 +133,14 @@ Result ISystemDisplayService::PresentSharedFrameBuffer(android::Fence fence,
u32 window_transform, s32 swap_interval,
u64 layer_id, s64 surface_id) {
LOG_DEBUG(Service_VI, "called");
- R_RETURN(m_surface_flinger->GetSystemBufferManager().PresentSharedFrameBuffer(
+ R_RETURN(m_shared_buffer_manager->PresentSharedFrameBuffer(
fence, crop_region, window_transform, swap_interval, layer_id, surface_id));
}
Result ISystemDisplayService::GetSharedFrameBufferAcquirableEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event, u64 layer_id) {
LOG_DEBUG(Service_VI, "called");
- R_RETURN(m_surface_flinger->GetSystemBufferManager().GetSharedFrameBufferAcquirableEvent(
- out_event, layer_id));
+ R_RETURN(m_shared_buffer_manager->GetSharedFrameBufferAcquirableEvent(out_event, layer_id));
}
} // namespace Service::VI
diff --git a/src/core/hle/service/vi/system_display_service.h b/src/core/hle/service/vi/system_display_service.h
index 6c3f57ad7..b84c9725f 100644
--- a/src/core/hle/service/vi/system_display_service.h
+++ b/src/core/hle/service/vi/system_display_service.h
@@ -5,18 +5,21 @@
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/nvnflinger/ui/fence.h"
#include "core/hle/service/service.h"
+#include "core/hle/service/vi/fbshare_buffer_manager.h"
namespace Service::Nvnflinger {
class Nvnflinger;
-struct SharedMemoryPoolLayout;
} // namespace Service::Nvnflinger
namespace Service::VI {
+class FbshareBufferManager;
+
class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
public:
explicit ISystemDisplayService(Core::System& system_,
- std::shared_ptr<Nvnflinger::Nvnflinger> surface_flinger);
+ std::shared_ptr<Nvnflinger::Nvnflinger> surface_flinger,
+ std::shared_ptr<FbshareBufferManager> shared_buffer_manager);
~ISystemDisplayService() override;
private:
@@ -27,7 +30,7 @@ private:
Result GetSharedBufferMemoryHandleId(
Out<s32> out_nvmap_handle, Out<u64> out_size,
- OutLargeData<Nvnflinger::SharedMemoryPoolLayout, BufferAttr_HipcMapAlias> out_pool_layout,
+ OutLargeData<SharedMemoryPoolLayout, BufferAttr_HipcMapAlias> out_pool_layout,
u64 buffer_id, ClientAppletResourceUserId aruid);
Result OpenSharedLayer(u64 layer_id);
Result ConnectSharedLayer(u64 layer_id);
@@ -42,6 +45,7 @@ private:
private:
const std::shared_ptr<Nvnflinger::Nvnflinger> m_surface_flinger;
+ const std::shared_ptr<FbshareBufferManager> m_shared_buffer_manager;
};
} // namespace Service::VI
diff --git a/src/core/hle/service/vi/system_root_service.cpp b/src/core/hle/service/vi/system_root_service.cpp
index 1d435ed6b..2254ed111 100644
--- a/src/core/hle/service/vi/system_root_service.cpp
+++ b/src/core/hle/service/vi/system_root_service.cpp
@@ -11,8 +11,10 @@
namespace Service::VI {
ISystemRootService::ISystemRootService(Core::System& system_,
- std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service)
- : ServiceFramework{system_, "vi:s"}, m_binder_service{std::move(binder_service)} {
+ std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
+ std::shared_ptr<FbshareBufferManager> shared_buffer_manager)
+ : ServiceFramework{system_, "vi:s"}, m_binder_service{std::move(binder_service)},
+ m_shared_buffer_manager{std::move(shared_buffer_manager)} {
static const FunctionInfo functions[] = {
{1, C<&ISystemRootService::GetDisplayService>, "GetDisplayService"},
{3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -26,7 +28,7 @@ Result ISystemRootService::GetDisplayService(
Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) {
LOG_DEBUG(Service_VI, "called");
R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_binder_service,
- Permission::System, policy));
+ m_shared_buffer_manager, Permission::System, policy));
}
} // namespace Service::VI
diff --git a/src/core/hle/service/vi/system_root_service.h b/src/core/hle/service/vi/system_root_service.h
index 6f07c39fd..16c997422 100644
--- a/src/core/hle/service/vi/system_root_service.h
+++ b/src/core/hle/service/vi/system_root_service.h
@@ -16,13 +16,15 @@ class IHOSBinderDriver;
namespace Service::VI {
+class FbshareBufferManager;
class IApplicationDisplayService;
enum class Policy : u32;
class ISystemRootService final : public ServiceFramework<ISystemRootService> {
public:
explicit ISystemRootService(Core::System& system_,
- std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service);
+ std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
+ std::shared_ptr<FbshareBufferManager> shared_buffer_manager);
~ISystemRootService() override;
private:
@@ -31,6 +33,7 @@ private:
Policy policy);
const std::shared_ptr<Nvnflinger::IHOSBinderDriver> m_binder_service;
+ const std::shared_ptr<FbshareBufferManager> m_shared_buffer_manager;
};
} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index d20f1fdea..f361b9f4c 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -2,11 +2,13 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
+#include "core/hle/service/nvdrv/nvdrv_interface.h"
#include "core/hle/service/nvnflinger/hos_binder_driver.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/vi/application_display_service.h"
#include "core/hle/service/vi/application_root_service.h"
+#include "core/hle/service/vi/fbshare_buffer_manager.h"
#include "core/hle/service/vi/manager_root_service.h"
#include "core/hle/service/vi/system_root_service.h"
#include "core/hle/service/vi/vi.h"
@@ -16,14 +18,22 @@ namespace Service::VI {
void LoopProcess(Core::System& system) {
const auto binder_service =
system.ServiceManager().GetService<Nvnflinger::IHOSBinderDriver>("dispdrv", true);
+ const auto nvdrv =
+ system.ServiceManager().GetService<Nvidia::NVDRV>("nvdrv:s", true)->GetModule();
+ const auto shared_buffer_manager =
+ std::make_shared<FbshareBufferManager>(system, binder_service->GetSurfaceFlinger(), nvdrv);
+
auto server_manager = std::make_unique<ServerManager>(system);
server_manager->RegisterNamedService(
- "vi:m", std::make_shared<IManagerRootService>(system, binder_service));
+ "vi:m",
+ std::make_shared<IManagerRootService>(system, binder_service, shared_buffer_manager));
server_manager->RegisterNamedService(
- "vi:s", std::make_shared<ISystemRootService>(system, binder_service));
+ "vi:s",
+ std::make_shared<ISystemRootService>(system, binder_service, shared_buffer_manager));
server_manager->RegisterNamedService(
- "vi:u", std::make_shared<IApplicationRootService>(system, binder_service));
+ "vi:u",
+ std::make_shared<IApplicationRootService>(system, binder_service, shared_buffer_manager));
ServerManager::RunServer(std::move(server_manager));
}