summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNarr the Reg <juangerman-13@hotmail.com>2023-09-29 07:45:49 +0200
committerNarr the Reg <juangerman-13@hotmail.com>2023-10-01 19:38:30 +0200
commit35f25882e027fd3c466edd44db1fc1c5bec75bde (patch)
tree8f7be0d40cc8ebb2bbbb8fec4113293bc72f5071
parentservice: ldn: Implement lp2p:m and stub IMonitorService (diff)
downloadyuzu-35f25882e027fd3c466edd44db1fc1c5bec75bde.tar
yuzu-35f25882e027fd3c466edd44db1fc1c5bec75bde.tar.gz
yuzu-35f25882e027fd3c466edd44db1fc1c5bec75bde.tar.bz2
yuzu-35f25882e027fd3c466edd44db1fc1c5bec75bde.tar.lz
yuzu-35f25882e027fd3c466edd44db1fc1c5bec75bde.tar.xz
yuzu-35f25882e027fd3c466edd44db1fc1c5bec75bde.tar.zst
yuzu-35f25882e027fd3c466edd44db1fc1c5bec75bde.zip
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.h14
-rw-r--r--src/core/hle/service/nvnflinger/buffer_item.h2
-rw-r--r--src/core/hle/service/nvnflinger/buffer_slot.h2
-rw-r--r--src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp351
-rw-r--r--src/core/hle/service/nvnflinger/fb_share_buffer_manager.h65
-rw-r--r--src/core/hle/service/nvnflinger/graphic_buffer_producer.h2
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.cpp11
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.h9
-rw-r--r--src/core/hle/service/nvnflinger/ui/fence.h3
-rw-r--r--src/core/hle/service/nvnflinger/ui/graphic_buffer.h4
-rw-r--r--src/core/hle/service/vi/vi.cpp129
12 files changed, 572 insertions, 22 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index d0f76e57e..e02ededfc 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -698,6 +698,8 @@ add_library(core STATIC
hle/service/nvnflinger/consumer_base.cpp
hle/service/nvnflinger/consumer_base.h
hle/service/nvnflinger/consumer_listener.h
+ hle/service/nvnflinger/fb_share_buffer_manager.cpp
+ hle/service/nvnflinger/fb_share_buffer_manager.h
hle/service/nvnflinger/graphic_buffer_producer.cpp
hle/service/nvnflinger/graphic_buffer_producer.h
hle/service/nvnflinger/hos_binder_driver_server.cpp
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h
index 40c65b430..4c0cc71cd 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.h
+++ b/src/core/hle/service/nvdrv/devices/nvmap.h
@@ -45,13 +45,6 @@ public:
IsSharedMemMapped = 6
};
-private:
- /// Id to use for the next handle that is created.
- u32 next_handle = 0;
-
- /// Id to use for the next object that is created.
- u32 next_id = 0;
-
struct IocCreateParams {
// Input
u32_le size{};
@@ -113,6 +106,13 @@ private:
NvResult IocParam(std::span<const u8> input, std::span<u8> output);
NvResult IocFree(std::span<const u8> input, std::span<u8> output);
+private:
+ /// Id to use for the next handle that is created.
+ u32 next_handle = 0;
+
+ /// Id to use for the next object that is created.
+ u32 next_id = 0;
+
NvCore::Container& container;
NvCore::NvMap& file;
};
diff --git a/src/core/hle/service/nvnflinger/buffer_item.h b/src/core/hle/service/nvnflinger/buffer_item.h
index 7fd808f54..3da8cc3aa 100644
--- a/src/core/hle/service/nvnflinger/buffer_item.h
+++ b/src/core/hle/service/nvnflinger/buffer_item.h
@@ -15,7 +15,7 @@
namespace Service::android {
-class GraphicBuffer;
+struct GraphicBuffer;
class BufferItem final {
public:
diff --git a/src/core/hle/service/nvnflinger/buffer_slot.h b/src/core/hle/service/nvnflinger/buffer_slot.h
index d25bca049..d8c9dec3b 100644
--- a/src/core/hle/service/nvnflinger/buffer_slot.h
+++ b/src/core/hle/service/nvnflinger/buffer_slot.h
@@ -13,7 +13,7 @@
namespace Service::android {
-class GraphicBuffer;
+struct GraphicBuffer;
enum class BufferState : u32 {
Free = 0,
diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
new file mode 100644
index 000000000..469a53244
--- /dev/null
+++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
@@ -0,0 +1,351 @@
+// 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/fb_share_buffer_manager.h"
+#include "core/hle/service/nvnflinger/pixel_format.h"
+#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
+#include "core/hle/service/vi/layer/vi_layer.h"
+#include "core/hle/service/vi/vi_results.h"
+
+namespace Service::Nvnflinger {
+
+namespace {
+
+Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address,
+ 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.
+ // FIXME: Because the gmmu can only point to cpu addresses, we need
+ // to map this in the application space to allow it to be used.
+ // FIXME: Add proper smmu emulation.
+ // FIXME: This memory belongs to vi's .data section.
+ auto& kernel = system.Kernel();
+ auto* process = system.ApplicationProcess();
+ auto& page_table = process->GetPageTable();
+
+ // 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)));
+
+ // 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::Io;
+ 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);
+
+ // Return the mapped page group.
+ *out_page_group = std::move(pg);
+
+ // We succeeded.
+ R_SUCCEED();
+}
+
+template <typename T>
+std::span<u8> SerializeIoc(T& params) {
+ return std::span(reinterpret_cast<u8*>(std::addressof(params)), sizeof(T));
+}
+
+Result CreateNvMapHandle(u32* out_nv_map_handle, Nvidia::Devices::nvmap& nvmap, u32 size) {
+ // Create a handle.
+ Nvidia::Devices::nvmap::IocCreateParams create_in_params{
+ .size = size,
+ .handle = 0,
+ };
+ Nvidia::Devices::nvmap::IocCreateParams create_out_params{};
+ R_UNLESS(nvmap.IocCreate(SerializeIoc(create_in_params), SerializeIoc(create_out_params)) ==
+ Nvidia::NvResult::Success,
+ VI::ResultOperationFailed);
+
+ // Assign the output handle.
+ *out_nv_map_handle = create_out_params.handle;
+
+ // We succeeded.
+ R_SUCCEED();
+}
+
+Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle) {
+ // Free the handle.
+ Nvidia::Devices::nvmap::IocFreeParams free_in_params{
+ .handle = handle,
+ };
+ Nvidia::Devices::nvmap::IocFreeParams free_out_params{};
+ R_UNLESS(nvmap.IocFree(SerializeIoc(free_in_params), SerializeIoc(free_out_params)) ==
+ Nvidia::NvResult::Success,
+ VI::ResultOperationFailed);
+
+ // We succeeded.
+ R_SUCCEED();
+}
+
+Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::ProcessAddress buffer,
+ u32 size) {
+ // Assign the allocated memory to the handle.
+ Nvidia::Devices::nvmap::IocAllocParams alloc_in_params{
+ .handle = handle,
+ .heap_mask = 0,
+ .flags = {},
+ .align = 0,
+ .kind = 0,
+ .address = GetInteger(buffer),
+ };
+ Nvidia::Devices::nvmap::IocAllocParams alloc_out_params{};
+ R_UNLESS(nvmap.IocAlloc(SerializeIoc(alloc_in_params), SerializeIoc(alloc_out_params)) ==
+ Nvidia::NvResult::Success,
+ VI::ResultOperationFailed);
+
+ // We succeeded.
+ R_SUCCEED();
+}
+
+Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv,
+ Common::ProcessAddress buffer, u32 size) {
+ // Get the nvmap device.
+ auto nvmap_fd = nvdrv.Open("/dev/nvmap");
+ 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 {
+ ASSERT(R_SUCCEEDED(FreeNvMapHandle(*nvmap, *out_handle)));
+ };
+
+ // Assign the allocated memory to the handle.
+ R_RETURN(AllocNvMapHandle(*nvmap, *out_handle, buffer, size));
+}
+
+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::GraphicBuffer>();
+ buffer->width = SharedBufferWidth;
+ buffer->height = SharedBufferHeight;
+ buffer->stride = SharedBufferBlockLinearStride;
+ buffer->format = SharedBufferBlockLinearFormat;
+ buffer->buffer_id = handle;
+ buffer->offset = slot * SharedBufferSlotSize;
+ ASSERT(producer.SetPreallocatedBuffer(slot, buffer) == android::Status::NoError);
+}
+
+} // namespace
+
+FbShareBufferManager::FbShareBufferManager(Core::System& system, Nvnflinger& flinger,
+ std::shared_ptr<Nvidia::Module> nvdrv)
+ : m_system(system), m_flinger(flinger), m_nvdrv(std::move(nvdrv)) {}
+
+FbShareBufferManager::~FbShareBufferManager() = default;
+
+Result FbShareBufferManager::Initialize(u64* out_buffer_id, u64* out_layer_id, u64 display_id) {
+ std::scoped_lock lk{m_guard};
+
+ // Ensure we have not already created a buffer.
+ R_UNLESS(m_buffer_id == 0, VI::ResultOperationFailed);
+
+ // Allocate memory and space for the shared buffer.
+ Common::ProcessAddress map_address;
+ R_TRY(AllocateIoForProcessAddressSpace(std::addressof(map_address),
+ std::addressof(m_buffer_page_group), m_system,
+ SharedBufferSize));
+
+ // Create an nvmap handle for the buffer and assign the memory to it.
+ R_TRY(AllocateHandleForBuffer(std::addressof(m_buffer_nvmap_handle), *m_nvdrv, map_address,
+ SharedBufferSize));
+
+ // Record the display id.
+ m_display_id = display_id;
+
+ // Create a layer for the display.
+ m_layer_id = m_flinger.CreateLayer(m_display_id).value();
+
+ // Set up the buffer.
+ m_buffer_id = m_next_buffer_id++;
+
+ // Get the layer.
+ VI::Layer* layer = m_flinger.FindLayer(m_display_id, m_layer_id);
+ ASSERT(layer != nullptr);
+
+ // Get the producer and set preallocated buffers.
+ auto& producer = layer->GetBufferQueue();
+ MakeGraphicBuffer(producer, 0, m_buffer_nvmap_handle);
+ MakeGraphicBuffer(producer, 1, m_buffer_nvmap_handle);
+
+ // Assign outputs.
+ *out_buffer_id = m_buffer_id;
+ *out_layer_id = m_layer_id;
+
+ // We succeeded.
+ R_SUCCEED();
+}
+
+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);
+
+ *out_pool_layout = SharedBufferPoolLayout;
+ *out_buffer_size = SharedBufferSize;
+ *out_nvmap_handle = m_buffer_nvmap_handle;
+
+ R_SUCCEED();
+}
+
+Result FbShareBufferManager::GetLayerFromId(VI::Layer** out_layer, u64 layer_id) {
+ // Ensure the layer id is valid.
+ R_UNLESS(m_layer_id > 0 && layer_id == m_layer_id, VI::ResultNotFound);
+
+ // Get the layer.
+ VI::Layer* layer = m_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);
+
+ // 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();
+}
+
+} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h
new file mode 100644
index 000000000..c809c01b4
--- /dev/null
+++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h
@@ -0,0 +1,65 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "common/math_util.h"
+#include "core/hle/service/nvnflinger/nvnflinger.h"
+#include "core/hle/service/nvnflinger/ui/fence.h"
+
+namespace Kernel {
+class KPageGroup;
+}
+
+namespace Service::Nvnflinger {
+
+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");
+
+class FbShareBufferManager final {
+public:
+ explicit FbShareBufferManager(Core::System& system, Nvnflinger& flinger,
+ std::shared_ptr<Nvidia::Module> nvdrv);
+ ~FbShareBufferManager();
+
+ Result Initialize(u64* out_buffer_id, u64* out_layer_handle, u64 display_id);
+ 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);
+
+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;
+ u64 m_layer_id = 0;
+ u32 m_buffer_nvmap_handle = 0;
+ SharedMemoryPoolLayout m_pool_layout = {};
+
+ std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group;
+
+ std::mutex m_guard;
+ Core::System& m_system;
+ Nvnflinger& m_flinger;
+ std::shared_ptr<Nvidia::Module> m_nvdrv;
+};
+
+} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/nvnflinger/graphic_buffer_producer.h b/src/core/hle/service/nvnflinger/graphic_buffer_producer.h
index 21d7b31f3..5d7cff7d3 100644
--- a/src/core/hle/service/nvnflinger/graphic_buffer_producer.h
+++ b/src/core/hle/service/nvnflinger/graphic_buffer_producer.h
@@ -19,6 +19,7 @@ class InputParcel;
#pragma pack(push, 1)
struct QueueBufferInput final {
explicit QueueBufferInput(InputParcel& parcel);
+ explicit QueueBufferInput() = default;
void Deflate(s64* timestamp_, bool* is_auto_timestamp_, Common::Rectangle<s32>* crop_,
NativeWindowScalingMode* scaling_mode_, NativeWindowTransform* transform_,
@@ -34,7 +35,6 @@ struct QueueBufferInput final {
*fence_ = fence;
}
-private:
s64 timestamp{};
s32 is_auto_timestamp{};
Common::Rectangle<s32> crop{};
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp
index 21f31f7a0..a07c621d9 100644
--- a/src/core/hle/service/nvnflinger/nvnflinger.cpp
+++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp
@@ -17,6 +17,7 @@
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
#include "core/hle/service/nvnflinger/buffer_queue_core.h"
+#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
#include "core/hle/service/nvnflinger/nvnflinger.h"
#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
@@ -331,4 +332,14 @@ s64 Nvnflinger::GetNextTicks() const {
return static_cast<s64>(speed_scale * (1000000000.f / effective_fps));
}
+FbShareBufferManager& Nvnflinger::GetSystemBufferManager() {
+ const auto lock_guard = Lock();
+
+ if (!system_buffer_manager) {
+ system_buffer_manager = std::make_unique<FbShareBufferManager>(system, *this, nvdrv);
+ }
+
+ return *system_buffer_manager;
+}
+
} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h
index f478c2bc6..14c783582 100644
--- a/src/core/hle/service/nvnflinger/nvnflinger.h
+++ b/src/core/hle/service/nvnflinger/nvnflinger.h
@@ -45,6 +45,9 @@ class BufferQueueProducer;
namespace Service::Nvnflinger {
+class FbShareBufferManager;
+class HosBinderDriverServer;
+
class Nvnflinger final {
public:
explicit Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_);
@@ -90,12 +93,16 @@ public:
[[nodiscard]] s64 GetNextTicks() const;
+ FbShareBufferManager& GetSystemBufferManager();
+
private:
struct Layer {
std::unique_ptr<android::BufferQueueCore> core;
std::unique_ptr<android::BufferQueueProducer> producer;
};
+ friend class FbShareBufferManager;
+
private:
[[nodiscard]] std::unique_lock<std::mutex> Lock() const {
return std::unique_lock{*guard};
@@ -140,6 +147,8 @@ private:
std::shared_ptr<Core::Timing::EventType> multi_composition_event;
std::shared_ptr<Core::Timing::EventType> single_composition_event;
+ std::unique_ptr<FbShareBufferManager> system_buffer_manager;
+
std::shared_ptr<std::mutex> guard;
Core::System& system;
diff --git a/src/core/hle/service/nvnflinger/ui/fence.h b/src/core/hle/service/nvnflinger/ui/fence.h
index 536e8156d..177aed758 100644
--- a/src/core/hle/service/nvnflinger/ui/fence.h
+++ b/src/core/hle/service/nvnflinger/ui/fence.h
@@ -20,6 +20,9 @@ public:
static constexpr Fence NoFence() {
Fence fence;
fence.fences[0].id = -1;
+ fence.fences[1].id = -1;
+ fence.fences[2].id = -1;
+ fence.fences[3].id = -1;
return fence;
}
diff --git a/src/core/hle/service/nvnflinger/ui/graphic_buffer.h b/src/core/hle/service/nvnflinger/ui/graphic_buffer.h
index 75d1705a8..3eac5cedd 100644
--- a/src/core/hle/service/nvnflinger/ui/graphic_buffer.h
+++ b/src/core/hle/service/nvnflinger/ui/graphic_buffer.h
@@ -12,8 +12,7 @@
namespace Service::android {
-class GraphicBuffer final {
-public:
+struct GraphicBuffer final {
constexpr GraphicBuffer() = default;
constexpr GraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_)
@@ -77,7 +76,6 @@ public:
return false;
}
-private:
u32 magic{};
s32 width{};
s32 height{};
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 2eb978379..b1bfb9898 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -20,9 +20,12 @@
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/nvdrv/devices/nvmap.h"
#include "core/hle/service/nvdrv/nvdata.h"
+#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/nvnflinger/binder.h"
#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
+#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
#include "core/hle/service/nvnflinger/nvnflinger.h"
#include "core/hle/service/nvnflinger/parcel.h"
@@ -131,8 +134,9 @@ private:
class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
public:
- explicit ISystemDisplayService(Core::System& system_)
- : ServiceFramework{system_, "ISystemDisplayService"} {
+ explicit ISystemDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_)
+ : ServiceFramework{system_, "ISystemDisplayService"}, nvnflinger{nvnflinger_} {
+ // clang-format off
static const FunctionInfo functions[] = {
{1200, nullptr, "GetZOrderCountMin"},
{1202, nullptr, "GetZOrderCountMax"},
@@ -170,22 +174,126 @@ public:
{3217, nullptr, "SetDisplayCmuLuma"},
{3218, nullptr, "SetDisplayCrcMode"},
{6013, nullptr, "GetLayerPresentationSubmissionTimestamps"},
- {8225, nullptr, "GetSharedBufferMemoryHandleId"},
- {8250, nullptr, "OpenSharedLayer"},
+ {8225, &ISystemDisplayService::GetSharedBufferMemoryHandleId, "GetSharedBufferMemoryHandleId"},
+ {8250, &ISystemDisplayService::OpenSharedLayer, "OpenSharedLayer"},
{8251, nullptr, "CloseSharedLayer"},
- {8252, nullptr, "ConnectSharedLayer"},
+ {8252, &ISystemDisplayService::ConnectSharedLayer, "ConnectSharedLayer"},
{8253, nullptr, "DisconnectSharedLayer"},
- {8254, nullptr, "AcquireSharedFrameBuffer"},
- {8255, nullptr, "PresentSharedFrameBuffer"},
- {8256, nullptr, "GetSharedFrameBufferAcquirableEvent"},
+ {8254, &ISystemDisplayService::AcquireSharedFrameBuffer, "AcquireSharedFrameBuffer"},
+ {8255, &ISystemDisplayService::PresentSharedFrameBuffer, "PresentSharedFrameBuffer"},
+ {8256, &ISystemDisplayService::GetSharedFrameBufferAcquirableEvent, "GetSharedFrameBufferAcquirableEvent"},
{8257, nullptr, "FillSharedFrameBufferColor"},
{8258, nullptr, "CancelSharedFrameBuffer"},
{9000, nullptr, "GetDp2hdmiController"},
};
+ // clang-format on
RegisterHandlers(functions);
}
private:
+ void GetSharedBufferMemoryHandleId(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const u64 buffer_id = rp.PopRaw<u64>();
+
+ LOG_INFO(Service_VI, "called. buffer_id={:#x}", buffer_id);
+
+ struct OutputParameters {
+ s32 nvmap_handle;
+ u64 size;
+ };
+
+ OutputParameters out{};
+ Nvnflinger::SharedMemoryPoolLayout layout{};
+ const auto result = nvnflinger.GetSystemBufferManager().GetSharedBufferMemoryHandleId(
+ &out.size, &out.nvmap_handle, &layout, buffer_id, 0);
+
+ ctx.WriteBuffer(&layout, sizeof(layout));
+
+ IPC::ResponseBuilder rb{ctx, 6};
+ rb.Push(result);
+ rb.PushRaw(out);
+ }
+
+ void OpenSharedLayer(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const u64 layer_id = rp.PopRaw<u64>();
+
+ LOG_INFO(Service_VI, "(STUBBED) called. layer_id={:#x}", layer_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ void ConnectSharedLayer(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const u64 layer_id = rp.PopRaw<u64>();
+
+ LOG_INFO(Service_VI, "(STUBBED) called. layer_id={:#x}", layer_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ void GetSharedFrameBufferAcquirableEvent(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_VI, "called");
+
+ IPC::RequestParser rp{ctx};
+ const u64 layer_id = rp.PopRaw<u64>();
+
+ Kernel::KReadableEvent* event{};
+ const auto result = nvnflinger.GetSystemBufferManager().GetSharedFrameBufferAcquirableEvent(
+ &event, layer_id);
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(result);
+ rb.PushCopyObjects(event);
+ }
+
+ void AcquireSharedFrameBuffer(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_VI, "called");
+
+ IPC::RequestParser rp{ctx};
+ const u64 layer_id = rp.PopRaw<u64>();
+
+ struct OutputParameters {
+ android::Fence fence;
+ std::array<s32, 4> slots;
+ s64 target_slot;
+ };
+ static_assert(sizeof(OutputParameters) == 0x40, "OutputParameters has wrong size");
+
+ OutputParameters out{};
+ const auto result = nvnflinger.GetSystemBufferManager().AcquireSharedFrameBuffer(
+ &out.fence, out.slots, &out.target_slot, layer_id);
+
+ IPC::ResponseBuilder rb{ctx, 18};
+ rb.Push(result);
+ rb.PushRaw(out);
+ }
+
+ void PresentSharedFrameBuffer(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_VI, "called");
+
+ struct InputParameters {
+ android::Fence fence;
+ Common::Rectangle<s32> crop_region;
+ u32 window_transform;
+ s32 swap_interval;
+ u64 layer_id;
+ s64 surface_id;
+ };
+ static_assert(sizeof(InputParameters) == 0x50, "InputParameters has wrong size");
+
+ IPC::RequestParser rp{ctx};
+ auto input = rp.PopRaw<InputParameters>();
+
+ const auto result = nvnflinger.GetSystemBufferManager().PresentSharedFrameBuffer(
+ input.fence, input.crop_region, input.window_transform, input.swap_interval,
+ input.layer_id, input.surface_id);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ }
+
void SetLayerZ(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 layer_id = rp.Pop<u64>();
@@ -228,6 +336,9 @@ private:
rb.PushRaw<float>(60.0f); // This wouldn't seem to be correct for 30 fps games.
rb.Push<u32>(0);
}
+
+private:
+ Nvnflinger::Nvnflinger& nvnflinger;
};
class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
@@ -453,7 +564,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
- rb.PushIpcInterface<ISystemDisplayService>(system);
+ rb.PushIpcInterface<ISystemDisplayService>(system, nv_flinger);
}
void GetManagerDisplayService(HLERequestContext& ctx) {