vi.cpp 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <array>
  6. #include <cstring>
  7. #include <memory>
  8. #include <optional>
  9. #include <type_traits>
  10. #include <utility>
  11. #include "common/alignment.h"
  12. #include "common/assert.h"
  13. #include "common/common_funcs.h"
  14. #include "common/logging/log.h"
  15. #include "common/math_util.h"
  16. #include "common/swap.h"
  17. #include "core/core_timing.h"
  18. #include "core/hle/ipc_helpers.h"
  19. #include "core/hle/kernel/readable_event.h"
  20. #include "core/hle/kernel/thread.h"
  21. #include "core/hle/kernel/writable_event.h"
  22. #include "core/hle/service/nvdrv/nvdata.h"
  23. #include "core/hle/service/nvdrv/nvdrv.h"
  24. #include "core/hle/service/nvflinger/buffer_queue.h"
  25. #include "core/hle/service/nvflinger/nvflinger.h"
  26. #include "core/hle/service/service.h"
  27. #include "core/hle/service/vi/vi.h"
  28. #include "core/hle/service/vi/vi_m.h"
  29. #include "core/hle/service/vi/vi_s.h"
  30. #include "core/hle/service/vi/vi_u.h"
  31. #include "core/settings.h"
  32. namespace Service::VI {
  33. constexpr ResultCode ERR_OPERATION_FAILED{ErrorModule::VI, 1};
  34. constexpr ResultCode ERR_PERMISSION_DENIED{ErrorModule::VI, 5};
  35. constexpr ResultCode ERR_UNSUPPORTED{ErrorModule::VI, 6};
  36. constexpr ResultCode ERR_NOT_FOUND{ErrorModule::VI, 7};
  37. struct DisplayInfo {
  38. /// The name of this particular display.
  39. char display_name[0x40]{"Default"};
  40. /// Whether or not the display has a limited number of layers.
  41. u8 has_limited_layers{1};
  42. INSERT_PADDING_BYTES(7);
  43. /// Indicates the total amount of layers supported by the display.
  44. /// @note This is only valid if has_limited_layers is set.
  45. u64 max_layers{1};
  46. /// Maximum width in pixels.
  47. u64 width{1920};
  48. /// Maximum height in pixels.
  49. u64 height{1080};
  50. };
  51. static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size");
  52. class Parcel {
  53. public:
  54. // This default size was chosen arbitrarily.
  55. static constexpr std::size_t DefaultBufferSize = 0x40;
  56. Parcel() : buffer(DefaultBufferSize) {}
  57. explicit Parcel(std::vector<u8> data) : buffer(std::move(data)) {}
  58. virtual ~Parcel() = default;
  59. template <typename T>
  60. T Read() {
  61. static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
  62. ASSERT(read_index + sizeof(T) <= buffer.size());
  63. T val;
  64. std::memcpy(&val, buffer.data() + read_index, sizeof(T));
  65. read_index += sizeof(T);
  66. read_index = Common::AlignUp(read_index, 4);
  67. return val;
  68. }
  69. template <typename T>
  70. T ReadUnaligned() {
  71. static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
  72. ASSERT(read_index + sizeof(T) <= buffer.size());
  73. T val;
  74. std::memcpy(&val, buffer.data() + read_index, sizeof(T));
  75. read_index += sizeof(T);
  76. return val;
  77. }
  78. std::vector<u8> ReadBlock(std::size_t length) {
  79. ASSERT(read_index + length <= buffer.size());
  80. const u8* const begin = buffer.data() + read_index;
  81. const u8* const end = begin + length;
  82. std::vector<u8> data(begin, end);
  83. read_index += length;
  84. read_index = Common::AlignUp(read_index, 4);
  85. return data;
  86. }
  87. std::u16string ReadInterfaceToken() {
  88. [[maybe_unused]] const u32 unknown = Read<u32_le>();
  89. const u32 length = Read<u32_le>();
  90. std::u16string token{};
  91. for (u32 ch = 0; ch < length + 1; ++ch) {
  92. token.push_back(ReadUnaligned<u16_le>());
  93. }
  94. read_index = Common::AlignUp(read_index, 4);
  95. return token;
  96. }
  97. template <typename T>
  98. void Write(const T& val) {
  99. static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
  100. if (buffer.size() < write_index + sizeof(T)) {
  101. buffer.resize(buffer.size() + sizeof(T) + DefaultBufferSize);
  102. }
  103. std::memcpy(buffer.data() + write_index, &val, sizeof(T));
  104. write_index += sizeof(T);
  105. write_index = Common::AlignUp(write_index, 4);
  106. }
  107. template <typename T>
  108. void WriteObject(const T& val) {
  109. static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
  110. const u32_le size = static_cast<u32>(sizeof(val));
  111. Write(size);
  112. // TODO(Subv): Support file descriptors.
  113. Write<u32_le>(0); // Fd count.
  114. Write(val);
  115. }
  116. void Deserialize() {
  117. ASSERT(buffer.size() > sizeof(Header));
  118. Header header{};
  119. std::memcpy(&header, buffer.data(), sizeof(Header));
  120. read_index = header.data_offset;
  121. DeserializeData();
  122. }
  123. std::vector<u8> Serialize() {
  124. ASSERT(read_index == 0);
  125. write_index = sizeof(Header);
  126. SerializeData();
  127. Header header{};
  128. header.data_size = static_cast<u32_le>(write_index - sizeof(Header));
  129. header.data_offset = sizeof(Header);
  130. header.objects_size = 4;
  131. header.objects_offset = sizeof(Header) + header.data_size;
  132. std::memcpy(buffer.data(), &header, sizeof(Header));
  133. return buffer;
  134. }
  135. protected:
  136. virtual void SerializeData() {}
  137. virtual void DeserializeData() {}
  138. private:
  139. struct Header {
  140. u32_le data_size;
  141. u32_le data_offset;
  142. u32_le objects_size;
  143. u32_le objects_offset;
  144. };
  145. static_assert(sizeof(Header) == 16, "ParcelHeader has wrong size");
  146. std::vector<u8> buffer;
  147. std::size_t read_index = 0;
  148. std::size_t write_index = 0;
  149. };
  150. class NativeWindow : public Parcel {
  151. public:
  152. explicit NativeWindow(u32 id) {
  153. data.id = id;
  154. }
  155. ~NativeWindow() override = default;
  156. protected:
  157. void SerializeData() override {
  158. Write(data);
  159. }
  160. private:
  161. struct Data {
  162. u32_le magic = 2;
  163. u32_le process_id = 1;
  164. u32_le id;
  165. INSERT_PADDING_WORDS(3);
  166. std::array<u8, 8> dispdrv = {'d', 'i', 's', 'p', 'd', 'r', 'v', '\0'};
  167. INSERT_PADDING_WORDS(2);
  168. };
  169. static_assert(sizeof(Data) == 0x28, "ParcelData has wrong size");
  170. Data data{};
  171. };
  172. class IGBPConnectRequestParcel : public Parcel {
  173. public:
  174. explicit IGBPConnectRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
  175. Deserialize();
  176. }
  177. ~IGBPConnectRequestParcel() override = default;
  178. void DeserializeData() override {
  179. std::u16string token = ReadInterfaceToken();
  180. data = Read<Data>();
  181. }
  182. struct Data {
  183. u32_le unk;
  184. u32_le api;
  185. u32_le producer_controlled_by_app;
  186. };
  187. Data data;
  188. };
  189. class IGBPConnectResponseParcel : public Parcel {
  190. public:
  191. explicit IGBPConnectResponseParcel(u32 width, u32 height) {
  192. data.width = width;
  193. data.height = height;
  194. }
  195. ~IGBPConnectResponseParcel() override = default;
  196. protected:
  197. void SerializeData() override {
  198. Write(data);
  199. }
  200. private:
  201. struct Data {
  202. u32_le width;
  203. u32_le height;
  204. u32_le transform_hint;
  205. u32_le num_pending_buffers;
  206. u32_le status;
  207. };
  208. static_assert(sizeof(Data) == 20, "ParcelData has wrong size");
  209. Data data{};
  210. };
  211. /// Represents a parcel containing one int '0' as its data
  212. /// Used by DetachBuffer and Disconnect
  213. class IGBPEmptyResponseParcel : public Parcel {
  214. protected:
  215. void SerializeData() override {
  216. Write(data);
  217. }
  218. private:
  219. struct Data {
  220. u32_le unk_0{};
  221. };
  222. Data data{};
  223. };
  224. class IGBPSetPreallocatedBufferRequestParcel : public Parcel {
  225. public:
  226. explicit IGBPSetPreallocatedBufferRequestParcel(std::vector<u8> buffer)
  227. : Parcel(std::move(buffer)) {
  228. Deserialize();
  229. }
  230. ~IGBPSetPreallocatedBufferRequestParcel() override = default;
  231. void DeserializeData() override {
  232. std::u16string token = ReadInterfaceToken();
  233. data = Read<Data>();
  234. buffer = Read<NVFlinger::IGBPBuffer>();
  235. }
  236. struct Data {
  237. u32_le slot;
  238. INSERT_PADDING_WORDS(1);
  239. u32_le graphic_buffer_length;
  240. INSERT_PADDING_WORDS(1);
  241. };
  242. Data data;
  243. NVFlinger::IGBPBuffer buffer;
  244. };
  245. class IGBPSetPreallocatedBufferResponseParcel : public Parcel {
  246. protected:
  247. void SerializeData() override {
  248. // TODO(Subv): Find out what this means
  249. Write<u32>(0);
  250. }
  251. };
  252. class IGBPDequeueBufferRequestParcel : public Parcel {
  253. public:
  254. explicit IGBPDequeueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
  255. Deserialize();
  256. }
  257. ~IGBPDequeueBufferRequestParcel() override = default;
  258. void DeserializeData() override {
  259. std::u16string token = ReadInterfaceToken();
  260. data = Read<Data>();
  261. }
  262. struct Data {
  263. u32_le pixel_format;
  264. u32_le width;
  265. u32_le height;
  266. u32_le get_frame_timestamps;
  267. u32_le usage;
  268. };
  269. Data data;
  270. };
  271. class IGBPDequeueBufferResponseParcel : public Parcel {
  272. public:
  273. explicit IGBPDequeueBufferResponseParcel(u32 slot, Service::Nvidia::MultiFence& multi_fence)
  274. : slot(slot), multi_fence(multi_fence) {}
  275. ~IGBPDequeueBufferResponseParcel() override = default;
  276. protected:
  277. void SerializeData() override {
  278. Write(slot);
  279. Write<u32_le>(1);
  280. WriteObject(multi_fence);
  281. Write<u32_le>(0);
  282. }
  283. u32_le slot;
  284. Service::Nvidia::MultiFence multi_fence;
  285. };
  286. class IGBPRequestBufferRequestParcel : public Parcel {
  287. public:
  288. explicit IGBPRequestBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
  289. Deserialize();
  290. }
  291. ~IGBPRequestBufferRequestParcel() override = default;
  292. void DeserializeData() override {
  293. std::u16string token = ReadInterfaceToken();
  294. slot = Read<u32_le>();
  295. }
  296. u32_le slot;
  297. };
  298. class IGBPRequestBufferResponseParcel : public Parcel {
  299. public:
  300. explicit IGBPRequestBufferResponseParcel(NVFlinger::IGBPBuffer buffer) : buffer(buffer) {}
  301. ~IGBPRequestBufferResponseParcel() override = default;
  302. protected:
  303. void SerializeData() override {
  304. // TODO(Subv): Figure out what this value means, writing non-zero here will make libnx
  305. // try to read an IGBPBuffer object from the parcel.
  306. Write<u32_le>(1);
  307. WriteObject(buffer);
  308. Write<u32_le>(0);
  309. }
  310. NVFlinger::IGBPBuffer buffer;
  311. };
  312. class IGBPQueueBufferRequestParcel : public Parcel {
  313. public:
  314. explicit IGBPQueueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
  315. Deserialize();
  316. }
  317. ~IGBPQueueBufferRequestParcel() override = default;
  318. void DeserializeData() override {
  319. std::u16string token = ReadInterfaceToken();
  320. data = Read<Data>();
  321. }
  322. struct Data {
  323. u32_le slot;
  324. INSERT_PADDING_WORDS(3);
  325. u32_le timestamp;
  326. s32_le is_auto_timestamp;
  327. s32_le crop_top;
  328. s32_le crop_left;
  329. s32_le crop_right;
  330. s32_le crop_bottom;
  331. s32_le scaling_mode;
  332. NVFlinger::BufferQueue::BufferTransformFlags transform;
  333. u32_le sticky_transform;
  334. INSERT_PADDING_WORDS(1);
  335. u32_le swap_interval;
  336. Service::Nvidia::MultiFence multi_fence;
  337. Common::Rectangle<int> GetCropRect() const {
  338. return {crop_left, crop_top, crop_right, crop_bottom};
  339. }
  340. };
  341. static_assert(sizeof(Data) == 96, "ParcelData has wrong size");
  342. Data data;
  343. };
  344. class IGBPQueueBufferResponseParcel : public Parcel {
  345. public:
  346. explicit IGBPQueueBufferResponseParcel(u32 width, u32 height) {
  347. data.width = width;
  348. data.height = height;
  349. }
  350. ~IGBPQueueBufferResponseParcel() override = default;
  351. protected:
  352. void SerializeData() override {
  353. Write(data);
  354. }
  355. private:
  356. struct Data {
  357. u32_le width;
  358. u32_le height;
  359. u32_le transform_hint;
  360. u32_le num_pending_buffers;
  361. u32_le status;
  362. };
  363. static_assert(sizeof(Data) == 20, "ParcelData has wrong size");
  364. Data data{};
  365. };
  366. class IGBPQueryRequestParcel : public Parcel {
  367. public:
  368. explicit IGBPQueryRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
  369. Deserialize();
  370. }
  371. ~IGBPQueryRequestParcel() override = default;
  372. void DeserializeData() override {
  373. std::u16string token = ReadInterfaceToken();
  374. type = Read<u32_le>();
  375. }
  376. u32 type;
  377. };
  378. class IGBPQueryResponseParcel : public Parcel {
  379. public:
  380. explicit IGBPQueryResponseParcel(u32 value) : value(value) {}
  381. ~IGBPQueryResponseParcel() override = default;
  382. protected:
  383. void SerializeData() override {
  384. Write(value);
  385. }
  386. private:
  387. u32_le value;
  388. };
  389. class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
  390. public:
  391. explicit IHOSBinderDriver(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
  392. : ServiceFramework("IHOSBinderDriver"), nv_flinger(std::move(nv_flinger)) {
  393. static const FunctionInfo functions[] = {
  394. {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"},
  395. {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"},
  396. {2, &IHOSBinderDriver::GetNativeHandle, "GetNativeHandle"},
  397. {3, &IHOSBinderDriver::TransactParcel, "TransactParcelAuto"},
  398. };
  399. RegisterHandlers(functions);
  400. }
  401. private:
  402. enum class TransactionId {
  403. RequestBuffer = 1,
  404. SetBufferCount = 2,
  405. DequeueBuffer = 3,
  406. DetachBuffer = 4,
  407. DetachNextBuffer = 5,
  408. AttachBuffer = 6,
  409. QueueBuffer = 7,
  410. CancelBuffer = 8,
  411. Query = 9,
  412. Connect = 10,
  413. Disconnect = 11,
  414. AllocateBuffers = 13,
  415. SetPreallocatedBuffer = 14
  416. };
  417. void TransactParcel(Kernel::HLERequestContext& ctx) {
  418. IPC::RequestParser rp{ctx};
  419. const u32 id = rp.Pop<u32>();
  420. const auto transaction = static_cast<TransactionId>(rp.Pop<u32>());
  421. const u32 flags = rp.Pop<u32>();
  422. LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id,
  423. static_cast<u32>(transaction), flags);
  424. auto& buffer_queue = nv_flinger->FindBufferQueue(id);
  425. switch (transaction) {
  426. case TransactionId::Connect: {
  427. IGBPConnectRequestParcel request{ctx.ReadBuffer()};
  428. IGBPConnectResponseParcel response{
  429. static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedWidth) *
  430. Settings::values.resolution_factor),
  431. static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedHeight) *
  432. Settings::values.resolution_factor)};
  433. ctx.WriteBuffer(response.Serialize());
  434. break;
  435. }
  436. case TransactionId::SetPreallocatedBuffer: {
  437. IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()};
  438. buffer_queue.SetPreallocatedBuffer(request.data.slot, request.buffer);
  439. IGBPSetPreallocatedBufferResponseParcel response{};
  440. ctx.WriteBuffer(response.Serialize());
  441. break;
  442. }
  443. case TransactionId::DequeueBuffer: {
  444. IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()};
  445. const u32 width{request.data.width};
  446. const u32 height{request.data.height};
  447. auto result = buffer_queue.DequeueBuffer(width, height);
  448. if (result) {
  449. // Buffer is available
  450. IGBPDequeueBufferResponseParcel response{result->first, *result->second};
  451. ctx.WriteBuffer(response.Serialize());
  452. } else {
  453. // Wait the current thread until a buffer becomes available
  454. ctx.SleepClientThread(
  455. "IHOSBinderDriver::DequeueBuffer", UINT64_MAX,
  456. [=](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx,
  457. Kernel::ThreadWakeupReason reason) {
  458. // Repeat TransactParcel DequeueBuffer when a buffer is available
  459. auto& buffer_queue = nv_flinger->FindBufferQueue(id);
  460. auto result = buffer_queue.DequeueBuffer(width, height);
  461. ASSERT_MSG(result != std::nullopt, "Could not dequeue buffer.");
  462. IGBPDequeueBufferResponseParcel response{result->first, *result->second};
  463. ctx.WriteBuffer(response.Serialize());
  464. IPC::ResponseBuilder rb{ctx, 2};
  465. rb.Push(RESULT_SUCCESS);
  466. },
  467. buffer_queue.GetWritableBufferWaitEvent());
  468. }
  469. break;
  470. }
  471. case TransactionId::RequestBuffer: {
  472. IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()};
  473. auto& buffer = buffer_queue.RequestBuffer(request.slot);
  474. IGBPRequestBufferResponseParcel response{buffer};
  475. ctx.WriteBuffer(response.Serialize());
  476. break;
  477. }
  478. case TransactionId::QueueBuffer: {
  479. IGBPQueueBufferRequestParcel request{ctx.ReadBuffer()};
  480. buffer_queue.QueueBuffer(request.data.slot, request.data.transform,
  481. request.data.GetCropRect(), request.data.swap_interval,
  482. request.data.multi_fence);
  483. IGBPQueueBufferResponseParcel response{1280, 720};
  484. ctx.WriteBuffer(response.Serialize());
  485. break;
  486. }
  487. case TransactionId::Query: {
  488. IGBPQueryRequestParcel request{ctx.ReadBuffer()};
  489. const u32 value =
  490. buffer_queue.Query(static_cast<NVFlinger::BufferQueue::QueryType>(request.type));
  491. IGBPQueryResponseParcel response{value};
  492. ctx.WriteBuffer(response.Serialize());
  493. break;
  494. }
  495. case TransactionId::CancelBuffer: {
  496. LOG_CRITICAL(Service_VI, "(STUBBED) called, transaction=CancelBuffer");
  497. break;
  498. }
  499. case TransactionId::Disconnect: {
  500. LOG_WARNING(Service_VI, "(STUBBED) called, transaction=Disconnect");
  501. const auto buffer = ctx.ReadBuffer();
  502. buffer_queue.Disconnect();
  503. IGBPEmptyResponseParcel response{};
  504. ctx.WriteBuffer(response.Serialize());
  505. break;
  506. }
  507. case TransactionId::DetachBuffer: {
  508. const auto buffer = ctx.ReadBuffer();
  509. IGBPEmptyResponseParcel response{};
  510. ctx.WriteBuffer(response.Serialize());
  511. break;
  512. }
  513. case TransactionId::SetBufferCount: {
  514. LOG_WARNING(Service_VI, "(STUBBED) called, transaction=SetBufferCount");
  515. [[maybe_unused]] const auto buffer = ctx.ReadBuffer();
  516. IGBPEmptyResponseParcel response{};
  517. ctx.WriteBuffer(response.Serialize());
  518. break;
  519. }
  520. default:
  521. ASSERT_MSG(false, "Unimplemented");
  522. }
  523. IPC::ResponseBuilder rb{ctx, 2};
  524. rb.Push(RESULT_SUCCESS);
  525. }
  526. void AdjustRefcount(Kernel::HLERequestContext& ctx) {
  527. IPC::RequestParser rp{ctx};
  528. const u32 id = rp.Pop<u32>();
  529. const s32 addval = rp.PopRaw<s32>();
  530. const u32 type = rp.Pop<u32>();
  531. LOG_WARNING(Service_VI, "(STUBBED) called id={}, addval={:08X}, type={:08X}", id, addval,
  532. type);
  533. IPC::ResponseBuilder rb{ctx, 2};
  534. rb.Push(RESULT_SUCCESS);
  535. }
  536. void GetNativeHandle(Kernel::HLERequestContext& ctx) {
  537. IPC::RequestParser rp{ctx};
  538. const u32 id = rp.Pop<u32>();
  539. const u32 unknown = rp.Pop<u32>();
  540. LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
  541. const auto& buffer_queue = nv_flinger->FindBufferQueue(id);
  542. // TODO(Subv): Find out what this actually is.
  543. IPC::ResponseBuilder rb{ctx, 2, 1};
  544. rb.Push(RESULT_SUCCESS);
  545. rb.PushCopyObjects(buffer_queue.GetBufferWaitEvent());
  546. }
  547. std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;
  548. }; // namespace VI
  549. class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
  550. public:
  551. explicit ISystemDisplayService() : ServiceFramework("ISystemDisplayService") {
  552. static const FunctionInfo functions[] = {
  553. {1200, nullptr, "GetZOrderCountMin"},
  554. {1202, nullptr, "GetZOrderCountMax"},
  555. {1203, nullptr, "GetDisplayLogicalResolution"},
  556. {1204, nullptr, "SetDisplayMagnification"},
  557. {2201, nullptr, "SetLayerPosition"},
  558. {2203, nullptr, "SetLayerSize"},
  559. {2204, nullptr, "GetLayerZ"},
  560. {2205, &ISystemDisplayService::SetLayerZ, "SetLayerZ"},
  561. {2207, &ISystemDisplayService::SetLayerVisibility, "SetLayerVisibility"},
  562. {2209, nullptr, "SetLayerAlpha"},
  563. {2312, nullptr, "CreateStrayLayer"},
  564. {2400, nullptr, "OpenIndirectLayer"},
  565. {2401, nullptr, "CloseIndirectLayer"},
  566. {2402, nullptr, "FlipIndirectLayer"},
  567. {3000, nullptr, "ListDisplayModes"},
  568. {3001, nullptr, "ListDisplayRgbRanges"},
  569. {3002, nullptr, "ListDisplayContentTypes"},
  570. {3200, &ISystemDisplayService::GetDisplayMode, "GetDisplayMode"},
  571. {3201, nullptr, "SetDisplayMode"},
  572. {3202, nullptr, "GetDisplayUnderscan"},
  573. {3203, nullptr, "SetDisplayUnderscan"},
  574. {3204, nullptr, "GetDisplayContentType"},
  575. {3205, nullptr, "SetDisplayContentType"},
  576. {3206, nullptr, "GetDisplayRgbRange"},
  577. {3207, nullptr, "SetDisplayRgbRange"},
  578. {3208, nullptr, "GetDisplayCmuMode"},
  579. {3209, nullptr, "SetDisplayCmuMode"},
  580. {3210, nullptr, "GetDisplayContrastRatio"},
  581. {3211, nullptr, "SetDisplayContrastRatio"},
  582. {3214, nullptr, "GetDisplayGamma"},
  583. {3215, nullptr, "SetDisplayGamma"},
  584. {3216, nullptr, "GetDisplayCmuLuma"},
  585. {3217, nullptr, "SetDisplayCmuLuma"},
  586. {8225, nullptr, "GetSharedBufferMemoryHandleId"},
  587. {8250, nullptr, "OpenSharedLayer"},
  588. {8251, nullptr, "CloseSharedLayer"},
  589. {8252, nullptr, "ConnectSharedLayer"},
  590. {8253, nullptr, "DisconnectSharedLayer"},
  591. {8254, nullptr, "AcquireSharedFrameBuffer"},
  592. {8255, nullptr, "PresentSharedFrameBuffer"},
  593. {8256, nullptr, "GetSharedFrameBufferAcquirableEvent"},
  594. {8257, nullptr, "FillSharedFrameBufferColor"},
  595. {8258, nullptr, "CancelSharedFrameBuffer"},
  596. };
  597. RegisterHandlers(functions);
  598. }
  599. private:
  600. void SetLayerZ(Kernel::HLERequestContext& ctx) {
  601. IPC::RequestParser rp{ctx};
  602. const u64 layer_id = rp.Pop<u64>();
  603. const u64 z_value = rp.Pop<u64>();
  604. LOG_WARNING(Service_VI, "(STUBBED) called. layer_id=0x{:016X}, z_value=0x{:016X}", layer_id,
  605. z_value);
  606. IPC::ResponseBuilder rb{ctx, 2};
  607. rb.Push(RESULT_SUCCESS);
  608. }
  609. // This function currently does nothing but return a success error code in
  610. // the vi library itself, so do the same thing, but log out the passed in values.
  611. void SetLayerVisibility(Kernel::HLERequestContext& ctx) {
  612. IPC::RequestParser rp{ctx};
  613. const u64 layer_id = rp.Pop<u64>();
  614. const bool visibility = rp.Pop<bool>();
  615. LOG_DEBUG(Service_VI, "called, layer_id=0x{:08X}, visibility={}", layer_id, visibility);
  616. IPC::ResponseBuilder rb{ctx, 2};
  617. rb.Push(RESULT_SUCCESS);
  618. }
  619. void GetDisplayMode(Kernel::HLERequestContext& ctx) {
  620. LOG_WARNING(Service_VI, "(STUBBED) called");
  621. IPC::ResponseBuilder rb{ctx, 6};
  622. rb.Push(RESULT_SUCCESS);
  623. if (Settings::values.use_docked_mode) {
  624. rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
  625. static_cast<u32>(Settings::values.resolution_factor));
  626. rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
  627. static_cast<u32>(Settings::values.resolution_factor));
  628. } else {
  629. rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) *
  630. static_cast<u32>(Settings::values.resolution_factor));
  631. rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) *
  632. static_cast<u32>(Settings::values.resolution_factor));
  633. }
  634. rb.PushRaw<float>(60.0f); // This wouldn't seem to be correct for 30 fps games.
  635. rb.Push<u32>(0);
  636. }
  637. };
  638. class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
  639. public:
  640. explicit IManagerDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
  641. : ServiceFramework("IManagerDisplayService"), nv_flinger(std::move(nv_flinger)) {
  642. // clang-format off
  643. static const FunctionInfo functions[] = {
  644. {200, nullptr, "AllocateProcessHeapBlock"},
  645. {201, nullptr, "FreeProcessHeapBlock"},
  646. {1020, &IManagerDisplayService::CloseDisplay, "CloseDisplay"},
  647. {1102, nullptr, "GetDisplayResolution"},
  648. {2010, &IManagerDisplayService::CreateManagedLayer, "CreateManagedLayer"},
  649. {2011, nullptr, "DestroyManagedLayer"},
  650. {2012, nullptr, "CreateStrayLayer"},
  651. {2050, nullptr, "CreateIndirectLayer"},
  652. {2051, nullptr, "DestroyIndirectLayer"},
  653. {2052, nullptr, "CreateIndirectProducerEndPoint"},
  654. {2053, nullptr, "DestroyIndirectProducerEndPoint"},
  655. {2054, nullptr, "CreateIndirectConsumerEndPoint"},
  656. {2055, nullptr, "DestroyIndirectConsumerEndPoint"},
  657. {2300, nullptr, "AcquireLayerTexturePresentingEvent"},
  658. {2301, nullptr, "ReleaseLayerTexturePresentingEvent"},
  659. {2302, nullptr, "GetDisplayHotplugEvent"},
  660. {2402, nullptr, "GetDisplayHotplugState"},
  661. {2501, nullptr, "GetCompositorErrorInfo"},
  662. {2601, nullptr, "GetDisplayErrorEvent"},
  663. {4201, nullptr, "SetDisplayAlpha"},
  664. {4203, nullptr, "SetDisplayLayerStack"},
  665. {4205, nullptr, "SetDisplayPowerState"},
  666. {4206, nullptr, "SetDefaultDisplay"},
  667. {6000, &IManagerDisplayService::AddToLayerStack, "AddToLayerStack"},
  668. {6001, nullptr, "RemoveFromLayerStack"},
  669. {6002, &IManagerDisplayService::SetLayerVisibility, "SetLayerVisibility"},
  670. {6003, nullptr, "SetLayerConfig"},
  671. {6004, nullptr, "AttachLayerPresentationTracer"},
  672. {6005, nullptr, "DetachLayerPresentationTracer"},
  673. {6006, nullptr, "StartLayerPresentationRecording"},
  674. {6007, nullptr, "StopLayerPresentationRecording"},
  675. {6008, nullptr, "StartLayerPresentationFenceWait"},
  676. {6009, nullptr, "StopLayerPresentationFenceWait"},
  677. {6010, nullptr, "GetLayerPresentationAllFencesExpiredEvent"},
  678. {6011, nullptr, "EnableLayerAutoClearTransitionBuffer"},
  679. {6012, nullptr, "DisableLayerAutoClearTransitionBuffer"},
  680. {7000, nullptr, "SetContentVisibility"},
  681. {8000, nullptr, "SetConductorLayer"},
  682. {8001, nullptr, "SetTimestampTracking"},
  683. {8100, nullptr, "SetIndirectProducerFlipOffset"},
  684. {8200, nullptr, "CreateSharedBufferStaticStorage"},
  685. {8201, nullptr, "CreateSharedBufferTransferMemory"},
  686. {8202, nullptr, "DestroySharedBuffer"},
  687. {8203, nullptr, "BindSharedLowLevelLayerToManagedLayer"},
  688. {8204, nullptr, "BindSharedLowLevelLayerToIndirectLayer"},
  689. {8207, nullptr, "UnbindSharedLowLevelLayer"},
  690. {8208, nullptr, "ConnectSharedLowLevelLayerToSharedBuffer"},
  691. {8209, nullptr, "DisconnectSharedLowLevelLayerFromSharedBuffer"},
  692. {8210, nullptr, "CreateSharedLayer"},
  693. {8211, nullptr, "DestroySharedLayer"},
  694. {8216, nullptr, "AttachSharedLayerToLowLevelLayer"},
  695. {8217, nullptr, "ForceDetachSharedLayerFromLowLevelLayer"},
  696. {8218, nullptr, "StartDetachSharedLayerFromLowLevelLayer"},
  697. {8219, nullptr, "FinishDetachSharedLayerFromLowLevelLayer"},
  698. {8220, nullptr, "GetSharedLayerDetachReadyEvent"},
  699. {8221, nullptr, "GetSharedLowLevelLayerSynchronizedEvent"},
  700. {8222, nullptr, "CheckSharedLowLevelLayerSynchronized"},
  701. {8223, nullptr, "RegisterSharedBufferImporterAruid"},
  702. {8224, nullptr, "UnregisterSharedBufferImporterAruid"},
  703. {8227, nullptr, "CreateSharedBufferProcessHeap"},
  704. {8228, nullptr, "GetSharedLayerLayerStacks"},
  705. {8229, nullptr, "SetSharedLayerLayerStacks"},
  706. {8291, nullptr, "PresentDetachedSharedFrameBufferToLowLevelLayer"},
  707. {8292, nullptr, "FillDetachedSharedFrameBufferColor"},
  708. {8293, nullptr, "GetDetachedSharedFrameBufferImage"},
  709. {8294, nullptr, "SetDetachedSharedFrameBufferImage"},
  710. {8295, nullptr, "CopyDetachedSharedFrameBufferImage"},
  711. {8296, nullptr, "SetDetachedSharedFrameBufferSubImage"},
  712. {8297, nullptr, "GetSharedFrameBufferContentParameter"},
  713. {8298, nullptr, "ExpandStartupLogoOnSharedFrameBuffer"},
  714. };
  715. // clang-format on
  716. RegisterHandlers(functions);
  717. }
  718. private:
  719. void CloseDisplay(Kernel::HLERequestContext& ctx) {
  720. IPC::RequestParser rp{ctx};
  721. const u64 display = rp.Pop<u64>();
  722. LOG_WARNING(Service_VI, "(STUBBED) called. display=0x{:016X}", display);
  723. IPC::ResponseBuilder rb{ctx, 2};
  724. rb.Push(RESULT_SUCCESS);
  725. }
  726. void CreateManagedLayer(Kernel::HLERequestContext& ctx) {
  727. IPC::RequestParser rp{ctx};
  728. const u32 unknown = rp.Pop<u32>();
  729. rp.Skip(1, false);
  730. const u64 display = rp.Pop<u64>();
  731. const u64 aruid = rp.Pop<u64>();
  732. LOG_WARNING(Service_VI,
  733. "(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}",
  734. unknown, display, aruid);
  735. const auto layer_id = nv_flinger->CreateLayer(display);
  736. if (!layer_id) {
  737. IPC::ResponseBuilder rb{ctx, 2};
  738. rb.Push(ERR_NOT_FOUND);
  739. return;
  740. }
  741. IPC::ResponseBuilder rb{ctx, 4};
  742. rb.Push(RESULT_SUCCESS);
  743. rb.Push(*layer_id);
  744. }
  745. void AddToLayerStack(Kernel::HLERequestContext& ctx) {
  746. IPC::RequestParser rp{ctx};
  747. const u32 stack = rp.Pop<u32>();
  748. const u64 layer_id = rp.Pop<u64>();
  749. LOG_WARNING(Service_VI, "(STUBBED) called. stack=0x{:08X}, layer_id=0x{:016X}", stack,
  750. layer_id);
  751. IPC::ResponseBuilder rb{ctx, 2};
  752. rb.Push(RESULT_SUCCESS);
  753. }
  754. void SetLayerVisibility(Kernel::HLERequestContext& ctx) {
  755. IPC::RequestParser rp{ctx};
  756. const u64 layer_id = rp.Pop<u64>();
  757. const bool visibility = rp.Pop<bool>();
  758. LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id,
  759. visibility);
  760. IPC::ResponseBuilder rb{ctx, 2};
  761. rb.Push(RESULT_SUCCESS);
  762. }
  763. std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;
  764. };
  765. class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
  766. public:
  767. explicit IApplicationDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger);
  768. private:
  769. enum class ConvertedScaleMode : u64 {
  770. Freeze = 0,
  771. ScaleToWindow = 1,
  772. ScaleAndCrop = 2,
  773. None = 3,
  774. PreserveAspectRatio = 4,
  775. };
  776. enum class NintendoScaleMode : u32 {
  777. None = 0,
  778. Freeze = 1,
  779. ScaleToWindow = 2,
  780. ScaleAndCrop = 3,
  781. PreserveAspectRatio = 4,
  782. };
  783. void GetRelayService(Kernel::HLERequestContext& ctx) {
  784. LOG_WARNING(Service_VI, "(STUBBED) called");
  785. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  786. rb.Push(RESULT_SUCCESS);
  787. rb.PushIpcInterface<IHOSBinderDriver>(nv_flinger);
  788. }
  789. void GetSystemDisplayService(Kernel::HLERequestContext& ctx) {
  790. LOG_WARNING(Service_VI, "(STUBBED) called");
  791. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  792. rb.Push(RESULT_SUCCESS);
  793. rb.PushIpcInterface<ISystemDisplayService>();
  794. }
  795. void GetManagerDisplayService(Kernel::HLERequestContext& ctx) {
  796. LOG_WARNING(Service_VI, "(STUBBED) called");
  797. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  798. rb.Push(RESULT_SUCCESS);
  799. rb.PushIpcInterface<IManagerDisplayService>(nv_flinger);
  800. }
  801. void GetIndirectDisplayTransactionService(Kernel::HLERequestContext& ctx) {
  802. LOG_WARNING(Service_VI, "(STUBBED) called");
  803. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  804. rb.Push(RESULT_SUCCESS);
  805. rb.PushIpcInterface<IHOSBinderDriver>(nv_flinger);
  806. }
  807. void OpenDisplay(Kernel::HLERequestContext& ctx) {
  808. LOG_WARNING(Service_VI, "(STUBBED) called");
  809. IPC::RequestParser rp{ctx};
  810. const auto name_buf = rp.PopRaw<std::array<char, 0x40>>();
  811. OpenDisplayImpl(ctx, std::string_view{name_buf.data(), name_buf.size()});
  812. }
  813. void OpenDefaultDisplay(Kernel::HLERequestContext& ctx) {
  814. LOG_DEBUG(Service_VI, "called");
  815. OpenDisplayImpl(ctx, "Default");
  816. }
  817. void OpenDisplayImpl(Kernel::HLERequestContext& ctx, std::string_view name) {
  818. const auto trim_pos = name.find('\0');
  819. if (trim_pos != std::string_view::npos) {
  820. name.remove_suffix(name.size() - trim_pos);
  821. }
  822. ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet");
  823. const auto display_id = nv_flinger->OpenDisplay(name);
  824. if (!display_id) {
  825. IPC::ResponseBuilder rb{ctx, 2};
  826. rb.Push(ERR_NOT_FOUND);
  827. return;
  828. }
  829. IPC::ResponseBuilder rb{ctx, 4};
  830. rb.Push(RESULT_SUCCESS);
  831. rb.Push<u64>(*display_id);
  832. }
  833. void CloseDisplay(Kernel::HLERequestContext& ctx) {
  834. IPC::RequestParser rp{ctx};
  835. const u64 display_id = rp.Pop<u64>();
  836. LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id);
  837. IPC::ResponseBuilder rb{ctx, 2};
  838. rb.Push(RESULT_SUCCESS);
  839. }
  840. // This literally does nothing internally in the actual service itself,
  841. // and just returns a successful result code regardless of the input.
  842. void SetDisplayEnabled(Kernel::HLERequestContext& ctx) {
  843. LOG_DEBUG(Service_VI, "called.");
  844. IPC::ResponseBuilder rb{ctx, 2};
  845. rb.Push(RESULT_SUCCESS);
  846. }
  847. void GetDisplayResolution(Kernel::HLERequestContext& ctx) {
  848. IPC::RequestParser rp{ctx};
  849. const u64 display_id = rp.Pop<u64>();
  850. LOG_DEBUG(Service_VI, "called. display_id=0x{:016X}", display_id);
  851. IPC::ResponseBuilder rb{ctx, 6};
  852. rb.Push(RESULT_SUCCESS);
  853. // This only returns the fixed values of 1280x720 and makes no distinguishing
  854. // between docked and undocked dimensions. We take the liberty of applying
  855. // the resolution scaling factor here.
  856. rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth) *
  857. static_cast<u32>(Settings::values.resolution_factor));
  858. rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight) *
  859. static_cast<u32>(Settings::values.resolution_factor));
  860. }
  861. void SetLayerScalingMode(Kernel::HLERequestContext& ctx) {
  862. IPC::RequestParser rp{ctx};
  863. const auto scaling_mode = rp.PopEnum<NintendoScaleMode>();
  864. const u64 unknown = rp.Pop<u64>();
  865. LOG_DEBUG(Service_VI, "called. scaling_mode=0x{:08X}, unknown=0x{:016X}",
  866. static_cast<u32>(scaling_mode), unknown);
  867. IPC::ResponseBuilder rb{ctx, 2};
  868. if (scaling_mode > NintendoScaleMode::PreserveAspectRatio) {
  869. LOG_ERROR(Service_VI, "Invalid scaling mode provided.");
  870. rb.Push(ERR_OPERATION_FAILED);
  871. return;
  872. }
  873. if (scaling_mode != NintendoScaleMode::ScaleToWindow &&
  874. scaling_mode != NintendoScaleMode::PreserveAspectRatio) {
  875. LOG_ERROR(Service_VI, "Unsupported scaling mode supplied.");
  876. rb.Push(ERR_UNSUPPORTED);
  877. return;
  878. }
  879. rb.Push(RESULT_SUCCESS);
  880. }
  881. void ListDisplays(Kernel::HLERequestContext& ctx) {
  882. LOG_WARNING(Service_VI, "(STUBBED) called");
  883. DisplayInfo display_info;
  884. display_info.width *= static_cast<u64>(Settings::values.resolution_factor);
  885. display_info.height *= static_cast<u64>(Settings::values.resolution_factor);
  886. ctx.WriteBuffer(&display_info, sizeof(DisplayInfo));
  887. IPC::ResponseBuilder rb{ctx, 4};
  888. rb.Push(RESULT_SUCCESS);
  889. rb.Push<u64>(1);
  890. }
  891. void OpenLayer(Kernel::HLERequestContext& ctx) {
  892. IPC::RequestParser rp{ctx};
  893. const auto name_buf = rp.PopRaw<std::array<u8, 0x40>>();
  894. const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
  895. const std::string display_name(name_buf.begin(), end);
  896. const u64 layer_id = rp.Pop<u64>();
  897. const u64 aruid = rp.Pop<u64>();
  898. LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid);
  899. const auto display_id = nv_flinger->OpenDisplay(display_name);
  900. if (!display_id) {
  901. IPC::ResponseBuilder rb{ctx, 2};
  902. rb.Push(ERR_NOT_FOUND);
  903. return;
  904. }
  905. const auto buffer_queue_id = nv_flinger->FindBufferQueueId(*display_id, layer_id);
  906. if (!buffer_queue_id) {
  907. IPC::ResponseBuilder rb{ctx, 2};
  908. rb.Push(ERR_NOT_FOUND);
  909. return;
  910. }
  911. NativeWindow native_window{*buffer_queue_id};
  912. IPC::ResponseBuilder rb{ctx, 4};
  913. rb.Push(RESULT_SUCCESS);
  914. rb.Push<u64>(ctx.WriteBuffer(native_window.Serialize()));
  915. }
  916. void CloseLayer(Kernel::HLERequestContext& ctx) {
  917. IPC::RequestParser rp{ctx};
  918. const auto layer_id{rp.Pop<u64>()};
  919. LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}", layer_id);
  920. nv_flinger->CloseLayer(layer_id);
  921. IPC::ResponseBuilder rb{ctx, 2};
  922. rb.Push(RESULT_SUCCESS);
  923. }
  924. void CreateStrayLayer(Kernel::HLERequestContext& ctx) {
  925. IPC::RequestParser rp{ctx};
  926. const u32 flags = rp.Pop<u32>();
  927. rp.Pop<u32>(); // padding
  928. const u64 display_id = rp.Pop<u64>();
  929. LOG_DEBUG(Service_VI, "called. flags=0x{:08X}, display_id=0x{:016X}", flags, display_id);
  930. // TODO(Subv): What's the difference between a Stray and a Managed layer?
  931. const auto layer_id = nv_flinger->CreateLayer(display_id);
  932. if (!layer_id) {
  933. IPC::ResponseBuilder rb{ctx, 2};
  934. rb.Push(ERR_NOT_FOUND);
  935. return;
  936. }
  937. const auto buffer_queue_id = nv_flinger->FindBufferQueueId(display_id, *layer_id);
  938. if (!buffer_queue_id) {
  939. IPC::ResponseBuilder rb{ctx, 2};
  940. rb.Push(ERR_NOT_FOUND);
  941. return;
  942. }
  943. NativeWindow native_window{*buffer_queue_id};
  944. IPC::ResponseBuilder rb{ctx, 6};
  945. rb.Push(RESULT_SUCCESS);
  946. rb.Push(*layer_id);
  947. rb.Push<u64>(ctx.WriteBuffer(native_window.Serialize()));
  948. }
  949. void DestroyStrayLayer(Kernel::HLERequestContext& ctx) {
  950. IPC::RequestParser rp{ctx};
  951. const u64 layer_id = rp.Pop<u64>();
  952. LOG_WARNING(Service_VI, "(STUBBED) called. layer_id=0x{:016X}", layer_id);
  953. IPC::ResponseBuilder rb{ctx, 2};
  954. rb.Push(RESULT_SUCCESS);
  955. }
  956. void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx) {
  957. IPC::RequestParser rp{ctx};
  958. const u64 display_id = rp.Pop<u64>();
  959. LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id);
  960. const auto vsync_event = nv_flinger->FindVsyncEvent(display_id);
  961. if (!vsync_event) {
  962. IPC::ResponseBuilder rb{ctx, 2};
  963. rb.Push(ERR_NOT_FOUND);
  964. return;
  965. }
  966. IPC::ResponseBuilder rb{ctx, 2, 1};
  967. rb.Push(RESULT_SUCCESS);
  968. rb.PushCopyObjects(vsync_event);
  969. }
  970. void ConvertScalingMode(Kernel::HLERequestContext& ctx) {
  971. IPC::RequestParser rp{ctx};
  972. const auto mode = rp.PopEnum<NintendoScaleMode>();
  973. LOG_DEBUG(Service_VI, "called mode={}", static_cast<u32>(mode));
  974. const auto converted_mode = ConvertScalingModeImpl(mode);
  975. if (converted_mode.Succeeded()) {
  976. IPC::ResponseBuilder rb{ctx, 4};
  977. rb.Push(RESULT_SUCCESS);
  978. rb.PushEnum(*converted_mode);
  979. } else {
  980. IPC::ResponseBuilder rb{ctx, 2};
  981. rb.Push(converted_mode.Code());
  982. }
  983. }
  984. static ResultVal<ConvertedScaleMode> ConvertScalingModeImpl(NintendoScaleMode mode) {
  985. switch (mode) {
  986. case NintendoScaleMode::None:
  987. return MakeResult(ConvertedScaleMode::None);
  988. case NintendoScaleMode::Freeze:
  989. return MakeResult(ConvertedScaleMode::Freeze);
  990. case NintendoScaleMode::ScaleToWindow:
  991. return MakeResult(ConvertedScaleMode::ScaleToWindow);
  992. case NintendoScaleMode::ScaleAndCrop:
  993. return MakeResult(ConvertedScaleMode::ScaleAndCrop);
  994. case NintendoScaleMode::PreserveAspectRatio:
  995. return MakeResult(ConvertedScaleMode::PreserveAspectRatio);
  996. default:
  997. return ERR_OPERATION_FAILED;
  998. }
  999. }
  1000. std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;
  1001. };
  1002. IApplicationDisplayService::IApplicationDisplayService(
  1003. std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
  1004. : ServiceFramework("IApplicationDisplayService"), nv_flinger(std::move(nv_flinger)) {
  1005. static const FunctionInfo functions[] = {
  1006. {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"},
  1007. {101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"},
  1008. {102, &IApplicationDisplayService::GetManagerDisplayService, "GetManagerDisplayService"},
  1009. {103, &IApplicationDisplayService::GetIndirectDisplayTransactionService,
  1010. "GetIndirectDisplayTransactionService"},
  1011. {1000, &IApplicationDisplayService::ListDisplays, "ListDisplays"},
  1012. {1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"},
  1013. {1011, &IApplicationDisplayService::OpenDefaultDisplay, "OpenDefaultDisplay"},
  1014. {1020, &IApplicationDisplayService::CloseDisplay, "CloseDisplay"},
  1015. {1101, &IApplicationDisplayService::SetDisplayEnabled, "SetDisplayEnabled"},
  1016. {1102, &IApplicationDisplayService::GetDisplayResolution, "GetDisplayResolution"},
  1017. {2020, &IApplicationDisplayService::OpenLayer, "OpenLayer"},
  1018. {2021, &IApplicationDisplayService::CloseLayer, "CloseLayer"},
  1019. {2030, &IApplicationDisplayService::CreateStrayLayer, "CreateStrayLayer"},
  1020. {2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"},
  1021. {2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"},
  1022. {2102, &IApplicationDisplayService::ConvertScalingMode, "ConvertScalingMode"},
  1023. {2450, nullptr, "GetIndirectLayerImageMap"},
  1024. {2451, nullptr, "GetIndirectLayerImageCropMap"},
  1025. {2460, nullptr, "GetIndirectLayerImageRequiredMemoryInfo"},
  1026. {5202, &IApplicationDisplayService::GetDisplayVsyncEvent, "GetDisplayVsyncEvent"},
  1027. {5203, nullptr, "GetDisplayVsyncEventForDebug"},
  1028. };
  1029. RegisterHandlers(functions);
  1030. }
  1031. static bool IsValidServiceAccess(Permission permission, Policy policy) {
  1032. if (permission == Permission::User) {
  1033. return policy == Policy::User;
  1034. }
  1035. if (permission == Permission::System || permission == Permission::Manager) {
  1036. return policy == Policy::User || policy == Policy::Compositor;
  1037. }
  1038. return false;
  1039. }
  1040. void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx,
  1041. std::shared_ptr<NVFlinger::NVFlinger> nv_flinger,
  1042. Permission permission) {
  1043. IPC::RequestParser rp{ctx};
  1044. const auto policy = rp.PopEnum<Policy>();
  1045. if (!IsValidServiceAccess(permission, policy)) {
  1046. IPC::ResponseBuilder rb{ctx, 2};
  1047. rb.Push(ERR_PERMISSION_DENIED);
  1048. return;
  1049. }
  1050. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  1051. rb.Push(RESULT_SUCCESS);
  1052. rb.PushIpcInterface<IApplicationDisplayService>(std::move(nv_flinger));
  1053. }
  1054. void InstallInterfaces(SM::ServiceManager& service_manager,
  1055. std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) {
  1056. std::make_shared<VI_M>(nv_flinger)->InstallAsService(service_manager);
  1057. std::make_shared<VI_S>(nv_flinger)->InstallAsService(service_manager);
  1058. std::make_shared<VI_U>(nv_flinger)->InstallAsService(service_manager);
  1059. }
  1060. } // namespace Service::VI