summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Subv2018-01-07 21:27:58 -0500
committerGravatar bunnei2018-01-10 23:28:09 -0500
commit25f29c2f4fd2415373f8af24fb61142ab4b343e6 (patch)
treed20a1c7c41051f37183b2d095f2edb34ea8a207b
parentNV: Implemented the nvdrv:a service and the /dev/nvmap device. (diff)
downloadyuzu-25f29c2f4fd2415373f8af24fb61142ab4b343e6.tar.gz
yuzu-25f29c2f4fd2415373f8af24fb61142ab4b343e6.tar.xz
yuzu-25f29c2f4fd2415373f8af24fb61142ab4b343e6.zip
NV: Implemented (with stubs) the vi:m service and some of its subservices.
The homebrew display test application now properly writes graphics data to the graphics buffer but we still don't have a way to compose the display layers.
-rw-r--r--src/core/CMakeLists.txt8
-rw-r--r--src/core/hle/service/service.cpp4
-rw-r--r--src/core/hle/service/vi/vi.cpp628
-rw-r--r--src/core/hle/service/vi/vi.h34
-rw-r--r--src/core/hle/service/vi/vi_m.cpp29
-rw-r--r--src/core/hle/service/vi/vi_m.h23
6 files changed, 726 insertions, 0 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index a5dc67b07..cc2b5b084 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -45,11 +45,15 @@ set(SRCS
45 hle/service/gsp_gpu.cpp 45 hle/service/gsp_gpu.cpp
46 hle/service/hid/hid.cpp 46 hle/service/hid/hid.cpp
47 hle/service/lm/lm.cpp 47 hle/service/lm/lm.cpp
48 hle/service/nvdrv/nvdrv.cpp
49 hle/service/nvdrv/nvdrv_a.cpp
48 hle/service/pctl/pctl.cpp 50 hle/service/pctl/pctl.cpp
49 hle/service/pctl/pctl_a.cpp 51 hle/service/pctl/pctl_a.cpp
50 hle/service/service.cpp 52 hle/service/service.cpp
51 hle/service/sm/controller.cpp 53 hle/service/sm/controller.cpp
52 hle/service/sm/sm.cpp 54 hle/service/sm/sm.cpp
55 hle/service/vi/vi.cpp
56 hle/service/vi/vi_m.cpp
53 hle/shared_page.cpp 57 hle/shared_page.cpp
54 hw/aes/arithmetic128.cpp 58 hw/aes/arithmetic128.cpp
55 hw/aes/ccm.cpp 59 hw/aes/ccm.cpp
@@ -128,11 +132,15 @@ set(HEADERS
128 hle/service/gsp_gpu.h 132 hle/service/gsp_gpu.h
129 hle/service/hid/hid.h 133 hle/service/hid/hid.h
130 hle/service/lm/lm.h 134 hle/service/lm/lm.h
135 hle/service/nvdrv/nvdrv.h
136 hle/service/nvdrv/nvdrv_a.h
131 hle/service/pctl/pctl.h 137 hle/service/pctl/pctl.h
132 hle/service/pctl/pctl_a.h 138 hle/service/pctl/pctl_a.h
133 hle/service/service.h 139 hle/service/service.h
134 hle/service/sm/controller.h 140 hle/service/sm/controller.h
135 hle/service/sm/sm.h 141 hle/service/sm/sm.h
142 hle/service/vi/vi.h
143 hle/service/vi/vi_m.h
136 hle/shared_page.h 144 hle/shared_page.h
137 hw/aes/arithmetic128.h 145 hw/aes/arithmetic128.h
138 hw/aes/ccm.h 146 hw/aes/ccm.h
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 3dfde8f39..389243035 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -21,10 +21,12 @@
21#include "core/hle/service/gsp_gpu.h" 21#include "core/hle/service/gsp_gpu.h"
22#include "core/hle/service/hid/hid.h" 22#include "core/hle/service/hid/hid.h"
23#include "core/hle/service/lm/lm.h" 23#include "core/hle/service/lm/lm.h"
24#include "core/hle/service/nvdrv/nvdrv.h"
24#include "core/hle/service/pctl/pctl.h" 25#include "core/hle/service/pctl/pctl.h"
25#include "core/hle/service/service.h" 26#include "core/hle/service/service.h"
26#include "core/hle/service/sm/controller.h" 27#include "core/hle/service/sm/controller.h"
27#include "core/hle/service/sm/sm.h" 28#include "core/hle/service/sm/sm.h"
29#include "core/hle/service/vi/vi.h"
28 30
29using Kernel::ClientPort; 31using Kernel::ClientPort;
30using Kernel::ServerPort; 32using Kernel::ServerPort;
@@ -165,7 +167,9 @@ void Init() {
165 AOC::InstallInterfaces(*SM::g_service_manager); 167 AOC::InstallInterfaces(*SM::g_service_manager);
166 APM::InstallInterfaces(*SM::g_service_manager); 168 APM::InstallInterfaces(*SM::g_service_manager);
167 LM::InstallInterfaces(*SM::g_service_manager); 169 LM::InstallInterfaces(*SM::g_service_manager);
170 NVDRV::InstallInterfaces(*SM::g_service_manager);
168 PCTL::InstallInterfaces(*SM::g_service_manager); 171 PCTL::InstallInterfaces(*SM::g_service_manager);
172 VI::InstallInterfaces(*SM::g_service_manager);
169 173
170 HID::Init(); 174 HID::Init();
171 175
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
new file mode 100644
index 000000000..fa7d08176
--- /dev/null
+++ b/src/core/hle/service/vi/vi.cpp
@@ -0,0 +1,628 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/alignment.h"
6#include "core/hle/ipc_helpers.h"
7#include "core/hle/service/vi/vi.h"
8#include "core/hle/service/vi/vi_m.h"
9
10namespace Service {
11namespace VI {
12
13struct IGBPBuffer {
14 u32_le magic;
15 u32_le width;
16 u32_le height;
17 u32_le stride;
18 u32_le format;
19 u32_le usage;
20 INSERT_PADDING_WORDS(1);
21 u32_le index;
22 INSERT_PADDING_WORDS(3);
23 u32_le gpu_buffer_id;
24 INSERT_PADDING_WORDS(17);
25 u32_le nvmap_handle;
26 INSERT_PADDING_WORDS(61);
27};
28
29static_assert(sizeof(IGBPBuffer) == 0x16C, "IGBPBuffer has wrong size");
30
31class Parcel {
32public:
33 // This default size was chosen arbitrarily.
34 static constexpr size_t DefaultBufferSize = 0x40;
35 Parcel() : buffer(DefaultBufferSize) {}
36 Parcel(std::vector<u8> data) : buffer(std::move(data)) {}
37 virtual ~Parcel() = default;
38
39 template <typename T>
40 T Read() {
41 T val;
42 std::memcpy(&val, buffer.data() + read_index, sizeof(T));
43 read_index += sizeof(T);
44 read_index = Common::AlignUp(read_index, 4);
45 return val;
46 }
47
48 template <typename T>
49 T ReadUnaligned() {
50 T val;
51 std::memcpy(&val, buffer.data() + read_index, sizeof(T));
52 read_index += sizeof(T);
53 return val;
54 }
55
56 std::vector<u8> ReadBlock(size_t length) {
57 std::vector<u8> data(length);
58 std::memcpy(data.data(), buffer.data() + read_index, length);
59 read_index += length;
60 read_index = Common::AlignUp(read_index, 4);
61 return data;
62 }
63
64 std::u16string ReadInterfaceToken() {
65 u32 unknown = Read<u32_le>();
66 u32 length = Read<u32_le>();
67
68 std::u16string token{};
69
70 for (u32 ch = 0; ch < length + 1; ++ch) {
71 token.push_back(ReadUnaligned<u16_le>());
72 }
73
74 read_index = Common::AlignUp(read_index, 4);
75
76 return token;
77 }
78
79 template <typename T>
80 void Write(const T& val) {
81 if (buffer.size() < write_index + sizeof(T))
82 buffer.resize(buffer.size() + sizeof(T) + DefaultBufferSize);
83 std::memcpy(buffer.data() + write_index, &val, sizeof(T));
84 write_index += sizeof(T);
85 write_index = Common::AlignUp(write_index, 4);
86 }
87
88 void Deserialize() {
89 Header header{};
90 std::memcpy(&header, buffer.data(), sizeof(Header));
91
92 read_index = header.data_offset;
93 DeserializeData();
94 }
95
96 std::vector<u8> Serialize() {
97 ASSERT(read_index == 0);
98 write_index = sizeof(Header);
99
100 SerializeData();
101
102 Header header{};
103 header.data_offset = sizeof(Header);
104 header.data_size = write_index - sizeof(Header);
105 std::memcpy(buffer.data(), &header, sizeof(Header));
106
107 return buffer;
108 }
109
110protected:
111 virtual void SerializeData(){};
112
113 virtual void DeserializeData(){};
114
115private:
116 struct Header {
117 u32_le data_size;
118 u32_le data_offset;
119 u32_le objects_size;
120 u32_le objects_offset;
121 };
122 static_assert(sizeof(Header) == 16, "ParcelHeader has wrong size");
123
124 std::vector<u8> buffer;
125 size_t read_index = 0;
126 size_t write_index = 0;
127};
128
129class NativeWindow : public Parcel {
130public:
131 NativeWindow(u32 id) : Parcel() {
132 data.id = id;
133 }
134 ~NativeWindow() override = default;
135
136protected:
137 void SerializeData() override {
138 Write(data);
139 }
140
141private:
142 struct Data {
143 u32_le magic = 2;
144 u32_le process_id;
145 u32_le id;
146 INSERT_PADDING_BYTES(0xC);
147 std::array<u8, 8> dspdrv = {'d', 's', 'p', 'd', 'r', 'v'};
148 INSERT_PADDING_BYTES(8);
149 };
150 static_assert(sizeof(Data) == 0x28, "ParcelData has wrong size");
151
152 Data data{};
153};
154
155class IGBPConnectRequestParcel : public Parcel {
156public:
157 IGBPConnectRequestParcel(const std::vector<u8>& buffer) : Parcel(buffer) {
158 Deserialize();
159 }
160 ~IGBPConnectRequestParcel() override = default;
161
162 void DeserializeData() {
163 std::u16string token = ReadInterfaceToken();
164 data = Read<Data>();
165 }
166
167 struct Data {
168 u32_le unk;
169 u32_le api;
170 u32_le producer_controlled_by_app;
171 };
172
173 Data data;
174};
175
176class IGBPConnectResponseParcel : public Parcel {
177public:
178 IGBPConnectResponseParcel(u32 width, u32 height) : Parcel() {
179 data.width = width;
180 data.height = height;
181 }
182 ~IGBPConnectResponseParcel() override = default;
183
184protected:
185 void SerializeData() override {
186 Write(data);
187 }
188
189private:
190 struct Data {
191 u32_le width;
192 u32_le height;
193 u32_le transform_hint;
194 u32_le num_pending_buffers;
195 u32_le status;
196 };
197 static_assert(sizeof(Data) == 20, "ParcelData has wrong size");
198
199 Data data{};
200};
201
202class IGBPSetPreallocatedBufferRequestParcel : public Parcel {
203public:
204 IGBPSetPreallocatedBufferRequestParcel(const std::vector<u8>& buffer) : Parcel(buffer) {
205 Deserialize();
206 }
207 ~IGBPSetPreallocatedBufferRequestParcel() override = default;
208
209 void DeserializeData() {
210 std::u16string token = ReadInterfaceToken();
211 data = Read<Data>();
212 ASSERT(data.graphic_buffer_length == sizeof(IGBPBuffer));
213 buffer = Read<IGBPBuffer>();
214 }
215
216 struct Data {
217 u32_le slot;
218 INSERT_PADDING_WORDS(1);
219 u32_le graphic_buffer_length;
220 INSERT_PADDING_WORDS(1);
221 };
222
223 Data data;
224 IGBPBuffer buffer;
225};
226
227class IGBPSetPreallocatedBufferResponseParcel : public Parcel {
228public:
229 IGBPSetPreallocatedBufferResponseParcel() : Parcel() {}
230 ~IGBPSetPreallocatedBufferResponseParcel() override = default;
231
232protected:
233 void SerializeData() override {
234 // TODO(Subv): Find out what this means
235 Write<u32>(0);
236 }
237};
238
239class IGBPDequeueBufferRequestParcel : public Parcel {
240public:
241 IGBPDequeueBufferRequestParcel(const std::vector<u8>& buffer) : Parcel(buffer) {
242 Deserialize();
243 }
244 ~IGBPDequeueBufferRequestParcel() override = default;
245
246 void DeserializeData() {
247 std::u16string token = ReadInterfaceToken();
248 data = Read<Data>();
249 }
250
251 struct Data {
252 u32_le pixel_format;
253 u32_le width;
254 u32_le height;
255 u32_le get_frame_timestamps;
256 u32_le usage;
257 };
258
259 Data data;
260};
261
262class IGBPDequeueBufferResponseParcel : public Parcel {
263public:
264 IGBPDequeueBufferResponseParcel(u32 slot) : Parcel(), slot(slot) {}
265 ~IGBPDequeueBufferResponseParcel() override = default;
266
267protected:
268 void SerializeData() override {
269 Write(slot);
270 // TODO(Subv): Find out how this Fence is used.
271 std::array<u32_le, 11> fence = {};
272 Write(fence);
273 Write<u32_le>(0);
274 }
275
276 u32_le slot;
277};
278
279class IGBPRequestBufferRequestParcel : public Parcel {
280public:
281 IGBPRequestBufferRequestParcel(const std::vector<u8>& buffer) : Parcel(buffer) {
282 Deserialize();
283 }
284 ~IGBPRequestBufferRequestParcel() override = default;
285
286 void DeserializeData() {
287 std::u16string token = ReadInterfaceToken();
288 slot = Read<u32_le>();
289 }
290
291 u32_le slot;
292};
293
294class IGBPRequestBufferResponseParcel : public Parcel {
295public:
296 IGBPRequestBufferResponseParcel(IGBPBuffer buffer) : Parcel(), buffer(buffer) {}
297 ~IGBPRequestBufferResponseParcel() override = default;
298
299protected:
300 void SerializeData() override {
301 // TODO(Subv): Find out what this all means
302 Write<u32_le>(1);
303
304 Write<u32_le>(sizeof(IGBPBuffer));
305 Write<u32_le>(0); // Unknown
306
307 Write(buffer);
308
309 Write<u32_le>(0);
310 }
311
312 IGBPBuffer buffer;
313};
314
315class IGBPQueueBufferRequestParcel : public Parcel {
316public:
317 IGBPQueueBufferRequestParcel(const std::vector<u8>& buffer) : Parcel(buffer) {
318 Deserialize();
319 }
320 ~IGBPQueueBufferRequestParcel() override = default;
321
322 void DeserializeData() {
323 std::u16string token = ReadInterfaceToken();
324 data = Read<Data>();
325 }
326
327 struct Data {
328 u32_le slot;
329 INSERT_PADDING_WORDS(2);
330 u32_le timestamp;
331 INSERT_PADDING_WORDS(20);
332 };
333 static_assert(sizeof(Data) == 96, "ParcelData has wrong size");
334
335 Data data;
336};
337
338class IGBPQueueBufferResponseParcel : public Parcel {
339public:
340 IGBPQueueBufferResponseParcel(u32 width, u32 height) : Parcel() {
341 data.width = width;
342 data.height = height;
343 }
344 ~IGBPQueueBufferResponseParcel() override = default;
345
346protected:
347 void SerializeData() override {
348 Write(data);
349 }
350
351private:
352 struct Data {
353 u32_le width;
354 u32_le height;
355 u32_le transform_hint;
356 u32_le num_pending_buffers;
357 u32_le status;
358 };
359 static_assert(sizeof(Data) == 20, "ParcelData has wrong size");
360
361 Data data{};
362};
363
364class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
365public:
366 IHOSBinderDriver() : ServiceFramework("IHOSBinderDriver") {
367 static const FunctionInfo functions[] = {
368 {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"},
369 {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"},
370 {2, nullptr, "GetNativeHandle"},
371 {3, nullptr, "TransactParcelAuto"},
372 };
373 RegisterHandlers(functions);
374 }
375 ~IHOSBinderDriver() = default;
376
377private:
378 enum class TransactionId {
379 RequestBuffer = 1,
380 SetBufferCount = 2,
381 DequeueBuffer = 3,
382 DetachBuffer = 4,
383 DetachNextBuffer = 5,
384 AttachBuffer = 6,
385 QueueBuffer = 7,
386 CancelBuffer = 8,
387 Query = 9,
388 Connect = 10,
389 Disconnect = 11,
390
391 AllocateBuffers = 13,
392 SetPreallocatedBuffer = 14
393 };
394
395 void TransactParcel(Kernel::HLERequestContext& ctx) {
396 IPC::RequestParser rp{ctx};
397 u32 id = rp.Pop<u32>();
398 auto transaction = static_cast<TransactionId>(rp.Pop<u32>());
399 u32 flags = rp.Pop<u32>();
400
401 auto& input_buffer = ctx.BufferDescriptorA()[0];
402 std::vector<u8> input_data(input_buffer.Size());
403 Memory::ReadBlock(input_buffer.Address(), input_data.data(), input_buffer.Size());
404
405 auto& output_buffer = ctx.BufferDescriptorB()[0];
406
407 if (transaction == TransactionId::Connect) {
408 IGBPConnectRequestParcel request{input_data};
409 IGBPConnectResponseParcel response{1280, 720};
410 auto response_buffer = response.Serialize();
411 Memory::WriteBlock(output_buffer.Address(), response_buffer.data(),
412 output_buffer.Size());
413 } else if (transaction == TransactionId::SetPreallocatedBuffer) {
414 IGBPSetPreallocatedBufferRequestParcel request{input_data};
415
416 LOG_WARNING(Service, "Adding graphics buffer %u", request.data.slot);
417 graphic_buffers.push_back(request.buffer);
418
419 IGBPSetPreallocatedBufferResponseParcel response{};
420 auto response_buffer = response.Serialize();
421 Memory::WriteBlock(output_buffer.Address(), response_buffer.data(),
422 output_buffer.Size());
423 } else if (transaction == TransactionId::DequeueBuffer) {
424 IGBPDequeueBufferRequestParcel request{input_data};
425
426 IGBPDequeueBufferResponseParcel response{0};
427 auto response_buffer = response.Serialize();
428 Memory::WriteBlock(output_buffer.Address(), response_buffer.data(),
429 output_buffer.Size());
430 } else if (transaction == TransactionId::RequestBuffer) {
431 IGBPRequestBufferRequestParcel request{input_data};
432
433 auto& buffer = graphic_buffers[request.slot];
434 IGBPRequestBufferResponseParcel response{buffer};
435 auto response_buffer = response.Serialize();
436 Memory::WriteBlock(output_buffer.Address(), response_buffer.data(),
437 output_buffer.Size());
438 } else if (transaction == TransactionId::QueueBuffer) {
439 IGBPQueueBufferRequestParcel request{input_data};
440
441 IGBPQueueBufferResponseParcel response{1280, 720};
442 auto response_buffer = response.Serialize();
443 Memory::WriteBlock(output_buffer.Address(), response_buffer.data(),
444 output_buffer.Size());
445
446 // TODO(Subv): Start drawing here?
447 } else {
448 ASSERT_MSG(false, "Unimplemented");
449 }
450
451 LOG_WARNING(Service, "(STUBBED) called");
452 IPC::RequestBuilder rb{ctx, 2};
453 rb.Push(RESULT_SUCCESS);
454 }
455
456 void AdjustRefcount(Kernel::HLERequestContext& ctx) {
457 IPC::RequestParser rp{ctx};
458 u32 id = rp.Pop<u32>();
459 s32 addval = rp.PopRaw<s32>();
460 u32 type = rp.Pop<u32>();
461
462 LOG_WARNING(Service, "(STUBBED) called id=%u, addval=%08X, type=%08X", id, addval, type);
463 IPC::RequestBuilder rb{ctx, 2};
464 rb.Push(RESULT_SUCCESS);
465 }
466
467 std::vector<IGBPBuffer> graphic_buffers;
468};
469
470class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
471public:
472 ISystemDisplayService() : ServiceFramework("ISystemDisplayService") {
473 static const FunctionInfo functions[] = {
474 {1200, nullptr, "GetZOrderCountMin"},
475 {2205, &ISystemDisplayService::SetLayerZ, "SetLayerZ"},
476 };
477 RegisterHandlers(functions);
478 }
479 ~ISystemDisplayService() = default;
480
481private:
482 void SetLayerZ(Kernel::HLERequestContext& ctx) {
483 LOG_WARNING(Service, "(STUBBED) called");
484 IPC::RequestParser rp{ctx};
485 u64 layer_id = rp.Pop<u64>();
486 u64 z_value = rp.Pop<u64>();
487
488 IPC::RequestBuilder rb = rp.MakeBuilder(2, 0, 0, 0);
489 rb.Push(RESULT_SUCCESS);
490 }
491};
492
493class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
494public:
495 IManagerDisplayService() : ServiceFramework("IManagerDisplayService") {
496 static const FunctionInfo functions[] = {
497 {1102, nullptr, "GetDisplayResolution"},
498 {2010, &IManagerDisplayService::CreateManagedLayer, "CreateManagedLayer"},
499 {6000, &IManagerDisplayService::AddToLayerStack, "AddToLayerStack"},
500 };
501 RegisterHandlers(functions);
502 }
503 ~IManagerDisplayService() = default;
504
505private:
506 void CreateManagedLayer(Kernel::HLERequestContext& ctx) {
507 LOG_WARNING(Service, "(STUBBED) called");
508 IPC::RequestParser rp{ctx};
509 u32 unknown = rp.Pop<u32>();
510 rp.Skip(1, false);
511 u64 display = rp.Pop<u64>();
512 u64 aruid = rp.Pop<u64>();
513
514 IPC::RequestBuilder rb = rp.MakeBuilder(4, 0, 0, 0);
515 rb.Push(RESULT_SUCCESS);
516 rb.Push<u64>(1); // LayerId
517 }
518
519 void AddToLayerStack(Kernel::HLERequestContext& ctx) {
520 LOG_WARNING(Service, "(STUBBED) called");
521 IPC::RequestParser rp{ctx};
522 u32 stack = rp.Pop<u32>();
523 u64 layer_id = rp.Pop<u64>();
524
525 IPC::RequestBuilder rb = rp.MakeBuilder(2, 0, 0, 0);
526 rb.Push(RESULT_SUCCESS);
527 }
528};
529
530void IApplicationDisplayService::GetRelayService(Kernel::HLERequestContext& ctx) {
531 LOG_WARNING(Service, "(STUBBED) called");
532
533 IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
534 rb.Push(RESULT_SUCCESS);
535 rb.PushIpcInterface<IHOSBinderDriver>();
536}
537
538void IApplicationDisplayService::GetSystemDisplayService(Kernel::HLERequestContext& ctx) {
539 LOG_WARNING(Service, "(STUBBED) called");
540
541 IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
542 rb.Push(RESULT_SUCCESS);
543 rb.PushIpcInterface<ISystemDisplayService>();
544}
545
546void IApplicationDisplayService::GetManagerDisplayService(Kernel::HLERequestContext& ctx) {
547 LOG_WARNING(Service, "(STUBBED) called");
548
549 IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
550 rb.Push(RESULT_SUCCESS);
551 rb.PushIpcInterface<IManagerDisplayService>();
552}
553
554void IApplicationDisplayService::OpenDisplay(Kernel::HLERequestContext& ctx) {
555 LOG_WARNING(Service, "(STUBBED) called");
556 IPC::RequestParser rp{ctx};
557 auto data = rp.PopRaw<std::array<u8, 0x40>>();
558 std::string display_name(data.begin(), data.end());
559
560 IPC::RequestBuilder rb = rp.MakeBuilder(4, 0, 0, 0);
561 rb.Push(RESULT_SUCCESS);
562 rb.Push<u64>(9); // DisplayId
563}
564
565void IApplicationDisplayService::OpenLayer(Kernel::HLERequestContext& ctx) {
566 LOG_WARNING(Service, "(STUBBED) called");
567 IPC::RequestParser rp{ctx};
568 auto name_buf = rp.PopRaw<std::array<u8, 0x40>>();
569 u64 layer_id = rp.Pop<u64>();
570 u64 aruid = rp.Pop<u64>();
571
572 std::string display_name(name_buf.begin(), name_buf.end());
573
574 auto& buffer = ctx.BufferDescriptorB()[0];
575
576 NativeWindow native_window{1};
577 auto data = native_window.Serialize();
578 Memory::WriteBlock(buffer.Address(), data.data(), data.size());
579
580 IPC::RequestBuilder rb = rp.MakeBuilder(4, 0, 0, 0);
581 rb.Push(RESULT_SUCCESS);
582 rb.Push<u64>(1280 * 720); // NativeWindowSize
583}
584
585void IApplicationDisplayService::SetLayerScalingMode(Kernel::HLERequestContext& ctx) {
586 LOG_WARNING(Service, "(STUBBED) called");
587 IPC::RequestParser rp{ctx};
588 u32 scaling_mode = rp.Pop<u32>();
589 u64 unknown = rp.Pop<u64>();
590
591 IPC::RequestBuilder rb = rp.MakeBuilder(2, 0, 0, 0);
592 rb.Push(RESULT_SUCCESS);
593}
594
595void IApplicationDisplayService::GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx) {
596 LOG_WARNING(Service, "(STUBBED) called");
597 IPC::RequestParser rp{ctx};
598 u64 display_id = rp.Pop<u64>();
599
600 IPC::RequestBuilder rb = rp.MakeBuilder(2, 1, 0, 0);
601 rb.Push(RESULT_SUCCESS);
602 rb.PushCopyObjects(vsync_event);
603}
604
605IApplicationDisplayService::IApplicationDisplayService()
606 : ServiceFramework("IApplicationDisplayService") {
607 static const FunctionInfo functions[] = {
608 {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"},
609 {101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"},
610 {102, &IApplicationDisplayService::GetManagerDisplayService, "GetManagerDisplayService"},
611 {103, nullptr, "GetIndirectDisplayTransactionService"},
612 {1000, nullptr, "ListDisplays"},
613 {1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"},
614 {2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"},
615 {2020, &IApplicationDisplayService::OpenLayer, "OpenLayer"},
616 {5202, &IApplicationDisplayService::GetDisplayVsyncEvent, "GetDisplayVsyncEvent"},
617 };
618 RegisterHandlers(functions);
619
620 vsync_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "Display VSync Event");
621}
622
623void InstallInterfaces(SM::ServiceManager& service_manager) {
624 std::make_shared<VI_M>()->InstallAsService(service_manager);
625}
626
627} // namespace VI
628} // namespace Service
diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h
new file mode 100644
index 000000000..fbc86498f
--- /dev/null
+++ b/src/core/hle/service/vi/vi.h
@@ -0,0 +1,34 @@
1// Copyright 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/kernel/event.h"
8#include "core/hle/service/service.h"
9
10namespace Service {
11namespace VI {
12
13class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
14public:
15 IApplicationDisplayService();
16 ~IApplicationDisplayService() = default;
17
18private:
19 void GetRelayService(Kernel::HLERequestContext& ctx);
20 void GetSystemDisplayService(Kernel::HLERequestContext& ctx);
21 void GetManagerDisplayService(Kernel::HLERequestContext& ctx);
22 void OpenDisplay(Kernel::HLERequestContext& ctx);
23 void SetLayerScalingMode(Kernel::HLERequestContext& ctx);
24 void OpenLayer(Kernel::HLERequestContext& ctx);
25 void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx);
26
27 Kernel::SharedPtr<Kernel::Event> vsync_event;
28};
29
30/// Registers all VI services with the specified service manager.
31void InstallInterfaces(SM::ServiceManager& service_manager);
32
33} // namespace VI
34} // namespace Service
diff --git a/src/core/hle/service/vi/vi_m.cpp b/src/core/hle/service/vi/vi_m.cpp
new file mode 100644
index 000000000..a883ba572
--- /dev/null
+++ b/src/core/hle/service/vi/vi_m.cpp
@@ -0,0 +1,29 @@
1// Copyright 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/logging/log.h"
6#include "core/hle/ipc_helpers.h"
7#include "core/hle/service/vi/vi.h"
8#include "core/hle/service/vi/vi_m.h"
9
10namespace Service {
11namespace VI {
12
13void VI_M::GetDisplayService(Kernel::HLERequestContext& ctx) {
14 LOG_WARNING(Service, "(STUBBED) called");
15
16 IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
17 rb.PushIpcInterface<IApplicationDisplayService>();
18}
19
20VI_M::VI_M() : ServiceFramework("vi:m") {
21 static const FunctionInfo functions[] = {
22 {2, &VI_M::GetDisplayService, "GetDisplayService"},
23 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
24 };
25 RegisterHandlers(functions);
26}
27
28} // namespace VI
29} // namespace Service
diff --git a/src/core/hle/service/vi/vi_m.h b/src/core/hle/service/vi/vi_m.h
new file mode 100644
index 000000000..bfc8c8121
--- /dev/null
+++ b/src/core/hle/service/vi/vi_m.h
@@ -0,0 +1,23 @@
1// Copyright 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include "core/hle/service/service.h"
9
10namespace Service {
11namespace VI {
12
13class VI_M final : public ServiceFramework<VI_M> {
14public:
15 VI_M();
16 ~VI_M() = default;
17
18private:
19 void GetDisplayService(Kernel::HLERequestContext& ctx);
20};
21
22} // namespace VI
23} // namespace Service