summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Narr the Reg2023-09-28 23:45:49 -0600
committerGravatar Narr the Reg2023-10-01 11:38:30 -0600
commit35f25882e027fd3c466edd44db1fc1c5bec75bde (patch)
tree8f7be0d40cc8ebb2bbbb8fec4113293bc72f5071
parentservice: ldn: Implement lp2p:m and stub IMonitorService (diff)
downloadyuzu-35f25882e027fd3c466edd44db1fc1c5bec75bde.tar.gz
yuzu-35f25882e027fd3c466edd44db1fc1c5bec75bde.tar.xz
yuzu-35f25882e027fd3c466edd44db1fc1c5bec75bde.zip
service: nvnflinger: Implement shared buffer
Co-authored-by: Liam <byteslice@airmail.cc>
-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
698 hle/service/nvnflinger/consumer_base.cpp 698 hle/service/nvnflinger/consumer_base.cpp
699 hle/service/nvnflinger/consumer_base.h 699 hle/service/nvnflinger/consumer_base.h
700 hle/service/nvnflinger/consumer_listener.h 700 hle/service/nvnflinger/consumer_listener.h
701 hle/service/nvnflinger/fb_share_buffer_manager.cpp
702 hle/service/nvnflinger/fb_share_buffer_manager.h
701 hle/service/nvnflinger/graphic_buffer_producer.cpp 703 hle/service/nvnflinger/graphic_buffer_producer.cpp
702 hle/service/nvnflinger/graphic_buffer_producer.h 704 hle/service/nvnflinger/graphic_buffer_producer.h
703 hle/service/nvnflinger/hos_binder_driver_server.cpp 705 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:
45 IsSharedMemMapped = 6 45 IsSharedMemMapped = 6
46 }; 46 };
47 47
48private:
49 /// Id to use for the next handle that is created.
50 u32 next_handle = 0;
51
52 /// Id to use for the next object that is created.
53 u32 next_id = 0;
54
55 struct IocCreateParams { 48 struct IocCreateParams {
56 // Input 49 // Input
57 u32_le size{}; 50 u32_le size{};
@@ -113,6 +106,13 @@ private:
113 NvResult IocParam(std::span<const u8> input, std::span<u8> output); 106 NvResult IocParam(std::span<const u8> input, std::span<u8> output);
114 NvResult IocFree(std::span<const u8> input, std::span<u8> output); 107 NvResult IocFree(std::span<const u8> input, std::span<u8> output);
115 108
109private:
110 /// Id to use for the next handle that is created.
111 u32 next_handle = 0;
112
113 /// Id to use for the next object that is created.
114 u32 next_id = 0;
115
116 NvCore::Container& container; 116 NvCore::Container& container;
117 NvCore::NvMap& file; 117 NvCore::NvMap& file;
118}; 118};
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 @@
15 15
16namespace Service::android { 16namespace Service::android {
17 17
18class GraphicBuffer; 18struct GraphicBuffer;
19 19
20class BufferItem final { 20class BufferItem final {
21public: 21public:
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 @@
13 13
14namespace Service::android { 14namespace Service::android {
15 15
16class GraphicBuffer; 16struct GraphicBuffer;
17 17
18enum class BufferState : u32 { 18enum class BufferState : u32 {
19 Free = 0, 19 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 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <random>
5
6#include "core/core.h"
7#include "core/hle/kernel/k_process.h"
8#include "core/hle/kernel/k_system_resource.h"
9#include "core/hle/service/nvdrv/devices/nvmap.h"
10#include "core/hle/service/nvdrv/nvdrv.h"
11#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
12#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
13#include "core/hle/service/nvnflinger/pixel_format.h"
14#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
15#include "core/hle/service/vi/layer/vi_layer.h"
16#include "core/hle/service/vi/vi_results.h"
17
18namespace Service::Nvnflinger {
19
20namespace {
21
22Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address,
23 std::unique_ptr<Kernel::KPageGroup>* out_page_group,
24 Core::System& system, u32 size) {
25 using Core::Memory::YUZU_PAGESIZE;
26
27 // Allocate memory for the system shared buffer.
28 // FIXME: Because the gmmu can only point to cpu addresses, we need
29 // to map this in the application space to allow it to be used.
30 // FIXME: Add proper smmu emulation.
31 // FIXME: This memory belongs to vi's .data section.
32 auto& kernel = system.Kernel();
33 auto* process = system.ApplicationProcess();
34 auto& page_table = process->GetPageTable();
35
36 // Hold a temporary page group reference while we try to map it.
37 auto pg = std::make_unique<Kernel::KPageGroup>(
38 kernel, std::addressof(kernel.GetSystemSystemResource().GetBlockInfoManager()));
39
40 // Allocate memory from secure pool.
41 R_TRY(kernel.MemoryManager().AllocateAndOpen(
42 pg.get(), size / YUZU_PAGESIZE,
43 Kernel::KMemoryManager::EncodeOption(Kernel::KMemoryManager::Pool::Secure,
44 Kernel::KMemoryManager::Direction::FromBack)));
45
46 // Get bounds of where mapping is possible.
47 const VAddr alias_code_begin = GetInteger(page_table.GetAliasCodeRegionStart());
48 const VAddr alias_code_size = page_table.GetAliasCodeRegionSize() / YUZU_PAGESIZE;
49 const auto state = Kernel::KMemoryState::Io;
50 const auto perm = Kernel::KMemoryPermission::UserReadWrite;
51 std::mt19937_64 rng{process->GetRandomEntropy(0)};
52
53 // Retry up to 64 times to map into alias code range.
54 Result res = ResultSuccess;
55 int i;
56 for (i = 0; i < 64; i++) {
57 *out_map_address = alias_code_begin + ((rng() % alias_code_size) * YUZU_PAGESIZE);
58 res = page_table.MapPageGroup(*out_map_address, *pg, state, perm);
59 if (R_SUCCEEDED(res)) {
60 break;
61 }
62 }
63
64 // Return failure, if necessary
65 R_UNLESS(i < 64, res);
66
67 // Return the mapped page group.
68 *out_page_group = std::move(pg);
69
70 // We succeeded.
71 R_SUCCEED();
72}
73
74template <typename T>
75std::span<u8> SerializeIoc(T& params) {
76 return std::span(reinterpret_cast<u8*>(std::addressof(params)), sizeof(T));
77}
78
79Result CreateNvMapHandle(u32* out_nv_map_handle, Nvidia::Devices::nvmap& nvmap, u32 size) {
80 // Create a handle.
81 Nvidia::Devices::nvmap::IocCreateParams create_in_params{
82 .size = size,
83 .handle = 0,
84 };
85 Nvidia::Devices::nvmap::IocCreateParams create_out_params{};
86 R_UNLESS(nvmap.IocCreate(SerializeIoc(create_in_params), SerializeIoc(create_out_params)) ==
87 Nvidia::NvResult::Success,
88 VI::ResultOperationFailed);
89
90 // Assign the output handle.
91 *out_nv_map_handle = create_out_params.handle;
92
93 // We succeeded.
94 R_SUCCEED();
95}
96
97Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle) {
98 // Free the handle.
99 Nvidia::Devices::nvmap::IocFreeParams free_in_params{
100 .handle = handle,
101 };
102 Nvidia::Devices::nvmap::IocFreeParams free_out_params{};
103 R_UNLESS(nvmap.IocFree(SerializeIoc(free_in_params), SerializeIoc(free_out_params)) ==
104 Nvidia::NvResult::Success,
105 VI::ResultOperationFailed);
106
107 // We succeeded.
108 R_SUCCEED();
109}
110
111Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::ProcessAddress buffer,
112 u32 size) {
113 // Assign the allocated memory to the handle.
114 Nvidia::Devices::nvmap::IocAllocParams alloc_in_params{
115 .handle = handle,
116 .heap_mask = 0,
117 .flags = {},
118 .align = 0,
119 .kind = 0,
120 .address = GetInteger(buffer),
121 };
122 Nvidia::Devices::nvmap::IocAllocParams alloc_out_params{};
123 R_UNLESS(nvmap.IocAlloc(SerializeIoc(alloc_in_params), SerializeIoc(alloc_out_params)) ==
124 Nvidia::NvResult::Success,
125 VI::ResultOperationFailed);
126
127 // We succeeded.
128 R_SUCCEED();
129}
130
131Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv,
132 Common::ProcessAddress buffer, u32 size) {
133 // Get the nvmap device.
134 auto nvmap_fd = nvdrv.Open("/dev/nvmap");
135 auto nvmap = nvdrv.GetDevice<Nvidia::Devices::nvmap>(nvmap_fd);
136 ASSERT(nvmap != nullptr);
137
138 // Create a handle.
139 R_TRY(CreateNvMapHandle(out_handle, *nvmap, size));
140
141 // Ensure we maintain a clean state on failure.
142 ON_RESULT_FAILURE {
143 ASSERT(R_SUCCEEDED(FreeNvMapHandle(*nvmap, *out_handle)));
144 };
145
146 // Assign the allocated memory to the handle.
147 R_RETURN(AllocNvMapHandle(*nvmap, *out_handle, buffer, size));
148}
149
150constexpr auto SharedBufferBlockLinearFormat = android::PixelFormat::Rgba8888;
151constexpr u32 SharedBufferBlockLinearBpp = 4;
152
153constexpr u32 SharedBufferBlockLinearWidth = 1280;
154constexpr u32 SharedBufferBlockLinearHeight = 768;
155constexpr u32 SharedBufferBlockLinearStride =
156 SharedBufferBlockLinearWidth * SharedBufferBlockLinearBpp;
157constexpr u32 SharedBufferNumSlots = 7;
158
159constexpr u32 SharedBufferWidth = 1280;
160constexpr u32 SharedBufferHeight = 720;
161constexpr u32 SharedBufferAsync = false;
162
163constexpr u32 SharedBufferSlotSize =
164 SharedBufferBlockLinearWidth * SharedBufferBlockLinearHeight * SharedBufferBlockLinearBpp;
165constexpr u32 SharedBufferSize = SharedBufferSlotSize * SharedBufferNumSlots;
166
167constexpr SharedMemoryPoolLayout SharedBufferPoolLayout = [] {
168 SharedMemoryPoolLayout layout{};
169 layout.num_slots = SharedBufferNumSlots;
170
171 for (u32 i = 0; i < SharedBufferNumSlots; i++) {
172 layout.slots[i].buffer_offset = i * SharedBufferSlotSize;
173 layout.slots[i].size = SharedBufferSlotSize;
174 layout.slots[i].width = SharedBufferWidth;
175 layout.slots[i].height = SharedBufferHeight;
176 }
177
178 return layout;
179}();
180
181void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 handle) {
182 auto buffer = std::make_shared<android::GraphicBuffer>();
183 buffer->width = SharedBufferWidth;
184 buffer->height = SharedBufferHeight;
185 buffer->stride = SharedBufferBlockLinearStride;
186 buffer->format = SharedBufferBlockLinearFormat;
187 buffer->buffer_id = handle;
188 buffer->offset = slot * SharedBufferSlotSize;
189 ASSERT(producer.SetPreallocatedBuffer(slot, buffer) == android::Status::NoError);
190}
191
192} // namespace
193
194FbShareBufferManager::FbShareBufferManager(Core::System& system, Nvnflinger& flinger,
195 std::shared_ptr<Nvidia::Module> nvdrv)
196 : m_system(system), m_flinger(flinger), m_nvdrv(std::move(nvdrv)) {}
197
198FbShareBufferManager::~FbShareBufferManager() = default;
199
200Result FbShareBufferManager::Initialize(u64* out_buffer_id, u64* out_layer_id, u64 display_id) {
201 std::scoped_lock lk{m_guard};
202
203 // Ensure we have not already created a buffer.
204 R_UNLESS(m_buffer_id == 0, VI::ResultOperationFailed);
205
206 // Allocate memory and space for the shared buffer.
207 Common::ProcessAddress map_address;
208 R_TRY(AllocateIoForProcessAddressSpace(std::addressof(map_address),
209 std::addressof(m_buffer_page_group), m_system,
210 SharedBufferSize));
211
212 // Create an nvmap handle for the buffer and assign the memory to it.
213 R_TRY(AllocateHandleForBuffer(std::addressof(m_buffer_nvmap_handle), *m_nvdrv, map_address,
214 SharedBufferSize));
215
216 // Record the display id.
217 m_display_id = display_id;
218
219 // Create a layer for the display.
220 m_layer_id = m_flinger.CreateLayer(m_display_id).value();
221
222 // Set up the buffer.
223 m_buffer_id = m_next_buffer_id++;
224
225 // Get the layer.
226 VI::Layer* layer = m_flinger.FindLayer(m_display_id, m_layer_id);
227 ASSERT(layer != nullptr);
228
229 // Get the producer and set preallocated buffers.
230 auto& producer = layer->GetBufferQueue();
231 MakeGraphicBuffer(producer, 0, m_buffer_nvmap_handle);
232 MakeGraphicBuffer(producer, 1, m_buffer_nvmap_handle);
233
234 // Assign outputs.
235 *out_buffer_id = m_buffer_id;
236 *out_layer_id = m_layer_id;
237
238 // We succeeded.
239 R_SUCCEED();
240}
241
242Result FbShareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size,
243 s32* out_nvmap_handle,
244 SharedMemoryPoolLayout* out_pool_layout,
245 u64 buffer_id,
246 u64 applet_resource_user_id) {
247 std::scoped_lock lk{m_guard};
248
249 R_UNLESS(m_buffer_id > 0, VI::ResultNotFound);
250 R_UNLESS(buffer_id == m_buffer_id, VI::ResultNotFound);
251
252 *out_pool_layout = SharedBufferPoolLayout;
253 *out_buffer_size = SharedBufferSize;
254 *out_nvmap_handle = m_buffer_nvmap_handle;
255
256 R_SUCCEED();
257}
258
259Result FbShareBufferManager::GetLayerFromId(VI::Layer** out_layer, u64 layer_id) {
260 // Ensure the layer id is valid.
261 R_UNLESS(m_layer_id > 0 && layer_id == m_layer_id, VI::ResultNotFound);
262
263 // Get the layer.
264 VI::Layer* layer = m_flinger.FindLayer(m_display_id, layer_id);
265 R_UNLESS(layer != nullptr, VI::ResultNotFound);
266
267 // We succeeded.
268 *out_layer = layer;
269 R_SUCCEED();
270}
271
272Result FbShareBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence,
273 std::array<s32, 4>& out_slot_indexes,
274 s64* out_target_slot, u64 layer_id) {
275 std::scoped_lock lk{m_guard};
276
277 // Get the layer.
278 VI::Layer* layer;
279 R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id));
280
281 // Get the producer.
282 auto& producer = layer->GetBufferQueue();
283
284 // Get the next buffer from the producer.
285 s32 slot;
286 R_UNLESS(producer.DequeueBuffer(std::addressof(slot), out_fence, SharedBufferAsync != 0,
287 SharedBufferWidth, SharedBufferHeight,
288 SharedBufferBlockLinearFormat, 0) == android::Status::NoError,
289 VI::ResultOperationFailed);
290
291 // Assign remaining outputs.
292 *out_target_slot = slot;
293 out_slot_indexes = {0, 1, -1, -1};
294
295 // We succeeded.
296 R_SUCCEED();
297}
298
299Result FbShareBufferManager::PresentSharedFrameBuffer(android::Fence fence,
300 Common::Rectangle<s32> crop_region,
301 u32 transform, s32 swap_interval,
302 u64 layer_id, s64 slot) {
303 std::scoped_lock lk{m_guard};
304
305 // Get the layer.
306 VI::Layer* layer;
307 R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id));
308
309 // Get the producer.
310 auto& producer = layer->GetBufferQueue();
311
312 // Request to queue the buffer.
313 std::shared_ptr<android::GraphicBuffer> buffer;
314 R_UNLESS(producer.RequestBuffer(static_cast<s32>(slot), std::addressof(buffer)) ==
315 android::Status::NoError,
316 VI::ResultOperationFailed);
317
318 // Queue the buffer to the producer.
319 android::QueueBufferInput input{};
320 android::QueueBufferOutput output{};
321 input.crop = crop_region;
322 input.fence = fence;
323 input.transform = static_cast<android::NativeWindowTransform>(transform);
324 input.swap_interval = swap_interval;
325 R_UNLESS(producer.QueueBuffer(static_cast<s32>(slot), input, std::addressof(output)) ==
326 android::Status::NoError,
327 VI::ResultOperationFailed);
328
329 // We succeeded.
330 R_SUCCEED();
331}
332
333Result FbShareBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event,
334 u64 layer_id) {
335 std::scoped_lock lk{m_guard};
336
337 // Get the layer.
338 VI::Layer* layer;
339 R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id));
340
341 // Get the producer.
342 auto& producer = layer->GetBufferQueue();
343
344 // Set the event.
345 *out_event = std::addressof(producer.GetNativeHandle());
346
347 // We succeeded.
348 R_SUCCEED();
349}
350
351} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/math_util.h"
7#include "core/hle/service/nvnflinger/nvnflinger.h"
8#include "core/hle/service/nvnflinger/ui/fence.h"
9
10namespace Kernel {
11class KPageGroup;
12}
13
14namespace Service::Nvnflinger {
15
16struct SharedMemorySlot {
17 u64 buffer_offset;
18 u64 size;
19 s32 width;
20 s32 height;
21};
22static_assert(sizeof(SharedMemorySlot) == 0x18, "SharedMemorySlot has wrong size");
23
24struct SharedMemoryPoolLayout {
25 s32 num_slots;
26 std::array<SharedMemorySlot, 0x10> slots;
27};
28static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size");
29
30class FbShareBufferManager final {
31public:
32 explicit FbShareBufferManager(Core::System& system, Nvnflinger& flinger,
33 std::shared_ptr<Nvidia::Module> nvdrv);
34 ~FbShareBufferManager();
35
36 Result Initialize(u64* out_buffer_id, u64* out_layer_handle, u64 display_id);
37 Result GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle,
38 SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id,
39 u64 applet_resource_user_id);
40 Result AcquireSharedFrameBuffer(android::Fence* out_fence, std::array<s32, 4>& out_slots,
41 s64* out_target_slot, u64 layer_id);
42 Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region,
43 u32 transform, s32 swap_interval, u64 layer_id, s64 slot);
44 Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id);
45
46private:
47 Result GetLayerFromId(VI::Layer** out_layer, u64 layer_id);
48
49private:
50 u64 m_next_buffer_id = 1;
51 u64 m_display_id = 0;
52 u64 m_buffer_id = 0;
53 u64 m_layer_id = 0;
54 u32 m_buffer_nvmap_handle = 0;
55 SharedMemoryPoolLayout m_pool_layout = {};
56
57 std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group;
58
59 std::mutex m_guard;
60 Core::System& m_system;
61 Nvnflinger& m_flinger;
62 std::shared_ptr<Nvidia::Module> m_nvdrv;
63};
64
65} // 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;
19#pragma pack(push, 1) 19#pragma pack(push, 1)
20struct QueueBufferInput final { 20struct QueueBufferInput final {
21 explicit QueueBufferInput(InputParcel& parcel); 21 explicit QueueBufferInput(InputParcel& parcel);
22 explicit QueueBufferInput() = default;
22 23
23 void Deflate(s64* timestamp_, bool* is_auto_timestamp_, Common::Rectangle<s32>* crop_, 24 void Deflate(s64* timestamp_, bool* is_auto_timestamp_, Common::Rectangle<s32>* crop_,
24 NativeWindowScalingMode* scaling_mode_, NativeWindowTransform* transform_, 25 NativeWindowScalingMode* scaling_mode_, NativeWindowTransform* transform_,
@@ -34,7 +35,6 @@ struct QueueBufferInput final {
34 *fence_ = fence; 35 *fence_ = fence;
35 } 36 }
36 37
37private:
38 s64 timestamp{}; 38 s64 timestamp{};
39 s32 is_auto_timestamp{}; 39 s32 is_auto_timestamp{};
40 Common::Rectangle<s32> crop{}; 40 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 @@
17#include "core/hle/service/nvdrv/nvdrv.h" 17#include "core/hle/service/nvdrv/nvdrv.h"
18#include "core/hle/service/nvnflinger/buffer_item_consumer.h" 18#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
19#include "core/hle/service/nvnflinger/buffer_queue_core.h" 19#include "core/hle/service/nvnflinger/buffer_queue_core.h"
20#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
20#include "core/hle/service/nvnflinger/hos_binder_driver_server.h" 21#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
21#include "core/hle/service/nvnflinger/nvnflinger.h" 22#include "core/hle/service/nvnflinger/nvnflinger.h"
22#include "core/hle/service/nvnflinger/ui/graphic_buffer.h" 23#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
@@ -331,4 +332,14 @@ s64 Nvnflinger::GetNextTicks() const {
331 return static_cast<s64>(speed_scale * (1000000000.f / effective_fps)); 332 return static_cast<s64>(speed_scale * (1000000000.f / effective_fps));
332} 333}
333 334
335FbShareBufferManager& Nvnflinger::GetSystemBufferManager() {
336 const auto lock_guard = Lock();
337
338 if (!system_buffer_manager) {
339 system_buffer_manager = std::make_unique<FbShareBufferManager>(system, *this, nvdrv);
340 }
341
342 return *system_buffer_manager;
343}
344
334} // namespace Service::Nvnflinger 345} // 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;
45 45
46namespace Service::Nvnflinger { 46namespace Service::Nvnflinger {
47 47
48class FbShareBufferManager;
49class HosBinderDriverServer;
50
48class Nvnflinger final { 51class Nvnflinger final {
49public: 52public:
50 explicit Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_); 53 explicit Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_);
@@ -90,12 +93,16 @@ public:
90 93
91 [[nodiscard]] s64 GetNextTicks() const; 94 [[nodiscard]] s64 GetNextTicks() const;
92 95
96 FbShareBufferManager& GetSystemBufferManager();
97
93private: 98private:
94 struct Layer { 99 struct Layer {
95 std::unique_ptr<android::BufferQueueCore> core; 100 std::unique_ptr<android::BufferQueueCore> core;
96 std::unique_ptr<android::BufferQueueProducer> producer; 101 std::unique_ptr<android::BufferQueueProducer> producer;
97 }; 102 };
98 103
104 friend class FbShareBufferManager;
105
99private: 106private:
100 [[nodiscard]] std::unique_lock<std::mutex> Lock() const { 107 [[nodiscard]] std::unique_lock<std::mutex> Lock() const {
101 return std::unique_lock{*guard}; 108 return std::unique_lock{*guard};
@@ -140,6 +147,8 @@ private:
140 std::shared_ptr<Core::Timing::EventType> multi_composition_event; 147 std::shared_ptr<Core::Timing::EventType> multi_composition_event;
141 std::shared_ptr<Core::Timing::EventType> single_composition_event; 148 std::shared_ptr<Core::Timing::EventType> single_composition_event;
142 149
150 std::unique_ptr<FbShareBufferManager> system_buffer_manager;
151
143 std::shared_ptr<std::mutex> guard; 152 std::shared_ptr<std::mutex> guard;
144 153
145 Core::System& system; 154 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:
20 static constexpr Fence NoFence() { 20 static constexpr Fence NoFence() {
21 Fence fence; 21 Fence fence;
22 fence.fences[0].id = -1; 22 fence.fences[0].id = -1;
23 fence.fences[1].id = -1;
24 fence.fences[2].id = -1;
25 fence.fences[3].id = -1;
23 return fence; 26 return fence;
24 } 27 }
25 28
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 @@
12 12
13namespace Service::android { 13namespace Service::android {
14 14
15class GraphicBuffer final { 15struct GraphicBuffer final {
16public:
17 constexpr GraphicBuffer() = default; 16 constexpr GraphicBuffer() = default;
18 17
19 constexpr GraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_) 18 constexpr GraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_)
@@ -77,7 +76,6 @@ public:
77 return false; 76 return false;
78 } 77 }
79 78
80private:
81 u32 magic{}; 79 u32 magic{};
82 s32 width{}; 80 s32 width{};
83 s32 height{}; 81 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 @@
20#include "core/hle/kernel/k_readable_event.h" 20#include "core/hle/kernel/k_readable_event.h"
21#include "core/hle/kernel/k_thread.h" 21#include "core/hle/kernel/k_thread.h"
22#include "core/hle/service/ipc_helpers.h" 22#include "core/hle/service/ipc_helpers.h"
23#include "core/hle/service/nvdrv/devices/nvmap.h"
23#include "core/hle/service/nvdrv/nvdata.h" 24#include "core/hle/service/nvdrv/nvdata.h"
25#include "core/hle/service/nvdrv/nvdrv.h"
24#include "core/hle/service/nvnflinger/binder.h" 26#include "core/hle/service/nvnflinger/binder.h"
25#include "core/hle/service/nvnflinger/buffer_queue_producer.h" 27#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
28#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
26#include "core/hle/service/nvnflinger/hos_binder_driver_server.h" 29#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
27#include "core/hle/service/nvnflinger/nvnflinger.h" 30#include "core/hle/service/nvnflinger/nvnflinger.h"
28#include "core/hle/service/nvnflinger/parcel.h" 31#include "core/hle/service/nvnflinger/parcel.h"
@@ -131,8 +134,9 @@ private:
131 134
132class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> { 135class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
133public: 136public:
134 explicit ISystemDisplayService(Core::System& system_) 137 explicit ISystemDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_)
135 : ServiceFramework{system_, "ISystemDisplayService"} { 138 : ServiceFramework{system_, "ISystemDisplayService"}, nvnflinger{nvnflinger_} {
139 // clang-format off
136 static const FunctionInfo functions[] = { 140 static const FunctionInfo functions[] = {
137 {1200, nullptr, "GetZOrderCountMin"}, 141 {1200, nullptr, "GetZOrderCountMin"},
138 {1202, nullptr, "GetZOrderCountMax"}, 142 {1202, nullptr, "GetZOrderCountMax"},
@@ -170,22 +174,126 @@ public:
170 {3217, nullptr, "SetDisplayCmuLuma"}, 174 {3217, nullptr, "SetDisplayCmuLuma"},
171 {3218, nullptr, "SetDisplayCrcMode"}, 175 {3218, nullptr, "SetDisplayCrcMode"},
172 {6013, nullptr, "GetLayerPresentationSubmissionTimestamps"}, 176 {6013, nullptr, "GetLayerPresentationSubmissionTimestamps"},
173 {8225, nullptr, "GetSharedBufferMemoryHandleId"}, 177 {8225, &ISystemDisplayService::GetSharedBufferMemoryHandleId, "GetSharedBufferMemoryHandleId"},
174 {8250, nullptr, "OpenSharedLayer"}, 178 {8250, &ISystemDisplayService::OpenSharedLayer, "OpenSharedLayer"},
175 {8251, nullptr, "CloseSharedLayer"}, 179 {8251, nullptr, "CloseSharedLayer"},
176 {8252, nullptr, "ConnectSharedLayer"}, 180 {8252, &ISystemDisplayService::ConnectSharedLayer, "ConnectSharedLayer"},
177 {8253, nullptr, "DisconnectSharedLayer"}, 181 {8253, nullptr, "DisconnectSharedLayer"},
178 {8254, nullptr, "AcquireSharedFrameBuffer"}, 182 {8254, &ISystemDisplayService::AcquireSharedFrameBuffer, "AcquireSharedFrameBuffer"},
179 {8255, nullptr, "PresentSharedFrameBuffer"}, 183 {8255, &ISystemDisplayService::PresentSharedFrameBuffer, "PresentSharedFrameBuffer"},
180 {8256, nullptr, "GetSharedFrameBufferAcquirableEvent"}, 184 {8256, &ISystemDisplayService::GetSharedFrameBufferAcquirableEvent, "GetSharedFrameBufferAcquirableEvent"},
181 {8257, nullptr, "FillSharedFrameBufferColor"}, 185 {8257, nullptr, "FillSharedFrameBufferColor"},
182 {8258, nullptr, "CancelSharedFrameBuffer"}, 186 {8258, nullptr, "CancelSharedFrameBuffer"},
183 {9000, nullptr, "GetDp2hdmiController"}, 187 {9000, nullptr, "GetDp2hdmiController"},
184 }; 188 };
189 // clang-format on
185 RegisterHandlers(functions); 190 RegisterHandlers(functions);
186 } 191 }
187 192
188private: 193private:
194 void GetSharedBufferMemoryHandleId(HLERequestContext& ctx) {
195 IPC::RequestParser rp{ctx};
196 const u64 buffer_id = rp.PopRaw<u64>();
197
198 LOG_INFO(Service_VI, "called. buffer_id={:#x}", buffer_id);
199
200 struct OutputParameters {
201 s32 nvmap_handle;
202 u64 size;
203 };
204
205 OutputParameters out{};
206 Nvnflinger::SharedMemoryPoolLayout layout{};
207 const auto result = nvnflinger.GetSystemBufferManager().GetSharedBufferMemoryHandleId(
208 &out.size, &out.nvmap_handle, &layout, buffer_id, 0);
209
210 ctx.WriteBuffer(&layout, sizeof(layout));
211
212 IPC::ResponseBuilder rb{ctx, 6};
213 rb.Push(result);
214 rb.PushRaw(out);
215 }
216
217 void OpenSharedLayer(HLERequestContext& ctx) {
218 IPC::RequestParser rp{ctx};
219 const u64 layer_id = rp.PopRaw<u64>();
220
221 LOG_INFO(Service_VI, "(STUBBED) called. layer_id={:#x}", layer_id);
222
223 IPC::ResponseBuilder rb{ctx, 2};
224 rb.Push(ResultSuccess);
225 }
226
227 void ConnectSharedLayer(HLERequestContext& ctx) {
228 IPC::RequestParser rp{ctx};
229 const u64 layer_id = rp.PopRaw<u64>();
230
231 LOG_INFO(Service_VI, "(STUBBED) called. layer_id={:#x}", layer_id);
232
233 IPC::ResponseBuilder rb{ctx, 2};
234 rb.Push(ResultSuccess);
235 }
236
237 void GetSharedFrameBufferAcquirableEvent(HLERequestContext& ctx) {
238 LOG_DEBUG(Service_VI, "called");
239
240 IPC::RequestParser rp{ctx};
241 const u64 layer_id = rp.PopRaw<u64>();
242
243 Kernel::KReadableEvent* event{};
244 const auto result = nvnflinger.GetSystemBufferManager().GetSharedFrameBufferAcquirableEvent(
245 &event, layer_id);
246
247 IPC::ResponseBuilder rb{ctx, 2, 1};
248 rb.Push(result);
249 rb.PushCopyObjects(event);
250 }
251
252 void AcquireSharedFrameBuffer(HLERequestContext& ctx) {
253 LOG_DEBUG(Service_VI, "called");
254
255 IPC::RequestParser rp{ctx};
256 const u64 layer_id = rp.PopRaw<u64>();
257
258 struct OutputParameters {
259 android::Fence fence;
260 std::array<s32, 4> slots;
261 s64 target_slot;
262 };
263 static_assert(sizeof(OutputParameters) == 0x40, "OutputParameters has wrong size");
264
265 OutputParameters out{};
266 const auto result = nvnflinger.GetSystemBufferManager().AcquireSharedFrameBuffer(
267 &out.fence, out.slots, &out.target_slot, layer_id);
268
269 IPC::ResponseBuilder rb{ctx, 18};
270 rb.Push(result);
271 rb.PushRaw(out);
272 }
273
274 void PresentSharedFrameBuffer(HLERequestContext& ctx) {
275 LOG_DEBUG(Service_VI, "called");
276
277 struct InputParameters {
278 android::Fence fence;
279 Common::Rectangle<s32> crop_region;
280 u32 window_transform;
281 s32 swap_interval;
282 u64 layer_id;
283 s64 surface_id;
284 };
285 static_assert(sizeof(InputParameters) == 0x50, "InputParameters has wrong size");
286
287 IPC::RequestParser rp{ctx};
288 auto input = rp.PopRaw<InputParameters>();
289
290 const auto result = nvnflinger.GetSystemBufferManager().PresentSharedFrameBuffer(
291 input.fence, input.crop_region, input.window_transform, input.swap_interval,
292 input.layer_id, input.surface_id);
293 IPC::ResponseBuilder rb{ctx, 2};
294 rb.Push(result);
295 }
296
189 void SetLayerZ(HLERequestContext& ctx) { 297 void SetLayerZ(HLERequestContext& ctx) {
190 IPC::RequestParser rp{ctx}; 298 IPC::RequestParser rp{ctx};
191 const u64 layer_id = rp.Pop<u64>(); 299 const u64 layer_id = rp.Pop<u64>();
@@ -228,6 +336,9 @@ private:
228 rb.PushRaw<float>(60.0f); // This wouldn't seem to be correct for 30 fps games. 336 rb.PushRaw<float>(60.0f); // This wouldn't seem to be correct for 30 fps games.
229 rb.Push<u32>(0); 337 rb.Push<u32>(0);
230 } 338 }
339
340private:
341 Nvnflinger::Nvnflinger& nvnflinger;
231}; 342};
232 343
233class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { 344class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
@@ -453,7 +564,7 @@ private:
453 564
454 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 565 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
455 rb.Push(ResultSuccess); 566 rb.Push(ResultSuccess);
456 rb.PushIpcInterface<ISystemDisplayService>(system); 567 rb.PushIpcInterface<ISystemDisplayService>(system, nv_flinger);
457 } 568 }
458 569
459 void GetManagerDisplayService(HLERequestContext& ctx) { 570 void GetManagerDisplayService(HLERequestContext& ctx) {