IApplicationDisplayService.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. using Ryujinx.Common;
  2. using Ryujinx.Cpu;
  3. using Ryujinx.HLE.HOS.Ipc;
  4. using Ryujinx.HLE.HOS.Kernel.Common;
  5. using Ryujinx.HLE.HOS.Services.SurfaceFlinger;
  6. using Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService;
  7. using System;
  8. using System.Text;
  9. namespace Ryujinx.HLE.HOS.Services.Vi.RootService
  10. {
  11. class IApplicationDisplayService : IpcService
  12. {
  13. private IdDictionary _displays;
  14. public IApplicationDisplayService()
  15. {
  16. _displays = new IdDictionary();
  17. }
  18. [Command(100)]
  19. // GetRelayService() -> object<nns::hosbinder::IHOSBinderDriver>
  20. public ResultCode GetRelayService(ServiceCtx context)
  21. {
  22. MakeObject(context, new HOSBinderDriverServer());
  23. return ResultCode.Success;
  24. }
  25. [Command(101)]
  26. // GetSystemDisplayService() -> object<nn::visrv::sf::ISystemDisplayService>
  27. public ResultCode GetSystemDisplayService(ServiceCtx context)
  28. {
  29. MakeObject(context, new ISystemDisplayService(this));
  30. return ResultCode.Success;
  31. }
  32. [Command(102)]
  33. // GetManagerDisplayService() -> object<nn::visrv::sf::IManagerDisplayService>
  34. public ResultCode GetManagerDisplayService(ServiceCtx context)
  35. {
  36. MakeObject(context, new IManagerDisplayService(this));
  37. return ResultCode.Success;
  38. }
  39. [Command(103)] // 2.0.0+
  40. // GetIndirectDisplayTransactionService() -> object<nns::hosbinder::IHOSBinderDriver>
  41. public ResultCode GetIndirectDisplayTransactionService(ServiceCtx context)
  42. {
  43. MakeObject(context, new HOSBinderDriverServer());
  44. return ResultCode.Success;
  45. }
  46. [Command(1000)]
  47. // ListDisplays() -> (u64, buffer<nn::vi::DisplayInfo, 6>)
  48. public ResultCode ListDisplays(ServiceCtx context)
  49. {
  50. long recBuffPtr = context.Request.ReceiveBuff[0].Position;
  51. MemoryHelper.FillWithZeros(context.Memory, recBuffPtr, 0x60);
  52. // Add only the default display to buffer
  53. context.Memory.Write((ulong)recBuffPtr, Encoding.ASCII.GetBytes("Default"));
  54. context.Memory.Write((ulong)recBuffPtr + 0x40, 0x1L);
  55. context.Memory.Write((ulong)recBuffPtr + 0x48, 0x1L);
  56. context.Memory.Write((ulong)recBuffPtr + 0x50, 1280L);
  57. context.Memory.Write((ulong)recBuffPtr + 0x58, 720L);
  58. context.ResponseData.Write(1L);
  59. return ResultCode.Success;
  60. }
  61. [Command(1010)]
  62. // OpenDisplay(nn::vi::DisplayName) -> u64
  63. public ResultCode OpenDisplay(ServiceCtx context)
  64. {
  65. string name = GetDisplayName(context);
  66. long displayId = _displays.Add(new Display(name));
  67. context.ResponseData.Write(displayId);
  68. return ResultCode.Success;
  69. }
  70. [Command(1020)]
  71. // CloseDisplay(u64)
  72. public ResultCode CloseDisplay(ServiceCtx context)
  73. {
  74. int displayId = context.RequestData.ReadInt32();
  75. _displays.Delete(displayId);
  76. return ResultCode.Success;
  77. }
  78. [Command(1102)]
  79. // GetDisplayResolution(u64) -> (u64, u64)
  80. public ResultCode GetDisplayResolution(ServiceCtx context)
  81. {
  82. long displayId = context.RequestData.ReadInt32();
  83. context.ResponseData.Write(1280);
  84. context.ResponseData.Write(720);
  85. return ResultCode.Success;
  86. }
  87. [Command(2020)]
  88. // OpenLayer(nn::vi::DisplayName, u64, nn::applet::AppletResourceUserId, pid) -> (u64, buffer<bytes, 6>)
  89. public ResultCode OpenLayer(ServiceCtx context)
  90. {
  91. // TODO: support multi display.
  92. byte[] displayName = context.RequestData.ReadBytes(0x40);
  93. long layerId = context.RequestData.ReadInt64();
  94. long userId = context.RequestData.ReadInt64();
  95. long parcelPtr = context.Request.ReceiveBuff[0].Position;
  96. IBinder producer = context.Device.System.SurfaceFlinger.OpenLayer(context.Process, layerId);
  97. Parcel parcel = new Parcel(0x28, 0x4);
  98. parcel.WriteObject(producer, "dispdrv\0");
  99. ReadOnlySpan<byte> parcelData = parcel.Finish();
  100. context.Memory.Write((ulong)parcelPtr, parcelData);
  101. context.ResponseData.Write((long)parcelData.Length);
  102. return ResultCode.Success;
  103. }
  104. [Command(2021)]
  105. // CloseLayer(u64)
  106. public ResultCode CloseLayer(ServiceCtx context)
  107. {
  108. long layerId = context.RequestData.ReadInt64();
  109. context.Device.System.SurfaceFlinger.CloseLayer(layerId);
  110. return ResultCode.Success;
  111. }
  112. [Command(2030)]
  113. // CreateStrayLayer(u32, u64) -> (u64, u64, buffer<bytes, 6>)
  114. public ResultCode CreateStrayLayer(ServiceCtx context)
  115. {
  116. long layerFlags = context.RequestData.ReadInt64();
  117. long displayId = context.RequestData.ReadInt64();
  118. long parcelPtr = context.Request.ReceiveBuff[0].Position;
  119. // TODO: support multi display.
  120. Display disp = _displays.GetData<Display>((int)displayId);
  121. IBinder producer = context.Device.System.SurfaceFlinger.CreateLayer(context.Process, out long layerId);
  122. Parcel parcel = new Parcel(0x28, 0x4);
  123. parcel.WriteObject(producer, "dispdrv\0");
  124. ReadOnlySpan<byte> parcelData = parcel.Finish();
  125. context.Memory.Write((ulong)parcelPtr, parcelData);
  126. context.ResponseData.Write(layerId);
  127. context.ResponseData.Write((long)parcelData.Length);
  128. return ResultCode.Success;
  129. }
  130. [Command(2031)]
  131. // DestroyStrayLayer(u64)
  132. public ResultCode DestroyStrayLayer(ServiceCtx context)
  133. {
  134. long layerId = context.RequestData.ReadInt64();
  135. context.Device.System.SurfaceFlinger.CloseLayer(layerId);
  136. return ResultCode.Success;
  137. }
  138. [Command(2101)]
  139. // SetLayerScalingMode(u32, u64)
  140. public ResultCode SetLayerScalingMode(ServiceCtx context)
  141. {
  142. int scalingMode = context.RequestData.ReadInt32();
  143. long layerId = context.RequestData.ReadInt64();
  144. return ResultCode.Success;
  145. }
  146. [Command(2102)] // 5.0.0+
  147. // ConvertScalingMode(unknown) -> unknown
  148. public ResultCode ConvertScalingMode(ServiceCtx context)
  149. {
  150. SourceScalingMode scalingMode = (SourceScalingMode)context.RequestData.ReadInt32();
  151. DestinationScalingMode? convertedScalingMode = ConvertScalingMode(scalingMode);
  152. if (!convertedScalingMode.HasValue)
  153. {
  154. // Scaling mode out of the range of valid values.
  155. return ResultCode.InvalidArguments;
  156. }
  157. if (scalingMode != SourceScalingMode.ScaleToWindow &&
  158. scalingMode != SourceScalingMode.PreserveAspectRatio)
  159. {
  160. // Invalid scaling mode specified.
  161. return ResultCode.InvalidScalingMode;
  162. }
  163. context.ResponseData.Write((ulong)convertedScalingMode);
  164. return ResultCode.Success;
  165. }
  166. private DestinationScalingMode? ConvertScalingMode(SourceScalingMode source)
  167. {
  168. switch (source)
  169. {
  170. case SourceScalingMode.None: return DestinationScalingMode.None;
  171. case SourceScalingMode.Freeze: return DestinationScalingMode.Freeze;
  172. case SourceScalingMode.ScaleAndCrop: return DestinationScalingMode.ScaleAndCrop;
  173. case SourceScalingMode.ScaleToWindow: return DestinationScalingMode.ScaleToWindow;
  174. case SourceScalingMode.PreserveAspectRatio: return DestinationScalingMode.PreserveAspectRatio;
  175. }
  176. return null;
  177. }
  178. [Command(2460)]
  179. // GetIndirectLayerImageRequiredMemoryInfo(u64 width, u64 height) -> (u64 size, u64 alignment)
  180. public ResultCode GetIndirectLayerImageRequiredMemoryInfo(ServiceCtx context)
  181. {
  182. /*
  183. // Doesn't occur in our case.
  184. if (sizePtr == null || address_alignmentPtr == null)
  185. {
  186. return ResultCode.InvalidArguments;
  187. }
  188. */
  189. int width = (int)context.RequestData.ReadUInt64();
  190. int height = (int)context.RequestData.ReadUInt64();
  191. if (height < 0 || width < 0)
  192. {
  193. return ResultCode.InvalidLayerSize;
  194. }
  195. else
  196. {
  197. /*
  198. // Doesn't occur in our case.
  199. if (!service_initialized)
  200. {
  201. return ResultCode.InvalidArguments;
  202. }
  203. */
  204. const ulong defaultAlignment = 0x1000;
  205. const ulong defaultSize = 0x20000;
  206. // NOTE: The official service setup a A8B8G8R8 texture with a linear layout and then query its size.
  207. // As we don't need this texture on the emulator, we can just simplify this logic and directly
  208. // do a linear layout size calculation. (stride * height * bytePerPixel)
  209. int pitch = BitUtils.AlignUp(BitUtils.DivRoundUp(width * 32, 8), 64);
  210. int memorySize = pitch * BitUtils.AlignUp(height, 64);
  211. ulong requiredMemorySize = (ulong)BitUtils.AlignUp(memorySize, (int)defaultAlignment);
  212. ulong size = (requiredMemorySize + defaultSize - 1) / defaultSize * defaultSize;
  213. context.ResponseData.Write(size);
  214. context.ResponseData.Write(defaultAlignment);
  215. }
  216. return ResultCode.Success;
  217. }
  218. [Command(5202)]
  219. // GetDisplayVsyncEvent(u64) -> handle<copy>
  220. public ResultCode GetDisplayVSyncEvent(ServiceCtx context)
  221. {
  222. string name = GetDisplayName(context);
  223. if (context.Process.HandleTable.GenerateHandle(context.Device.System.VsyncEvent.ReadableEvent, out int handle) != KernelResult.Success)
  224. {
  225. throw new InvalidOperationException("Out of handles!");
  226. }
  227. context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
  228. return ResultCode.Success;
  229. }
  230. private string GetDisplayName(ServiceCtx context)
  231. {
  232. string name = string.Empty;
  233. for (int index = 0; index < 8 &&
  234. context.RequestData.BaseStream.Position <
  235. context.RequestData.BaseStream.Length; index++)
  236. {
  237. byte chr = context.RequestData.ReadByte();
  238. if (chr >= 0x20 && chr < 0x7f)
  239. {
  240. name += (char)chr;
  241. }
  242. }
  243. return name;
  244. }
  245. }
  246. }