summaryrefslogtreecommitdiff
path: root/src/core/hle/service/vi
diff options
context:
space:
mode:
authorGravatar Liam2024-02-14 23:44:05 -0500
committerGravatar Liam2024-02-17 18:08:38 -0500
commit812f23d05c77fb10407546c3e7a95447fcbea395 (patch)
treebbfb035c35ccffb6dbe0995002c2937bd94edc2d /src/core/hle/service/vi
parentvi: move shared buffer management from nvnflinger (diff)
downloadyuzu-812f23d05c77fb10407546c3e7a95447fcbea395.tar.gz
yuzu-812f23d05c77fb10407546c3e7a95447fcbea395.tar.xz
yuzu-812f23d05c77fb10407546c3e7a95447fcbea395.zip
vi: manage resources independently of nvnflinger and refactor
Diffstat (limited to 'src/core/hle/service/vi')
-rw-r--r--src/core/hle/service/vi/application_display_service.cpp118
-rw-r--r--src/core/hle/service/vi/application_display_service.h31
-rw-r--r--src/core/hle/service/vi/application_root_service.cpp13
-rw-r--r--src/core/hle/service/vi/application_root_service.h13
-rw-r--r--src/core/hle/service/vi/conductor.cpp114
-rw-r--r--src/core/hle/service/vi/conductor.h57
-rw-r--r--src/core/hle/service/vi/container.cpp227
-rw-r--r--src/core/hle/service/vi/container.h92
-rw-r--r--src/core/hle/service/vi/display.h44
-rw-r--r--src/core/hle/service/vi/display/vi_display.cpp143
-rw-r--r--src/core/hle/service/vi/display/vi_display.h143
-rw-r--r--src/core/hle/service/vi/display_list.h83
-rw-r--r--src/core/hle/service/vi/layer.h79
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.cpp18
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.h118
-rw-r--r--src/core/hle/service/vi/layer_list.h69
-rw-r--r--src/core/hle/service/vi/manager_display_service.cpp49
-rw-r--r--src/core/hle/service/vi/manager_display_service.h22
-rw-r--r--src/core/hle/service/vi/manager_root_service.cpp13
-rw-r--r--src/core/hle/service/vi/manager_root_service.h13
-rw-r--r--src/core/hle/service/vi/service_creator.cpp5
-rw-r--r--src/core/hle/service/vi/service_creator.h9
-rw-r--r--src/core/hle/service/vi/shared_buffer_manager.cpp (renamed from src/core/hle/service/vi/fbshare_buffer_manager.cpp)132
-rw-r--r--src/core/hle/service/vi/shared_buffer_manager.h (renamed from src/core/hle/service/vi/fbshare_buffer_manager.h)41
-rw-r--r--src/core/hle/service/vi/system_display_service.cpp28
-rw-r--r--src/core/hle/service/vi/system_display_service.h16
-rw-r--r--src/core/hle/service/vi/system_root_service.cpp12
-rw-r--r--src/core/hle/service/vi/system_root_service.h13
-rw-r--r--src/core/hle/service/vi/vi.cpp31
-rw-r--r--src/core/hle/service/vi/vi.h4
-rw-r--r--src/core/hle/service/vi/vi_types.h2
-rw-r--r--src/core/hle/service/vi/vsync_manager.cpp26
-rw-r--r--src/core/hle/service/vi/vsync_manager.h29
33 files changed, 1086 insertions, 721 deletions
diff --git a/src/core/hle/service/vi/application_display_service.cpp b/src/core/hle/service/vi/application_display_service.cpp
index 9c009f902..6b0bcb536 100644
--- a/src/core/hle/service/vi/application_display_service.cpp
+++ b/src/core/hle/service/vi/application_display_service.cpp
@@ -3,23 +3,20 @@
3 3
4#include "core/hle/service/cmif_serialization.h" 4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/nvnflinger/hos_binder_driver.h" 5#include "core/hle/service/nvnflinger/hos_binder_driver.h"
6#include "core/hle/service/nvnflinger/nvnflinger.h"
7#include "core/hle/service/nvnflinger/parcel.h" 6#include "core/hle/service/nvnflinger/parcel.h"
7#include "core/hle/service/os/event.h"
8#include "core/hle/service/vi/application_display_service.h" 8#include "core/hle/service/vi/application_display_service.h"
9#include "core/hle/service/vi/container.h"
9#include "core/hle/service/vi/manager_display_service.h" 10#include "core/hle/service/vi/manager_display_service.h"
10#include "core/hle/service/vi/system_display_service.h" 11#include "core/hle/service/vi/system_display_service.h"
11#include "core/hle/service/vi/vi_results.h" 12#include "core/hle/service/vi/vi_results.h"
12 13
13namespace Service::VI { 14namespace Service::VI {
14 15
15IApplicationDisplayService::IApplicationDisplayService( 16IApplicationDisplayService::IApplicationDisplayService(Core::System& system_,
16 Core::System& system_, std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service, 17 std::shared_ptr<Container> container)
17 std::shared_ptr<FbshareBufferManager> shared_buffer_manager)
18 : ServiceFramework{system_, "IApplicationDisplayService"}, 18 : ServiceFramework{system_, "IApplicationDisplayService"},
19 m_binder_service{std::move(binder_service)}, 19 m_container{std::move(container)}, m_context{system, "IApplicationDisplayService"} {
20 m_surface_flinger{m_binder_service->GetSurfaceFlinger()},
21 m_shared_buffer_manager{std::move(shared_buffer_manager)} {
22
23 // clang-format off 20 // clang-format off
24 static const FunctionInfo functions[] = { 21 static const FunctionInfo functions[] = {
25 {100, C<&IApplicationDisplayService::GetRelayService>, "GetRelayService"}, 22 {100, C<&IApplicationDisplayService::GetRelayService>, "GetRelayService"},
@@ -50,39 +47,41 @@ IApplicationDisplayService::IApplicationDisplayService(
50} 47}
51 48
52IApplicationDisplayService::~IApplicationDisplayService() { 49IApplicationDisplayService::~IApplicationDisplayService() {
50 for (auto& [display_id, event] : m_display_vsync_events) {
51 m_container->UnlinkVsyncEvent(display_id, &event);
52 }
53 for (const auto layer_id : m_open_layer_ids) {
54 m_container->CloseLayer(layer_id);
55 }
53 for (const auto layer_id : m_stray_layer_ids) { 56 for (const auto layer_id : m_stray_layer_ids) {
54 m_surface_flinger->DestroyLayer(layer_id); 57 m_container->DestroyStrayLayer(layer_id);
55 } 58 }
56} 59}
57 60
58Result IApplicationDisplayService::GetRelayService( 61Result IApplicationDisplayService::GetRelayService(
59 Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_relay_service) { 62 Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_relay_service) {
60 LOG_WARNING(Service_VI, "(STUBBED) called"); 63 LOG_WARNING(Service_VI, "(STUBBED) called");
61 *out_relay_service = m_binder_service; 64 R_RETURN(m_container->GetBinderDriver(out_relay_service));
62 R_SUCCEED();
63} 65}
64 66
65Result IApplicationDisplayService::GetSystemDisplayService( 67Result IApplicationDisplayService::GetSystemDisplayService(
66 Out<SharedPointer<ISystemDisplayService>> out_system_display_service) { 68 Out<SharedPointer<ISystemDisplayService>> out_system_display_service) {
67 LOG_WARNING(Service_VI, "(STUBBED) called"); 69 LOG_WARNING(Service_VI, "(STUBBED) called");
68 *out_system_display_service = 70 *out_system_display_service = std::make_shared<ISystemDisplayService>(system, m_container);
69 std::make_shared<ISystemDisplayService>(system, m_surface_flinger, m_shared_buffer_manager);
70 R_SUCCEED(); 71 R_SUCCEED();
71} 72}
72 73
73Result IApplicationDisplayService::GetManagerDisplayService( 74Result IApplicationDisplayService::GetManagerDisplayService(
74 Out<SharedPointer<IManagerDisplayService>> out_manager_display_service) { 75 Out<SharedPointer<IManagerDisplayService>> out_manager_display_service) {
75 LOG_WARNING(Service_VI, "(STUBBED) called"); 76 LOG_WARNING(Service_VI, "(STUBBED) called");
76 *out_manager_display_service = 77 *out_manager_display_service = std::make_shared<IManagerDisplayService>(system, m_container);
77 std::make_shared<IManagerDisplayService>(system, m_surface_flinger);
78 R_SUCCEED(); 78 R_SUCCEED();
79} 79}
80 80
81Result IApplicationDisplayService::GetIndirectDisplayTransactionService( 81Result IApplicationDisplayService::GetIndirectDisplayTransactionService(
82 Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_indirect_display_transaction_service) { 82 Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_indirect_display_transaction_service) {
83 LOG_WARNING(Service_VI, "(STUBBED) called"); 83 LOG_WARNING(Service_VI, "(STUBBED) called");
84 *out_indirect_display_transaction_service = m_binder_service; 84 R_RETURN(m_container->GetBinderDriver(out_indirect_display_transaction_service));
85 R_SUCCEED();
86} 85}
87 86
88Result IApplicationDisplayService::OpenDisplay(Out<u64> out_display_id, DisplayName display_name) { 87Result IApplicationDisplayService::OpenDisplay(Out<u64> out_display_id, DisplayName display_name) {
@@ -92,14 +91,7 @@ Result IApplicationDisplayService::OpenDisplay(Out<u64> out_display_id, DisplayN
92 ASSERT_MSG(strcmp(display_name.data(), "Default") == 0, 91 ASSERT_MSG(strcmp(display_name.data(), "Default") == 0,
93 "Non-default displays aren't supported yet"); 92 "Non-default displays aren't supported yet");
94 93
95 const auto display_id = m_surface_flinger->OpenDisplay(display_name.data()); 94 R_RETURN(m_container->OpenDisplay(out_display_id, display_name));
96 if (!display_id) {
97 LOG_ERROR(Service_VI, "Display not found! display_name={}", display_name.data());
98 R_THROW(VI::ResultNotFound);
99 }
100
101 *out_display_id = *display_id;
102 R_SUCCEED();
103} 95}
104 96
105Result IApplicationDisplayService::OpenDefaultDisplay(Out<u64> out_display_id) { 97Result IApplicationDisplayService::OpenDefaultDisplay(Out<u64> out_display_id) {
@@ -109,8 +101,7 @@ Result IApplicationDisplayService::OpenDefaultDisplay(Out<u64> out_display_id) {
109 101
110Result IApplicationDisplayService::CloseDisplay(u64 display_id) { 102Result IApplicationDisplayService::CloseDisplay(u64 display_id) {
111 LOG_DEBUG(Service_VI, "called"); 103 LOG_DEBUG(Service_VI, "called");
112 R_SUCCEED_IF(m_surface_flinger->CloseDisplay(display_id)); 104 R_RETURN(m_container->CloseDisplay(display_id));
113 R_THROW(ResultUnknown);
114} 105}
115 106
116Result IApplicationDisplayService::SetDisplayEnabled(u32 state, u64 display_id) { 107Result IApplicationDisplayService::SetDisplayEnabled(u32 state, u64 display_id) {
@@ -171,25 +162,19 @@ Result IApplicationDisplayService::OpenLayer(Out<u64> out_size,
171 162
172 LOG_DEBUG(Service_VI, "called. layer_id={}, aruid={:#x}", layer_id, aruid.pid); 163 LOG_DEBUG(Service_VI, "called. layer_id={}, aruid={:#x}", layer_id, aruid.pid);
173 164
174 const auto display_id = m_surface_flinger->OpenDisplay(display_name.data()); 165 u64 display_id;
175 if (!display_id) { 166 R_TRY(m_container->OpenDisplay(&display_id, display_name));
176 LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id);
177 R_THROW(VI::ResultNotFound);
178 }
179 167
180 const auto buffer_queue_id = m_surface_flinger->FindBufferQueueId(*display_id, layer_id); 168 s32 producer_binder_id;
181 if (!buffer_queue_id) { 169 R_TRY(m_container->OpenLayer(&producer_binder_id, layer_id, aruid.pid));
182 LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id);
183 R_THROW(VI::ResultNotFound);
184 }
185 170
186 if (!m_surface_flinger->OpenLayer(layer_id)) { 171 {
187 LOG_WARNING(Service_VI, "Tried to open layer which was already open"); 172 std::scoped_lock lk{m_lock};
188 R_THROW(VI::ResultOperationFailed); 173 m_open_layer_ids.insert(layer_id);
189 } 174 }
190 175
191 android::OutputParcel parcel; 176 android::OutputParcel parcel;
192 parcel.WriteInterface(NativeWindow{*buffer_queue_id}); 177 parcel.WriteInterface(NativeWindow{producer_binder_id});
193 178
194 const auto buffer = parcel.Serialize(); 179 const auto buffer = parcel.Serialize();
195 std::memcpy(out_native_window.data(), buffer.data(), 180 std::memcpy(out_native_window.data(), buffer.data(),
@@ -202,12 +187,13 @@ Result IApplicationDisplayService::OpenLayer(Out<u64> out_size,
202Result IApplicationDisplayService::CloseLayer(u64 layer_id) { 187Result IApplicationDisplayService::CloseLayer(u64 layer_id) {
203 LOG_DEBUG(Service_VI, "called. layer_id={}", layer_id); 188 LOG_DEBUG(Service_VI, "called. layer_id={}", layer_id);
204 189
205 if (!m_surface_flinger->CloseLayer(layer_id)) { 190 {
206 LOG_WARNING(Service_VI, "Tried to close layer which was not open"); 191 std::scoped_lock lk{m_lock};
207 R_THROW(VI::ResultOperationFailed); 192 R_UNLESS(m_open_layer_ids.contains(layer_id), VI::ResultNotFound);
193 m_open_layer_ids.erase(layer_id);
208 } 194 }
209 195
210 R_SUCCEED(); 196 R_RETURN(m_container->CloseLayer(layer_id));
211} 197}
212 198
213Result IApplicationDisplayService::CreateStrayLayer( 199Result IApplicationDisplayService::CreateStrayLayer(
@@ -215,27 +201,19 @@ Result IApplicationDisplayService::CreateStrayLayer(
215 u32 flags, u64 display_id) { 201 u32 flags, u64 display_id) {
216 LOG_DEBUG(Service_VI, "called. flags={}, display_id={}", flags, display_id); 202 LOG_DEBUG(Service_VI, "called. flags={}, display_id={}", flags, display_id);
217 203
218 const auto layer_id = m_surface_flinger->CreateLayer(display_id); 204 s32 producer_binder_id;
219 if (!layer_id) { 205 R_TRY(m_container->CreateStrayLayer(&producer_binder_id, out_layer_id, display_id));
220 LOG_ERROR(Service_VI, "Layer not found! display_id={}", display_id);
221 R_THROW(VI::ResultNotFound);
222 }
223 206
224 m_stray_layer_ids.push_back(*layer_id); 207 std::scoped_lock lk{m_lock};
225 const auto buffer_queue_id = m_surface_flinger->FindBufferQueueId(display_id, *layer_id); 208 m_stray_layer_ids.insert(*out_layer_id);
226 if (!buffer_queue_id) {
227 LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id);
228 R_THROW(VI::ResultNotFound);
229 }
230 209
231 android::OutputParcel parcel; 210 android::OutputParcel parcel;
232 parcel.WriteInterface(NativeWindow{*buffer_queue_id}); 211 parcel.WriteInterface(NativeWindow{producer_binder_id});
233 212
234 const auto buffer = parcel.Serialize(); 213 const auto buffer = parcel.Serialize();
235 std::memcpy(out_native_window.data(), buffer.data(), 214 std::memcpy(out_native_window.data(), buffer.data(),
236 std::min(out_native_window.size(), buffer.size())); 215 std::min(out_native_window.size(), buffer.size()));
237 216
238 *out_layer_id = *layer_id;
239 *out_size = buffer.size(); 217 *out_size = buffer.size();
240 218
241 R_SUCCEED(); 219 R_SUCCEED();
@@ -243,25 +221,27 @@ Result IApplicationDisplayService::CreateStrayLayer(
243 221
244Result IApplicationDisplayService::DestroyStrayLayer(u64 layer_id) { 222Result IApplicationDisplayService::DestroyStrayLayer(u64 layer_id) {
245 LOG_WARNING(Service_VI, "(STUBBED) called. layer_id={}", layer_id); 223 LOG_WARNING(Service_VI, "(STUBBED) called. layer_id={}", layer_id);
246 m_surface_flinger->DestroyLayer(layer_id); 224
247 R_SUCCEED(); 225 {
226 std::scoped_lock lk{m_lock};
227 R_UNLESS(m_stray_layer_ids.contains(layer_id), VI::ResultNotFound);
228 m_stray_layer_ids.erase(layer_id);
229 }
230
231 R_RETURN(m_container->DestroyStrayLayer(layer_id));
248} 232}
249 233
250Result IApplicationDisplayService::GetDisplayVsyncEvent( 234Result IApplicationDisplayService::GetDisplayVsyncEvent(
251 OutCopyHandle<Kernel::KReadableEvent> out_vsync_event, u64 display_id) { 235 OutCopyHandle<Kernel::KReadableEvent> out_vsync_event, u64 display_id) {
252 LOG_DEBUG(Service_VI, "called. display_id={}", display_id); 236 LOG_DEBUG(Service_VI, "called. display_id={}", display_id);
253 237
254 const auto result = m_surface_flinger->FindVsyncEvent(out_vsync_event, display_id); 238 std::scoped_lock lk{m_lock};
255 if (result != ResultSuccess) {
256 if (result == ResultNotFound) {
257 LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id);
258 }
259 239
260 R_THROW(result); 240 auto [it, created] = m_display_vsync_events.emplace(display_id, m_context);
261 } 241 R_UNLESS(created, VI::ResultPermissionDenied);
262 242
263 R_UNLESS(!m_vsync_event_fetched, VI::ResultPermissionDenied); 243 m_container->LinkVsyncEvent(display_id, &it->second);
264 m_vsync_event_fetched = true; 244 *out_vsync_event = it->second.GetHandle();
265 245
266 R_SUCCEED(); 246 R_SUCCEED();
267} 247}
diff --git a/src/core/hle/service/vi/application_display_service.h b/src/core/hle/service/vi/application_display_service.h
index 5022b2f63..1bdeb8f84 100644
--- a/src/core/hle/service/vi/application_display_service.h
+++ b/src/core/hle/service/vi/application_display_service.h
@@ -1,7 +1,12 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <map>
5#include <set>
6
4#include "core/hle/service/cmif_types.h" 7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/os/event.h"
5#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
6#include "core/hle/service/vi/vi_types.h" 11#include "core/hle/service/vi/vi_types.h"
7 12
@@ -10,28 +15,25 @@ class KReadableEvent;
10} 15}
11 16
12namespace Service::Nvnflinger { 17namespace Service::Nvnflinger {
13class Nvnflinger;
14class IHOSBinderDriver; 18class IHOSBinderDriver;
15} // namespace Service::Nvnflinger 19}
16 20
17namespace Service::VI { 21namespace Service::VI {
18 22
19class FbshareBufferManager; 23class Container;
20class IManagerDisplayService; 24class IManagerDisplayService;
21class ISystemDisplayService; 25class ISystemDisplayService;
22 26
23class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { 27class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
24public: 28public:
25 IApplicationDisplayService(Core::System& system_, 29 IApplicationDisplayService(Core::System& system_, std::shared_ptr<Container> container);
26 std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
27 std::shared_ptr<FbshareBufferManager> shared_buffer_manager);
28 ~IApplicationDisplayService() override; 30 ~IApplicationDisplayService() override;
29 31
30 std::shared_ptr<FbshareBufferManager> GetSharedBufferManager() const { 32 std::shared_ptr<Container> GetContainer() const {
31 return m_shared_buffer_manager; 33 return m_container;
32 } 34 }
33 35
34private: 36public:
35 Result GetRelayService(Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_relay_service); 37 Result GetRelayService(Out<SharedPointer<Nvnflinger::IHOSBinderDriver>> out_relay_service);
36 Result GetSystemDisplayService( 38 Result GetSystemDisplayService(
37 Out<SharedPointer<ISystemDisplayService>> out_system_display_service); 39 Out<SharedPointer<ISystemDisplayService>> out_system_display_service);
@@ -66,10 +68,13 @@ private:
66 s64 width, s64 height); 68 s64 width, s64 height);
67 69
68private: 70private:
69 const std::shared_ptr<Nvnflinger::IHOSBinderDriver> m_binder_service; 71 const std::shared_ptr<Container> m_container;
70 const std::shared_ptr<Nvnflinger::Nvnflinger> m_surface_flinger; 72
71 const std::shared_ptr<FbshareBufferManager> m_shared_buffer_manager; 73 KernelHelpers::ServiceContext m_context;
72 std::vector<u64> m_stray_layer_ids; 74 std::mutex m_lock{};
75 std::set<u64> m_open_layer_ids{};
76 std::set<u64> m_stray_layer_ids{};
77 std::map<u64, Event> m_display_vsync_events{};
73 bool m_vsync_event_fetched{false}; 78 bool m_vsync_event_fetched{false};
74}; 79};
75 80
diff --git a/src/core/hle/service/vi/application_root_service.cpp b/src/core/hle/service/vi/application_root_service.cpp
index ed8c9b1b3..7f35a048d 100644
--- a/src/core/hle/service/vi/application_root_service.cpp
+++ b/src/core/hle/service/vi/application_root_service.cpp
@@ -4,17 +4,16 @@
4#include "core/hle/service/cmif_serialization.h" 4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/vi/application_display_service.h" 5#include "core/hle/service/vi/application_display_service.h"
6#include "core/hle/service/vi/application_root_service.h" 6#include "core/hle/service/vi/application_root_service.h"
7#include "core/hle/service/vi/container.h"
7#include "core/hle/service/vi/service_creator.h" 8#include "core/hle/service/vi/service_creator.h"
8#include "core/hle/service/vi/vi.h" 9#include "core/hle/service/vi/vi.h"
9#include "core/hle/service/vi/vi_types.h" 10#include "core/hle/service/vi/vi_types.h"
10 11
11namespace Service::VI { 12namespace Service::VI {
12 13
13IApplicationRootService::IApplicationRootService( 14IApplicationRootService::IApplicationRootService(Core::System& system_,
14 Core::System& system_, std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service, 15 std::shared_ptr<Container> container)
15 std::shared_ptr<FbshareBufferManager> shared_buffer_manager) 16 : ServiceFramework{system_, "vi:u"}, m_container{std::move(container)} {
16 : ServiceFramework{system_, "vi:u"}, m_binder_service{std::move(binder_service)},
17 m_shared_buffer_manager{std::move(shared_buffer_manager)} {
18 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
19 {0, C<&IApplicationRootService::GetDisplayService>, "GetDisplayService"}, 18 {0, C<&IApplicationRootService::GetDisplayService>, "GetDisplayService"},
20 {1, nullptr, "GetDisplayServiceWithProxyNameExchange"}, 19 {1, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -27,8 +26,8 @@ IApplicationRootService::~IApplicationRootService() = default;
27Result IApplicationRootService::GetDisplayService( 26Result IApplicationRootService::GetDisplayService(
28 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) { 27 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) {
29 LOG_DEBUG(Service_VI, "called"); 28 LOG_DEBUG(Service_VI, "called");
30 R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_binder_service, 29 R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_container,
31 m_shared_buffer_manager, Permission::User, policy)); 30 Permission::User, policy));
32} 31}
33 32
34} // namespace Service::VI 33} // 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 5970b6e68..15aa4483d 100644
--- a/src/core/hle/service/vi/application_root_service.h
+++ b/src/core/hle/service/vi/application_root_service.h
@@ -10,21 +10,15 @@ namespace Core {
10class System; 10class System;
11} 11}
12 12
13namespace Service::Nvnflinger {
14class IHOSBinderDriver;
15} // namespace Service::Nvnflinger
16
17namespace Service::VI { 13namespace Service::VI {
18 14
19class FbshareBufferManager; 15class Container;
20class IApplicationDisplayService; 16class IApplicationDisplayService;
21enum class Policy : u32; 17enum class Policy : u32;
22 18
23class IApplicationRootService final : public ServiceFramework<IApplicationRootService> { 19class IApplicationRootService final : public ServiceFramework<IApplicationRootService> {
24public: 20public:
25 explicit IApplicationRootService(Core::System& system_, 21 explicit IApplicationRootService(Core::System& system_, std::shared_ptr<Container> container);
26 std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
27 std::shared_ptr<FbshareBufferManager> shared_buffer_manager);
28 ~IApplicationRootService() override; 22 ~IApplicationRootService() override;
29 23
30private: 24private:
@@ -33,8 +27,7 @@ private:
33 Policy policy); 27 Policy policy);
34 28
35private: 29private:
36 const std::shared_ptr<Nvnflinger::IHOSBinderDriver> m_binder_service; 30 const std::shared_ptr<Container> m_container;
37 const std::shared_ptr<FbshareBufferManager> m_shared_buffer_manager;
38}; 31};
39 32
40} // namespace Service::VI 33} // namespace Service::VI
diff --git a/src/core/hle/service/vi/conductor.cpp b/src/core/hle/service/vi/conductor.cpp
new file mode 100644
index 000000000..c8ce4fca0
--- /dev/null
+++ b/src/core/hle/service/vi/conductor.cpp
@@ -0,0 +1,114 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/settings.h"
5#include "core/core.h"
6#include "core/core_timing.h"
7#include "core/hle/service/vi/conductor.h"
8#include "core/hle/service/vi/container.h"
9#include "core/hle/service/vi/display_list.h"
10#include "core/hle/service/vi/vsync_manager.h"
11
12constexpr auto FrameNs = std::chrono::nanoseconds{1000000000 / 60};
13
14namespace Service::VI {
15
16Conductor::Conductor(Core::System& system, Container& container, DisplayList& displays)
17 : m_system(system), m_container(container) {
18 displays.ForEachDisplay([&](Display& display) {
19 m_vsync_managers.insert({display.GetId(), VsyncManager{}});
20 });
21
22 if (system.IsMulticore()) {
23 m_event = Core::Timing::CreateEvent(
24 "ScreenComposition",
25 [this](s64 time,
26 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
27 m_signal.Set();
28 return std::chrono::nanoseconds(this->GetNextTicks());
29 });
30
31 system.CoreTiming().ScheduleLoopingEvent(FrameNs, FrameNs, m_event);
32 m_thread = std::jthread([this](std::stop_token token) { this->VsyncThread(token); });
33 } else {
34 m_event = Core::Timing::CreateEvent(
35 "ScreenComposition",
36 [this](s64 time,
37 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
38 this->ProcessVsync();
39 return std::chrono::nanoseconds(this->GetNextTicks());
40 });
41
42 system.CoreTiming().ScheduleLoopingEvent(FrameNs, FrameNs, m_event);
43 }
44}
45
46Conductor::~Conductor() {
47 m_system.CoreTiming().UnscheduleEvent(m_event);
48
49 if (m_system.IsMulticore()) {
50 m_thread.request_stop();
51 m_signal.Set();
52 }
53}
54
55void Conductor::LinkVsyncEvent(u64 display_id, Event* event) {
56 if (auto it = m_vsync_managers.find(display_id); it != m_vsync_managers.end()) {
57 it->second.LinkVsyncEvent(event);
58 }
59}
60
61void Conductor::UnlinkVsyncEvent(u64 display_id, Event* event) {
62 if (auto it = m_vsync_managers.find(display_id); it != m_vsync_managers.end()) {
63 it->second.UnlinkVsyncEvent(event);
64 }
65}
66
67void Conductor::ProcessVsync() {
68 for (auto& [display_id, manager] : m_vsync_managers) {
69 m_container.ComposeOnDisplay(&m_swap_interval, &m_compose_speed_scale, display_id);
70 manager.SignalVsync();
71 }
72}
73
74void Conductor::VsyncThread(std::stop_token token) {
75 Common::SetCurrentThreadName("VSyncThread");
76
77 while (!token.stop_requested()) {
78 m_signal.Wait();
79
80 if (m_system.IsShuttingDown()) {
81 return;
82 }
83
84 this->ProcessVsync();
85 }
86}
87
88s64 Conductor::GetNextTicks() const {
89 const auto& settings = Settings::values;
90 auto speed_scale = 1.f;
91 if (settings.use_multi_core.GetValue()) {
92 if (settings.use_speed_limit.GetValue()) {
93 // Scales the speed based on speed_limit setting on MC. SC is handled by
94 // SpeedLimiter::DoSpeedLimiting.
95 speed_scale = 100.f / settings.speed_limit.GetValue();
96 } else {
97 // Run at unlocked framerate.
98 speed_scale = 0.01f;
99 }
100 }
101
102 // Adjust by speed limit determined during composition.
103 speed_scale /= m_compose_speed_scale;
104
105 if (m_system.GetNVDECActive() && settings.use_video_framerate.GetValue()) {
106 // Run at intended presentation rate during video playback.
107 speed_scale = 1.f;
108 }
109
110 const f32 effective_fps = 60.f / static_cast<f32>(m_swap_interval);
111 return static_cast<s64>(speed_scale * (1000000000.f / effective_fps));
112}
113
114} // namespace Service::VI
diff --git a/src/core/hle/service/vi/conductor.h b/src/core/hle/service/vi/conductor.h
new file mode 100644
index 000000000..52e3595d2
--- /dev/null
+++ b/src/core/hle/service/vi/conductor.h
@@ -0,0 +1,57 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <unordered_map>
8
9#include "common/common_types.h"
10#include "common/polyfill_thread.h"
11#include "common/thread.h"
12
13namespace Core {
14class System;
15}
16
17namespace Core::Timing {
18struct EventType;
19}
20
21namespace Service {
22class Event;
23}
24
25namespace Service::VI {
26
27class Container;
28class DisplayList;
29class VsyncManager;
30
31class Conductor {
32public:
33 explicit Conductor(Core::System& system, Container& container, DisplayList& displays);
34 ~Conductor();
35
36 void LinkVsyncEvent(u64 display_id, Event* event);
37 void UnlinkVsyncEvent(u64 display_id, Event* event);
38
39private:
40 void ProcessVsync();
41 void VsyncThread(std::stop_token token);
42 s64 GetNextTicks() const;
43
44private:
45 Core::System& m_system;
46 Container& m_container;
47 std::unordered_map<u64, VsyncManager> m_vsync_managers;
48 std::shared_ptr<Core::Timing::EventType> m_event;
49 Common::Event m_signal;
50 std::jthread m_thread;
51
52private:
53 s32 m_swap_interval = 1;
54 f32 m_compose_speed_scale = 1.0f;
55};
56
57} // namespace Service::VI
diff --git a/src/core/hle/service/vi/container.cpp b/src/core/hle/service/vi/container.cpp
new file mode 100644
index 000000000..2d6b9cbfe
--- /dev/null
+++ b/src/core/hle/service/vi/container.cpp
@@ -0,0 +1,227 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/hle/service/nvdrv/nvdrv_interface.h"
6#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
7#include "core/hle/service/nvnflinger/hos_binder_driver.h"
8#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
9#include "core/hle/service/nvnflinger/surface_flinger.h"
10#include "core/hle/service/sm/sm.h"
11#include "core/hle/service/vi/container.h"
12#include "core/hle/service/vi/vi_results.h"
13
14namespace Service::VI {
15
16Container::Container(Core::System& system) {
17 m_displays.CreateDisplay(DisplayName{"Default"});
18 m_displays.CreateDisplay(DisplayName{"External"});
19 m_displays.CreateDisplay(DisplayName{"Edid"});
20 m_displays.CreateDisplay(DisplayName{"Internal"});
21 m_displays.CreateDisplay(DisplayName{"Null"});
22
23 m_binder_driver =
24 system.ServiceManager().GetService<Nvnflinger::IHOSBinderDriver>("dispdrv", true);
25 m_surface_flinger = m_binder_driver->GetSurfaceFlinger();
26
27 const auto nvdrv =
28 system.ServiceManager().GetService<Nvidia::NVDRV>("nvdrv:s", true)->GetModule();
29 m_shared_buffer_manager.emplace(system, *this, nvdrv);
30
31 m_displays.ForEachDisplay(
32 [&](auto& display) { m_surface_flinger->AddDisplay(display.GetId()); });
33
34 m_conductor.emplace(system, *this, m_displays);
35}
36
37Container::~Container() {
38 this->OnTerminate();
39}
40
41void Container::OnTerminate() {
42 std::scoped_lock lk{m_lock};
43
44 m_is_shut_down = true;
45
46 m_layers.ForEachLayer([&](auto& layer) {
47 if (layer.IsOpen()) {
48 this->DestroyBufferQueueLocked(&layer);
49 }
50 });
51
52 m_displays.ForEachDisplay(
53 [&](auto& display) { m_surface_flinger->RemoveDisplay(display.GetId()); });
54}
55
56SharedBufferManager* Container::GetSharedBufferManager() {
57 return std::addressof(*m_shared_buffer_manager);
58}
59
60Result Container::GetBinderDriver(
61 std::shared_ptr<Nvnflinger::IHOSBinderDriver>* out_binder_driver) {
62 *out_binder_driver = m_binder_driver;
63 R_SUCCEED();
64}
65
66Result Container::GetLayerProducerHandle(
67 std::shared_ptr<android::BufferQueueProducer>* out_producer, u64 layer_id) {
68 std::scoped_lock lk{m_lock};
69
70 auto* const layer = m_layers.GetLayerById(layer_id);
71 R_UNLESS(layer != nullptr, VI::ResultNotFound);
72
73 const auto binder = m_binder_driver->GetServer()->TryGetBinder(layer->GetProducerBinderId());
74 R_UNLESS(binder != nullptr, VI::ResultNotFound);
75
76 *out_producer = std::static_pointer_cast<android::BufferQueueProducer>(binder);
77 R_SUCCEED();
78}
79
80Result Container::OpenDisplay(u64* out_display_id, const DisplayName& display_name) {
81 auto* const display = m_displays.GetDisplayByName(display_name);
82 R_UNLESS(display != nullptr, VI::ResultNotFound);
83
84 *out_display_id = display->GetId();
85 R_SUCCEED();
86}
87
88Result Container::CloseDisplay(u64 display_id) {
89 R_SUCCEED();
90}
91
92Result Container::CreateManagedLayer(u64* out_layer_id, u64 display_id, u64 owner_aruid) {
93 std::scoped_lock lk{m_lock};
94 R_RETURN(this->CreateLayerLocked(out_layer_id, display_id, owner_aruid));
95}
96
97Result Container::DestroyManagedLayer(u64 layer_id) {
98 std::scoped_lock lk{m_lock};
99
100 // Try to close, if open, but don't fail if not.
101 this->CloseLayerLocked(layer_id);
102
103 R_RETURN(this->DestroyLayerLocked(layer_id));
104}
105
106Result Container::OpenLayer(s32* out_producer_binder_id, u64 layer_id, u64 aruid) {
107 std::scoped_lock lk{m_lock};
108 R_RETURN(this->OpenLayerLocked(out_producer_binder_id, layer_id, aruid));
109}
110
111Result Container::CloseLayer(u64 layer_id) {
112 std::scoped_lock lk{m_lock};
113 R_RETURN(this->CloseLayerLocked(layer_id));
114}
115
116Result Container::SetLayerVisibility(u64 layer_id, bool visible) {
117 std::scoped_lock lk{m_lock};
118
119 auto* const layer = m_layers.GetLayerById(layer_id);
120 R_UNLESS(layer != nullptr, VI::ResultNotFound);
121
122 m_surface_flinger->SetLayerVisibility(layer->GetConsumerBinderId(), visible);
123 R_SUCCEED();
124}
125
126Result Container::SetLayerBlending(u64 layer_id, bool enabled) {
127 std::scoped_lock lk{m_lock};
128
129 auto* const layer = m_layers.GetLayerById(layer_id);
130 R_UNLESS(layer != nullptr, VI::ResultNotFound);
131
132 m_surface_flinger->SetLayerBlending(layer->GetConsumerBinderId(),
133 enabled ? Nvnflinger::LayerBlending::Coverage
134 : Nvnflinger::LayerBlending::None);
135 R_SUCCEED();
136}
137
138void Container::LinkVsyncEvent(u64 display_id, Event* event) {
139 std::scoped_lock lk{m_lock};
140 m_conductor->LinkVsyncEvent(display_id, event);
141}
142
143void Container::UnlinkVsyncEvent(u64 display_id, Event* event) {
144 std::scoped_lock lk{m_lock};
145 m_conductor->UnlinkVsyncEvent(display_id, event);
146}
147
148Result Container::CreateStrayLayer(s32* out_producer_binder_id, u64* out_layer_id, u64 display_id) {
149 std::scoped_lock lk{m_lock};
150 R_TRY(this->CreateLayerLocked(out_layer_id, display_id, {}));
151 R_RETURN(this->OpenLayerLocked(out_producer_binder_id, *out_layer_id, {}));
152}
153
154Result Container::DestroyStrayLayer(u64 layer_id) {
155 std::scoped_lock lk{m_lock};
156 R_TRY(this->CloseLayerLocked(layer_id));
157 R_RETURN(this->DestroyLayerLocked(layer_id));
158}
159
160Result Container::CreateLayerLocked(u64* out_layer_id, u64 display_id, u64 owner_aruid) {
161 auto* const display = m_displays.GetDisplayById(display_id);
162 R_UNLESS(display != nullptr, VI::ResultNotFound);
163
164 auto* const layer = m_layers.CreateLayer(owner_aruid, display);
165 R_UNLESS(layer != nullptr, VI::ResultNotFound);
166
167 *out_layer_id = layer->GetId();
168 R_SUCCEED();
169}
170
171Result Container::DestroyLayerLocked(u64 layer_id) {
172 R_SUCCEED_IF(m_layers.DestroyLayer(layer_id));
173 R_THROW(VI::ResultNotFound);
174}
175
176Result Container::OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid) {
177 R_UNLESS(!m_is_shut_down, VI::ResultOperationFailed);
178
179 auto* const layer = m_layers.GetLayerById(layer_id);
180 R_UNLESS(layer != nullptr, VI::ResultNotFound);
181 R_UNLESS(!layer->IsOpen(), VI::ResultOperationFailed);
182 R_UNLESS(layer->GetOwnerAruid() == aruid, VI::ResultPermissionDenied);
183
184 this->CreateBufferQueueLocked(layer);
185 *out_producer_binder_id = layer->GetProducerBinderId();
186
187 R_SUCCEED();
188}
189
190Result Container::CloseLayerLocked(u64 layer_id) {
191 auto* const layer = m_layers.GetLayerById(layer_id);
192 R_UNLESS(layer != nullptr, VI::ResultNotFound);
193 R_UNLESS(layer->IsOpen(), VI::ResultOperationFailed);
194
195 this->DestroyBufferQueueLocked(layer);
196
197 R_SUCCEED();
198}
199
200void Container::CreateBufferQueueLocked(Layer* layer) {
201 s32 consumer_binder_id, producer_binder_id;
202 m_surface_flinger->CreateBufferQueue(&consumer_binder_id, &producer_binder_id);
203 layer->Open(consumer_binder_id, producer_binder_id);
204
205 if (auto* display = layer->GetDisplay(); display != nullptr) {
206 m_surface_flinger->AddLayerToDisplayStack(display->GetId(), consumer_binder_id);
207 }
208}
209
210void Container::DestroyBufferQueueLocked(Layer* layer) {
211 if (auto* display = layer->GetDisplay(); display != nullptr) {
212 m_surface_flinger->RemoveLayerFromDisplayStack(display->GetId(),
213 layer->GetConsumerBinderId());
214 }
215
216 layer->Close();
217 m_surface_flinger->DestroyBufferQueue(layer->GetConsumerBinderId(),
218 layer->GetProducerBinderId());
219}
220
221void Container::ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale,
222 u64 display_id) {
223 std::scoped_lock lk{m_lock};
224 m_surface_flinger->ComposeDisplay(out_swap_interval, out_compose_speed_scale, display_id);
225}
226
227} // namespace Service::VI
diff --git a/src/core/hle/service/vi/container.h b/src/core/hle/service/vi/container.h
new file mode 100644
index 000000000..155c4c629
--- /dev/null
+++ b/src/core/hle/service/vi/container.h
@@ -0,0 +1,92 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <mutex>
8#include <optional>
9
10#include "core/hle/service/vi/conductor.h"
11#include "core/hle/service/vi/display_list.h"
12#include "core/hle/service/vi/layer_list.h"
13#include "core/hle/service/vi/shared_buffer_manager.h"
14
15union Result;
16
17namespace Service::android {
18class BufferQueueProducer;
19}
20
21namespace Service::Nvnflinger {
22class IHOSBinderDriver;
23class SurfaceFlinger;
24} // namespace Service::Nvnflinger
25
26namespace Service {
27class Event;
28}
29
30namespace Service::VI {
31
32class SharedBufferManager;
33
34class Container {
35public:
36 explicit Container(Core::System& system);
37 ~Container();
38
39 void OnTerminate();
40
41 SharedBufferManager* GetSharedBufferManager();
42
43 Result GetBinderDriver(std::shared_ptr<Nvnflinger::IHOSBinderDriver>* out_binder_driver);
44 Result GetLayerProducerHandle(std::shared_ptr<android::BufferQueueProducer>* out_producer,
45 u64 layer_id);
46
47 Result OpenDisplay(u64* out_display_id, const DisplayName& display_name);
48 Result CloseDisplay(u64 display_id);
49
50 // Managed layers are created by the interaction between am and ommdisp
51 // on behalf of an applet. Their lifetime ends with the lifetime of the
52 // applet's ISelfController.
53 Result CreateManagedLayer(u64* out_layer_id, u64 display_id, u64 owner_aruid);
54 Result DestroyManagedLayer(u64 layer_id);
55 Result OpenLayer(s32* out_producer_binder_id, u64 layer_id, u64 aruid);
56 Result CloseLayer(u64 layer_id);
57
58 // Stray layers are created by non-applet sysmodules. Their lifetime ends
59 // with the lifetime of the IApplicationDisplayService which created them.
60 Result CreateStrayLayer(s32* out_producer_binder_id, u64* out_layer_id, u64 display_id);
61 Result DestroyStrayLayer(u64 layer_id);
62
63 Result SetLayerVisibility(u64 layer_id, bool visible);
64 Result SetLayerBlending(u64 layer_id, bool enabled);
65
66 void LinkVsyncEvent(u64 display_id, Event* event);
67 void UnlinkVsyncEvent(u64 display_id, Event* event);
68
69private:
70 Result CreateLayerLocked(u64* out_layer_id, u64 display_id, u64 owner_aruid);
71 Result DestroyLayerLocked(u64 layer_id);
72 Result OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid);
73 Result CloseLayerLocked(u64 layer_id);
74
75 void CreateBufferQueueLocked(Layer* layer);
76 void DestroyBufferQueueLocked(Layer* layer);
77
78public:
79 void ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id);
80
81private:
82 std::mutex m_lock{};
83 DisplayList m_displays{};
84 LayerList m_layers{};
85 std::shared_ptr<Nvnflinger::IHOSBinderDriver> m_binder_driver{};
86 std::shared_ptr<Nvnflinger::SurfaceFlinger> m_surface_flinger{};
87 std::optional<SharedBufferManager> m_shared_buffer_manager{};
88 std::optional<Conductor> m_conductor{};
89 bool m_is_shut_down{};
90};
91
92} // namespace Service::VI
diff --git a/src/core/hle/service/vi/display.h b/src/core/hle/service/vi/display.h
new file mode 100644
index 000000000..fceda75e3
--- /dev/null
+++ b/src/core/hle/service/vi/display.h
@@ -0,0 +1,44 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/vi/vi_types.h"
7
8namespace Service::VI {
9
10class Display {
11public:
12 constexpr Display() = default;
13
14 void Initialize(u64 id, const DisplayName& display_name) {
15 m_id = id;
16 m_display_name = display_name;
17 m_is_initialized = true;
18 }
19
20 void Finalize() {
21 m_id = {};
22 m_display_name = {};
23 m_is_initialized = {};
24 }
25
26 u64 GetId() const {
27 return m_id;
28 }
29
30 const DisplayName& GetDisplayName() const {
31 return m_display_name;
32 }
33
34 bool IsInitialized() const {
35 return m_is_initialized;
36 }
37
38private:
39 u64 m_id{};
40 DisplayName m_display_name{};
41 bool m_is_initialized{};
42};
43
44} // namespace Service::VI
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp
deleted file mode 100644
index 7f2af9acc..000000000
--- a/src/core/hle/service/vi/display/vi_display.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <algorithm>
5#include <utility>
6
7#include <fmt/format.h>
8
9#include "common/assert.h"
10#include "core/core.h"
11#include "core/hle/kernel/k_event.h"
12#include "core/hle/kernel/k_readable_event.h"
13#include "core/hle/service/kernel_helpers.h"
14#include "core/hle/service/nvdrv/core/container.h"
15#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
16#include "core/hle/service/nvnflinger/buffer_queue_consumer.h"
17#include "core/hle/service/nvnflinger/buffer_queue_core.h"
18#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
19#include "core/hle/service/nvnflinger/hardware_composer.h"
20#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
21#include "core/hle/service/vi/display/vi_display.h"
22#include "core/hle/service/vi/layer/vi_layer.h"
23#include "core/hle/service/vi/vi_results.h"
24
25namespace Service::VI {
26
27struct BufferQueue {
28 std::shared_ptr<android::BufferQueueCore> core;
29 std::unique_ptr<android::BufferQueueProducer> producer;
30 std::unique_ptr<android::BufferQueueConsumer> consumer;
31};
32
33static BufferQueue CreateBufferQueue(KernelHelpers::ServiceContext& service_context,
34 Service::Nvidia::NvCore::NvMap& nvmap) {
35 auto buffer_queue_core = std::make_shared<android::BufferQueueCore>();
36 return {
37 buffer_queue_core,
38 std::make_unique<android::BufferQueueProducer>(service_context, buffer_queue_core, nvmap),
39 std::make_unique<android::BufferQueueConsumer>(buffer_queue_core)};
40}
41
42Display::Display(u64 id, std::string name_,
43 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_,
44 KernelHelpers::ServiceContext& service_context_, Core::System& system_)
45 : display_id{id}, name{std::move(name_)}, hos_binder_driver_server{hos_binder_driver_server_},
46 service_context{service_context_} {
47 hardware_composer = std::make_unique<Nvnflinger::HardwareComposer>();
48 vsync_event = service_context.CreateEvent(fmt::format("Display VSync Event {}", id));
49}
50
51Display::~Display() {
52 service_context.CloseEvent(vsync_event);
53}
54
55Layer& Display::GetLayer(std::size_t index) {
56 size_t i = 0;
57 for (auto& layer : layers) {
58 if (!layer->IsOpen() || !layer->IsVisible()) {
59 continue;
60 }
61
62 if (i == index) {
63 return *layer;
64 }
65
66 i++;
67 }
68
69 UNREACHABLE();
70}
71
72size_t Display::GetNumLayers() const {
73 return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen() && l->IsVisible(); });
74}
75
76Kernel::KReadableEvent* Display::GetVSyncEvent() {
77 return &vsync_event->GetReadableEvent();
78}
79
80void Display::SignalVSyncEvent() {
81 vsync_event->Signal();
82}
83
84void Display::CreateLayer(u64 layer_id, u32 binder_id,
85 Service::Nvidia::NvCore::Container& nv_core) {
86 auto [core, producer, consumer] = CreateBufferQueue(service_context, nv_core.GetNvMapFile());
87
88 auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(consumer));
89 buffer_item_consumer->Connect(false);
90
91 layers.emplace_back(std::make_unique<Layer>(layer_id, binder_id, *core, *producer,
92 std::move(buffer_item_consumer)));
93
94 if (is_abandoned) {
95 this->FindLayer(layer_id)->GetConsumer().Abandon();
96 }
97
98 hos_binder_driver_server.RegisterProducer(std::move(producer));
99}
100
101void Display::DestroyLayer(u64 layer_id) {
102 if (auto* layer = this->FindLayer(layer_id); layer != nullptr) {
103 layer->GetConsumer().Abandon();
104 }
105
106 std::erase_if(layers,
107 [layer_id](const auto& layer) { return layer->GetLayerId() == layer_id; });
108}
109
110void Display::Abandon() {
111 for (auto& layer : layers) {
112 layer->GetConsumer().Abandon();
113 }
114 is_abandoned = true;
115}
116
117Layer* Display::FindLayer(u64 layer_id) {
118 const auto itr =
119 std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr<Layer>& layer) {
120 return layer->GetLayerId() == layer_id;
121 });
122
123 if (itr == layers.end()) {
124 return nullptr;
125 }
126
127 return itr->get();
128}
129
130const Layer* Display::FindLayer(u64 layer_id) const {
131 const auto itr =
132 std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr<Layer>& layer) {
133 return layer->GetLayerId() == layer_id;
134 });
135
136 if (itr == layers.end()) {
137 return nullptr;
138 }
139
140 return itr->get();
141}
142
143} // namespace Service::VI
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h
deleted file mode 100644
index 220292cff..000000000
--- a/src/core/hle/service/vi/display/vi_display.h
+++ /dev/null
@@ -1,143 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <string>
8#include <vector>
9
10#include "common/common_funcs.h"
11#include "common/common_types.h"
12#include "core/hle/result.h"
13
14namespace Core {
15class System;
16}
17
18namespace Kernel {
19class KEvent;
20class KReadableEvent;
21} // namespace Kernel
22
23namespace Service::android {
24class BufferQueueProducer;
25}
26
27namespace Service::KernelHelpers {
28class ServiceContext;
29}
30
31namespace Service::Nvnflinger {
32class HardwareComposer;
33class HosBinderDriverServer;
34} // namespace Service::Nvnflinger
35
36namespace Service::Nvidia::NvCore {
37class Container;
38class NvMap;
39} // namespace Service::Nvidia::NvCore
40
41namespace Service::VI {
42
43class Layer;
44
45/// Represents a single display type
46class Display {
47public:
48 YUZU_NON_COPYABLE(Display);
49 YUZU_NON_MOVEABLE(Display);
50
51 /// Constructs a display with a given unique ID and name.
52 ///
53 /// @param id The unique ID for this display.
54 /// @param hos_binder_driver_server_ Nvnflinger HOSBinderDriver server instance.
55 /// @param service_context_ The ServiceContext for the owning service.
56 /// @param name_ The name for this display.
57 /// @param system_ The global system instance.
58 ///
59 Display(u64 id, std::string name_, Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_,
60 KernelHelpers::ServiceContext& service_context_, Core::System& system_);
61 ~Display();
62
63 /// Gets the unique ID assigned to this display.
64 u64 GetID() const {
65 return display_id;
66 }
67
68 /// Gets the name of this display
69 const std::string& GetName() const {
70 return name;
71 }
72
73 /// Whether or not this display has any layers added to it.
74 bool HasLayers() const {
75 return GetNumLayers() > 0;
76 }
77
78 /// Gets a layer for this display based off an index.
79 Layer& GetLayer(std::size_t index);
80
81 std::size_t GetNumLayers() const;
82
83 /// Gets the internal vsync event.
84 Kernel::KReadableEvent* GetVSyncEvent();
85
86 /// Signals the internal vsync event.
87 void SignalVSyncEvent();
88
89 /// Creates and adds a layer to this display with the given ID.
90 ///
91 /// @param layer_id The ID to assign to the created layer.
92 /// @param binder_id The ID assigned to the buffer queue.
93 ///
94 void CreateLayer(u64 layer_id, u32 binder_id, Service::Nvidia::NvCore::Container& core);
95
96 /// Removes a layer from this display with the given ID.
97 ///
98 /// @param layer_id The ID assigned to the layer to destroy.
99 ///
100 void DestroyLayer(u64 layer_id);
101
102 /// Resets the display for a new connection.
103 void Reset() {
104 layers.clear();
105 }
106
107 void Abandon();
108
109 /// Attempts to find a layer with the given ID.
110 ///
111 /// @param layer_id The layer ID.
112 ///
113 /// @returns If found, the Layer instance with the given ID.
114 /// If not found, then nullptr is returned.
115 ///
116 Layer* FindLayer(u64 layer_id);
117
118 /// Attempts to find a layer with the given ID.
119 ///
120 /// @param layer_id The layer ID.
121 ///
122 /// @returns If found, the Layer instance with the given ID.
123 /// If not found, then nullptr is returned.
124 ///
125 const Layer* FindLayer(u64 layer_id) const;
126
127 Nvnflinger::HardwareComposer& GetComposer() const {
128 return *hardware_composer;
129 }
130
131private:
132 u64 display_id;
133 std::string name;
134 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server;
135 KernelHelpers::ServiceContext& service_context;
136
137 std::vector<std::unique_ptr<Layer>> layers;
138 std::unique_ptr<Nvnflinger::HardwareComposer> hardware_composer;
139 Kernel::KEvent* vsync_event{};
140 bool is_abandoned{};
141};
142
143} // namespace Service::VI
diff --git a/src/core/hle/service/vi/display_list.h b/src/core/hle/service/vi/display_list.h
new file mode 100644
index 000000000..f710ac472
--- /dev/null
+++ b/src/core/hle/service/vi/display_list.h
@@ -0,0 +1,83 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <cstring>
7
8#include "core/hle/service/vi/display.h"
9
10namespace Service::VI {
11
12class DisplayList {
13public:
14 constexpr DisplayList() = default;
15
16 bool CreateDisplay(const DisplayName& name) {
17 Display* const display = this->GetFreeDisplay();
18 if (!display) {
19 return false;
20 }
21
22 display->Initialize(m_next_id++, name);
23 return true;
24 }
25
26 bool DestroyDisplay(u64 display_id) {
27 Display* display = this->GetDisplayById(display_id);
28 if (!display) {
29 return false;
30 }
31
32 display->Finalize();
33 return true;
34 }
35
36 Display* GetDisplayByName(const DisplayName& name) {
37 for (auto& display : m_displays) {
38 if (display.IsInitialized() &&
39 std::strncmp(name.data(), display.GetDisplayName().data(), sizeof(DisplayName)) ==
40 0) {
41 return &display;
42 }
43 }
44
45 return nullptr;
46 }
47
48 Display* GetDisplayById(u64 display_id) {
49 for (auto& display : m_displays) {
50 if (display.IsInitialized() && display.GetId() == display_id) {
51 return &display;
52 }
53 }
54
55 return nullptr;
56 }
57
58 template <typename F>
59 void ForEachDisplay(F&& cb) {
60 for (auto& display : m_displays) {
61 if (display.IsInitialized()) {
62 cb(display);
63 }
64 }
65 }
66
67private:
68 Display* GetFreeDisplay() {
69 for (auto& display : m_displays) {
70 if (!display.IsInitialized()) {
71 return &display;
72 }
73 }
74
75 return nullptr;
76 }
77
78private:
79 std::array<Display, 8> m_displays{};
80 u64 m_next_id{};
81};
82
83} // namespace Service::VI
diff --git a/src/core/hle/service/vi/layer.h b/src/core/hle/service/vi/layer.h
new file mode 100644
index 000000000..b85c8df61
--- /dev/null
+++ b/src/core/hle/service/vi/layer.h
@@ -0,0 +1,79 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7
8namespace Service::VI {
9
10class Display;
11
12class Layer {
13public:
14 constexpr Layer() = default;
15
16 void Initialize(u64 id, u64 owner_aruid, Display* display) {
17 m_id = id;
18 m_owner_aruid = owner_aruid;
19 m_display = display;
20 m_is_initialized = true;
21 }
22
23 void Finalize() {
24 m_id = {};
25 m_display = {};
26 m_is_initialized = {};
27 }
28
29 void Open(s32 consumer_binder_id, s32 producer_binder_id) {
30 m_consumer_binder_id = consumer_binder_id;
31 m_producer_binder_id = producer_binder_id;
32 m_is_open = true;
33 }
34
35 void Close() {
36 m_producer_binder_id = {};
37 m_consumer_binder_id = {};
38 m_is_open = {};
39 }
40
41 u64 GetId() const {
42 return m_id;
43 }
44
45 u64 GetOwnerAruid() const {
46 return m_owner_aruid;
47 }
48
49 Display* GetDisplay() const {
50 return m_display;
51 }
52
53 s32 GetConsumerBinderId() const {
54 return m_consumer_binder_id;
55 }
56
57 s32 GetProducerBinderId() const {
58 return m_producer_binder_id;
59 }
60
61 bool IsInitialized() const {
62 return m_is_initialized;
63 }
64
65 bool IsOpen() const {
66 return m_is_open;
67 }
68
69private:
70 u64 m_id{};
71 u64 m_owner_aruid{};
72 Display* m_display{};
73 s32 m_consumer_binder_id{};
74 s32 m_producer_binder_id{};
75 bool m_is_initialized{};
76 bool m_is_open{};
77};
78
79} // namespace Service::VI
diff --git a/src/core/hle/service/vi/layer/vi_layer.cpp b/src/core/hle/service/vi/layer/vi_layer.cpp
deleted file mode 100644
index eca35d82a..000000000
--- a/src/core/hle/service/vi/layer/vi_layer.cpp
+++ /dev/null
@@ -1,18 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/nvnflinger/hwc_layer.h"
5#include "core/hle/service/vi/layer/vi_layer.h"
6
7namespace Service::VI {
8
9Layer::Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_,
10 android::BufferQueueProducer& binder_,
11 std::shared_ptr<android::BufferItemConsumer>&& consumer_)
12 : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, consumer{std::move(
13 consumer_)},
14 blending{Nvnflinger::LayerBlending::None}, open{false}, visible{true} {}
15
16Layer::~Layer() = default;
17
18} // namespace Service::VI
diff --git a/src/core/hle/service/vi/layer/vi_layer.h b/src/core/hle/service/vi/layer/vi_layer.h
deleted file mode 100644
index 14e229903..000000000
--- a/src/core/hle/service/vi/layer/vi_layer.h
+++ /dev/null
@@ -1,118 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <utility>
8
9#include "common/common_types.h"
10
11namespace Service::android {
12class BufferItemConsumer;
13class BufferQueueCore;
14class BufferQueueProducer;
15} // namespace Service::android
16
17namespace Service::Nvnflinger {
18enum class LayerBlending : u32;
19}
20
21namespace Service::VI {
22
23/// Represents a single display layer.
24class Layer {
25public:
26 /// Constructs a layer with a given ID and buffer queue.
27 ///
28 /// @param layer_id_ The ID to assign to this layer.
29 /// @param binder_id_ The binder ID to assign to this layer.
30 /// @param binder_ The buffer producer queue for this layer to use.
31 ///
32 Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_,
33 android::BufferQueueProducer& binder_,
34 std::shared_ptr<android::BufferItemConsumer>&& consumer_);
35 ~Layer();
36
37 Layer(const Layer&) = delete;
38 Layer& operator=(const Layer&) = delete;
39
40 Layer(Layer&&) = default;
41 Layer& operator=(Layer&&) = delete;
42
43 /// Gets the ID for this layer.
44 u64 GetLayerId() const {
45 return layer_id;
46 }
47
48 /// Gets the binder ID for this layer.
49 u32 GetBinderId() const {
50 return binder_id;
51 }
52
53 /// Gets a reference to the buffer queue this layer is using.
54 android::BufferQueueProducer& GetBufferQueue() {
55 return binder;
56 }
57
58 /// Gets a const reference to the buffer queue this layer is using.
59 const android::BufferQueueProducer& GetBufferQueue() const {
60 return binder;
61 }
62
63 android::BufferItemConsumer& GetConsumer() {
64 return *consumer;
65 }
66
67 const android::BufferItemConsumer& GetConsumer() const {
68 return *consumer;
69 }
70
71 android::BufferQueueCore& Core() {
72 return core;
73 }
74
75 const android::BufferQueueCore& Core() const {
76 return core;
77 }
78
79 bool IsVisible() const {
80 return visible;
81 }
82
83 void SetVisibility(bool v) {
84 visible = v;
85 }
86
87 bool IsOpen() const {
88 return open;
89 }
90
91 bool Close() {
92 return std::exchange(open, false);
93 }
94
95 bool Open() {
96 return !std::exchange(open, true);
97 }
98
99 Nvnflinger::LayerBlending GetBlending() {
100 return blending;
101 }
102
103 void SetBlending(Nvnflinger::LayerBlending b) {
104 blending = b;
105 }
106
107private:
108 const u64 layer_id;
109 const u32 binder_id;
110 android::BufferQueueCore& core;
111 android::BufferQueueProducer& binder;
112 std::shared_ptr<android::BufferItemConsumer> consumer;
113 Service::Nvnflinger::LayerBlending blending;
114 bool open;
115 bool visible;
116};
117
118} // namespace Service::VI
diff --git a/src/core/hle/service/vi/layer_list.h b/src/core/hle/service/vi/layer_list.h
new file mode 100644
index 000000000..1738ede9a
--- /dev/null
+++ b/src/core/hle/service/vi/layer_list.h
@@ -0,0 +1,69 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/vi/layer.h"
7
8namespace Service::VI {
9
10class LayerList {
11public:
12 constexpr LayerList() = default;
13
14 Layer* CreateLayer(u64 owner_aruid, Display* display) {
15 Layer* const layer = GetFreeLayer();
16 if (!layer) {
17 return nullptr;
18 }
19
20 layer->Initialize(++m_next_id, owner_aruid, display);
21 return layer;
22 }
23
24 bool DestroyLayer(u64 layer_id) {
25 Layer* const layer = GetLayerById(layer_id);
26 if (!layer) {
27 return false;
28 }
29
30 layer->Finalize();
31 return true;
32 }
33
34 Layer* GetLayerById(u64 layer_id) {
35 for (auto& layer : m_layers) {
36 if (layer.IsInitialized() && layer.GetId() == layer_id) {
37 return &layer;
38 }
39 }
40
41 return nullptr;
42 }
43
44 template <typename F>
45 void ForEachLayer(F&& cb) {
46 for (auto& layer : m_layers) {
47 if (layer.IsInitialized()) {
48 cb(layer);
49 }
50 }
51 }
52
53private:
54 Layer* GetFreeLayer() {
55 for (auto& layer : m_layers) {
56 if (!layer.IsInitialized()) {
57 return &layer;
58 }
59 }
60
61 return nullptr;
62 }
63
64private:
65 std::array<Layer, 8> m_layers{};
66 u64 m_next_id{};
67};
68
69} // namespace Service::VI
diff --git a/src/core/hle/service/vi/manager_display_service.cpp b/src/core/hle/service/vi/manager_display_service.cpp
index 22454ba61..9f856282e 100644
--- a/src/core/hle/service/vi/manager_display_service.cpp
+++ b/src/core/hle/service/vi/manager_display_service.cpp
@@ -2,23 +2,21 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/service/cmif_serialization.h" 4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/nvnflinger/nvnflinger.h" 5#include "core/hle/service/vi/container.h"
6#include "core/hle/service/vi/manager_display_service.h" 6#include "core/hle/service/vi/manager_display_service.h"
7#include "core/hle/service/vi/vi_results.h"
8 7
9namespace Service::VI { 8namespace Service::VI {
10 9
11IManagerDisplayService::IManagerDisplayService( 10IManagerDisplayService::IManagerDisplayService(Core::System& system_,
12 Core::System& system_, std::shared_ptr<Nvnflinger::Nvnflinger> surface_flinger) 11 std::shared_ptr<Container> container)
13 : ServiceFramework{system_, "IManagerDisplayService"}, 12 : ServiceFramework{system_, "IManagerDisplayService"}, m_container{std::move(container)} {
14 m_surface_flinger{std::move(surface_flinger)} {
15 // clang-format off 13 // clang-format off
16 static const FunctionInfo functions[] = { 14 static const FunctionInfo functions[] = {
17 {200, nullptr, "AllocateProcessHeapBlock"}, 15 {200, nullptr, "AllocateProcessHeapBlock"},
18 {201, nullptr, "FreeProcessHeapBlock"}, 16 {201, nullptr, "FreeProcessHeapBlock"},
19 {1102, nullptr, "GetDisplayResolution"}, 17 {1102, nullptr, "GetDisplayResolution"},
20 {2010, C<&IManagerDisplayService::CreateManagedLayer>, "CreateManagedLayer"}, 18 {2010, C<&IManagerDisplayService::CreateManagedLayer>, "CreateManagedLayer"},
21 {2011, nullptr, "DestroyManagedLayer"}, 19 {2011, C<&IManagerDisplayService::DestroyManagedLayer>, "DestroyManagedLayer"},
22 {2012, nullptr, "CreateStrayLayer"}, 20 {2012, nullptr, "CreateStrayLayer"},
23 {2050, nullptr, "CreateIndirectLayer"}, 21 {2050, nullptr, "CreateIndirectLayer"},
24 {2051, nullptr, "DestroyIndirectLayer"}, 22 {2051, nullptr, "DestroyIndirectLayer"},
@@ -103,19 +101,30 @@ IManagerDisplayService::IManagerDisplayService(
103 101
104IManagerDisplayService::~IManagerDisplayService() = default; 102IManagerDisplayService::~IManagerDisplayService() = default;
105 103
106Result IManagerDisplayService::CreateManagedLayer(Out<u64> out_layer_id, u32 unknown, 104Result IManagerDisplayService::CreateSharedLayerSession(Kernel::KProcess* owner_process,
107 u64 display_id, AppletResourceUserId aruid) { 105 u64* out_buffer_id, u64* out_layer_handle,
108 LOG_WARNING(Service_VI, "(STUBBED) called. unknown={}, display={}, aruid={}", unknown, 106 u64 display_id, bool enable_blending) {
109 display_id, aruid.pid); 107 R_RETURN(m_container->GetSharedBufferManager()->CreateSession(
108 owner_process, out_buffer_id, out_layer_handle, display_id, enable_blending));
109}
110 110
111 const auto layer_id = m_surface_flinger->CreateLayer(display_id); 111void IManagerDisplayService::DestroySharedLayerSession(Kernel::KProcess* owner_process) {
112 if (!layer_id) { 112 m_container->GetSharedBufferManager()->DestroySession(owner_process);
113 LOG_ERROR(Service_VI, "Layer not found! display={}", display_id); 113}
114 R_THROW(VI::ResultNotFound);
115 }
116 114
117 *out_layer_id = *layer_id; 115Result IManagerDisplayService::SetLayerBlending(bool enabled, u64 layer_id) {
118 R_SUCCEED(); 116 R_RETURN(m_container->SetLayerBlending(layer_id, enabled));
117}
118
119Result IManagerDisplayService::CreateManagedLayer(Out<u64> out_layer_id, u32 flags, u64 display_id,
120 AppletResourceUserId aruid) {
121 LOG_DEBUG(Service_VI, "called. flags={}, display={}, aruid={}", flags, display_id, aruid.pid);
122 R_RETURN(m_container->CreateManagedLayer(out_layer_id, display_id, aruid.pid));
123}
124
125Result IManagerDisplayService::DestroyManagedLayer(u64 layer_id) {
126 LOG_DEBUG(Service_VI, "called. layer_id={}", layer_id);
127 R_RETURN(m_container->DestroyManagedLayer(layer_id));
119} 128}
120 129
121Result IManagerDisplayService::AddToLayerStack(u32 stack_id, u64 layer_id) { 130Result IManagerDisplayService::AddToLayerStack(u32 stack_id, u64 layer_id) {
@@ -124,8 +133,8 @@ Result IManagerDisplayService::AddToLayerStack(u32 stack_id, u64 layer_id) {
124} 133}
125 134
126Result IManagerDisplayService::SetLayerVisibility(bool visible, u64 layer_id) { 135Result IManagerDisplayService::SetLayerVisibility(bool visible, u64 layer_id) {
127 LOG_WARNING(Service_VI, "(STUBBED) called, layer_id={}, visible={}", layer_id, visible); 136 LOG_DEBUG(Service_VI, "called, layer_id={}, visible={}", layer_id, visible);
128 R_SUCCEED(); 137 R_RETURN(m_container->SetLayerVisibility(layer_id, visible));
129} 138}
130 139
131} // namespace Service::VI 140} // namespace Service::VI
diff --git a/src/core/hle/service/vi/manager_display_service.h b/src/core/hle/service/vi/manager_display_service.h
index 4a3d53ff8..b1bdf7f41 100644
--- a/src/core/hle/service/vi/manager_display_service.h
+++ b/src/core/hle/service/vi/manager_display_service.h
@@ -4,22 +4,34 @@
4#include "core/hle/service/cmif_types.h" 4#include "core/hle/service/cmif_types.h"
5#include "core/hle/service/service.h" 5#include "core/hle/service/service.h"
6 6
7namespace Kernel {
8class KProcess;
9}
10
7namespace Service::VI { 11namespace Service::VI {
8 12
13class Container;
14
9class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { 15class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
10public: 16public:
11 explicit IManagerDisplayService(Core::System& system_, 17 explicit IManagerDisplayService(Core::System& system_, std::shared_ptr<Container> container);
12 std::shared_ptr<Nvnflinger::Nvnflinger> surface_flinger);
13 ~IManagerDisplayService() override; 18 ~IManagerDisplayService() override;
14 19
15private: 20 Result CreateSharedLayerSession(Kernel::KProcess* owner_process, u64* out_buffer_id,
16 Result CreateManagedLayer(Out<u64> out_layer_id, u32 unknown, u64 display_id, 21 u64* out_layer_handle, u64 display_id, bool enable_blending);
22 void DestroySharedLayerSession(Kernel::KProcess* owner_process);
23
24 Result SetLayerBlending(bool enabled, u64 layer_id);
25
26public:
27 Result CreateManagedLayer(Out<u64> out_layer_id, u32 flags, u64 display_id,
17 AppletResourceUserId aruid); 28 AppletResourceUserId aruid);
29 Result DestroyManagedLayer(u64 layer_id);
18 Result AddToLayerStack(u32 stack_id, u64 layer_id); 30 Result AddToLayerStack(u32 stack_id, u64 layer_id);
19 Result SetLayerVisibility(bool visible, u64 layer_id); 31 Result SetLayerVisibility(bool visible, u64 layer_id);
20 32
21private: 33private:
22 const std::shared_ptr<Nvnflinger::Nvnflinger> m_surface_flinger; 34 const std::shared_ptr<Container> m_container;
23}; 35};
24 36
25} // namespace Service::VI 37} // 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 b61f0ecb6..0f16a15b4 100644
--- a/src/core/hle/service/vi/manager_root_service.cpp
+++ b/src/core/hle/service/vi/manager_root_service.cpp
@@ -4,6 +4,7 @@
4#include "core/hle/service/cmif_serialization.h" 4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/nvnflinger/hos_binder_driver.h" 5#include "core/hle/service/nvnflinger/hos_binder_driver.h"
6#include "core/hle/service/vi/application_display_service.h" 6#include "core/hle/service/vi/application_display_service.h"
7#include "core/hle/service/vi/container.h"
7#include "core/hle/service/vi/manager_root_service.h" 8#include "core/hle/service/vi/manager_root_service.h"
8#include "core/hle/service/vi/service_creator.h" 9#include "core/hle/service/vi/service_creator.h"
9#include "core/hle/service/vi/vi.h" 10#include "core/hle/service/vi/vi.h"
@@ -11,11 +12,9 @@
11 12
12namespace Service::VI { 13namespace Service::VI {
13 14
14IManagerRootService::IManagerRootService( 15IManagerRootService::IManagerRootService(Core::System& system_,
15 Core::System& system_, std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service, 16 std::shared_ptr<Container> container)
16 std::shared_ptr<FbshareBufferManager> shared_buffer_manager) 17 : ServiceFramework{system_, "vi:m"}, m_container{std::move(container)} {
17 : ServiceFramework{system_, "vi:m"}, m_binder_service{std::move(binder_service)},
18 m_shared_buffer_manager{std::move(shared_buffer_manager)} {
19 static const FunctionInfo functions[] = { 18 static const FunctionInfo functions[] = {
20 {2, C<&IManagerRootService::GetDisplayService>, "GetDisplayService"}, 19 {2, C<&IManagerRootService::GetDisplayService>, "GetDisplayService"},
21 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, 20 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -32,8 +31,8 @@ IManagerRootService::~IManagerRootService() = default;
32Result IManagerRootService::GetDisplayService( 31Result IManagerRootService::GetDisplayService(
33 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) { 32 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) {
34 LOG_DEBUG(Service_VI, "called"); 33 LOG_DEBUG(Service_VI, "called");
35 R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_binder_service, 34 R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_container,
36 m_shared_buffer_manager, Permission::Manager, policy)); 35 Permission::Manager, policy));
37} 36}
38 37
39} // namespace Service::VI 38} // 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 509445b7b..77cd32869 100644
--- a/src/core/hle/service/vi/manager_root_service.h
+++ b/src/core/hle/service/vi/manager_root_service.h
@@ -10,21 +10,15 @@ namespace Core {
10class System; 10class System;
11} 11}
12 12
13namespace Service::Nvnflinger {
14class IHOSBinderDriver;
15} // namespace Service::Nvnflinger
16
17namespace Service::VI { 13namespace Service::VI {
18 14
19class FbshareBufferManager; 15class Container;
20class IApplicationDisplayService; 16class IApplicationDisplayService;
21enum class Policy : u32; 17enum class Policy : u32;
22 18
23class IManagerRootService final : public ServiceFramework<IManagerRootService> { 19class IManagerRootService final : public ServiceFramework<IManagerRootService> {
24public: 20public:
25 explicit IManagerRootService(Core::System& system_, 21 explicit IManagerRootService(Core::System& system_, std::shared_ptr<Container> container);
26 std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
27 std::shared_ptr<FbshareBufferManager> shared_buffer_manager);
28 ~IManagerRootService() override; 22 ~IManagerRootService() override;
29 23
30 Result GetDisplayService( 24 Result GetDisplayService(
@@ -32,8 +26,7 @@ public:
32 Policy policy); 26 Policy policy);
33 27
34private: 28private:
35 const std::shared_ptr<Nvnflinger::IHOSBinderDriver> m_binder_service; 29 const std::shared_ptr<Container> m_container;
36 const std::shared_ptr<FbshareBufferManager> m_shared_buffer_manager;
37}; 30};
38 31
39} // namespace Service::VI 32} // namespace Service::VI
diff --git a/src/core/hle/service/vi/service_creator.cpp b/src/core/hle/service/vi/service_creator.cpp
index 414bd6655..2b8e5f957 100644
--- a/src/core/hle/service/vi/service_creator.cpp
+++ b/src/core/hle/service/vi/service_creator.cpp
@@ -22,8 +22,7 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) {
22 22
23Result GetApplicationDisplayService( 23Result GetApplicationDisplayService(
24 std::shared_ptr<IApplicationDisplayService>* out_application_display_service, 24 std::shared_ptr<IApplicationDisplayService>* out_application_display_service,
25 Core::System& system, std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service, 25 Core::System& system, std::shared_ptr<Container> container, Permission permission,
26 std::shared_ptr<FbshareBufferManager> shared_buffer_manager, Permission permission,
27 Policy policy) { 26 Policy policy) {
28 27
29 if (!IsValidServiceAccess(permission, policy)) { 28 if (!IsValidServiceAccess(permission, policy)) {
@@ -32,7 +31,7 @@ Result GetApplicationDisplayService(
32 } 31 }
33 32
34 *out_application_display_service = 33 *out_application_display_service =
35 std::make_shared<IApplicationDisplayService>(system, binder_service, shared_buffer_manager); 34 std::make_shared<IApplicationDisplayService>(system, std::move(container));
36 R_SUCCEED(); 35 R_SUCCEED();
37} 36}
38 37
diff --git a/src/core/hle/service/vi/service_creator.h b/src/core/hle/service/vi/service_creator.h
index 6691f25c0..c6ba1797d 100644
--- a/src/core/hle/service/vi/service_creator.h
+++ b/src/core/hle/service/vi/service_creator.h
@@ -11,23 +11,18 @@ namespace Core {
11class System; 11class System;
12} 12}
13 13
14namespace Service::Nvnflinger {
15class IHOSBinderDriver;
16} // namespace Service::Nvnflinger
17
18union Result; 14union Result;
19 15
20namespace Service::VI { 16namespace Service::VI {
21 17
22class FbshareBufferManager; 18class Container;
23class IApplicationDisplayService; 19class IApplicationDisplayService;
24enum class Permission; 20enum class Permission;
25enum class Policy : u32; 21enum class Policy : u32;
26 22
27Result GetApplicationDisplayService( 23Result GetApplicationDisplayService(
28 std::shared_ptr<IApplicationDisplayService>* out_application_display_service, 24 std::shared_ptr<IApplicationDisplayService>* out_application_display_service,
29 Core::System& system, std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service, 25 Core::System& system, std::shared_ptr<Container> container, Permission permission,
30 std::shared_ptr<FbshareBufferManager> shared_buffer_manager, Permission permission,
31 Policy policy); 26 Policy policy);
32 27
33} // namespace Service::VI 28} // namespace Service::VI
diff --git a/src/core/hle/service/vi/fbshare_buffer_manager.cpp b/src/core/hle/service/vi/shared_buffer_manager.cpp
index e61c02e1c..869b18961 100644
--- a/src/core/hle/service/vi/fbshare_buffer_manager.cpp
+++ b/src/core/hle/service/vi/shared_buffer_manager.cpp
@@ -11,8 +11,8 @@
11#include "core/hle/service/nvnflinger/buffer_queue_producer.h" 11#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
12#include "core/hle/service/nvnflinger/pixel_format.h" 12#include "core/hle/service/nvnflinger/pixel_format.h"
13#include "core/hle/service/nvnflinger/ui/graphic_buffer.h" 13#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
14#include "core/hle/service/vi/fbshare_buffer_manager.h" 14#include "core/hle/service/vi/container.h"
15#include "core/hle/service/vi/layer/vi_layer.h" 15#include "core/hle/service/vi/shared_buffer_manager.h"
16#include "core/hle/service/vi/vi_results.h" 16#include "core/hle/service/vi/vi_results.h"
17#include "video_core/gpu.h" 17#include "video_core/gpu.h"
18#include "video_core/host1x/host1x.h" 18#include "video_core/host1x/host1x.h"
@@ -203,16 +203,15 @@ void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 han
203 203
204} // namespace 204} // namespace
205 205
206FbshareBufferManager::FbshareBufferManager(Core::System& system, 206SharedBufferManager::SharedBufferManager(Core::System& system, Container& container,
207 std::shared_ptr<Nvnflinger::Nvnflinger> surface_flinger, 207 std::shared_ptr<Nvidia::Module> nvdrv)
208 std::shared_ptr<Nvidia::Module> nvdrv) 208 : m_system(system), m_container(container), m_nvdrv(std::move(nvdrv)) {}
209 : m_system(system), m_surface_flinger(std::move(surface_flinger)), m_nvdrv(std::move(nvdrv)) {}
210 209
211FbshareBufferManager::~FbshareBufferManager() = default; 210SharedBufferManager::~SharedBufferManager() = default;
212 211
213Result FbshareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id, 212Result SharedBufferManager::CreateSession(Kernel::KProcess* owner_process, u64* out_buffer_id,
214 u64* out_layer_handle, u64 display_id, 213 u64* out_layer_handle, u64 display_id,
215 Nvnflinger::LayerBlending blending) { 214 bool enable_blending) {
216 std::scoped_lock lk{m_guard}; 215 std::scoped_lock lk{m_guard};
217 216
218 // Ensure we haven't already created. 217 // Ensure we haven't already created.
@@ -237,7 +236,7 @@ Result FbshareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* ou
237 owner_process, m_system)); 236 owner_process, m_system));
238 237
239 // Create new session. 238 // Create new session.
240 auto [it, was_emplaced] = m_sessions.emplace(aruid, FbshareSession{}); 239 auto [it, was_emplaced] = m_sessions.emplace(aruid, SharedBufferSession{});
241 auto& session = it->second; 240 auto& session = it->second;
242 241
243 auto& container = m_nvdrv->GetContainer(); 242 auto& container = m_nvdrv->GetContainer();
@@ -249,17 +248,18 @@ Result FbshareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* ou
249 session.nvmap_fd, map_address, SharedBufferSize)); 248 session.nvmap_fd, map_address, SharedBufferSize));
250 249
251 // Create and open a layer for the display. 250 // Create and open a layer for the display.
252 session.layer_id = m_surface_flinger->CreateLayer(m_display_id, blending).value(); 251 s32 producer_binder_id;
253 m_surface_flinger->OpenLayer(session.layer_id); 252 R_TRY(m_container.CreateStrayLayer(std::addressof(producer_binder_id),
253 std::addressof(session.layer_id), display_id));
254 254
255 // Get the layer. 255 // Configure blending.
256 VI::Layer* layer = m_surface_flinger->FindLayer(m_display_id, session.layer_id); 256 R_ASSERT(m_container.SetLayerBlending(session.layer_id, enable_blending));
257 ASSERT(layer != nullptr);
258 257
259 // Get the producer and set preallocated buffers. 258 // Get the producer and set preallocated buffers.
260 auto& producer = layer->GetBufferQueue(); 259 std::shared_ptr<android::BufferQueueProducer> producer;
261 MakeGraphicBuffer(producer, 0, session.buffer_nvmap_handle); 260 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), session.layer_id));
262 MakeGraphicBuffer(producer, 1, session.buffer_nvmap_handle); 261 MakeGraphicBuffer(*producer, 0, session.buffer_nvmap_handle);
262 MakeGraphicBuffer(*producer, 1, session.buffer_nvmap_handle);
263 263
264 // Assign outputs. 264 // Assign outputs.
265 *out_buffer_id = m_buffer_id; 265 *out_buffer_id = m_buffer_id;
@@ -269,7 +269,7 @@ Result FbshareBufferManager::Initialize(Kernel::KProcess* owner_process, u64* ou
269 R_SUCCEED(); 269 R_SUCCEED();
270} 270}
271 271
272void FbshareBufferManager::Finalize(Kernel::KProcess* owner_process) { 272void SharedBufferManager::DestroySession(Kernel::KProcess* owner_process) {
273 std::scoped_lock lk{m_guard}; 273 std::scoped_lock lk{m_guard};
274 274
275 if (m_buffer_id == 0) { 275 if (m_buffer_id == 0) {
@@ -285,7 +285,7 @@ void FbshareBufferManager::Finalize(Kernel::KProcess* owner_process) {
285 auto& session = it->second; 285 auto& session = it->second;
286 286
287 // Destroy the layer. 287 // Destroy the layer.
288 m_surface_flinger->DestroyLayer(session.layer_id); 288 R_ASSERT(m_container.DestroyStrayLayer(session.layer_id));
289 289
290 // Close nvmap handle. 290 // Close nvmap handle.
291 FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd); 291 FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd);
@@ -301,11 +301,11 @@ void FbshareBufferManager::Finalize(Kernel::KProcess* owner_process) {
301 m_sessions.erase(it); 301 m_sessions.erase(it);
302} 302}
303 303
304Result FbshareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size, 304Result SharedBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size,
305 s32* out_nvmap_handle, 305 s32* out_nvmap_handle,
306 SharedMemoryPoolLayout* out_pool_layout, 306 SharedMemoryPoolLayout* out_pool_layout,
307 u64 buffer_id, 307 u64 buffer_id,
308 u64 applet_resource_user_id) { 308 u64 applet_resource_user_id) {
309 std::scoped_lock lk{m_guard}; 309 std::scoped_lock lk{m_guard};
310 310
311 R_UNLESS(m_buffer_id > 0, VI::ResultNotFound); 311 R_UNLESS(m_buffer_id > 0, VI::ResultNotFound);
@@ -319,36 +319,20 @@ Result FbshareBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size,
319 R_SUCCEED(); 319 R_SUCCEED();
320} 320}
321 321
322Result FbshareBufferManager::GetLayerFromId(VI::Layer** out_layer, u64 layer_id) { 322Result SharedBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence,
323 // Ensure the layer id is valid. 323 std::array<s32, 4>& out_slot_indexes,
324 R_UNLESS(layer_id > 0, VI::ResultNotFound); 324 s64* out_target_slot, u64 layer_id) {
325
326 // Get the layer.
327 VI::Layer* layer = m_surface_flinger->FindLayer(m_display_id, layer_id);
328 R_UNLESS(layer != nullptr, VI::ResultNotFound);
329
330 // We succeeded.
331 *out_layer = layer;
332 R_SUCCEED();
333}
334
335Result FbshareBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence,
336 std::array<s32, 4>& out_slot_indexes,
337 s64* out_target_slot, u64 layer_id) {
338 std::scoped_lock lk{m_guard}; 325 std::scoped_lock lk{m_guard};
339 326
340 // Get the layer.
341 VI::Layer* layer;
342 R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id));
343
344 // Get the producer. 327 // Get the producer.
345 auto& producer = layer->GetBufferQueue(); 328 std::shared_ptr<android::BufferQueueProducer> producer;
329 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
346 330
347 // Get the next buffer from the producer. 331 // Get the next buffer from the producer.
348 s32 slot; 332 s32 slot;
349 R_UNLESS(producer.DequeueBuffer(std::addressof(slot), out_fence, SharedBufferAsync != 0, 333 R_UNLESS(producer->DequeueBuffer(std::addressof(slot), out_fence, SharedBufferAsync != 0,
350 SharedBufferWidth, SharedBufferHeight, 334 SharedBufferWidth, SharedBufferHeight,
351 SharedBufferBlockLinearFormat, 0) == android::Status::NoError, 335 SharedBufferBlockLinearFormat, 0) == android::Status::NoError,
352 VI::ResultOperationFailed); 336 VI::ResultOperationFailed);
353 337
354 // Assign remaining outputs. 338 // Assign remaining outputs.
@@ -359,27 +343,24 @@ Result FbshareBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence,
359 R_SUCCEED(); 343 R_SUCCEED();
360} 344}
361 345
362Result FbshareBufferManager::PresentSharedFrameBuffer(android::Fence fence, 346Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence,
363 Common::Rectangle<s32> crop_region, 347 Common::Rectangle<s32> crop_region,
364 u32 transform, s32 swap_interval, 348 u32 transform, s32 swap_interval, u64 layer_id,
365 u64 layer_id, s64 slot) { 349 s64 slot) {
366 std::scoped_lock lk{m_guard}; 350 std::scoped_lock lk{m_guard};
367 351
368 // Get the layer.
369 VI::Layer* layer;
370 R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id));
371
372 // Get the producer. 352 // Get the producer.
373 auto& producer = layer->GetBufferQueue(); 353 std::shared_ptr<android::BufferQueueProducer> producer;
354 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
374 355
375 // Request to queue the buffer. 356 // Request to queue the buffer.
376 std::shared_ptr<android::GraphicBuffer> buffer; 357 std::shared_ptr<android::GraphicBuffer> buffer;
377 R_UNLESS(producer.RequestBuffer(static_cast<s32>(slot), std::addressof(buffer)) == 358 R_UNLESS(producer->RequestBuffer(static_cast<s32>(slot), std::addressof(buffer)) ==
378 android::Status::NoError, 359 android::Status::NoError,
379 VI::ResultOperationFailed); 360 VI::ResultOperationFailed);
380 361
381 ON_RESULT_FAILURE { 362 ON_RESULT_FAILURE {
382 producer.CancelBuffer(static_cast<s32>(slot), fence); 363 producer->CancelBuffer(static_cast<s32>(slot), fence);
383 }; 364 };
384 365
385 // Queue the buffer to the producer. 366 // Queue the buffer to the producer.
@@ -389,7 +370,7 @@ Result FbshareBufferManager::PresentSharedFrameBuffer(android::Fence fence,
389 input.fence = fence; 370 input.fence = fence;
390 input.transform = static_cast<android::NativeWindowTransform>(transform); 371 input.transform = static_cast<android::NativeWindowTransform>(transform);
391 input.swap_interval = swap_interval; 372 input.swap_interval = swap_interval;
392 R_UNLESS(producer.QueueBuffer(static_cast<s32>(slot), input, std::addressof(output)) == 373 R_UNLESS(producer->QueueBuffer(static_cast<s32>(slot), input, std::addressof(output)) ==
393 android::Status::NoError, 374 android::Status::NoError,
394 VI::ResultOperationFailed); 375 VI::ResultOperationFailed);
395 376
@@ -397,25 +378,36 @@ Result FbshareBufferManager::PresentSharedFrameBuffer(android::Fence fence,
397 R_SUCCEED(); 378 R_SUCCEED();
398} 379}
399 380
400Result FbshareBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, 381Result SharedBufferManager::CancelSharedFrameBuffer(u64 layer_id, s64 slot) {
401 u64 layer_id) {
402 std::scoped_lock lk{m_guard}; 382 std::scoped_lock lk{m_guard};
403 383
404 // Get the layer. 384 // Get the producer.
405 VI::Layer* layer; 385 std::shared_ptr<android::BufferQueueProducer> producer;
406 R_TRY(this->GetLayerFromId(std::addressof(layer), layer_id)); 386 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
387
388 // Cancel.
389 producer->CancelBuffer(static_cast<s32>(slot), android::Fence::NoFence());
390
391 // We succeeded.
392 R_SUCCEED();
393}
394
395Result SharedBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event,
396 u64 layer_id) {
397 std::scoped_lock lk{m_guard};
407 398
408 // Get the producer. 399 // Get the producer.
409 auto& producer = layer->GetBufferQueue(); 400 std::shared_ptr<android::BufferQueueProducer> producer;
401 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
410 402
411 // Set the event. 403 // Set the event.
412 *out_event = std::addressof(producer.GetNativeHandle()); 404 *out_event = producer->GetNativeHandle({});
413 405
414 // We succeeded. 406 // We succeeded.
415 R_SUCCEED(); 407 R_SUCCEED();
416} 408}
417 409
418Result FbshareBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) { 410Result SharedBufferManager::WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index) {
419 std::vector<u8> capture_buffer(m_system.GPU().GetAppletCaptureBuffer()); 411 std::vector<u8> capture_buffer(m_system.GPU().GetAppletCaptureBuffer());
420 Common::ScratchBuffer<u32> scratch; 412 Common::ScratchBuffer<u32> scratch;
421 413
diff --git a/src/core/hle/service/vi/fbshare_buffer_manager.h b/src/core/hle/service/vi/shared_buffer_manager.h
index b9e99e61f..7c9bb7199 100644
--- a/src/core/hle/service/vi/fbshare_buffer_manager.h
+++ b/src/core/hle/service/vi/shared_buffer_manager.h
@@ -8,16 +8,28 @@
8#include "common/math_util.h" 8#include "common/math_util.h"
9#include "core/hle/service/nvdrv/core/container.h" 9#include "core/hle/service/nvdrv/core/container.h"
10#include "core/hle/service/nvdrv/nvdata.h" 10#include "core/hle/service/nvdrv/nvdata.h"
11#include "core/hle/service/nvnflinger/hwc_layer.h"
12#include "core/hle/service/nvnflinger/nvnflinger.h" 11#include "core/hle/service/nvnflinger/nvnflinger.h"
13#include "core/hle/service/nvnflinger/ui/fence.h" 12#include "core/hle/service/nvnflinger/ui/fence.h"
14 13
15namespace Kernel { 14namespace Kernel {
16class KPageGroup; 15class KPageGroup;
16class KReadableEvent;
17} // namespace Kernel
18
19namespace Service::android {
20class BufferQueueProducer;
21}
22
23namespace Service::Nvidia {
24class Module;
17} 25}
18 26
27union Result;
28
19namespace Service::VI { 29namespace Service::VI {
20 30
31class Container;
32
21struct SharedMemorySlot { 33struct SharedMemorySlot {
22 u64 buffer_offset; 34 u64 buffer_offset;
23 u64 size; 35 u64 size;
@@ -32,18 +44,17 @@ struct SharedMemoryPoolLayout {
32}; 44};
33static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size"); 45static_assert(sizeof(SharedMemoryPoolLayout) == 0x188, "SharedMemoryPoolLayout has wrong size");
34 46
35struct FbshareSession; 47struct SharedBufferSession;
36 48
37class FbshareBufferManager final { 49class SharedBufferManager final {
38public: 50public:
39 explicit FbshareBufferManager(Core::System& system, 51 explicit SharedBufferManager(Core::System& system, Container& container,
40 std::shared_ptr<Nvnflinger::Nvnflinger> surface_flinger, 52 std::shared_ptr<Nvidia::Module> nvdrv);
41 std::shared_ptr<Nvidia::Module> nvdrv); 53 ~SharedBufferManager();
42 ~FbshareBufferManager();
43 54
44 Result Initialize(Kernel::KProcess* owner_process, u64* out_buffer_id, u64* out_layer_handle, 55 Result CreateSession(Kernel::KProcess* owner_process, u64* out_buffer_id, u64* out_layer_handle,
45 u64 display_id, Nvnflinger::LayerBlending blending); 56 u64 display_id, bool enable_blending);
46 void Finalize(Kernel::KProcess* owner_process); 57 void DestroySession(Kernel::KProcess* owner_process);
47 58
48 Result GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle, 59 Result GetSharedBufferMemoryHandleId(u64* out_buffer_size, s32* out_nvmap_handle,
49 SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id, 60 SharedMemoryPoolLayout* out_pool_layout, u64 buffer_id,
@@ -52,28 +63,26 @@ public:
52 s64* out_target_slot, u64 layer_id); 63 s64* out_target_slot, u64 layer_id);
53 Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region, 64 Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region,
54 u32 transform, s32 swap_interval, u64 layer_id, s64 slot); 65 u32 transform, s32 swap_interval, u64 layer_id, s64 slot);
66 Result CancelSharedFrameBuffer(u64 layer_id, s64 slot);
55 Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id); 67 Result GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, u64 layer_id);
56 68
57 Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index); 69 Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_layer_index);
58 70
59private: 71private:
60 Result GetLayerFromId(VI::Layer** out_layer, u64 layer_id);
61
62private:
63 u64 m_next_buffer_id = 1; 72 u64 m_next_buffer_id = 1;
64 u64 m_display_id = 0; 73 u64 m_display_id = 0;
65 u64 m_buffer_id = 0; 74 u64 m_buffer_id = 0;
66 SharedMemoryPoolLayout m_pool_layout = {}; 75 SharedMemoryPoolLayout m_pool_layout = {};
67 std::map<u64, FbshareSession> m_sessions; 76 std::map<u64, SharedBufferSession> m_sessions;
68 std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group; 77 std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group;
69 78
70 std::mutex m_guard; 79 std::mutex m_guard;
71 Core::System& m_system; 80 Core::System& m_system;
72 const std::shared_ptr<Nvnflinger::Nvnflinger> m_surface_flinger; 81 Container& m_container;
73 const std::shared_ptr<Nvidia::Module> m_nvdrv; 82 const std::shared_ptr<Nvidia::Module> m_nvdrv;
74}; 83};
75 84
76struct FbshareSession { 85struct SharedBufferSession {
77 Nvidia::DeviceFD nvmap_fd = {}; 86 Nvidia::DeviceFD nvmap_fd = {};
78 Nvidia::NvCore::SessionId session_id = {}; 87 Nvidia::NvCore::SessionId session_id = {};
79 u64 layer_id = {}; 88 u64 layer_id = {};
diff --git a/src/core/hle/service/vi/system_display_service.cpp b/src/core/hle/service/vi/system_display_service.cpp
index 4670cf4cc..9e28fdda3 100644
--- a/src/core/hle/service/vi/system_display_service.cpp
+++ b/src/core/hle/service/vi/system_display_service.cpp
@@ -3,17 +3,15 @@
3 3
4#include "common/settings.h" 4#include "common/settings.h"
5#include "core/hle/service/cmif_serialization.h" 5#include "core/hle/service/cmif_serialization.h"
6#include "core/hle/service/vi/container.h"
6#include "core/hle/service/vi/system_display_service.h" 7#include "core/hle/service/vi/system_display_service.h"
7#include "core/hle/service/vi/vi_types.h" 8#include "core/hle/service/vi/vi_types.h"
8 9
9namespace Service::VI { 10namespace Service::VI {
10 11
11ISystemDisplayService::ISystemDisplayService( 12ISystemDisplayService::ISystemDisplayService(Core::System& system_,
12 Core::System& system_, std::shared_ptr<Nvnflinger::Nvnflinger> surface_flinger, 13 std::shared_ptr<Container> container)
13 std::shared_ptr<FbshareBufferManager> shared_buffer_manager) 14 : ServiceFramework{system_, "ISystemDisplayService"}, m_container{std::move(container)} {
14 : ServiceFramework{system_, "ISystemDisplayService"},
15 m_surface_flinger{std::move(surface_flinger)},
16 m_shared_buffer_manager{std::move(shared_buffer_manager)} {
17 // clang-format off 15 // clang-format off
18 static const FunctionInfo functions[] = { 16 static const FunctionInfo functions[] = {
19 {1200, nullptr, "GetZOrderCountMin"}, 17 {1200, nullptr, "GetZOrderCountMin"},
@@ -61,7 +59,7 @@ ISystemDisplayService::ISystemDisplayService(
61 {8255, C<&ISystemDisplayService::PresentSharedFrameBuffer>, "PresentSharedFrameBuffer"}, 59 {8255, C<&ISystemDisplayService::PresentSharedFrameBuffer>, "PresentSharedFrameBuffer"},
62 {8256, C<&ISystemDisplayService::GetSharedFrameBufferAcquirableEvent>, "GetSharedFrameBufferAcquirableEvent"}, 60 {8256, C<&ISystemDisplayService::GetSharedFrameBufferAcquirableEvent>, "GetSharedFrameBufferAcquirableEvent"},
63 {8257, nullptr, "FillSharedFrameBufferColor"}, 61 {8257, nullptr, "FillSharedFrameBufferColor"},
64 {8258, nullptr, "CancelSharedFrameBuffer"}, 62 {8258, C<&ISystemDisplayService::CancelSharedFrameBuffer>, "CancelSharedFrameBuffer"},
65 {9000, nullptr, "GetDp2hdmiController"}, 63 {9000, nullptr, "GetDp2hdmiController"},
66 }; 64 };
67 // clang-format on 65 // clang-format on
@@ -106,7 +104,7 @@ Result ISystemDisplayService::GetSharedBufferMemoryHandleId(
106 ClientAppletResourceUserId aruid) { 104 ClientAppletResourceUserId aruid) {
107 LOG_INFO(Service_VI, "called. buffer_id={}, aruid={:#x}", buffer_id, aruid.pid); 105 LOG_INFO(Service_VI, "called. buffer_id={}, aruid={:#x}", buffer_id, aruid.pid);
108 106
109 R_RETURN(m_shared_buffer_manager->GetSharedBufferMemoryHandleId( 107 R_RETURN(m_container->GetSharedBufferManager()->GetSharedBufferMemoryHandleId(
110 out_size, out_nvmap_handle, out_pool_layout, buffer_id, aruid.pid)); 108 out_size, out_nvmap_handle, out_pool_layout, buffer_id, aruid.pid));
111} 109}
112 110
@@ -124,8 +122,8 @@ Result ISystemDisplayService::AcquireSharedFrameBuffer(Out<android::Fence> out_f
124 Out<std::array<s32, 4>> out_slots, 122 Out<std::array<s32, 4>> out_slots,
125 Out<s64> out_target_slot, u64 layer_id) { 123 Out<s64> out_target_slot, u64 layer_id) {
126 LOG_DEBUG(Service_VI, "called"); 124 LOG_DEBUG(Service_VI, "called");
127 R_RETURN(m_shared_buffer_manager->AcquireSharedFrameBuffer(out_fence, *out_slots, 125 R_RETURN(m_container->GetSharedBufferManager()->AcquireSharedFrameBuffer(
128 out_target_slot, layer_id)); 126 out_fence, *out_slots, out_target_slot, layer_id));
129} 127}
130 128
131Result ISystemDisplayService::PresentSharedFrameBuffer(android::Fence fence, 129Result ISystemDisplayService::PresentSharedFrameBuffer(android::Fence fence,
@@ -133,14 +131,20 @@ Result ISystemDisplayService::PresentSharedFrameBuffer(android::Fence fence,
133 u32 window_transform, s32 swap_interval, 131 u32 window_transform, s32 swap_interval,
134 u64 layer_id, s64 surface_id) { 132 u64 layer_id, s64 surface_id) {
135 LOG_DEBUG(Service_VI, "called"); 133 LOG_DEBUG(Service_VI, "called");
136 R_RETURN(m_shared_buffer_manager->PresentSharedFrameBuffer( 134 R_RETURN(m_container->GetSharedBufferManager()->PresentSharedFrameBuffer(
137 fence, crop_region, window_transform, swap_interval, layer_id, surface_id)); 135 fence, crop_region, window_transform, swap_interval, layer_id, surface_id));
138} 136}
139 137
140Result ISystemDisplayService::GetSharedFrameBufferAcquirableEvent( 138Result ISystemDisplayService::GetSharedFrameBufferAcquirableEvent(
141 OutCopyHandle<Kernel::KReadableEvent> out_event, u64 layer_id) { 139 OutCopyHandle<Kernel::KReadableEvent> out_event, u64 layer_id) {
142 LOG_DEBUG(Service_VI, "called"); 140 LOG_DEBUG(Service_VI, "called");
143 R_RETURN(m_shared_buffer_manager->GetSharedFrameBufferAcquirableEvent(out_event, layer_id)); 141 R_RETURN(m_container->GetSharedBufferManager()->GetSharedFrameBufferAcquirableEvent(out_event,
142 layer_id));
143}
144
145Result ISystemDisplayService::CancelSharedFrameBuffer(u64 layer_id, s64 slot) {
146 LOG_DEBUG(Service_VI, "called");
147 R_RETURN(m_container->GetSharedBufferManager()->CancelSharedFrameBuffer(layer_id, slot));
144} 148}
145 149
146} // namespace Service::VI 150} // 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 b84c9725f..63c1a4dc5 100644
--- a/src/core/hle/service/vi/system_display_service.h
+++ b/src/core/hle/service/vi/system_display_service.h
@@ -5,21 +5,15 @@
5#include "core/hle/service/cmif_types.h" 5#include "core/hle/service/cmif_types.h"
6#include "core/hle/service/nvnflinger/ui/fence.h" 6#include "core/hle/service/nvnflinger/ui/fence.h"
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8#include "core/hle/service/vi/fbshare_buffer_manager.h" 8#include "core/hle/service/vi/shared_buffer_manager.h"
9
10namespace Service::Nvnflinger {
11class Nvnflinger;
12} // namespace Service::Nvnflinger
13 9
14namespace Service::VI { 10namespace Service::VI {
15 11
16class FbshareBufferManager; 12class Container;
17 13
18class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> { 14class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
19public: 15public:
20 explicit ISystemDisplayService(Core::System& system_, 16 explicit ISystemDisplayService(Core::System& system_, std::shared_ptr<Container> container);
21 std::shared_ptr<Nvnflinger::Nvnflinger> surface_flinger,
22 std::shared_ptr<FbshareBufferManager> shared_buffer_manager);
23 ~ISystemDisplayService() override; 17 ~ISystemDisplayService() override;
24 18
25private: 19private:
@@ -42,10 +36,10 @@ private:
42 Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region, 36 Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region,
43 u32 window_transform, s32 swap_interval, u64 layer_id, 37 u32 window_transform, s32 swap_interval, u64 layer_id,
44 s64 surface_id); 38 s64 surface_id);
39 Result CancelSharedFrameBuffer(u64 layer_id, s64 slot);
45 40
46private: 41private:
47 const std::shared_ptr<Nvnflinger::Nvnflinger> m_surface_flinger; 42 const std::shared_ptr<Container> m_container;
48 const std::shared_ptr<FbshareBufferManager> m_shared_buffer_manager;
49}; 43};
50 44
51} // namespace Service::VI 45} // 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 2254ed111..3489727d8 100644
--- a/src/core/hle/service/vi/system_root_service.cpp
+++ b/src/core/hle/service/vi/system_root_service.cpp
@@ -3,6 +3,7 @@
3 3
4#include "core/hle/service/cmif_serialization.h" 4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/vi/application_display_service.h" 5#include "core/hle/service/vi/application_display_service.h"
6#include "core/hle/service/vi/container.h"
6#include "core/hle/service/vi/service_creator.h" 7#include "core/hle/service/vi/service_creator.h"
7#include "core/hle/service/vi/system_root_service.h" 8#include "core/hle/service/vi/system_root_service.h"
8#include "core/hle/service/vi/vi.h" 9#include "core/hle/service/vi/vi.h"
@@ -10,11 +11,8 @@
10 11
11namespace Service::VI { 12namespace Service::VI {
12 13
13ISystemRootService::ISystemRootService(Core::System& system_, 14ISystemRootService::ISystemRootService(Core::System& system_, std::shared_ptr<Container> container)
14 std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service, 15 : ServiceFramework{system_, "vi:s"}, m_container{std::move(container)} {
15 std::shared_ptr<FbshareBufferManager> shared_buffer_manager)
16 : ServiceFramework{system_, "vi:s"}, m_binder_service{std::move(binder_service)},
17 m_shared_buffer_manager{std::move(shared_buffer_manager)} {
18 static const FunctionInfo functions[] = { 16 static const FunctionInfo functions[] = {
19 {1, C<&ISystemRootService::GetDisplayService>, "GetDisplayService"}, 17 {1, C<&ISystemRootService::GetDisplayService>, "GetDisplayService"},
20 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, 18 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -27,8 +25,8 @@ ISystemRootService::~ISystemRootService() = default;
27Result ISystemRootService::GetDisplayService( 25Result ISystemRootService::GetDisplayService(
28 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) { 26 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) {
29 LOG_DEBUG(Service_VI, "called"); 27 LOG_DEBUG(Service_VI, "called");
30 R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_binder_service, 28 R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_container,
31 m_shared_buffer_manager, Permission::System, policy)); 29 Permission::System, policy));
32} 30}
33 31
34} // namespace Service::VI 32} // 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 16c997422..9d5aa53d3 100644
--- a/src/core/hle/service/vi/system_root_service.h
+++ b/src/core/hle/service/vi/system_root_service.h
@@ -10,21 +10,15 @@ namespace Core {
10class System; 10class System;
11} 11}
12 12
13namespace Service::Nvnflinger {
14class IHOSBinderDriver;
15} // namespace Service::Nvnflinger
16
17namespace Service::VI { 13namespace Service::VI {
18 14
19class FbshareBufferManager; 15class Container;
20class IApplicationDisplayService; 16class IApplicationDisplayService;
21enum class Policy : u32; 17enum class Policy : u32;
22 18
23class ISystemRootService final : public ServiceFramework<ISystemRootService> { 19class ISystemRootService final : public ServiceFramework<ISystemRootService> {
24public: 20public:
25 explicit ISystemRootService(Core::System& system_, 21 explicit ISystemRootService(Core::System& system_, std::shared_ptr<Container> container);
26 std::shared_ptr<Nvnflinger::IHOSBinderDriver> binder_service,
27 std::shared_ptr<FbshareBufferManager> shared_buffer_manager);
28 ~ISystemRootService() override; 22 ~ISystemRootService() override;
29 23
30private: 24private:
@@ -32,8 +26,7 @@ private:
32 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, 26 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service,
33 Policy policy); 27 Policy policy);
34 28
35 const std::shared_ptr<Nvnflinger::IHOSBinderDriver> m_binder_service; 29 const std::shared_ptr<Container> m_container;
36 const std::shared_ptr<FbshareBufferManager> m_shared_buffer_manager;
37}; 30};
38 31
39} // namespace Service::VI 32} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index f361b9f4c..b388efaf6 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -2,38 +2,29 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/core.h" 4#include "core/core.h"
5#include "core/hle/service/nvdrv/nvdrv_interface.h"
6#include "core/hle/service/nvnflinger/hos_binder_driver.h"
7#include "core/hle/service/server_manager.h" 5#include "core/hle/service/server_manager.h"
8#include "core/hle/service/sm/sm.h"
9#include "core/hle/service/vi/application_display_service.h"
10#include "core/hle/service/vi/application_root_service.h" 6#include "core/hle/service/vi/application_root_service.h"
11#include "core/hle/service/vi/fbshare_buffer_manager.h" 7#include "core/hle/service/vi/container.h"
12#include "core/hle/service/vi/manager_root_service.h" 8#include "core/hle/service/vi/manager_root_service.h"
13#include "core/hle/service/vi/system_root_service.h" 9#include "core/hle/service/vi/system_root_service.h"
14#include "core/hle/service/vi/vi.h" 10#include "core/hle/service/vi/vi.h"
15 11
16namespace Service::VI { 12namespace Service::VI {
17 13
18void LoopProcess(Core::System& system) { 14void LoopProcess(Core::System& system, std::stop_token token) {
19 const auto binder_service = 15 const auto container = std::make_shared<Container>(system);
20 system.ServiceManager().GetService<Nvnflinger::IHOSBinderDriver>("dispdrv", true);
21 const auto nvdrv =
22 system.ServiceManager().GetService<Nvidia::NVDRV>("nvdrv:s", true)->GetModule();
23 const auto shared_buffer_manager =
24 std::make_shared<FbshareBufferManager>(system, binder_service->GetSurfaceFlinger(), nvdrv);
25 16
26 auto server_manager = std::make_unique<ServerManager>(system); 17 auto server_manager = std::make_unique<ServerManager>(system);
27 18
19 server_manager->RegisterNamedService("vi:m",
20 std::make_shared<IManagerRootService>(system, container));
21 server_manager->RegisterNamedService("vi:s",
22 std::make_shared<ISystemRootService>(system, container));
28 server_manager->RegisterNamedService( 23 server_manager->RegisterNamedService(
29 "vi:m", 24 "vi:u", std::make_shared<IApplicationRootService>(system, container));
30 std::make_shared<IManagerRootService>(system, binder_service, shared_buffer_manager)); 25
31 server_manager->RegisterNamedService( 26 std::stop_callback cb(token, [=] { container->OnTerminate(); });
32 "vi:s", 27
33 std::make_shared<ISystemRootService>(system, binder_service, shared_buffer_manager));
34 server_manager->RegisterNamedService(
35 "vi:u",
36 std::make_shared<IApplicationRootService>(system, binder_service, shared_buffer_manager));
37 ServerManager::RunServer(std::move(server_manager)); 28 ServerManager::RunServer(std::move(server_manager));
38} 29}
39 30
diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h
index 0c3dc175d..7c1f350d8 100644
--- a/src/core/hle/service/vi/vi.h
+++ b/src/core/hle/service/vi/vi.h
@@ -3,12 +3,14 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "common/polyfill_thread.h"
7
6namespace Core { 8namespace Core {
7class System; 9class System;
8} 10}
9 11
10namespace Service::VI { 12namespace Service::VI {
11 13
12void LoopProcess(Core::System& system); 14void LoopProcess(Core::System& system, std::stop_token token);
13 15
14} // namespace Service::VI 16} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_types.h b/src/core/hle/service/vi/vi_types.h
index 91e4b380c..7f2c70aef 100644
--- a/src/core/hle/service/vi/vi_types.h
+++ b/src/core/hle/service/vi/vi_types.h
@@ -68,7 +68,7 @@ static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size");
68 68
69class NativeWindow final { 69class NativeWindow final {
70public: 70public:
71 constexpr explicit NativeWindow(u32 id_) : id{id_} {} 71 constexpr explicit NativeWindow(s32 id_) : id{static_cast<u64>(id_)} {}
72 constexpr explicit NativeWindow(const NativeWindow& other) = default; 72 constexpr explicit NativeWindow(const NativeWindow& other) = default;
73 73
74private: 74private:
diff --git a/src/core/hle/service/vi/vsync_manager.cpp b/src/core/hle/service/vi/vsync_manager.cpp
new file mode 100644
index 000000000..bdc4dfa96
--- /dev/null
+++ b/src/core/hle/service/vi/vsync_manager.cpp
@@ -0,0 +1,26 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/os/event.h"
5#include "core/hle/service/vi/vsync_manager.h"
6
7namespace Service::VI {
8
9VsyncManager::VsyncManager() = default;
10VsyncManager::~VsyncManager() = default;
11
12void VsyncManager::SignalVsync() {
13 for (auto* event : m_vsync_events) {
14 event->Signal();
15 }
16}
17
18void VsyncManager::LinkVsyncEvent(Event* event) {
19 m_vsync_events.insert(event);
20}
21
22void VsyncManager::UnlinkVsyncEvent(Event* event) {
23 m_vsync_events.erase(event);
24}
25
26} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vsync_manager.h b/src/core/hle/service/vi/vsync_manager.h
new file mode 100644
index 000000000..5d45bb5ee
--- /dev/null
+++ b/src/core/hle/service/vi/vsync_manager.h
@@ -0,0 +1,29 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <set>
7
8namespace Service {
9class Event;
10}
11
12namespace Service::VI {
13
14class DisplayList;
15
16class VsyncManager {
17public:
18 explicit VsyncManager();
19 ~VsyncManager();
20
21 void SignalVsync();
22 void LinkVsyncEvent(Event* event);
23 void UnlinkVsyncEvent(Event* event);
24
25private:
26 std::set<Event*> m_vsync_events;
27};
28
29} // namespace Service::VI