IGraphicBufferProducer.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. using Ryujinx.Common.Logging;
  2. using Ryujinx.HLE.HOS.Kernel.Threading;
  3. using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
  4. using System;
  5. using System.Runtime.CompilerServices;
  6. using System.Runtime.InteropServices;
  7. namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
  8. {
  9. abstract class IGraphicBufferProducer : IBinder
  10. {
  11. public string InterfaceToken => "android.gui.IGraphicBufferProducer";
  12. enum TransactionCode : uint
  13. {
  14. RequestBuffer = 1,
  15. SetBufferCount,
  16. DequeueBuffer,
  17. DetachBuffer,
  18. DetachNextBuffer,
  19. AttachBuffer,
  20. QueueBuffer,
  21. CancelBuffer,
  22. Query,
  23. Connect,
  24. Disconnect,
  25. SetSidebandStream,
  26. AllocateBuffers,
  27. SetPreallocatedBuffer,
  28. Reserved15,
  29. GetBufferInfo,
  30. GetBufferHistory
  31. }
  32. [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x54)]
  33. public struct QueueBufferInput : IFlattenable
  34. {
  35. public long Timestamp;
  36. public int IsAutoTimestamp;
  37. public Rect Crop;
  38. public NativeWindowScalingMode ScalingMode;
  39. public NativeWindowTransform Transform;
  40. public uint StickyTransform;
  41. public int Async;
  42. public int SwapInterval;
  43. public AndroidFence Fence;
  44. public void Flatten(Parcel parcel)
  45. {
  46. parcel.WriteUnmanagedType(ref this);
  47. }
  48. public uint GetFdCount()
  49. {
  50. return 0;
  51. }
  52. public uint GetFlattenedSize()
  53. {
  54. return (uint)Unsafe.SizeOf<QueueBufferInput>();
  55. }
  56. public void Unflatten(Parcel parcel)
  57. {
  58. this = parcel.ReadUnmanagedType<QueueBufferInput>();
  59. }
  60. }
  61. public struct QueueBufferOutput
  62. {
  63. public uint Width;
  64. public uint Height;
  65. public NativeWindowTransform TransformHint;
  66. public uint NumPendingBuffers;
  67. public ulong FrameNumber;
  68. public void WriteToParcel(Parcel parcel)
  69. {
  70. parcel.WriteUInt32(Width);
  71. parcel.WriteUInt32(Height);
  72. parcel.WriteUnmanagedType(ref TransformHint);
  73. parcel.WriteUInt32(NumPendingBuffers);
  74. if (TransformHint.HasFlag(NativeWindowTransform.ReturnFrameNumber))
  75. {
  76. parcel.WriteUInt64(FrameNumber);
  77. }
  78. }
  79. }
  80. public ResultCode AdjustRefcount(int addVal, int type)
  81. {
  82. // TODO?
  83. return ResultCode.Success;
  84. }
  85. public void GetNativeHandle(uint typeId, out KReadableEvent readableEvent)
  86. {
  87. if (typeId == 0xF)
  88. {
  89. readableEvent = GetWaitBufferFreeEvent();
  90. }
  91. else
  92. {
  93. throw new NotImplementedException($"Unimplemented native event type {typeId}!");
  94. }
  95. }
  96. public void OnTransact(uint code, uint flags, Parcel inputParcel, Parcel outputParcel)
  97. {
  98. Status status = Status.Success;
  99. int slot;
  100. AndroidFence fence;
  101. QueueBufferInput queueInput;
  102. QueueBufferOutput queueOutput;
  103. NativeWindowApi api;
  104. AndroidStrongPointer<GraphicBuffer> graphicBuffer;
  105. AndroidStrongPointer<AndroidFence> strongFence;
  106. switch ((TransactionCode)code)
  107. {
  108. case TransactionCode.RequestBuffer:
  109. slot = inputParcel.ReadInt32();
  110. status = RequestBuffer(slot, out graphicBuffer);
  111. outputParcel.WriteStrongPointer(ref graphicBuffer);
  112. outputParcel.WriteStatus(status);
  113. break;
  114. case TransactionCode.SetBufferCount:
  115. int bufferCount = inputParcel.ReadInt32();
  116. status = SetBufferCount(bufferCount);
  117. outputParcel.WriteStatus(status);
  118. break;
  119. case TransactionCode.DequeueBuffer:
  120. bool async = inputParcel.ReadBoolean();
  121. uint width = inputParcel.ReadUInt32();
  122. uint height = inputParcel.ReadUInt32();
  123. PixelFormat format = inputParcel.ReadUnmanagedType<PixelFormat>();
  124. uint usage = inputParcel.ReadUInt32();
  125. status = DequeueBuffer(out int dequeueSlot, out fence, async, width, height, format, usage);
  126. strongFence = new AndroidStrongPointer<AndroidFence>(fence);
  127. outputParcel.WriteInt32(dequeueSlot);
  128. outputParcel.WriteStrongPointer(ref strongFence);
  129. outputParcel.WriteStatus(status);
  130. break;
  131. case TransactionCode.DetachBuffer:
  132. slot = inputParcel.ReadInt32();
  133. status = DetachBuffer(slot);
  134. outputParcel.WriteStatus(status);
  135. break;
  136. case TransactionCode.DetachNextBuffer:
  137. status = DetachNextBuffer(out graphicBuffer, out fence);
  138. strongFence = new AndroidStrongPointer<AndroidFence>(fence);
  139. outputParcel.WriteStrongPointer(ref graphicBuffer);
  140. outputParcel.WriteStrongPointer(ref strongFence);
  141. outputParcel.WriteStatus(status);
  142. break;
  143. case TransactionCode.AttachBuffer:
  144. graphicBuffer = inputParcel.ReadStrongPointer<GraphicBuffer>();
  145. status = AttachBuffer(out slot, graphicBuffer);
  146. outputParcel.WriteInt32(slot);
  147. outputParcel.WriteStatus(status);
  148. break;
  149. case TransactionCode.QueueBuffer:
  150. slot = inputParcel.ReadInt32();
  151. queueInput = inputParcel.ReadFlattenable<QueueBufferInput>();
  152. status = QueueBuffer(slot, ref queueInput, out queueOutput);
  153. queueOutput.WriteToParcel(outputParcel);
  154. outputParcel.WriteStatus(status);
  155. break;
  156. case TransactionCode.CancelBuffer:
  157. slot = inputParcel.ReadInt32();
  158. fence = inputParcel.ReadFlattenable<AndroidFence>();
  159. CancelBuffer(slot, ref fence);
  160. outputParcel.WriteStatus(Status.Success);
  161. break;
  162. case TransactionCode.Query:
  163. NativeWindowAttribute what = inputParcel.ReadUnmanagedType<NativeWindowAttribute>();
  164. status = Query(what, out int outValue);
  165. outputParcel.WriteInt32(outValue);
  166. outputParcel.WriteStatus(status);
  167. break;
  168. case TransactionCode.Connect:
  169. bool hasListener = inputParcel.ReadBoolean();
  170. IProducerListener listener = null;
  171. if (hasListener)
  172. {
  173. throw new NotImplementedException("Connect with a strong binder listener isn't implemented");
  174. }
  175. api = inputParcel.ReadUnmanagedType<NativeWindowApi>();
  176. bool producerControlledByApp = inputParcel.ReadBoolean();
  177. status = Connect(listener, api, producerControlledByApp, out queueOutput);
  178. queueOutput.WriteToParcel(outputParcel);
  179. outputParcel.WriteStatus(status);
  180. break;
  181. case TransactionCode.Disconnect:
  182. api = inputParcel.ReadUnmanagedType<NativeWindowApi>();
  183. status = Disconnect(api);
  184. outputParcel.WriteStatus(status);
  185. break;
  186. case TransactionCode.SetPreallocatedBuffer:
  187. slot = inputParcel.ReadInt32();
  188. graphicBuffer = inputParcel.ReadStrongPointer<GraphicBuffer>();
  189. status = SetPreallocatedBuffer(slot, graphicBuffer);
  190. outputParcel.WriteStatus(status);
  191. break;
  192. case TransactionCode.GetBufferHistory:
  193. int bufferHistoryCount = inputParcel.ReadInt32();
  194. status = GetBufferHistory(bufferHistoryCount, out Span<BufferInfo> bufferInfos);
  195. outputParcel.WriteStatus(status);
  196. outputParcel.WriteInt32(bufferInfos.Length);
  197. outputParcel.WriteUnmanagedSpan<BufferInfo>(bufferInfos);
  198. break;
  199. default:
  200. throw new NotImplementedException($"Transaction {(TransactionCode)code} not implemented");
  201. }
  202. if (status != Status.Success)
  203. {
  204. Logger.Error?.Print(LogClass.SurfaceFlinger, $"Error returned by transaction {(TransactionCode)code}: {status}");
  205. }
  206. }
  207. protected abstract KReadableEvent GetWaitBufferFreeEvent();
  208. public abstract Status RequestBuffer(int slot, out AndroidStrongPointer<GraphicBuffer> graphicBuffer);
  209. public abstract Status SetBufferCount(int bufferCount);
  210. public abstract Status DequeueBuffer(out int slot, out AndroidFence fence, bool async, uint width, uint height, PixelFormat format, uint usage);
  211. public abstract Status DetachBuffer(int slot);
  212. public abstract Status DetachNextBuffer(out AndroidStrongPointer<GraphicBuffer> graphicBuffer, out AndroidFence fence);
  213. public abstract Status AttachBuffer(out int slot, AndroidStrongPointer<GraphicBuffer> graphicBuffer);
  214. public abstract Status QueueBuffer(int slot, ref QueueBufferInput input, out QueueBufferOutput output);
  215. public abstract void CancelBuffer(int slot, ref AndroidFence fence);
  216. public abstract Status Query(NativeWindowAttribute what, out int outValue);
  217. public abstract Status Connect(IProducerListener listener, NativeWindowApi api, bool producerControlledByApp, out QueueBufferOutput output);
  218. public abstract Status Disconnect(NativeWindowApi api);
  219. public abstract Status SetPreallocatedBuffer(int slot, AndroidStrongPointer<GraphicBuffer> graphicBuffer);
  220. public abstract Status GetBufferHistory(int bufferHistoryCount, out Span<BufferInfo> bufferInfos);
  221. }
  222. }