SurfaceFlinger.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. using Ryujinx.Common.Logging;
  2. using Ryujinx.Graphics.GAL;
  3. using Ryujinx.Graphics.Gpu;
  4. using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Diagnostics;
  8. using System.Threading;
  9. namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
  10. {
  11. class SurfaceFlinger : IConsumerListener, IDisposable
  12. {
  13. private const int TargetFps = 60;
  14. private Switch _device;
  15. private Dictionary<long, Layer> _layers;
  16. private bool _isRunning;
  17. private Thread _composerThread;
  18. private Stopwatch _chrono;
  19. private long _ticks;
  20. private long _ticksPerFrame;
  21. private int _swapInterval;
  22. private readonly object Lock = new object();
  23. public long LastId { get; private set; }
  24. private class Layer
  25. {
  26. public int ProducerBinderId;
  27. public IGraphicBufferProducer Producer;
  28. public BufferItemConsumer Consumer;
  29. public BufferQueueCore Core;
  30. public long Owner;
  31. }
  32. private class TextureCallbackInformation
  33. {
  34. public Layer Layer;
  35. public BufferItem Item;
  36. }
  37. public SurfaceFlinger(Switch device)
  38. {
  39. _device = device;
  40. _layers = new Dictionary<long, Layer>();
  41. LastId = 0;
  42. _composerThread = new Thread(HandleComposition)
  43. {
  44. Name = "SurfaceFlinger.Composer"
  45. };
  46. _chrono = new Stopwatch();
  47. _ticks = 0;
  48. UpdateSwapInterval(1);
  49. _composerThread.Start();
  50. }
  51. private void UpdateSwapInterval(int swapInterval)
  52. {
  53. _swapInterval = swapInterval;
  54. // If the swap interval is 0, Game VSync is disabled.
  55. if (_swapInterval == 0)
  56. {
  57. _ticksPerFrame = 1;
  58. }
  59. else
  60. {
  61. _ticksPerFrame = Stopwatch.Frequency / (TargetFps / _swapInterval);
  62. }
  63. }
  64. public IGraphicBufferProducer OpenLayer(long pid, long layerId)
  65. {
  66. bool needCreate;
  67. lock (Lock)
  68. {
  69. needCreate = GetLayerByIdLocked(layerId) == null;
  70. }
  71. if (needCreate)
  72. {
  73. CreateLayerFromId(pid, layerId);
  74. }
  75. return GetProducerByLayerId(layerId);
  76. }
  77. public IGraphicBufferProducer CreateLayer(long pid, out long layerId)
  78. {
  79. layerId = 1;
  80. lock (Lock)
  81. {
  82. foreach (KeyValuePair<long, Layer> pair in _layers)
  83. {
  84. if (pair.Key >= layerId)
  85. {
  86. layerId = pair.Key + 1;
  87. }
  88. }
  89. }
  90. CreateLayerFromId(pid, layerId);
  91. return GetProducerByLayerId(layerId);
  92. }
  93. private void CreateLayerFromId(long pid, long layerId)
  94. {
  95. lock (Lock)
  96. {
  97. Logger.Info?.Print(LogClass.SurfaceFlinger, $"Creating layer {layerId}");
  98. BufferQueueCore core = BufferQueue.CreateBufferQueue(_device, pid, out BufferQueueProducer producer, out BufferQueueConsumer consumer);
  99. _layers.Add(layerId, new Layer
  100. {
  101. ProducerBinderId = HOSBinderDriverServer.RegisterBinderObject(producer),
  102. Producer = producer,
  103. Consumer = new BufferItemConsumer(_device, consumer, 0, -1, false, this),
  104. Core = core,
  105. Owner = pid
  106. });
  107. LastId = layerId;
  108. }
  109. }
  110. public bool CloseLayer(long layerId)
  111. {
  112. lock (Lock)
  113. {
  114. Layer layer = GetLayerByIdLocked(layerId);
  115. if (layer != null)
  116. {
  117. HOSBinderDriverServer.UnregisterBinderObject(layer.ProducerBinderId);
  118. }
  119. return _layers.Remove(layerId);
  120. }
  121. }
  122. private Layer GetLayerByIdLocked(long layerId)
  123. {
  124. foreach (KeyValuePair<long, Layer> pair in _layers)
  125. {
  126. if (pair.Key == layerId)
  127. {
  128. return pair.Value;
  129. }
  130. }
  131. return null;
  132. }
  133. public IGraphicBufferProducer GetProducerByLayerId(long layerId)
  134. {
  135. lock (Lock)
  136. {
  137. Layer layer = GetLayerByIdLocked(layerId);
  138. if (layer != null)
  139. {
  140. return layer.Producer;
  141. }
  142. }
  143. return null;
  144. }
  145. private void HandleComposition()
  146. {
  147. _isRunning = true;
  148. while (_isRunning)
  149. {
  150. _ticks += _chrono.ElapsedTicks;
  151. _chrono.Restart();
  152. if (_ticks >= _ticksPerFrame)
  153. {
  154. Compose();
  155. _device.System?.SignalVsync();
  156. _ticks = Math.Min(_ticks - _ticksPerFrame, _ticksPerFrame);
  157. }
  158. // Sleep the minimal amount of time to avoid being too expensive.
  159. Thread.Sleep(1);
  160. }
  161. }
  162. public void Compose()
  163. {
  164. lock (Lock)
  165. {
  166. // TODO: support multilayers (& multidisplay ?)
  167. if (_layers.Count == 0)
  168. {
  169. return;
  170. }
  171. Layer layer = GetLayerByIdLocked(LastId);
  172. Status acquireStatus = layer.Consumer.AcquireBuffer(out BufferItem item, 0);
  173. if (acquireStatus == Status.Success)
  174. {
  175. // If device vsync is disabled, reflect the change.
  176. if (!_device.EnableDeviceVsync)
  177. {
  178. if (_swapInterval != 0)
  179. {
  180. UpdateSwapInterval(0);
  181. }
  182. }
  183. else if (item.SwapInterval != _swapInterval)
  184. {
  185. UpdateSwapInterval(item.SwapInterval);
  186. }
  187. PostFrameBuffer(layer, item);
  188. }
  189. else if (acquireStatus != Status.NoBufferAvailaible && acquireStatus != Status.InvalidOperation)
  190. {
  191. throw new InvalidOperationException();
  192. }
  193. }
  194. }
  195. private void PostFrameBuffer(Layer layer, BufferItem item)
  196. {
  197. int frameBufferWidth = item.GraphicBuffer.Object.Width;
  198. int frameBufferHeight = item.GraphicBuffer.Object.Height;
  199. int nvMapHandle = item.GraphicBuffer.Object.Buffer.Surfaces[0].NvMapHandle;
  200. if (nvMapHandle == 0)
  201. {
  202. nvMapHandle = item.GraphicBuffer.Object.Buffer.NvMapId;
  203. }
  204. int bufferOffset = item.GraphicBuffer.Object.Buffer.Surfaces[0].Offset;
  205. NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(layer.Owner, nvMapHandle);
  206. ulong frameBufferAddress = (ulong)(map.Address + bufferOffset);
  207. Format format = ConvertColorFormat(item.GraphicBuffer.Object.Buffer.Surfaces[0].ColorFormat);
  208. int bytesPerPixel =
  209. format == Format.B5G6R5Unorm ||
  210. format == Format.R4G4B4A4Unorm ? 2 : 4;
  211. int gobBlocksInY = 1 << item.GraphicBuffer.Object.Buffer.Surfaces[0].BlockHeightLog2;
  212. // Note: Rotation is being ignored.
  213. Rect cropRect = item.Crop;
  214. bool flipX = item.Transform.HasFlag(NativeWindowTransform.FlipX);
  215. bool flipY = item.Transform.HasFlag(NativeWindowTransform.FlipY);
  216. ImageCrop crop = new ImageCrop(
  217. cropRect.Left,
  218. cropRect.Right,
  219. cropRect.Top,
  220. cropRect.Bottom,
  221. flipX,
  222. flipY);
  223. TextureCallbackInformation textureCallbackInformation = new TextureCallbackInformation
  224. {
  225. Layer = layer,
  226. Item = item,
  227. };
  228. _device.Gpu.Window.EnqueueFrameThreadSafe(
  229. frameBufferAddress,
  230. frameBufferWidth,
  231. frameBufferHeight,
  232. 0,
  233. false,
  234. gobBlocksInY,
  235. format,
  236. bytesPerPixel,
  237. crop,
  238. AcquireBuffer,
  239. ReleaseBuffer,
  240. textureCallbackInformation);
  241. }
  242. private void ReleaseBuffer(object obj)
  243. {
  244. ReleaseBuffer((TextureCallbackInformation)obj);
  245. }
  246. private void ReleaseBuffer(TextureCallbackInformation information)
  247. {
  248. AndroidFence fence = AndroidFence.NoFence;
  249. information.Layer.Consumer.ReleaseBuffer(information.Item, ref fence);
  250. }
  251. private void AcquireBuffer(GpuContext ignored, object obj)
  252. {
  253. AcquireBuffer((TextureCallbackInformation)obj);
  254. }
  255. private void AcquireBuffer(TextureCallbackInformation information)
  256. {
  257. information.Item.Fence.WaitForever(_device.Gpu);
  258. }
  259. public static Format ConvertColorFormat(ColorFormat colorFormat)
  260. {
  261. return colorFormat switch
  262. {
  263. ColorFormat.A8B8G8R8 => Format.R8G8B8A8Unorm,
  264. ColorFormat.X8B8G8R8 => Format.R8G8B8A8Unorm,
  265. ColorFormat.R5G6B5 => Format.B5G6R5Unorm,
  266. ColorFormat.A8R8G8B8 => Format.B8G8R8A8Unorm,
  267. ColorFormat.A4B4G4R4 => Format.R4G4B4A4Unorm,
  268. _ => throw new NotImplementedException($"Color Format \"{colorFormat}\" not implemented!"),
  269. };
  270. }
  271. public void Dispose()
  272. {
  273. _isRunning = false;
  274. foreach (Layer layer in _layers.Values)
  275. {
  276. layer.Core.PrepareForExit();
  277. }
  278. }
  279. public void OnFrameAvailable(ref BufferItem item)
  280. {
  281. _device.Statistics.RecordGameFrameTime();
  282. }
  283. public void OnFrameReplaced(ref BufferItem item)
  284. {
  285. _device.Statistics.RecordGameFrameTime();
  286. }
  287. public void OnBuffersReleased() {}
  288. }
  289. }