IApplicationDisplayService.cs 11 KB

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