aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpineappleEA <pineaea@gmail.com>2024-02-14 20:17:22 +0100
committerpineappleEA <pineaea@gmail.com>2024-02-14 20:17:22 +0100
commit9cc5d38fdf3d2e8f77a7d79f937d04cdabbc3a2e (patch)
tree7871b215bd0a013d3add9c760efcd8f51eba541a
parent603970064d5714da3c58eac0d9f95516b81d7892 (diff)
early-access version 4139EA-4139
-rwxr-xr-xREADME.md2
-rwxr-xr-xsrc/core/CMakeLists.txt24
-rwxr-xr-xsrc/core/hle/service/am/service/common_state_getter.cpp1
-rwxr-xr-xsrc/core/hle/service/nvnflinger/binder.h5
-rwxr-xr-xsrc/core/hle/service/nvnflinger/buffer_queue_producer.cpp9
-rwxr-xr-xsrc/core/hle/service/nvnflinger/buffer_queue_producer.h3
-rwxr-xr-xsrc/core/hle/service/vi/application_display_service.cpp319
-rwxr-xr-xsrc/core/hle/service/vi/application_display_service.h65
-rwxr-xr-xsrc/core/hle/service/vi/application_root_service.cpp34
-rwxr-xr-xsrc/core/hle/service/vi/application_root_service.h39
-rwxr-xr-xsrc/core/hle/service/vi/hos_binder_driver.cpp53
-rwxr-xr-xsrc/core/hle/service/vi/hos_binder_driver.h30
-rwxr-xr-xsrc/core/hle/service/vi/manager_display_service.cpp130
-rwxr-xr-xsrc/core/hle/service/vi/manager_display_service.h24
-rwxr-xr-xsrc/core/hle/service/vi/manager_root_service.cpp38
-rwxr-xr-xsrc/core/hle/service/vi/manager_root_service.h38
-rwxr-xr-xsrc/core/hle/service/vi/service_creator.cpp39
-rwxr-xr-xsrc/core/hle/service/vi/service_creator.h33
-rwxr-xr-xsrc/core/hle/service/vi/system_display_service.cpp145
-rwxr-xr-xsrc/core/hle/service/vi/system_display_service.h45
-rwxr-xr-xsrc/core/hle/service/vi/system_root_service.cpp33
-rwxr-xr-xsrc/core/hle/service/vi/system_root_service.h38
-rwxr-xr-xsrc/core/hle/service/vi/vi.cpp967
-rwxr-xr-xsrc/core/hle/service/vi/vi.h34
-rwxr-xr-xsrc/core/hle/service/vi/vi_types.h84
25 files changed, 1228 insertions, 1004 deletions
diff --git a/README.md b/README.md
index 4166e0658..2380e0551 100755
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
1yuzu emulator early access 1yuzu emulator early access
2============= 2=============
3 3
4This is the source code for early-access 4138. 4This is the source code for early-access 4139.
5 5
6## Legal Notice 6## Legal Notice
7 7
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 23fd1401c..2701b481d 100755
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -959,14 +959,26 @@ add_library(core STATIC
959 hle/service/vi/display/vi_display.h 959 hle/service/vi/display/vi_display.h
960 hle/service/vi/layer/vi_layer.cpp 960 hle/service/vi/layer/vi_layer.cpp
961 hle/service/vi/layer/vi_layer.h 961 hle/service/vi/layer/vi_layer.h
962 hle/service/vi/application_display_service.cpp
963 hle/service/vi/application_display_service.h
964 hle/service/vi/application_root_service.cpp
965 hle/service/vi/application_root_service.h
966 hle/service/vi/hos_binder_driver.cpp
967 hle/service/vi/hos_binder_driver.h
968 hle/service/vi/manager_display_service.cpp
969 hle/service/vi/manager_display_service.h
970 hle/service/vi/manager_root_service.cpp
971 hle/service/vi/manager_root_service.h
972 hle/service/vi/service_creator.cpp
973 hle/service/vi/service_creator.h
974 hle/service/vi/system_display_service.cpp
975 hle/service/vi/system_display_service.h
976 hle/service/vi/system_root_service.cpp
977 hle/service/vi/system_root_service.h
978 hle/service/vi/vi_results.h
979 hle/service/vi/vi_types.h
962 hle/service/vi/vi.cpp 980 hle/service/vi/vi.cpp
963 hle/service/vi/vi.h 981 hle/service/vi/vi.h
964 hle/service/vi/vi_m.cpp
965 hle/service/vi/vi_m.h
966 hle/service/vi/vi_s.cpp
967 hle/service/vi/vi_s.h
968 hle/service/vi/vi_u.cpp
969 hle/service/vi/vi_u.h
970 internal_network/network.cpp 982 internal_network/network.cpp
971 internal_network/network.h 983 internal_network/network.h
972 internal_network/network_interface.cpp 984 internal_network/network_interface.cpp
diff --git a/src/core/hle/service/am/service/common_state_getter.cpp b/src/core/hle/service/am/service/common_state_getter.cpp
index 12d7e8cb1..548498e83 100755
--- a/src/core/hle/service/am/service/common_state_getter.cpp
+++ b/src/core/hle/service/am/service/common_state_getter.cpp
@@ -11,6 +11,7 @@
11#include "core/hle/service/pm/pm.h" 11#include "core/hle/service/pm/pm.h"
12#include "core/hle/service/sm/sm.h" 12#include "core/hle/service/sm/sm.h"
13#include "core/hle/service/vi/vi.h" 13#include "core/hle/service/vi/vi.h"
14#include "core/hle/service/vi/vi_types.h"
14 15
15namespace Service::AM { 16namespace Service::AM {
16 17
diff --git a/src/core/hle/service/nvnflinger/binder.h b/src/core/hle/service/nvnflinger/binder.h
index aef1477e3..179938192 100755
--- a/src/core/hle/service/nvnflinger/binder.h
+++ b/src/core/hle/service/nvnflinger/binder.h
@@ -6,6 +6,8 @@
6 6
7#pragma once 7#pragma once
8 8
9#include <span>
10
9#include "common/common_types.h" 11#include "common/common_types.h"
10 12
11namespace Kernel { 13namespace Kernel {
@@ -38,7 +40,8 @@ enum class TransactionId {
38class IBinder { 40class IBinder {
39public: 41public:
40 virtual ~IBinder() = default; 42 virtual ~IBinder() = default;
41 virtual void Transact(HLERequestContext& ctx, android::TransactionId code, u32 flags) = 0; 43 virtual void Transact(android::TransactionId code, u32 flags, std::span<const u8> parcel_data,
44 std::span<u8> parcel_reply) = 0;
42 virtual Kernel::KReadableEvent& GetNativeHandle() = 0; 45 virtual Kernel::KReadableEvent& GetNativeHandle() = 0;
43}; 46};
44 47
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
index 5d8762d25..ec83beb9b 100755
--- a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
+++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
@@ -807,9 +807,10 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
807 return Status::NoError; 807 return Status::NoError;
808} 808}
809 809
810void BufferQueueProducer::Transact(HLERequestContext& ctx, TransactionId code, u32 flags) { 810void BufferQueueProducer::Transact(TransactionId code, u32 flags, std::span<const u8> parcel_data,
811 std::span<u8> parcel_reply) {
811 Status status{Status::NoError}; 812 Status status{Status::NoError};
812 InputParcel parcel_in{ctx.ReadBuffer()}; 813 InputParcel parcel_in{parcel_data};
813 OutputParcel parcel_out{}; 814 OutputParcel parcel_out{};
814 815
815 switch (code) { 816 switch (code) {
@@ -917,7 +918,9 @@ void BufferQueueProducer::Transact(HLERequestContext& ctx, TransactionId code, u
917 918
918 parcel_out.Write(status); 919 parcel_out.Write(status);
919 920
920 ctx.WriteBuffer(parcel_out.Serialize()); 921 const auto serialized = parcel_out.Serialize();
922 std::memcpy(parcel_reply.data(), serialized.data(),
923 std::min(parcel_reply.size(), serialized.size()));
921} 924}
922 925
923Kernel::KReadableEvent& BufferQueueProducer::GetNativeHandle() { 926Kernel::KReadableEvent& BufferQueueProducer::GetNativeHandle() {
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.h b/src/core/hle/service/nvnflinger/buffer_queue_producer.h
index 64c17d56c..4682b0f84 100755
--- a/src/core/hle/service/nvnflinger/buffer_queue_producer.h
+++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.h
@@ -47,7 +47,8 @@ public:
47 Service::Nvidia::NvCore::NvMap& nvmap_); 47 Service::Nvidia::NvCore::NvMap& nvmap_);
48 ~BufferQueueProducer(); 48 ~BufferQueueProducer();
49 49
50 void Transact(HLERequestContext& ctx, android::TransactionId code, u32 flags) override; 50 void Transact(android::TransactionId code, u32 flags, std::span<const u8> parcel_data,
51 std::span<u8> parcel_reply) override;
51 52
52 Kernel::KReadableEvent& GetNativeHandle() override; 53 Kernel::KReadableEvent& GetNativeHandle() override;
53 54
diff --git a/src/core/hle/service/vi/application_display_service.cpp b/src/core/hle/service/vi/application_display_service.cpp
new file mode 100755
index 000000000..78229e30f
--- /dev/null
+++ b/src/core/hle/service/vi/application_display_service.cpp
@@ -0,0 +1,319 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/nvnflinger/nvnflinger.h"
6#include "core/hle/service/nvnflinger/parcel.h"
7#include "core/hle/service/vi/application_display_service.h"
8#include "core/hle/service/vi/hos_binder_driver.h"
9#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/vi_results.h"
12
13namespace Service::VI {
14
15IApplicationDisplayService::IApplicationDisplayService(
16 Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger,
17 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server)
18 : ServiceFramework{system_, "IApplicationDisplayService"}, m_nvnflinger{nvnflinger},
19 m_hos_binder_driver_server{hos_binder_driver_server} {
20
21 // clang-format off
22 static const FunctionInfo functions[] = {
23 {100, C<&IApplicationDisplayService::GetRelayService>, "GetRelayService"},
24 {101, C<&IApplicationDisplayService::GetSystemDisplayService>, "GetSystemDisplayService"},
25 {102, C<&IApplicationDisplayService::GetManagerDisplayService>, "GetManagerDisplayService"},
26 {103, C<&IApplicationDisplayService::GetIndirectDisplayTransactionService>, "GetIndirectDisplayTransactionService"},
27 {1000, C<&IApplicationDisplayService::ListDisplays>, "ListDisplays"},
28 {1010, C<&IApplicationDisplayService::OpenDisplay>, "OpenDisplay"},
29 {1011, C<&IApplicationDisplayService::OpenDefaultDisplay>, "OpenDefaultDisplay"},
30 {1020, C<&IApplicationDisplayService::CloseDisplay>, "CloseDisplay"},
31 {1101, C<&IApplicationDisplayService::SetDisplayEnabled>, "SetDisplayEnabled"},
32 {1102, C<&IApplicationDisplayService::GetDisplayResolution>, "GetDisplayResolution"},
33 {2020, C<&IApplicationDisplayService::OpenLayer>, "OpenLayer"},
34 {2021, C<&IApplicationDisplayService::CloseLayer>, "CloseLayer"},
35 {2030, C<&IApplicationDisplayService::CreateStrayLayer>, "CreateStrayLayer"},
36 {2031, C<&IApplicationDisplayService::DestroyStrayLayer>, "DestroyStrayLayer"},
37 {2101, C<&IApplicationDisplayService::SetLayerScalingMode>, "SetLayerScalingMode"},
38 {2102, C<&IApplicationDisplayService::ConvertScalingMode>, "ConvertScalingMode"},
39 {2450, C<&IApplicationDisplayService::GetIndirectLayerImageMap>, "GetIndirectLayerImageMap"},
40 {2451, nullptr, "GetIndirectLayerImageCropMap"},
41 {2460, C<&IApplicationDisplayService::GetIndirectLayerImageRequiredMemoryInfo>, "GetIndirectLayerImageRequiredMemoryInfo"},
42 {5202, C<&IApplicationDisplayService::GetDisplayVsyncEvent>, "GetDisplayVsyncEvent"},
43 {5203, nullptr, "GetDisplayVsyncEventForDebug"},
44 };
45 // clang-format on
46
47 RegisterHandlers(functions);
48}
49
50IApplicationDisplayService::~IApplicationDisplayService() {
51 for (const auto layer_id : m_stray_layer_ids) {
52 m_nvnflinger.DestroyLayer(layer_id);
53 }
54}
55
56Result IApplicationDisplayService::GetRelayService(
57 Out<SharedPointer<IHOSBinderDriver>> out_relay_service) {
58 LOG_WARNING(Service_VI, "(STUBBED) called");
59 *out_relay_service = std::make_shared<IHOSBinderDriver>(system, m_hos_binder_driver_server);
60 R_SUCCEED();
61}
62
63Result IApplicationDisplayService::GetSystemDisplayService(
64 Out<SharedPointer<ISystemDisplayService>> out_system_display_service) {
65 LOG_WARNING(Service_VI, "(STUBBED) called");
66 *out_system_display_service = std::make_shared<ISystemDisplayService>(system, m_nvnflinger);
67 R_SUCCEED();
68}
69
70Result IApplicationDisplayService::GetManagerDisplayService(
71 Out<SharedPointer<IManagerDisplayService>> out_manager_display_service) {
72 LOG_WARNING(Service_VI, "(STUBBED) called");
73 *out_manager_display_service = std::make_shared<IManagerDisplayService>(system, m_nvnflinger);
74 R_SUCCEED();
75}
76
77Result IApplicationDisplayService::GetIndirectDisplayTransactionService(
78 Out<SharedPointer<IHOSBinderDriver>> out_indirect_display_transaction_service) {
79 LOG_WARNING(Service_VI, "(STUBBED) called");
80 *out_indirect_display_transaction_service =
81 std::make_shared<IHOSBinderDriver>(system, m_hos_binder_driver_server);
82 R_SUCCEED();
83}
84
85Result IApplicationDisplayService::OpenDisplay(Out<u64> out_display_id, DisplayName display_name) {
86 LOG_WARNING(Service_VI, "(STUBBED) called");
87
88 display_name[display_name.size() - 1] = '\0';
89 ASSERT_MSG(strcmp(display_name.data(), "Default") == 0,
90 "Non-default displays aren't supported yet");
91
92 const auto display_id = m_nvnflinger.OpenDisplay(display_name.data());
93 if (!display_id) {
94 LOG_ERROR(Service_VI, "Display not found! display_name={}", display_name.data());
95 R_THROW(VI::ResultNotFound);
96 }
97
98 *out_display_id = *display_id;
99 R_SUCCEED();
100}
101
102Result IApplicationDisplayService::OpenDefaultDisplay(Out<u64> out_display_id) {
103 LOG_DEBUG(Service_VI, "called");
104 R_RETURN(this->OpenDisplay(out_display_id, DisplayName{"Default"}));
105}
106
107Result IApplicationDisplayService::CloseDisplay(u64 display_id) {
108 LOG_DEBUG(Service_VI, "called");
109 R_SUCCEED_IF(m_nvnflinger.CloseDisplay(display_id));
110 R_THROW(ResultUnknown);
111}
112
113Result IApplicationDisplayService::SetDisplayEnabled(u32 state, u64 display_id) {
114 LOG_DEBUG(Service_VI, "called");
115
116 // This literally does nothing internally in the actual service itself,
117 // and just returns a successful result code regardless of the input.
118 R_SUCCEED();
119}
120
121Result IApplicationDisplayService::GetDisplayResolution(Out<s64> out_width, Out<s64> out_height,
122 u64 display_id) {
123 LOG_DEBUG(Service_VI, "called. display_id={}", display_id);
124
125 // This only returns the fixed values of 1280x720 and makes no distinguishing
126 // between docked and undocked dimensions.
127 *out_width = static_cast<s64>(DisplayResolution::UndockedWidth);
128 *out_height = static_cast<s64>(DisplayResolution::UndockedHeight);
129 R_SUCCEED();
130}
131
132Result IApplicationDisplayService::SetLayerScalingMode(NintendoScaleMode scale_mode, u64 layer_id) {
133 LOG_DEBUG(Service_VI, "called. scale_mode={}, unknown=0x{:016X}", scale_mode, layer_id);
134
135 if (scale_mode > NintendoScaleMode::PreserveAspectRatio) {
136 LOG_ERROR(Service_VI, "Invalid scaling mode provided.");
137 R_THROW(VI::ResultOperationFailed);
138 }
139
140 if (scale_mode != NintendoScaleMode::ScaleToWindow &&
141 scale_mode != NintendoScaleMode::PreserveAspectRatio) {
142 LOG_ERROR(Service_VI, "Unsupported scaling mode supplied.");
143 R_THROW(VI::ResultNotSupported);
144 }
145
146 R_SUCCEED();
147}
148
149Result IApplicationDisplayService::ListDisplays(
150 Out<u64> out_count, OutArray<DisplayInfo, BufferAttr_HipcMapAlias> out_displays) {
151 LOG_WARNING(Service_VI, "(STUBBED) called");
152
153 if (out_displays.size() > 0) {
154 out_displays[0] = DisplayInfo{};
155 *out_count = 1;
156 } else {
157 *out_count = 0;
158 }
159
160 R_SUCCEED();
161}
162
163Result IApplicationDisplayService::OpenLayer(Out<u64> out_size,
164 OutBuffer<BufferAttr_HipcMapAlias> out_native_window,
165 DisplayName display_name, u64 layer_id,
166 ClientAppletResourceUserId aruid) {
167 display_name[display_name.size() - 1] = '\0';
168
169 LOG_DEBUG(Service_VI, "called. layer_id={}, aruid={:#x}", layer_id, aruid.pid);
170
171 const auto display_id = m_nvnflinger.OpenDisplay(display_name.data());
172 if (!display_id) {
173 LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id);
174 R_THROW(VI::ResultNotFound);
175 }
176
177 const auto buffer_queue_id = m_nvnflinger.FindBufferQueueId(*display_id, layer_id);
178 if (!buffer_queue_id) {
179 LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id);
180 R_THROW(VI::ResultNotFound);
181 }
182
183 if (!m_nvnflinger.OpenLayer(layer_id)) {
184 LOG_WARNING(Service_VI, "Tried to open layer which was already open");
185 R_THROW(VI::ResultOperationFailed);
186 }
187
188 android::OutputParcel parcel;
189 parcel.WriteInterface(NativeWindow{*buffer_queue_id});
190
191 const auto buffer = parcel.Serialize();
192 std::memcpy(out_native_window.data(), buffer.data(),
193 std::min(out_native_window.size(), buffer.size()));
194 *out_size = buffer.size();
195
196 R_SUCCEED();
197}
198
199Result IApplicationDisplayService::CloseLayer(u64 layer_id) {
200 LOG_DEBUG(Service_VI, "called. layer_id={}", layer_id);
201
202 if (!m_nvnflinger.CloseLayer(layer_id)) {
203 LOG_WARNING(Service_VI, "Tried to close layer which was not open");
204 R_THROW(VI::ResultOperationFailed);
205 }
206
207 R_SUCCEED();
208}
209
210Result IApplicationDisplayService::CreateStrayLayer(
211 Out<u64> out_layer_id, Out<u64> out_size, OutBuffer<BufferAttr_HipcMapAlias> out_native_window,
212 u32 flags, u64 display_id) {
213 LOG_DEBUG(Service_VI, "called. flags={}, display_id={}", flags, display_id);
214
215 const auto layer_id = m_nvnflinger.CreateLayer(display_id);
216 if (!layer_id) {
217 LOG_ERROR(Service_VI, "Layer not found! display_id={}", display_id);
218 R_THROW(VI::ResultNotFound);
219 }
220
221 m_stray_layer_ids.push_back(*layer_id);
222 const auto buffer_queue_id = m_nvnflinger.FindBufferQueueId(display_id, *layer_id);
223 if (!buffer_queue_id) {
224 LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id);
225 R_THROW(VI::ResultNotFound);
226 }
227
228 android::OutputParcel parcel;
229 parcel.WriteInterface(NativeWindow{*buffer_queue_id});
230
231 const auto buffer = parcel.Serialize();
232 std::memcpy(out_native_window.data(), buffer.data(),
233 std::min(out_native_window.size(), buffer.size()));
234
235 *out_layer_id = *layer_id;
236 *out_size = buffer.size();
237
238 R_SUCCEED();
239}
240
241Result IApplicationDisplayService::DestroyStrayLayer(u64 layer_id) {
242 LOG_WARNING(Service_VI, "(STUBBED) called. layer_id={}", layer_id);
243 m_nvnflinger.DestroyLayer(layer_id);
244 R_SUCCEED();
245}
246
247Result IApplicationDisplayService::GetDisplayVsyncEvent(
248 OutCopyHandle<Kernel::KReadableEvent> out_vsync_event, u64 display_id) {
249 LOG_DEBUG(Service_VI, "called. display_id={}", display_id);
250
251 const auto result = m_nvnflinger.FindVsyncEvent(out_vsync_event, display_id);
252 if (result != ResultSuccess) {
253 if (result == ResultNotFound) {
254 LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id);
255 }
256
257 R_THROW(result);
258 }
259
260 R_UNLESS(!m_vsync_event_fetched, VI::ResultPermissionDenied);
261 m_vsync_event_fetched = true;
262
263 R_SUCCEED();
264}
265
266Result IApplicationDisplayService::ConvertScalingMode(Out<ConvertedScaleMode> out_scaling_mode,
267 NintendoScaleMode mode) {
268 LOG_DEBUG(Service_VI, "called mode={}", mode);
269
270 switch (mode) {
271 case NintendoScaleMode::None:
272 *out_scaling_mode = ConvertedScaleMode::None;
273 R_SUCCEED();
274 case NintendoScaleMode::Freeze:
275 *out_scaling_mode = ConvertedScaleMode::Freeze;
276 R_SUCCEED();
277 case NintendoScaleMode::ScaleToWindow:
278 *out_scaling_mode = ConvertedScaleMode::ScaleToWindow;
279 R_SUCCEED();
280 case NintendoScaleMode::ScaleAndCrop:
281 *out_scaling_mode = ConvertedScaleMode::ScaleAndCrop;
282 R_SUCCEED();
283 case NintendoScaleMode::PreserveAspectRatio:
284 *out_scaling_mode = ConvertedScaleMode::PreserveAspectRatio;
285 R_SUCCEED();
286 default:
287 LOG_ERROR(Service_VI, "Invalid scaling mode specified, mode={}", mode);
288 R_THROW(VI::ResultOperationFailed);
289 }
290}
291
292Result IApplicationDisplayService::GetIndirectLayerImageMap(
293 Out<u64> out_size, Out<u64> out_stride,
294 OutBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> out_buffer,
295 s64 width, s64 height, u64 indirect_layer_consumer_handle, ClientAppletResourceUserId aruid) {
296 LOG_WARNING(
297 Service_VI,
298 "(STUBBED) called, width={}, height={}, indirect_layer_consumer_handle={}, aruid={:#x}",
299 width, height, indirect_layer_consumer_handle, aruid.pid);
300 *out_size = 0;
301 *out_stride = 0;
302 R_SUCCEED();
303}
304
305Result IApplicationDisplayService::GetIndirectLayerImageRequiredMemoryInfo(Out<s64> out_size,
306 Out<s64> out_alignment,
307 s64 width, s64 height) {
308 LOG_DEBUG(Service_VI, "called width={}, height={}", width, height);
309
310 constexpr u64 base_size = 0x20000;
311 const auto texture_size = width * height * 4;
312
313 *out_alignment = 0x1000;
314 *out_size = (texture_size + base_size - 1) / base_size * base_size;
315
316 R_SUCCEED();
317}
318
319} // namespace Service::VI
diff --git a/src/core/hle/service/vi/application_display_service.h b/src/core/hle/service/vi/application_display_service.h
new file mode 100755
index 000000000..5dff4bb31
--- /dev/null
+++ b/src/core/hle/service/vi/application_display_service.h
@@ -0,0 +1,65 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_types.h"
5#include "core/hle/service/service.h"
6#include "core/hle/service/vi/vi_types.h"
7
8namespace Kernel {
9class KReadableEvent;
10}
11
12namespace Service::VI {
13
14class IHOSBinderDriver;
15class IManagerDisplayService;
16class ISystemDisplayService;
17
18class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
19public:
20 IApplicationDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger,
21 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server);
22 ~IApplicationDisplayService() override;
23
24private:
25 Result GetRelayService(Out<SharedPointer<IHOSBinderDriver>> out_relay_service);
26 Result GetSystemDisplayService(
27 Out<SharedPointer<ISystemDisplayService>> out_system_display_service);
28 Result GetManagerDisplayService(
29 Out<SharedPointer<IManagerDisplayService>> out_manager_display_service);
30 Result GetIndirectDisplayTransactionService(
31 Out<SharedPointer<IHOSBinderDriver>> out_indirect_display_transaction_service);
32 Result OpenDisplay(Out<u64> out_display_id, DisplayName display_name);
33 Result OpenDefaultDisplay(Out<u64> out_display_id);
34 Result CloseDisplay(u64 display_id);
35 Result SetDisplayEnabled(u32 state, u64 display_id);
36 Result GetDisplayResolution(Out<s64> out_width, Out<s64> out_height, u64 display_id);
37 Result SetLayerScalingMode(NintendoScaleMode scale_mode, u64 layer_id);
38 Result ListDisplays(Out<u64> out_count,
39 OutArray<DisplayInfo, BufferAttr_HipcMapAlias> out_displays);
40 Result OpenLayer(Out<u64> out_size, OutBuffer<BufferAttr_HipcMapAlias> out_native_window,
41 DisplayName display_name, u64 layer_id, ClientAppletResourceUserId aruid);
42 Result CloseLayer(u64 layer_id);
43 Result CreateStrayLayer(Out<u64> out_layer_id, Out<u64> out_size,
44 OutBuffer<BufferAttr_HipcMapAlias> out_native_window, u32 flags,
45 u64 display_id);
46 Result DestroyStrayLayer(u64 layer_id);
47 Result GetDisplayVsyncEvent(OutCopyHandle<Kernel::KReadableEvent> out_vsync_event,
48 u64 display_id);
49 Result ConvertScalingMode(Out<ConvertedScaleMode> out_scaling_mode, NintendoScaleMode mode);
50 Result GetIndirectLayerImageMap(
51 Out<u64> out_size, Out<u64> out_stride,
52 OutBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> out_buffer,
53 s64 width, s64 height, u64 indirect_layer_consumer_handle,
54 ClientAppletResourceUserId aruid);
55 Result GetIndirectLayerImageRequiredMemoryInfo(Out<s64> out_size, Out<s64> out_alignment,
56 s64 width, s64 height);
57
58private:
59 Nvnflinger::Nvnflinger& m_nvnflinger;
60 Nvnflinger::HosBinderDriverServer& m_hos_binder_driver_server;
61 std::vector<u64> m_stray_layer_ids;
62 bool m_vsync_event_fetched{false};
63};
64
65} // namespace Service::VI
diff --git a/src/core/hle/service/vi/application_root_service.cpp b/src/core/hle/service/vi/application_root_service.cpp
new file mode 100755
index 000000000..7af7f062c
--- /dev/null
+++ b/src/core/hle/service/vi/application_root_service.cpp
@@ -0,0 +1,34 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/vi/application_display_service.h"
6#include "core/hle/service/vi/application_root_service.h"
7#include "core/hle/service/vi/service_creator.h"
8#include "core/hle/service/vi/vi.h"
9#include "core/hle/service/vi/vi_types.h"
10
11namespace Service::VI {
12
13IApplicationRootService::IApplicationRootService(
14 Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger,
15 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server)
16 : ServiceFramework{system_, "vi:u"}, m_nvnflinger{nvnflinger}, m_hos_binder_driver_server{
17 hos_binder_driver_server} {
18 static const FunctionInfo functions[] = {
19 {0, C<&IApplicationRootService::GetDisplayService>, "GetDisplayService"},
20 {1, nullptr, "GetDisplayServiceWithProxyNameExchange"},
21 };
22 RegisterHandlers(functions);
23}
24
25IApplicationRootService::~IApplicationRootService() = default;
26
27Result IApplicationRootService::GetDisplayService(
28 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) {
29 LOG_DEBUG(Service_VI, "called");
30 R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_nvnflinger,
31 m_hos_binder_driver_server, Permission::User, policy));
32}
33
34} // 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
new file mode 100755
index 000000000..9dbf28cb4
--- /dev/null
+++ b/src/core/hle/service/vi/application_root_service.h
@@ -0,0 +1,39 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::Nvnflinger {
14class HosBinderDriverServer;
15class Nvnflinger;
16} // namespace Service::Nvnflinger
17
18namespace Service::VI {
19
20class IApplicationDisplayService;
21enum class Policy : u32;
22
23class IApplicationRootService final : public ServiceFramework<IApplicationRootService> {
24public:
25 explicit IApplicationRootService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger,
26 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server);
27 ~IApplicationRootService() override;
28
29private:
30 Result GetDisplayService(
31 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service,
32 Policy policy);
33
34private:
35 Nvnflinger::Nvnflinger& m_nvnflinger;
36 Nvnflinger::HosBinderDriverServer& m_hos_binder_driver_server;
37};
38
39} // namespace Service::VI
diff --git a/src/core/hle/service/vi/hos_binder_driver.cpp b/src/core/hle/service/vi/hos_binder_driver.cpp
new file mode 100755
index 000000000..ba0317245
--- /dev/null
+++ b/src/core/hle/service/vi/hos_binder_driver.cpp
@@ -0,0 +1,53 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/nvnflinger/binder.h"
6#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
7#include "core/hle/service/vi/hos_binder_driver.h"
8
9namespace Service::VI {
10
11IHOSBinderDriver::IHOSBinderDriver(Core::System& system_, Nvnflinger::HosBinderDriverServer& server)
12 : ServiceFramework{system_, "IHOSBinderDriver"}, m_server(server) {
13 static const FunctionInfo functions[] = {
14 {0, C<&IHOSBinderDriver::TransactParcel>, "TransactParcel"},
15 {1, C<&IHOSBinderDriver::AdjustRefcount>, "AdjustRefcount"},
16 {2, C<&IHOSBinderDriver::GetNativeHandle>, "GetNativeHandle"},
17 {3, C<&IHOSBinderDriver::TransactParcelAuto>, "TransactParcelAuto"},
18 };
19 RegisterHandlers(functions);
20}
21
22IHOSBinderDriver::~IHOSBinderDriver() = default;
23
24Result IHOSBinderDriver::TransactParcel(s32 binder_id, android::TransactionId transaction_id,
25 InBuffer<BufferAttr_HipcMapAlias> parcel_data,
26 OutBuffer<BufferAttr_HipcMapAlias> parcel_reply,
27 u32 flags) {
28 LOG_DEBUG(Service_VI, "called. id={} transaction={}, flags={}", binder_id, transaction_id,
29 flags);
30 m_server.TryGetProducer(binder_id)->Transact(transaction_id, flags, parcel_data, parcel_reply);
31 R_SUCCEED();
32}
33
34Result IHOSBinderDriver::AdjustRefcount(s32 binder_id, s32 addval, s32 type) {
35 LOG_WARNING(Service_VI, "(STUBBED) called id={}, addval={}, type={}", binder_id, addval, type);
36 R_SUCCEED();
37}
38
39Result IHOSBinderDriver::GetNativeHandle(s32 binder_id, u32 type_id,
40 OutCopyHandle<Kernel::KReadableEvent> out_handle) {
41 LOG_WARNING(Service_VI, "(STUBBED) called id={}, type_id={}", binder_id, type_id);
42 *out_handle = &m_server.TryGetProducer(binder_id)->GetNativeHandle();
43 R_SUCCEED();
44}
45
46Result IHOSBinderDriver::TransactParcelAuto(s32 binder_id, android::TransactionId transaction_id,
47 InBuffer<BufferAttr_HipcAutoSelect> parcel_data,
48 OutBuffer<BufferAttr_HipcAutoSelect> parcel_reply,
49 u32 flags) {
50 R_RETURN(this->TransactParcel(binder_id, transaction_id, parcel_data, parcel_reply, flags));
51}
52
53} // namespace Service::VI
diff --git a/src/core/hle/service/vi/hos_binder_driver.h b/src/core/hle/service/vi/hos_binder_driver.h
new file mode 100755
index 000000000..ed6e8cdbe
--- /dev/null
+++ b/src/core/hle/service/vi/hos_binder_driver.h
@@ -0,0 +1,30 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_types.h"
5#include "core/hle/service/nvnflinger/binder.h"
6#include "core/hle/service/service.h"
7
8namespace Service::VI {
9
10class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
11public:
12 explicit IHOSBinderDriver(Core::System& system_, Nvnflinger::HosBinderDriverServer& server);
13 ~IHOSBinderDriver() override;
14
15private:
16 Result TransactParcel(s32 binder_id, android::TransactionId transaction_id,
17 InBuffer<BufferAttr_HipcMapAlias> parcel_data,
18 OutBuffer<BufferAttr_HipcMapAlias> parcel_reply, u32 flags);
19 Result AdjustRefcount(s32 binder_id, s32 addval, s32 type);
20 Result GetNativeHandle(s32 binder_id, u32 type_id,
21 OutCopyHandle<Kernel::KReadableEvent> out_handle);
22 Result TransactParcelAuto(s32 binder_id, android::TransactionId transaction_id,
23 InBuffer<BufferAttr_HipcAutoSelect> parcel_data,
24 OutBuffer<BufferAttr_HipcAutoSelect> parcel_reply, u32 flags);
25
26private:
27 Nvnflinger::HosBinderDriverServer& m_server;
28};
29
30} // 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
new file mode 100755
index 000000000..17f2f3b8f
--- /dev/null
+++ b/src/core/hle/service/vi/manager_display_service.cpp
@@ -0,0 +1,130 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/nvnflinger/nvnflinger.h"
6#include "core/hle/service/vi/manager_display_service.h"
7#include "core/hle/service/vi/vi_results.h"
8
9namespace Service::VI {
10
11IManagerDisplayService::IManagerDisplayService(Core::System& system_,
12 Nvnflinger::Nvnflinger& nvnflinger)
13 : ServiceFramework{system_, "IManagerDisplayService"}, m_nvnflinger{nvnflinger} {
14 // clang-format off
15 static const FunctionInfo functions[] = {
16 {200, nullptr, "AllocateProcessHeapBlock"},
17 {201, nullptr, "FreeProcessHeapBlock"},
18 {1102, nullptr, "GetDisplayResolution"},
19 {2010, C<&IManagerDisplayService::CreateManagedLayer>, "CreateManagedLayer"},
20 {2011, nullptr, "DestroyManagedLayer"},
21 {2012, nullptr, "CreateStrayLayer"},
22 {2050, nullptr, "CreateIndirectLayer"},
23 {2051, nullptr, "DestroyIndirectLayer"},
24 {2052, nullptr, "CreateIndirectProducerEndPoint"},
25 {2053, nullptr, "DestroyIndirectProducerEndPoint"},
26 {2054, nullptr, "CreateIndirectConsumerEndPoint"},
27 {2055, nullptr, "DestroyIndirectConsumerEndPoint"},
28 {2060, nullptr, "CreateWatermarkCompositor"},
29 {2062, nullptr, "SetWatermarkText"},
30 {2063, nullptr, "SetWatermarkLayerStacks"},
31 {2300, nullptr, "AcquireLayerTexturePresentingEvent"},
32 {2301, nullptr, "ReleaseLayerTexturePresentingEvent"},
33 {2302, nullptr, "GetDisplayHotplugEvent"},
34 {2303, nullptr, "GetDisplayModeChangedEvent"},
35 {2402, nullptr, "GetDisplayHotplugState"},
36 {2501, nullptr, "GetCompositorErrorInfo"},
37 {2601, nullptr, "GetDisplayErrorEvent"},
38 {2701, nullptr, "GetDisplayFatalErrorEvent"},
39 {4201, nullptr, "SetDisplayAlpha"},
40 {4203, nullptr, "SetDisplayLayerStack"},
41 {4205, nullptr, "SetDisplayPowerState"},
42 {4206, nullptr, "SetDefaultDisplay"},
43 {4207, nullptr, "ResetDisplayPanel"},
44 {4208, nullptr, "SetDisplayFatalErrorEnabled"},
45 {4209, nullptr, "IsDisplayPanelOn"},
46 {4300, nullptr, "GetInternalPanelId"},
47 {6000, C<&IManagerDisplayService::AddToLayerStack>, "AddToLayerStack"},
48 {6001, nullptr, "RemoveFromLayerStack"},
49 {6002, C<&IManagerDisplayService::SetLayerVisibility>, "SetLayerVisibility"},
50 {6003, nullptr, "SetLayerConfig"},
51 {6004, nullptr, "AttachLayerPresentationTracer"},
52 {6005, nullptr, "DetachLayerPresentationTracer"},
53 {6006, nullptr, "StartLayerPresentationRecording"},
54 {6007, nullptr, "StopLayerPresentationRecording"},
55 {6008, nullptr, "StartLayerPresentationFenceWait"},
56 {6009, nullptr, "StopLayerPresentationFenceWait"},
57 {6010, nullptr, "GetLayerPresentationAllFencesExpiredEvent"},
58 {6011, nullptr, "EnableLayerAutoClearTransitionBuffer"},
59 {6012, nullptr, "DisableLayerAutoClearTransitionBuffer"},
60 {6013, nullptr, "SetLayerOpacity"},
61 {6014, nullptr, "AttachLayerWatermarkCompositor"},
62 {6015, nullptr, "DetachLayerWatermarkCompositor"},
63 {7000, nullptr, "SetContentVisibility"},
64 {8000, nullptr, "SetConductorLayer"},
65 {8001, nullptr, "SetTimestampTracking"},
66 {8100, nullptr, "SetIndirectProducerFlipOffset"},
67 {8200, nullptr, "CreateSharedBufferStaticStorage"},
68 {8201, nullptr, "CreateSharedBufferTransferMemory"},
69 {8202, nullptr, "DestroySharedBuffer"},
70 {8203, nullptr, "BindSharedLowLevelLayerToManagedLayer"},
71 {8204, nullptr, "BindSharedLowLevelLayerToIndirectLayer"},
72 {8207, nullptr, "UnbindSharedLowLevelLayer"},
73 {8208, nullptr, "ConnectSharedLowLevelLayerToSharedBuffer"},
74 {8209, nullptr, "DisconnectSharedLowLevelLayerFromSharedBuffer"},
75 {8210, nullptr, "CreateSharedLayer"},
76 {8211, nullptr, "DestroySharedLayer"},
77 {8216, nullptr, "AttachSharedLayerToLowLevelLayer"},
78 {8217, nullptr, "ForceDetachSharedLayerFromLowLevelLayer"},
79 {8218, nullptr, "StartDetachSharedLayerFromLowLevelLayer"},
80 {8219, nullptr, "FinishDetachSharedLayerFromLowLevelLayer"},
81 {8220, nullptr, "GetSharedLayerDetachReadyEvent"},
82 {8221, nullptr, "GetSharedLowLevelLayerSynchronizedEvent"},
83 {8222, nullptr, "CheckSharedLowLevelLayerSynchronized"},
84 {8223, nullptr, "RegisterSharedBufferImporterAruid"},
85 {8224, nullptr, "UnregisterSharedBufferImporterAruid"},
86 {8227, nullptr, "CreateSharedBufferProcessHeap"},
87 {8228, nullptr, "GetSharedLayerLayerStacks"},
88 {8229, nullptr, "SetSharedLayerLayerStacks"},
89 {8291, nullptr, "PresentDetachedSharedFrameBufferToLowLevelLayer"},
90 {8292, nullptr, "FillDetachedSharedFrameBufferColor"},
91 {8293, nullptr, "GetDetachedSharedFrameBufferImage"},
92 {8294, nullptr, "SetDetachedSharedFrameBufferImage"},
93 {8295, nullptr, "CopyDetachedSharedFrameBufferImage"},
94 {8296, nullptr, "SetDetachedSharedFrameBufferSubImage"},
95 {8297, nullptr, "GetSharedFrameBufferContentParameter"},
96 {8298, nullptr, "ExpandStartupLogoOnSharedFrameBuffer"},
97 };
98 // clang-format on
99
100 RegisterHandlers(functions);
101}
102
103IManagerDisplayService::~IManagerDisplayService() = default;
104
105Result IManagerDisplayService::CreateManagedLayer(Out<u64> out_layer_id, u32 unknown,
106 u64 display_id, AppletResourceUserId aruid) {
107 LOG_WARNING(Service_VI, "(STUBBED) called. unknown={}, display={}, aruid={}", unknown,
108 display_id, aruid.pid);
109
110 const auto layer_id = m_nvnflinger.CreateLayer(display_id);
111 if (!layer_id) {
112 LOG_ERROR(Service_VI, "Layer not found! display={}", display_id);
113 R_THROW(VI::ResultNotFound);
114 }
115
116 *out_layer_id = *layer_id;
117 R_SUCCEED();
118}
119
120Result IManagerDisplayService::AddToLayerStack(u32 stack_id, u64 layer_id) {
121 LOG_WARNING(Service_VI, "(STUBBED) called. stack_id={}, layer_id={}", stack_id, layer_id);
122 R_SUCCEED();
123}
124
125Result IManagerDisplayService::SetLayerVisibility(bool visible, u64 layer_id) {
126 LOG_WARNING(Service_VI, "(STUBBED) called, layer_id={}, visible={}", layer_id, visible);
127 R_SUCCEED();
128}
129
130} // 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
new file mode 100755
index 000000000..60e646ee0
--- /dev/null
+++ b/src/core/hle/service/vi/manager_display_service.h
@@ -0,0 +1,24 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_types.h"
5#include "core/hle/service/service.h"
6
7namespace Service::VI {
8
9class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
10public:
11 explicit IManagerDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger);
12 ~IManagerDisplayService() override;
13
14private:
15 Result CreateManagedLayer(Out<u64> out_layer_id, u32 unknown, u64 display_id,
16 AppletResourceUserId aruid);
17 Result AddToLayerStack(u32 stack_id, u64 layer_id);
18 Result SetLayerVisibility(bool visible, u64 layer_id);
19
20private:
21 Nvnflinger::Nvnflinger& m_nvnflinger;
22};
23
24} // 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
new file mode 100755
index 000000000..a7eee4f04
--- /dev/null
+++ b/src/core/hle/service/vi/manager_root_service.cpp
@@ -0,0 +1,38 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/vi/application_display_service.h"
6#include "core/hle/service/vi/manager_root_service.h"
7#include "core/hle/service/vi/service_creator.h"
8#include "core/hle/service/vi/vi.h"
9#include "core/hle/service/vi/vi_types.h"
10
11namespace Service::VI {
12
13IManagerRootService::IManagerRootService(
14 Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger,
15 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server)
16 : ServiceFramework{system_, "vi:m"}, m_nvnflinger{nvnflinger}, m_hos_binder_driver_server{
17 hos_binder_driver_server} {
18 static const FunctionInfo functions[] = {
19 {2, C<&IManagerRootService::GetDisplayService>, "GetDisplayService"},
20 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
21 {100, nullptr, "PrepareFatal"},
22 {101, nullptr, "ShowFatal"},
23 {102, nullptr, "DrawFatalRectangle"},
24 {103, nullptr, "DrawFatalText32"},
25 };
26 RegisterHandlers(functions);
27}
28
29IManagerRootService::~IManagerRootService() = default;
30
31Result IManagerRootService::GetDisplayService(
32 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) {
33 LOG_DEBUG(Service_VI, "called");
34 R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_nvnflinger,
35 m_hos_binder_driver_server, Permission::Manager, policy));
36}
37
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
new file mode 100755
index 000000000..e6cb77aeb
--- /dev/null
+++ b/src/core/hle/service/vi/manager_root_service.h
@@ -0,0 +1,38 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::Nvnflinger {
14class HosBinderDriverServer;
15class Nvnflinger;
16} // namespace Service::Nvnflinger
17
18namespace Service::VI {
19
20class IApplicationDisplayService;
21enum class Policy : u32;
22
23class IManagerRootService final : public ServiceFramework<IManagerRootService> {
24public:
25 explicit IManagerRootService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger,
26 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server);
27 ~IManagerRootService() override;
28
29private:
30 Result GetDisplayService(
31 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service,
32 Policy policy);
33
34 Nvnflinger::Nvnflinger& m_nvnflinger;
35 Nvnflinger::HosBinderDriverServer& m_hos_binder_driver_server;
36};
37
38} // namespace Service::VI
diff --git a/src/core/hle/service/vi/service_creator.cpp b/src/core/hle/service/vi/service_creator.cpp
new file mode 100755
index 000000000..1de9d61a4
--- /dev/null
+++ b/src/core/hle/service/vi/service_creator.cpp
@@ -0,0 +1,39 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/vi/application_display_service.h"
5#include "core/hle/service/vi/service_creator.h"
6#include "core/hle/service/vi/vi_results.h"
7#include "core/hle/service/vi/vi_types.h"
8
9namespace Service::VI {
10
11static bool IsValidServiceAccess(Permission permission, Policy policy) {
12 if (permission == Permission::User) {
13 return policy == Policy::User;
14 }
15
16 if (permission == Permission::System || permission == Permission::Manager) {
17 return policy == Policy::User || policy == Policy::Compositor;
18 }
19
20 return false;
21}
22
23Result GetApplicationDisplayService(
24 std::shared_ptr<IApplicationDisplayService>* out_application_display_service,
25 Core::System& system, Nvnflinger::Nvnflinger& nvnflinger,
26 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server, Permission permission,
27 Policy policy) {
28
29 if (!IsValidServiceAccess(permission, policy)) {
30 LOG_ERROR(Service_VI, "Permission denied for policy {}", policy);
31 R_THROW(ResultPermissionDenied);
32 }
33
34 *out_application_display_service =
35 std::make_shared<IApplicationDisplayService>(system, nvnflinger, hos_binder_driver_server);
36 R_SUCCEED();
37}
38
39} // namespace Service::VI
diff --git a/src/core/hle/service/vi/service_creator.h b/src/core/hle/service/vi/service_creator.h
new file mode 100755
index 000000000..8963bcd26
--- /dev/null
+++ b/src/core/hle/service/vi/service_creator.h
@@ -0,0 +1,33 @@
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
8#include "common/common_types.h"
9
10namespace Core {
11class System;
12}
13
14namespace Service::Nvnflinger {
15class HosBinderDriverServer;
16class Nvnflinger;
17} // namespace Service::Nvnflinger
18
19union Result;
20
21namespace Service::VI {
22
23class IApplicationDisplayService;
24enum class Permission;
25enum class Policy : u32;
26
27Result GetApplicationDisplayService(
28 std::shared_ptr<IApplicationDisplayService>* out_application_display_service,
29 Core::System& system, Nvnflinger::Nvnflinger& nvnflinger,
30 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server, Permission permission,
31 Policy policy);
32
33} // namespace Service::VI
diff --git a/src/core/hle/service/vi/system_display_service.cpp b/src/core/hle/service/vi/system_display_service.cpp
new file mode 100755
index 000000000..1e1cfc817
--- /dev/null
+++ b/src/core/hle/service/vi/system_display_service.cpp
@@ -0,0 +1,145 @@
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/hle/service/cmif_serialization.h"
6#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
7#include "core/hle/service/vi/system_display_service.h"
8#include "core/hle/service/vi/vi_types.h"
9
10namespace Service::VI {
11
12ISystemDisplayService::ISystemDisplayService(Core::System& system_,
13 Nvnflinger::Nvnflinger& nvnflinger)
14 : ServiceFramework{system_, "ISystemDisplayService"}, m_nvnflinger{nvnflinger} {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {1200, nullptr, "GetZOrderCountMin"},
18 {1202, nullptr, "GetZOrderCountMax"},
19 {1203, nullptr, "GetDisplayLogicalResolution"},
20 {1204, nullptr, "SetDisplayMagnification"},
21 {2201, nullptr, "SetLayerPosition"},
22 {2203, nullptr, "SetLayerSize"},
23 {2204, nullptr, "GetLayerZ"},
24 {2205, C<&ISystemDisplayService::SetLayerZ>, "SetLayerZ"},
25 {2207, C<&ISystemDisplayService::SetLayerVisibility>, "SetLayerVisibility"},
26 {2209, nullptr, "SetLayerAlpha"},
27 {2210, nullptr, "SetLayerPositionAndSize"},
28 {2312, nullptr, "CreateStrayLayer"},
29 {2400, nullptr, "OpenIndirectLayer"},
30 {2401, nullptr, "CloseIndirectLayer"},
31 {2402, nullptr, "FlipIndirectLayer"},
32 {3000, nullptr, "ListDisplayModes"},
33 {3001, nullptr, "ListDisplayRgbRanges"},
34 {3002, nullptr, "ListDisplayContentTypes"},
35 {3200, C<&ISystemDisplayService::GetDisplayMode>, "GetDisplayMode"},
36 {3201, nullptr, "SetDisplayMode"},
37 {3202, nullptr, "GetDisplayUnderscan"},
38 {3203, nullptr, "SetDisplayUnderscan"},
39 {3204, nullptr, "GetDisplayContentType"},
40 {3205, nullptr, "SetDisplayContentType"},
41 {3206, nullptr, "GetDisplayRgbRange"},
42 {3207, nullptr, "SetDisplayRgbRange"},
43 {3208, nullptr, "GetDisplayCmuMode"},
44 {3209, nullptr, "SetDisplayCmuMode"},
45 {3210, nullptr, "GetDisplayContrastRatio"},
46 {3211, nullptr, "SetDisplayContrastRatio"},
47 {3214, nullptr, "GetDisplayGamma"},
48 {3215, nullptr, "SetDisplayGamma"},
49 {3216, nullptr, "GetDisplayCmuLuma"},
50 {3217, nullptr, "SetDisplayCmuLuma"},
51 {3218, nullptr, "SetDisplayCrcMode"},
52 {6013, nullptr, "GetLayerPresentationSubmissionTimestamps"},
53 {8225, C<&ISystemDisplayService::GetSharedBufferMemoryHandleId>, "GetSharedBufferMemoryHandleId"},
54 {8250, C<&ISystemDisplayService::OpenSharedLayer>, "OpenSharedLayer"},
55 {8251, nullptr, "CloseSharedLayer"},
56 {8252, C<&ISystemDisplayService::ConnectSharedLayer>, "ConnectSharedLayer"},
57 {8253, nullptr, "DisconnectSharedLayer"},
58 {8254, C<&ISystemDisplayService::AcquireSharedFrameBuffer>, "AcquireSharedFrameBuffer"},
59 {8255, C<&ISystemDisplayService::PresentSharedFrameBuffer>, "PresentSharedFrameBuffer"},
60 {8256, C<&ISystemDisplayService::GetSharedFrameBufferAcquirableEvent>, "GetSharedFrameBufferAcquirableEvent"},
61 {8257, nullptr, "FillSharedFrameBufferColor"},
62 {8258, nullptr, "CancelSharedFrameBuffer"},
63 {9000, nullptr, "GetDp2hdmiController"},
64 };
65 // clang-format on
66 RegisterHandlers(functions);
67}
68
69ISystemDisplayService::~ISystemDisplayService() = default;
70
71Result ISystemDisplayService::SetLayerZ(u32 z_value, u64 layer_id) {
72 LOG_WARNING(Service_VI, "(STUBBED) called. layer_id={}, z_value={}", layer_id, z_value);
73 R_SUCCEED();
74}
75
76// This function currently does nothing but return a success error code in
77// the vi library itself, so do the same thing, but log out the passed in values.
78Result ISystemDisplayService::SetLayerVisibility(bool visible, u64 layer_id) {
79 LOG_DEBUG(Service_VI, "called, layer_id={}, visible={}", layer_id, visible);
80 R_SUCCEED();
81}
82
83Result ISystemDisplayService::GetDisplayMode(Out<u32> out_width, Out<u32> out_height,
84 Out<f32> out_refresh_rate, Out<u32> out_unknown) {
85 LOG_WARNING(Service_VI, "(STUBBED) called");
86
87 if (Settings::IsDockedMode()) {
88 *out_width = static_cast<u32>(DisplayResolution::DockedWidth);
89 *out_height = static_cast<u32>(DisplayResolution::DockedHeight);
90 } else {
91 *out_width = static_cast<u32>(DisplayResolution::UndockedWidth);
92 *out_height = static_cast<u32>(DisplayResolution::UndockedHeight);
93 }
94
95 *out_refresh_rate = 60.f; // This wouldn't seem to be correct for 30 fps games.
96 *out_unknown = 0;
97
98 R_SUCCEED();
99}
100
101Result ISystemDisplayService::GetSharedBufferMemoryHandleId(
102 Out<s32> out_nvmap_handle, Out<u64> out_size,
103 OutLargeData<Nvnflinger::SharedMemoryPoolLayout, BufferAttr_HipcMapAlias> out_pool_layout,
104 u64 buffer_id, ClientAppletResourceUserId aruid) {
105 LOG_INFO(Service_VI, "called. buffer_id={}, aruid={:#x}", buffer_id, aruid.pid);
106
107 R_RETURN(m_nvnflinger.GetSystemBufferManager().GetSharedBufferMemoryHandleId(
108 out_size, out_nvmap_handle, out_pool_layout, buffer_id, aruid.pid));
109}
110
111Result ISystemDisplayService::OpenSharedLayer(u64 layer_id) {
112 LOG_INFO(Service_VI, "(STUBBED) called. layer_id={}", layer_id);
113 R_SUCCEED();
114}
115
116Result ISystemDisplayService::ConnectSharedLayer(u64 layer_id) {
117 LOG_INFO(Service_VI, "(STUBBED) called. layer_id={}", layer_id);
118 R_SUCCEED();
119}
120
121Result ISystemDisplayService::AcquireSharedFrameBuffer(Out<android::Fence> out_fence,
122 Out<std::array<s32, 4>> out_slots,
123 Out<s64> out_target_slot, u64 layer_id) {
124 LOG_DEBUG(Service_VI, "called");
125 R_RETURN(m_nvnflinger.GetSystemBufferManager().AcquireSharedFrameBuffer(
126 out_fence, *out_slots, out_target_slot, layer_id));
127}
128
129Result ISystemDisplayService::PresentSharedFrameBuffer(android::Fence fence,
130 Common::Rectangle<s32> crop_region,
131 u32 window_transform, s32 swap_interval,
132 u64 layer_id, s64 surface_id) {
133 LOG_DEBUG(Service_VI, "called");
134 R_RETURN(m_nvnflinger.GetSystemBufferManager().PresentSharedFrameBuffer(
135 fence, crop_region, window_transform, swap_interval, layer_id, surface_id));
136}
137
138Result ISystemDisplayService::GetSharedFrameBufferAcquirableEvent(
139 OutCopyHandle<Kernel::KReadableEvent> out_event, u64 layer_id) {
140 LOG_DEBUG(Service_VI, "called");
141 R_RETURN(m_nvnflinger.GetSystemBufferManager().GetSharedFrameBufferAcquirableEvent(out_event,
142 layer_id));
143}
144
145} // 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
new file mode 100755
index 000000000..cfcb196fd
--- /dev/null
+++ b/src/core/hle/service/vi/system_display_service.h
@@ -0,0 +1,45 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/math_util.h"
5#include "core/hle/service/cmif_types.h"
6#include "core/hle/service/nvnflinger/ui/fence.h"
7#include "core/hle/service/service.h"
8
9namespace Service::Nvnflinger {
10struct SharedMemoryPoolLayout;
11}
12
13namespace Service::VI {
14
15class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
16public:
17 explicit ISystemDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger);
18 ~ISystemDisplayService() override;
19
20private:
21 Result SetLayerZ(u32 z_value, u64 layer_id);
22 Result SetLayerVisibility(bool visible, u64 layer_id);
23 Result GetDisplayMode(Out<u32> out_width, Out<u32> out_height, Out<f32> out_refresh_rate,
24 Out<u32> out_unknown);
25
26 Result GetSharedBufferMemoryHandleId(
27 Out<s32> out_nvmap_handle, Out<u64> out_size,
28 OutLargeData<Nvnflinger::SharedMemoryPoolLayout, BufferAttr_HipcMapAlias> out_pool_layout,
29 u64 buffer_id, ClientAppletResourceUserId aruid);
30 Result OpenSharedLayer(u64 layer_id);
31 Result ConnectSharedLayer(u64 layer_id);
32 Result GetSharedFrameBufferAcquirableEvent(OutCopyHandle<Kernel::KReadableEvent> out_event,
33 u64 layer_id);
34 Result AcquireSharedFrameBuffer(Out<android::Fence> out_fence,
35 Out<std::array<s32, 4>> out_slots, Out<s64> out_target_slot,
36 u64 layer_id);
37 Result PresentSharedFrameBuffer(android::Fence fence, Common::Rectangle<s32> crop_region,
38 u32 window_transform, s32 swap_interval, u64 layer_id,
39 s64 surface_id);
40
41private:
42 Nvnflinger::Nvnflinger& m_nvnflinger;
43};
44
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
new file mode 100755
index 000000000..8789b4cfb
--- /dev/null
+++ b/src/core/hle/service/vi/system_root_service.cpp
@@ -0,0 +1,33 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/vi/application_display_service.h"
6#include "core/hle/service/vi/service_creator.h"
7#include "core/hle/service/vi/system_root_service.h"
8#include "core/hle/service/vi/vi.h"
9#include "core/hle/service/vi/vi_types.h"
10
11namespace Service::VI {
12
13ISystemRootService::ISystemRootService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger,
14 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server)
15 : ServiceFramework{system_, "vi:s"}, m_nvnflinger{nvnflinger}, m_hos_binder_driver_server{
16 hos_binder_driver_server} {
17 static const FunctionInfo functions[] = {
18 {1, C<&ISystemRootService::GetDisplayService>, "GetDisplayService"},
19 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
20 };
21 RegisterHandlers(functions);
22}
23
24ISystemRootService::~ISystemRootService() = default;
25
26Result ISystemRootService::GetDisplayService(
27 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service, Policy policy) {
28 LOG_DEBUG(Service_VI, "called");
29 R_RETURN(GetApplicationDisplayService(out_application_display_service, system, m_nvnflinger,
30 m_hos_binder_driver_server, Permission::System, policy));
31}
32
33} // 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
new file mode 100755
index 000000000..2c547faa5
--- /dev/null
+++ b/src/core/hle/service/vi/system_root_service.h
@@ -0,0 +1,38 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::Nvnflinger {
14class HosBinderDriverServer;
15class Nvnflinger;
16} // namespace Service::Nvnflinger
17
18namespace Service::VI {
19
20class IApplicationDisplayService;
21enum class Policy : u32;
22
23class ISystemRootService final : public ServiceFramework<ISystemRootService> {
24public:
25 explicit ISystemRootService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger,
26 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server);
27 ~ISystemRootService() override;
28
29private:
30 Result GetDisplayService(
31 Out<SharedPointer<IApplicationDisplayService>> out_application_display_service,
32 Policy policy);
33
34 Nvnflinger::Nvnflinger& m_nvnflinger;
35 Nvnflinger::HosBinderDriverServer& m_hos_binder_driver_server;
36};
37
38} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 77c6a069b..18442b265 100755
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -1,974 +1,25 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 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 <algorithm>
5#include <array>
6#include <cstring>
7#include <memory>
8#include <optional>
9#include <type_traits>
10#include <utility>
11
12#include "common/alignment.h"
13#include "common/assert.h"
14#include "common/common_funcs.h"
15#include "common/logging/log.h"
16#include "common/math_util.h"
17#include "common/settings.h"
18#include "common/string_util.h"
19#include "common/swap.h"
20#include "core/core_timing.h"
21#include "core/hle/kernel/k_readable_event.h"
22#include "core/hle/kernel/k_thread.h"
23#include "core/hle/service/ipc_helpers.h"
24#include "core/hle/service/nvdrv/devices/nvmap.h"
25#include "core/hle/service/nvdrv/nvdata.h"
26#include "core/hle/service/nvdrv/nvdrv.h"
27#include "core/hle/service/nvnflinger/binder.h"
28#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
29#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
30#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
31#include "core/hle/service/nvnflinger/nvnflinger.h"
32#include "core/hle/service/nvnflinger/parcel.h"
33#include "core/hle/service/server_manager.h" 4#include "core/hle/service/server_manager.h"
34#include "core/hle/service/service.h" 5#include "core/hle/service/vi/application_display_service.h"
6#include "core/hle/service/vi/application_root_service.h"
7#include "core/hle/service/vi/manager_root_service.h"
8#include "core/hle/service/vi/system_root_service.h"
35#include "core/hle/service/vi/vi.h" 9#include "core/hle/service/vi/vi.h"
36#include "core/hle/service/vi/vi_m.h"
37#include "core/hle/service/vi/vi_results.h"
38#include "core/hle/service/vi/vi_s.h"
39#include "core/hle/service/vi/vi_u.h"
40 10
41namespace Service::VI { 11namespace Service::VI {
42 12
43struct DisplayInfo {
44 /// The name of this particular display.
45 char display_name[0x40]{"Default"};
46
47 /// Whether or not the display has a limited number of layers.
48 u8 has_limited_layers{1};
49 INSERT_PADDING_BYTES(7);
50
51 /// Indicates the total amount of layers supported by the display.
52 /// @note This is only valid if has_limited_layers is set.
53 u64 max_layers{1};
54
55 /// Maximum width in pixels.
56 u64 width{1920};
57
58 /// Maximum height in pixels.
59 u64 height{1080};
60};
61static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size");
62
63class NativeWindow final {
64public:
65 constexpr explicit NativeWindow(u32 id_) : id{id_} {}
66 constexpr explicit NativeWindow(const NativeWindow& other) = default;
67
68private:
69 const u32 magic = 2;
70 const u32 process_id = 1;
71 const u64 id;
72 INSERT_PADDING_WORDS(2);
73 std::array<u8, 8> dispdrv = {'d', 'i', 's', 'p', 'd', 'r', 'v', '\0'};
74 INSERT_PADDING_WORDS(2);
75};
76static_assert(sizeof(NativeWindow) == 0x28, "NativeWindow has wrong size");
77
78class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
79public:
80 explicit IHOSBinderDriver(Core::System& system_, Nvnflinger::HosBinderDriverServer& server_)
81 : ServiceFramework{system_, "IHOSBinderDriver"}, server(server_) {
82 static const FunctionInfo functions[] = {
83 {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"},
84 {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"},
85 {2, &IHOSBinderDriver::GetNativeHandle, "GetNativeHandle"},
86 {3, &IHOSBinderDriver::TransactParcel, "TransactParcelAuto"},
87 };
88 RegisterHandlers(functions);
89 }
90
91private:
92 void TransactParcel(HLERequestContext& ctx) {
93 IPC::RequestParser rp{ctx};
94 const u32 id = rp.Pop<u32>();
95 const auto transaction = static_cast<android::TransactionId>(rp.Pop<u32>());
96 const u32 flags = rp.Pop<u32>();
97
98 LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id,
99 transaction, flags);
100
101 server.TryGetProducer(id)->Transact(ctx, transaction, flags);
102
103 IPC::ResponseBuilder rb{ctx, 2};
104 rb.Push(ResultSuccess);
105 }
106
107 void AdjustRefcount(HLERequestContext& ctx) {
108 IPC::RequestParser rp{ctx};
109 const u32 id = rp.Pop<u32>();
110 const s32 addval = rp.PopRaw<s32>();
111 const u32 type = rp.Pop<u32>();
112
113 LOG_WARNING(Service_VI, "(STUBBED) called id={}, addval={:08X}, type={:08X}", id, addval,
114 type);
115
116 IPC::ResponseBuilder rb{ctx, 2};
117 rb.Push(ResultSuccess);
118 }
119
120 void GetNativeHandle(HLERequestContext& ctx) {
121 IPC::RequestParser rp{ctx};
122 const u32 id = rp.Pop<u32>();
123 const u32 unknown = rp.Pop<u32>();
124
125 LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
126
127 IPC::ResponseBuilder rb{ctx, 2, 1};
128 rb.Push(ResultSuccess);
129 rb.PushCopyObjects(server.TryGetProducer(id)->GetNativeHandle());
130 }
131
132private:
133 Nvnflinger::HosBinderDriverServer& server;
134};
135
136class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
137public:
138 explicit ISystemDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_)
139 : ServiceFramework{system_, "ISystemDisplayService"}, nvnflinger{nvnflinger_} {
140 // clang-format off
141 static const FunctionInfo functions[] = {
142 {1200, nullptr, "GetZOrderCountMin"},
143 {1202, nullptr, "GetZOrderCountMax"},
144 {1203, nullptr, "GetDisplayLogicalResolution"},
145 {1204, nullptr, "SetDisplayMagnification"},
146 {2201, nullptr, "SetLayerPosition"},
147 {2203, nullptr, "SetLayerSize"},
148 {2204, nullptr, "GetLayerZ"},
149 {2205, &ISystemDisplayService::SetLayerZ, "SetLayerZ"},
150 {2207, &ISystemDisplayService::SetLayerVisibility, "SetLayerVisibility"},
151 {2209, nullptr, "SetLayerAlpha"},
152 {2210, nullptr, "SetLayerPositionAndSize"},
153 {2312, nullptr, "CreateStrayLayer"},
154 {2400, nullptr, "OpenIndirectLayer"},
155 {2401, nullptr, "CloseIndirectLayer"},
156 {2402, nullptr, "FlipIndirectLayer"},
157 {3000, nullptr, "ListDisplayModes"},
158 {3001, nullptr, "ListDisplayRgbRanges"},
159 {3002, nullptr, "ListDisplayContentTypes"},
160 {3200, &ISystemDisplayService::GetDisplayMode, "GetDisplayMode"},
161 {3201, nullptr, "SetDisplayMode"},
162 {3202, nullptr, "GetDisplayUnderscan"},
163 {3203, nullptr, "SetDisplayUnderscan"},
164 {3204, nullptr, "GetDisplayContentType"},
165 {3205, nullptr, "SetDisplayContentType"},
166 {3206, nullptr, "GetDisplayRgbRange"},
167 {3207, nullptr, "SetDisplayRgbRange"},
168 {3208, nullptr, "GetDisplayCmuMode"},
169 {3209, nullptr, "SetDisplayCmuMode"},
170 {3210, nullptr, "GetDisplayContrastRatio"},
171 {3211, nullptr, "SetDisplayContrastRatio"},
172 {3214, nullptr, "GetDisplayGamma"},
173 {3215, nullptr, "SetDisplayGamma"},
174 {3216, nullptr, "GetDisplayCmuLuma"},
175 {3217, nullptr, "SetDisplayCmuLuma"},
176 {3218, nullptr, "SetDisplayCrcMode"},
177 {6013, nullptr, "GetLayerPresentationSubmissionTimestamps"},
178 {8225, &ISystemDisplayService::GetSharedBufferMemoryHandleId, "GetSharedBufferMemoryHandleId"},
179 {8250, &ISystemDisplayService::OpenSharedLayer, "OpenSharedLayer"},
180 {8251, nullptr, "CloseSharedLayer"},
181 {8252, &ISystemDisplayService::ConnectSharedLayer, "ConnectSharedLayer"},
182 {8253, nullptr, "DisconnectSharedLayer"},
183 {8254, &ISystemDisplayService::AcquireSharedFrameBuffer, "AcquireSharedFrameBuffer"},
184 {8255, &ISystemDisplayService::PresentSharedFrameBuffer, "PresentSharedFrameBuffer"},
185 {8256, &ISystemDisplayService::GetSharedFrameBufferAcquirableEvent, "GetSharedFrameBufferAcquirableEvent"},
186 {8257, nullptr, "FillSharedFrameBufferColor"},
187 {8258, nullptr, "CancelSharedFrameBuffer"},
188 {9000, nullptr, "GetDp2hdmiController"},
189 };
190 // clang-format on
191 RegisterHandlers(functions);
192 }
193
194private:
195 void GetSharedBufferMemoryHandleId(HLERequestContext& ctx) {
196 IPC::RequestParser rp{ctx};
197 const u64 buffer_id = rp.PopRaw<u64>();
198 const u64 aruid = ctx.GetPID();
199
200 LOG_INFO(Service_VI, "called. buffer_id={:#x}, aruid={:#x}", buffer_id, aruid);
201
202 struct OutputParameters {
203 s32 nvmap_handle;
204 u64 size;
205 };
206
207 OutputParameters out{};
208 Nvnflinger::SharedMemoryPoolLayout layout{};
209 const auto result = nvnflinger.GetSystemBufferManager().GetSharedBufferMemoryHandleId(
210 &out.size, &out.nvmap_handle, &layout, buffer_id, aruid);
211
212 ctx.WriteBuffer(&layout, sizeof(layout));
213
214 IPC::ResponseBuilder rb{ctx, 6};
215 rb.Push(result);
216 rb.PushRaw(out);
217 }
218
219 void OpenSharedLayer(HLERequestContext& ctx) {
220 IPC::RequestParser rp{ctx};
221 const u64 layer_id = rp.PopRaw<u64>();
222
223 LOG_INFO(Service_VI, "(STUBBED) called. layer_id={:#x}", layer_id);
224
225 IPC::ResponseBuilder rb{ctx, 2};
226 rb.Push(ResultSuccess);
227 }
228
229 void ConnectSharedLayer(HLERequestContext& ctx) {
230 IPC::RequestParser rp{ctx};
231 const u64 layer_id = rp.PopRaw<u64>();
232
233 LOG_INFO(Service_VI, "(STUBBED) called. layer_id={:#x}", layer_id);
234
235 IPC::ResponseBuilder rb{ctx, 2};
236 rb.Push(ResultSuccess);
237 }
238
239 void GetSharedFrameBufferAcquirableEvent(HLERequestContext& ctx) {
240 LOG_DEBUG(Service_VI, "called");
241
242 IPC::RequestParser rp{ctx};
243 const u64 layer_id = rp.PopRaw<u64>();
244
245 Kernel::KReadableEvent* event{};
246 const auto result = nvnflinger.GetSystemBufferManager().GetSharedFrameBufferAcquirableEvent(
247 &event, layer_id);
248
249 IPC::ResponseBuilder rb{ctx, 2, 1};
250 rb.Push(result);
251 rb.PushCopyObjects(event);
252 }
253
254 void AcquireSharedFrameBuffer(HLERequestContext& ctx) {
255 LOG_DEBUG(Service_VI, "called");
256
257 IPC::RequestParser rp{ctx};
258 const u64 layer_id = rp.PopRaw<u64>();
259
260 struct OutputParameters {
261 android::Fence fence;
262 std::array<s32, 4> slots;
263 s64 target_slot;
264 };
265 static_assert(sizeof(OutputParameters) == 0x40, "OutputParameters has wrong size");
266
267 OutputParameters out{};
268 const auto result = nvnflinger.GetSystemBufferManager().AcquireSharedFrameBuffer(
269 &out.fence, out.slots, &out.target_slot, layer_id);
270
271 IPC::ResponseBuilder rb{ctx, 18};
272 rb.Push(result);
273 rb.PushRaw(out);
274 }
275
276 void PresentSharedFrameBuffer(HLERequestContext& ctx) {
277 LOG_DEBUG(Service_VI, "called");
278
279 struct InputParameters {
280 android::Fence fence;
281 Common::Rectangle<s32> crop_region;
282 u32 window_transform;
283 s32 swap_interval;
284 u64 layer_id;
285 s64 surface_id;
286 };
287 static_assert(sizeof(InputParameters) == 0x50, "InputParameters has wrong size");
288
289 IPC::RequestParser rp{ctx};
290 auto input = rp.PopRaw<InputParameters>();
291
292 const auto result = nvnflinger.GetSystemBufferManager().PresentSharedFrameBuffer(
293 input.fence, input.crop_region, input.window_transform, input.swap_interval,
294 input.layer_id, input.surface_id);
295 IPC::ResponseBuilder rb{ctx, 2};
296 rb.Push(result);
297 }
298
299 void SetLayerZ(HLERequestContext& ctx) {
300 IPC::RequestParser rp{ctx};
301 const u64 layer_id = rp.Pop<u64>();
302 const u64 z_value = rp.Pop<u64>();
303
304 LOG_WARNING(Service_VI, "(STUBBED) called. layer_id=0x{:016X}, z_value=0x{:016X}", layer_id,
305 z_value);
306
307 IPC::ResponseBuilder rb{ctx, 2};
308 rb.Push(ResultSuccess);
309 }
310
311 // This function currently does nothing but return a success error code in
312 // the vi library itself, so do the same thing, but log out the passed in values.
313 void SetLayerVisibility(HLERequestContext& ctx) {
314 IPC::RequestParser rp{ctx};
315 const u64 layer_id = rp.Pop<u64>();
316 const bool visibility = rp.Pop<bool>();
317
318 LOG_DEBUG(Service_VI, "called, layer_id=0x{:08X}, visibility={}", layer_id, visibility);
319
320 IPC::ResponseBuilder rb{ctx, 2};
321 rb.Push(ResultSuccess);
322 }
323
324 void GetDisplayMode(HLERequestContext& ctx) {
325 LOG_WARNING(Service_VI, "(STUBBED) called");
326
327 IPC::ResponseBuilder rb{ctx, 6};
328 rb.Push(ResultSuccess);
329
330 if (Settings::IsDockedMode()) {
331 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth));
332 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight));
333 } else {
334 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth));
335 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight));
336 }
337
338 rb.PushRaw<float>(60.0f); // This wouldn't seem to be correct for 30 fps games.
339 rb.Push<u32>(0);
340 }
341
342private:
343 Nvnflinger::Nvnflinger& nvnflinger;
344};
345
346class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
347public:
348 explicit IManagerDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_)
349 : ServiceFramework{system_, "IManagerDisplayService"}, nvnflinger{nvnflinger_} {
350 // clang-format off
351 static const FunctionInfo functions[] = {
352 {200, nullptr, "AllocateProcessHeapBlock"},
353 {201, nullptr, "FreeProcessHeapBlock"},
354 {1020, &IManagerDisplayService::CloseDisplay, "CloseDisplay"},
355 {1102, nullptr, "GetDisplayResolution"},
356 {2010, &IManagerDisplayService::CreateManagedLayer, "CreateManagedLayer"},
357 {2011, nullptr, "DestroyManagedLayer"},
358 {2012, nullptr, "CreateStrayLayer"},
359 {2050, nullptr, "CreateIndirectLayer"},
360 {2051, nullptr, "DestroyIndirectLayer"},
361 {2052, nullptr, "CreateIndirectProducerEndPoint"},
362 {2053, nullptr, "DestroyIndirectProducerEndPoint"},
363 {2054, nullptr, "CreateIndirectConsumerEndPoint"},
364 {2055, nullptr, "DestroyIndirectConsumerEndPoint"},
365 {2060, nullptr, "CreateWatermarkCompositor"},
366 {2062, nullptr, "SetWatermarkText"},
367 {2063, nullptr, "SetWatermarkLayerStacks"},
368 {2300, nullptr, "AcquireLayerTexturePresentingEvent"},
369 {2301, nullptr, "ReleaseLayerTexturePresentingEvent"},
370 {2302, nullptr, "GetDisplayHotplugEvent"},
371 {2303, nullptr, "GetDisplayModeChangedEvent"},
372 {2402, nullptr, "GetDisplayHotplugState"},
373 {2501, nullptr, "GetCompositorErrorInfo"},
374 {2601, nullptr, "GetDisplayErrorEvent"},
375 {2701, nullptr, "GetDisplayFatalErrorEvent"},
376 {4201, nullptr, "SetDisplayAlpha"},
377 {4203, nullptr, "SetDisplayLayerStack"},
378 {4205, nullptr, "SetDisplayPowerState"},
379 {4206, nullptr, "SetDefaultDisplay"},
380 {4207, nullptr, "ResetDisplayPanel"},
381 {4208, nullptr, "SetDisplayFatalErrorEnabled"},
382 {4209, nullptr, "IsDisplayPanelOn"},
383 {4300, nullptr, "GetInternalPanelId"},
384 {6000, &IManagerDisplayService::AddToLayerStack, "AddToLayerStack"},
385 {6001, nullptr, "RemoveFromLayerStack"},
386 {6002, &IManagerDisplayService::SetLayerVisibility, "SetLayerVisibility"},
387 {6003, nullptr, "SetLayerConfig"},
388 {6004, nullptr, "AttachLayerPresentationTracer"},
389 {6005, nullptr, "DetachLayerPresentationTracer"},
390 {6006, nullptr, "StartLayerPresentationRecording"},
391 {6007, nullptr, "StopLayerPresentationRecording"},
392 {6008, nullptr, "StartLayerPresentationFenceWait"},
393 {6009, nullptr, "StopLayerPresentationFenceWait"},
394 {6010, nullptr, "GetLayerPresentationAllFencesExpiredEvent"},
395 {6011, nullptr, "EnableLayerAutoClearTransitionBuffer"},
396 {6012, nullptr, "DisableLayerAutoClearTransitionBuffer"},
397 {6013, nullptr, "SetLayerOpacity"},
398 {6014, nullptr, "AttachLayerWatermarkCompositor"},
399 {6015, nullptr, "DetachLayerWatermarkCompositor"},
400 {7000, nullptr, "SetContentVisibility"},
401 {8000, nullptr, "SetConductorLayer"},
402 {8001, nullptr, "SetTimestampTracking"},
403 {8100, nullptr, "SetIndirectProducerFlipOffset"},
404 {8200, nullptr, "CreateSharedBufferStaticStorage"},
405 {8201, nullptr, "CreateSharedBufferTransferMemory"},
406 {8202, nullptr, "DestroySharedBuffer"},
407 {8203, nullptr, "BindSharedLowLevelLayerToManagedLayer"},
408 {8204, nullptr, "BindSharedLowLevelLayerToIndirectLayer"},
409 {8207, nullptr, "UnbindSharedLowLevelLayer"},
410 {8208, nullptr, "ConnectSharedLowLevelLayerToSharedBuffer"},
411 {8209, nullptr, "DisconnectSharedLowLevelLayerFromSharedBuffer"},
412 {8210, nullptr, "CreateSharedLayer"},
413 {8211, nullptr, "DestroySharedLayer"},
414 {8216, nullptr, "AttachSharedLayerToLowLevelLayer"},
415 {8217, nullptr, "ForceDetachSharedLayerFromLowLevelLayer"},
416 {8218, nullptr, "StartDetachSharedLayerFromLowLevelLayer"},
417 {8219, nullptr, "FinishDetachSharedLayerFromLowLevelLayer"},
418 {8220, nullptr, "GetSharedLayerDetachReadyEvent"},
419 {8221, nullptr, "GetSharedLowLevelLayerSynchronizedEvent"},
420 {8222, nullptr, "CheckSharedLowLevelLayerSynchronized"},
421 {8223, nullptr, "RegisterSharedBufferImporterAruid"},
422 {8224, nullptr, "UnregisterSharedBufferImporterAruid"},
423 {8227, nullptr, "CreateSharedBufferProcessHeap"},
424 {8228, nullptr, "GetSharedLayerLayerStacks"},
425 {8229, nullptr, "SetSharedLayerLayerStacks"},
426 {8291, nullptr, "PresentDetachedSharedFrameBufferToLowLevelLayer"},
427 {8292, nullptr, "FillDetachedSharedFrameBufferColor"},
428 {8293, nullptr, "GetDetachedSharedFrameBufferImage"},
429 {8294, nullptr, "SetDetachedSharedFrameBufferImage"},
430 {8295, nullptr, "CopyDetachedSharedFrameBufferImage"},
431 {8296, nullptr, "SetDetachedSharedFrameBufferSubImage"},
432 {8297, nullptr, "GetSharedFrameBufferContentParameter"},
433 {8298, nullptr, "ExpandStartupLogoOnSharedFrameBuffer"},
434 };
435 // clang-format on
436
437 RegisterHandlers(functions);
438 }
439
440private:
441 void CloseDisplay(HLERequestContext& ctx) {
442 IPC::RequestParser rp{ctx};
443 const u64 display = rp.Pop<u64>();
444
445 const Result rc = nvnflinger.CloseDisplay(display) ? ResultSuccess : ResultUnknown;
446
447 IPC::ResponseBuilder rb{ctx, 2};
448 rb.Push(rc);
449 }
450
451 void CreateManagedLayer(HLERequestContext& ctx) {
452 IPC::RequestParser rp{ctx};
453 const u32 unknown = rp.Pop<u32>();
454 rp.Skip(1, false);
455 const u64 display = rp.Pop<u64>();
456 const u64 aruid = rp.Pop<u64>();
457
458 LOG_WARNING(Service_VI,
459 "(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}",
460 unknown, display, aruid);
461
462 const auto layer_id = nvnflinger.CreateLayer(display);
463 if (!layer_id) {
464 LOG_ERROR(Service_VI, "Layer not found! display=0x{:016X}", display);
465 IPC::ResponseBuilder rb{ctx, 2};
466 rb.Push(ResultNotFound);
467 return;
468 }
469
470 IPC::ResponseBuilder rb{ctx, 4};
471 rb.Push(ResultSuccess);
472 rb.Push(*layer_id);
473 }
474
475 void AddToLayerStack(HLERequestContext& ctx) {
476 IPC::RequestParser rp{ctx};
477 const u32 stack = rp.Pop<u32>();
478 const u64 layer_id = rp.Pop<u64>();
479
480 LOG_WARNING(Service_VI, "(STUBBED) called. stack=0x{:08X}, layer_id=0x{:016X}", stack,
481 layer_id);
482
483 IPC::ResponseBuilder rb{ctx, 2};
484 rb.Push(ResultSuccess);
485 }
486
487 void SetLayerVisibility(HLERequestContext& ctx) {
488 IPC::RequestParser rp{ctx};
489 const u64 layer_id = rp.Pop<u64>();
490 const bool visibility = rp.Pop<bool>();
491
492 LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id,
493 visibility);
494
495 IPC::ResponseBuilder rb{ctx, 2};
496 rb.Push(ResultSuccess);
497 }
498
499 Nvnflinger::Nvnflinger& nvnflinger;
500};
501
502class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
503public:
504 IApplicationDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_,
505 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_)
506 : ServiceFramework{system_, "IApplicationDisplayService"}, nvnflinger{nvnflinger_},
507 hos_binder_driver_server{hos_binder_driver_server_} {
508
509 static const FunctionInfo functions[] = {
510 {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"},
511 {101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"},
512 {102, &IApplicationDisplayService::GetManagerDisplayService,
513 "GetManagerDisplayService"},
514 {103, &IApplicationDisplayService::GetIndirectDisplayTransactionService,
515 "GetIndirectDisplayTransactionService"},
516 {1000, &IApplicationDisplayService::ListDisplays, "ListDisplays"},
517 {1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"},
518 {1011, &IApplicationDisplayService::OpenDefaultDisplay, "OpenDefaultDisplay"},
519 {1020, &IApplicationDisplayService::CloseDisplay, "CloseDisplay"},
520 {1101, &IApplicationDisplayService::SetDisplayEnabled, "SetDisplayEnabled"},
521 {1102, &IApplicationDisplayService::GetDisplayResolution, "GetDisplayResolution"},
522 {2020, &IApplicationDisplayService::OpenLayer, "OpenLayer"},
523 {2021, &IApplicationDisplayService::CloseLayer, "CloseLayer"},
524 {2030, &IApplicationDisplayService::CreateStrayLayer, "CreateStrayLayer"},
525 {2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"},
526 {2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"},
527 {2102, &IApplicationDisplayService::ConvertScalingMode, "ConvertScalingMode"},
528 {2450, &IApplicationDisplayService::GetIndirectLayerImageMap,
529 "GetIndirectLayerImageMap"},
530 {2451, nullptr, "GetIndirectLayerImageCropMap"},
531 {2460, &IApplicationDisplayService::GetIndirectLayerImageRequiredMemoryInfo,
532 "GetIndirectLayerImageRequiredMemoryInfo"},
533 {5202, &IApplicationDisplayService::GetDisplayVsyncEvent, "GetDisplayVsyncEvent"},
534 {5203, nullptr, "GetDisplayVsyncEventForDebug"},
535 };
536 RegisterHandlers(functions);
537 }
538
539 ~IApplicationDisplayService() {
540 for (const auto layer_id : stray_layer_ids) {
541 nvnflinger.DestroyLayer(layer_id);
542 }
543 }
544
545private:
546 enum class ConvertedScaleMode : u64 {
547 Freeze = 0,
548 ScaleToWindow = 1,
549 ScaleAndCrop = 2,
550 None = 3,
551 PreserveAspectRatio = 4,
552 };
553
554 enum class NintendoScaleMode : u32 {
555 None = 0,
556 Freeze = 1,
557 ScaleToWindow = 2,
558 ScaleAndCrop = 3,
559 PreserveAspectRatio = 4,
560 };
561
562 void GetRelayService(HLERequestContext& ctx) {
563 LOG_WARNING(Service_VI, "(STUBBED) called");
564
565 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
566 rb.Push(ResultSuccess);
567 rb.PushIpcInterface<IHOSBinderDriver>(system, hos_binder_driver_server);
568 }
569
570 void GetSystemDisplayService(HLERequestContext& ctx) {
571 LOG_WARNING(Service_VI, "(STUBBED) called");
572
573 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
574 rb.Push(ResultSuccess);
575 rb.PushIpcInterface<ISystemDisplayService>(system, nvnflinger);
576 }
577
578 void GetManagerDisplayService(HLERequestContext& ctx) {
579 LOG_WARNING(Service_VI, "(STUBBED) called");
580
581 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
582 rb.Push(ResultSuccess);
583 rb.PushIpcInterface<IManagerDisplayService>(system, nvnflinger);
584 }
585
586 void GetIndirectDisplayTransactionService(HLERequestContext& ctx) {
587 LOG_WARNING(Service_VI, "(STUBBED) called");
588
589 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
590 rb.Push(ResultSuccess);
591 rb.PushIpcInterface<IHOSBinderDriver>(system, hos_binder_driver_server);
592 }
593
594 void OpenDisplay(HLERequestContext& ctx) {
595 LOG_WARNING(Service_VI, "(STUBBED) called");
596
597 IPC::RequestParser rp{ctx};
598 const auto name_buf = rp.PopRaw<std::array<char, 0x40>>();
599
600 OpenDisplayImpl(ctx, std::string_view{name_buf.data(), name_buf.size()});
601 }
602
603 void OpenDefaultDisplay(HLERequestContext& ctx) {
604 LOG_DEBUG(Service_VI, "called");
605
606 OpenDisplayImpl(ctx, "Default");
607 }
608
609 void OpenDisplayImpl(HLERequestContext& ctx, std::string_view name) {
610 const auto trim_pos = name.find('\0');
611
612 if (trim_pos != std::string_view::npos) {
613 name.remove_suffix(name.size() - trim_pos);
614 }
615
616 ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet");
617
618 const auto display_id = nvnflinger.OpenDisplay(name);
619 if (!display_id) {
620 LOG_ERROR(Service_VI, "Display not found! display_name={}", name);
621 IPC::ResponseBuilder rb{ctx, 2};
622 rb.Push(ResultNotFound);
623 return;
624 }
625
626 IPC::ResponseBuilder rb{ctx, 4};
627 rb.Push(ResultSuccess);
628 rb.Push<u64>(*display_id);
629 }
630
631 void CloseDisplay(HLERequestContext& ctx) {
632 IPC::RequestParser rp{ctx};
633 const u64 display_id = rp.Pop<u64>();
634
635 const Result rc = nvnflinger.CloseDisplay(display_id) ? ResultSuccess : ResultUnknown;
636
637 IPC::ResponseBuilder rb{ctx, 2};
638 rb.Push(rc);
639 }
640
641 // This literally does nothing internally in the actual service itself,
642 // and just returns a successful result code regardless of the input.
643 void SetDisplayEnabled(HLERequestContext& ctx) {
644 LOG_DEBUG(Service_VI, "called.");
645
646 IPC::ResponseBuilder rb{ctx, 2};
647 rb.Push(ResultSuccess);
648 }
649
650 void GetDisplayResolution(HLERequestContext& ctx) {
651 IPC::RequestParser rp{ctx};
652 const u64 display_id = rp.Pop<u64>();
653
654 LOG_DEBUG(Service_VI, "called. display_id=0x{:016X}", display_id);
655
656 IPC::ResponseBuilder rb{ctx, 6};
657 rb.Push(ResultSuccess);
658
659 // This only returns the fixed values of 1280x720 and makes no distinguishing
660 // between docked and undocked dimensions. We take the liberty of applying
661 // the resolution scaling factor here.
662 rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth));
663 rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight));
664 }
665
666 void SetLayerScalingMode(HLERequestContext& ctx) {
667 IPC::RequestParser rp{ctx};
668 const auto scaling_mode = rp.PopEnum<NintendoScaleMode>();
669 const u64 unknown = rp.Pop<u64>();
670
671 LOG_DEBUG(Service_VI, "called. scaling_mode=0x{:08X}, unknown=0x{:016X}", scaling_mode,
672 unknown);
673
674 IPC::ResponseBuilder rb{ctx, 2};
675
676 if (scaling_mode > NintendoScaleMode::PreserveAspectRatio) {
677 LOG_ERROR(Service_VI, "Invalid scaling mode provided.");
678 rb.Push(ResultOperationFailed);
679 return;
680 }
681
682 if (scaling_mode != NintendoScaleMode::ScaleToWindow &&
683 scaling_mode != NintendoScaleMode::PreserveAspectRatio) {
684 LOG_ERROR(Service_VI, "Unsupported scaling mode supplied.");
685 rb.Push(ResultNotSupported);
686 return;
687 }
688
689 rb.Push(ResultSuccess);
690 }
691
692 void ListDisplays(HLERequestContext& ctx) {
693 LOG_WARNING(Service_VI, "(STUBBED) called");
694
695 const DisplayInfo display_info;
696 ctx.WriteBuffer(&display_info, sizeof(DisplayInfo));
697 IPC::ResponseBuilder rb{ctx, 4};
698 rb.Push(ResultSuccess);
699 rb.Push<u64>(1);
700 }
701
702 void OpenLayer(HLERequestContext& ctx) {
703 IPC::RequestParser rp{ctx};
704 const auto name_buf = rp.PopRaw<std::array<u8, 0x40>>();
705 const std::string display_name(Common::StringFromBuffer(name_buf));
706
707 const u64 layer_id = rp.Pop<u64>();
708 const u64 aruid = rp.Pop<u64>();
709
710 LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid);
711
712 const auto display_id = nvnflinger.OpenDisplay(display_name);
713 if (!display_id) {
714 LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id);
715 IPC::ResponseBuilder rb{ctx, 2};
716 rb.Push(ResultNotFound);
717 return;
718 }
719
720 const auto buffer_queue_id = nvnflinger.FindBufferQueueId(*display_id, layer_id);
721 if (!buffer_queue_id) {
722 LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id);
723 IPC::ResponseBuilder rb{ctx, 2};
724 rb.Push(ResultNotFound);
725 return;
726 }
727
728 if (!nvnflinger.OpenLayer(layer_id)) {
729 LOG_WARNING(Service_VI, "Tried to open layer which was already open");
730 IPC::ResponseBuilder rb{ctx, 2};
731 rb.Push(ResultOperationFailed);
732 return;
733 }
734
735 android::OutputParcel parcel;
736 parcel.WriteInterface(NativeWindow{*buffer_queue_id});
737
738 const auto buffer_size = ctx.WriteBuffer(parcel.Serialize());
739
740 IPC::ResponseBuilder rb{ctx, 4};
741 rb.Push(ResultSuccess);
742 rb.Push<u64>(buffer_size);
743 }
744
745 void CloseLayer(HLERequestContext& ctx) {
746 IPC::RequestParser rp{ctx};
747 const auto layer_id{rp.Pop<u64>()};
748
749 LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}", layer_id);
750
751 if (!nvnflinger.CloseLayer(layer_id)) {
752 LOG_WARNING(Service_VI, "Tried to close layer which was not open");
753 IPC::ResponseBuilder rb{ctx, 2};
754 rb.Push(ResultOperationFailed);
755 return;
756 }
757
758 IPC::ResponseBuilder rb{ctx, 2};
759 rb.Push(ResultSuccess);
760 }
761
762 void CreateStrayLayer(HLERequestContext& ctx) {
763 IPC::RequestParser rp{ctx};
764 const u32 flags = rp.Pop<u32>();
765 rp.Pop<u32>(); // padding
766 const u64 display_id = rp.Pop<u64>();
767
768 LOG_DEBUG(Service_VI, "called. flags=0x{:08X}, display_id=0x{:016X}", flags, display_id);
769
770 // TODO(Subv): What's the difference between a Stray and a Managed layer?
771
772 const auto layer_id = nvnflinger.CreateLayer(display_id);
773 if (!layer_id) {
774 LOG_ERROR(Service_VI, "Layer not found! display_id={}", display_id);
775 IPC::ResponseBuilder rb{ctx, 2};
776 rb.Push(ResultNotFound);
777 return;
778 }
779
780 stray_layer_ids.push_back(*layer_id);
781 const auto buffer_queue_id = nvnflinger.FindBufferQueueId(display_id, *layer_id);
782 if (!buffer_queue_id) {
783 LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id);
784 IPC::ResponseBuilder rb{ctx, 2};
785 rb.Push(ResultNotFound);
786 return;
787 }
788
789 android::OutputParcel parcel;
790 parcel.WriteInterface(NativeWindow{*buffer_queue_id});
791
792 const auto buffer_size = ctx.WriteBuffer(parcel.Serialize());
793
794 IPC::ResponseBuilder rb{ctx, 6};
795 rb.Push(ResultSuccess);
796 rb.Push(*layer_id);
797 rb.Push<u64>(buffer_size);
798 }
799
800 void DestroyStrayLayer(HLERequestContext& ctx) {
801 IPC::RequestParser rp{ctx};
802 const u64 layer_id = rp.Pop<u64>();
803
804 LOG_WARNING(Service_VI, "(STUBBED) called. layer_id=0x{:016X}", layer_id);
805 nvnflinger.DestroyLayer(layer_id);
806
807 IPC::ResponseBuilder rb{ctx, 2};
808 rb.Push(ResultSuccess);
809 }
810
811 void GetDisplayVsyncEvent(HLERequestContext& ctx) {
812 IPC::RequestParser rp{ctx};
813 const u64 display_id = rp.Pop<u64>();
814
815 LOG_DEBUG(Service_VI, "called. display_id={}", display_id);
816
817 Kernel::KReadableEvent* vsync_event{};
818 const auto result = nvnflinger.FindVsyncEvent(&vsync_event, display_id);
819 if (result != ResultSuccess) {
820 if (result == ResultNotFound) {
821 LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id);
822 }
823
824 IPC::ResponseBuilder rb{ctx, 2};
825 rb.Push(result);
826 return;
827 }
828 if (vsync_event_fetched) {
829 IPC::ResponseBuilder rb{ctx, 2};
830 rb.Push(VI::ResultPermissionDenied);
831 return;
832 }
833 vsync_event_fetched = true;
834
835 IPC::ResponseBuilder rb{ctx, 2, 1};
836 rb.Push(ResultSuccess);
837 rb.PushCopyObjects(vsync_event);
838 }
839
840 void ConvertScalingMode(HLERequestContext& ctx) {
841 IPC::RequestParser rp{ctx};
842 const auto mode = rp.PopEnum<NintendoScaleMode>();
843 LOG_DEBUG(Service_VI, "called mode={}", mode);
844
845 ConvertedScaleMode converted_mode{};
846 const auto result = ConvertScalingModeImpl(&converted_mode, mode);
847
848 if (result == ResultSuccess) {
849 IPC::ResponseBuilder rb{ctx, 4};
850 rb.Push(ResultSuccess);
851 rb.PushEnum(converted_mode);
852 } else {
853 IPC::ResponseBuilder rb{ctx, 2};
854 rb.Push(result);
855 }
856 }
857
858 void GetIndirectLayerImageMap(HLERequestContext& ctx) {
859 IPC::RequestParser rp{ctx};
860 const auto width = rp.Pop<s64>();
861 const auto height = rp.Pop<s64>();
862 const auto indirect_layer_consumer_handle = rp.Pop<u64>();
863 const auto applet_resource_user_id = rp.Pop<u64>();
864
865 LOG_WARNING(Service_VI,
866 "(STUBBED) called, width={}, height={}, indirect_layer_consumer_handle={}, "
867 "applet_resource_user_id={}",
868 width, height, indirect_layer_consumer_handle, applet_resource_user_id);
869
870 std::vector<u8> out_buffer(0x46);
871 ctx.WriteBuffer(out_buffer);
872
873 // TODO: Figure out what these are
874
875 constexpr s64 unknown_result_1 = 0;
876 constexpr s64 unknown_result_2 = 0;
877
878 IPC::ResponseBuilder rb{ctx, 6};
879 rb.Push(unknown_result_1);
880 rb.Push(unknown_result_2);
881 rb.Push(ResultSuccess);
882 }
883
884 void GetIndirectLayerImageRequiredMemoryInfo(HLERequestContext& ctx) {
885 IPC::RequestParser rp{ctx};
886 const auto width = rp.Pop<u64>();
887 const auto height = rp.Pop<u64>();
888 LOG_DEBUG(Service_VI, "called width={}, height={}", width, height);
889
890 constexpr u64 base_size = 0x20000;
891 constexpr u64 alignment = 0x1000;
892 const auto texture_size = width * height * 4;
893 const auto out_size = (texture_size + base_size - 1) / base_size * base_size;
894
895 IPC::ResponseBuilder rb{ctx, 6};
896 rb.Push(ResultSuccess);
897 rb.Push(out_size);
898 rb.Push(alignment);
899 }
900
901 static Result ConvertScalingModeImpl(ConvertedScaleMode* out_scaling_mode,
902 NintendoScaleMode mode) {
903 switch (mode) {
904 case NintendoScaleMode::None:
905 *out_scaling_mode = ConvertedScaleMode::None;
906 return ResultSuccess;
907 case NintendoScaleMode::Freeze:
908 *out_scaling_mode = ConvertedScaleMode::Freeze;
909 return ResultSuccess;
910 case NintendoScaleMode::ScaleToWindow:
911 *out_scaling_mode = ConvertedScaleMode::ScaleToWindow;
912 return ResultSuccess;
913 case NintendoScaleMode::ScaleAndCrop:
914 *out_scaling_mode = ConvertedScaleMode::ScaleAndCrop;
915 return ResultSuccess;
916 case NintendoScaleMode::PreserveAspectRatio:
917 *out_scaling_mode = ConvertedScaleMode::PreserveAspectRatio;
918 return ResultSuccess;
919 default:
920 LOG_ERROR(Service_VI, "Invalid scaling mode specified, mode={}", mode);
921 return ResultOperationFailed;
922 }
923 }
924
925 Nvnflinger::Nvnflinger& nvnflinger;
926 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server;
927 std::vector<u64> stray_layer_ids;
928 bool vsync_event_fetched{false};
929};
930
931static bool IsValidServiceAccess(Permission permission, Policy policy) {
932 if (permission == Permission::User) {
933 return policy == Policy::User;
934 }
935
936 if (permission == Permission::System || permission == Permission::Manager) {
937 return policy == Policy::User || policy == Policy::Compositor;
938 }
939
940 return false;
941}
942
943void detail::GetDisplayServiceImpl(HLERequestContext& ctx, Core::System& system,
944 Nvnflinger::Nvnflinger& nvnflinger,
945 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server,
946 Permission permission) {
947 IPC::RequestParser rp{ctx};
948 const auto policy = rp.PopEnum<Policy>();
949
950 if (!IsValidServiceAccess(permission, policy)) {
951 LOG_ERROR(Service_VI, "Permission denied for policy {}", policy);
952 IPC::ResponseBuilder rb{ctx, 2};
953 rb.Push(ResultPermissionDenied);
954 return;
955 }
956
957 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
958 rb.Push(ResultSuccess);
959 rb.PushIpcInterface<IApplicationDisplayService>(system, nvnflinger, hos_binder_driver_server);
960}
961
962void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nvnflinger, 13void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nvnflinger,
963 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) { 14 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) {
964 auto server_manager = std::make_unique<ServerManager>(system); 15 auto server_manager = std::make_unique<ServerManager>(system);
965 16
17 server_manager->RegisterNamedService("vi:m", std::make_shared<IManagerRootService>(
18 system, nvnflinger, hos_binder_driver_server));
966 server_manager->RegisterNamedService( 19 server_manager->RegisterNamedService(
967 "vi:m", std::make_shared<VI_M>(system, nvnflinger, hos_binder_driver_server)); 20 "vi:s", std::make_shared<ISystemRootService>(system, nvnflinger, hos_binder_driver_server));
968 server_manager->RegisterNamedService( 21 server_manager->RegisterNamedService("vi:u", std::make_shared<IApplicationRootService>(
969 "vi:s", std::make_shared<VI_S>(system, nvnflinger, hos_binder_driver_server)); 22 system, nvnflinger, hos_binder_driver_server));
970 server_manager->RegisterNamedService(
971 "vi:u", std::make_shared<VI_U>(system, nvnflinger, hos_binder_driver_server));
972 ServerManager::RunServer(std::move(server_manager)); 23 ServerManager::RunServer(std::move(server_manager));
973} 24}
974 25
diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h
index 25e0aed66..a81a701b0 100755
--- a/src/core/hle/service/vi/vi.h
+++ b/src/core/hle/service/vi/vi.h
@@ -3,16 +3,10 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "common/common_types.h"
7
8namespace Core { 6namespace Core {
9class System; 7class System;
10} 8}
11 9
12namespace Service {
13class HLERequestContext;
14}
15
16namespace Service::Nvnflinger { 10namespace Service::Nvnflinger {
17class HosBinderDriverServer; 11class HosBinderDriverServer;
18class Nvnflinger; 12class Nvnflinger;
@@ -20,34 +14,6 @@ class Nvnflinger;
20 14
21namespace Service::VI { 15namespace Service::VI {
22 16
23enum class DisplayResolution : u32 {
24 DockedWidth = 1920,
25 DockedHeight = 1080,
26 UndockedWidth = 1280,
27 UndockedHeight = 720,
28};
29
30/// Permission level for a particular VI service instance
31enum class Permission {
32 User,
33 System,
34 Manager,
35};
36
37/// A policy type that may be requested via GetDisplayService and
38/// GetDisplayServiceWithProxyNameExchange
39enum class Policy {
40 User,
41 Compositor,
42};
43
44namespace detail {
45void GetDisplayServiceImpl(HLERequestContext& ctx, Core::System& system,
46 Nvnflinger::Nvnflinger& nv_flinger,
47 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server,
48 Permission permission);
49} // namespace detail
50
51void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nvnflinger, 17void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nvnflinger,
52 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server); 18 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server);
53 19
diff --git a/src/core/hle/service/vi/vi_types.h b/src/core/hle/service/vi/vi_types.h
new file mode 100755
index 000000000..91e4b380c
--- /dev/null
+++ b/src/core/hle/service/vi/vi_types.h
@@ -0,0 +1,84 @@
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_funcs.h"
7
8namespace Service::VI {
9
10enum class DisplayResolution : u32 {
11 DockedWidth = 1920,
12 DockedHeight = 1080,
13 UndockedWidth = 1280,
14 UndockedHeight = 720,
15};
16
17/// Permission level for a particular VI service instance
18enum class Permission {
19 User,
20 System,
21 Manager,
22};
23
24/// A policy type that may be requested via GetDisplayService and
25/// GetDisplayServiceWithProxyNameExchange
26enum class Policy : u32 {
27 User,
28 Compositor,
29};
30
31enum class ConvertedScaleMode : u64 {
32 Freeze = 0,
33 ScaleToWindow = 1,
34 ScaleAndCrop = 2,
35 None = 3,
36 PreserveAspectRatio = 4,
37};
38
39enum class NintendoScaleMode : u32 {
40 None = 0,
41 Freeze = 1,
42 ScaleToWindow = 2,
43 ScaleAndCrop = 3,
44 PreserveAspectRatio = 4,
45};
46
47using DisplayName = std::array<char, 0x40>;
48
49struct DisplayInfo {
50 /// The name of this particular display.
51 DisplayName display_name{"Default"};
52
53 /// Whether or not the display has a limited number of layers.
54 u8 has_limited_layers{1};
55 INSERT_PADDING_BYTES(7);
56
57 /// Indicates the total amount of layers supported by the display.
58 /// @note This is only valid if has_limited_layers is set.
59 u64 max_layers{1};
60
61 /// Maximum width in pixels.
62 u64 width{1920};
63
64 /// Maximum height in pixels.
65 u64 height{1080};
66};
67static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size");
68
69class NativeWindow final {
70public:
71 constexpr explicit NativeWindow(u32 id_) : id{id_} {}
72 constexpr explicit NativeWindow(const NativeWindow& other) = default;
73
74private:
75 const u32 magic = 2;
76 const u32 process_id = 1;
77 const u64 id;
78 INSERT_PADDING_WORDS(2);
79 std::array<u8, 8> dispdrv = {'d', 'i', 's', 'p', 'd', 'r', 'v', '\0'};
80 INSERT_PADDING_WORDS(2);
81};
82static_assert(sizeof(NativeWindow) == 0x28, "NativeWindow has wrong size");
83
84} // namespace Service::VI