BufferQueueProducer.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871
  1. using Ryujinx.Common.Logging;
  2. using Ryujinx.Cpu;
  3. using Ryujinx.HLE.HOS.Kernel.Threading;
  4. using Ryujinx.HLE.HOS.Services.Settings;
  5. using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
  6. using Ryujinx.HLE.HOS.Services.Time.Clock;
  7. using System;
  8. using System.Threading;
  9. namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
  10. {
  11. class BufferQueueProducer : IGraphicBufferProducer
  12. {
  13. public BufferQueueCore Core { get; }
  14. private readonly ITickSource _tickSource;
  15. private uint _stickyTransform;
  16. private uint _nextCallbackTicket;
  17. private uint _currentCallbackTicket;
  18. private uint _callbackTicket;
  19. private readonly object _callbackLock = new object();
  20. public BufferQueueProducer(BufferQueueCore core, ITickSource tickSource)
  21. {
  22. Core = core;
  23. _tickSource = tickSource;
  24. _stickyTransform = 0;
  25. _callbackTicket = 0;
  26. _nextCallbackTicket = 0;
  27. _currentCallbackTicket = 0;
  28. }
  29. public override Status RequestBuffer(int slot, out AndroidStrongPointer<GraphicBuffer> graphicBuffer)
  30. {
  31. graphicBuffer = new AndroidStrongPointer<GraphicBuffer>();
  32. lock (Core.Lock)
  33. {
  34. if (Core.IsAbandoned)
  35. {
  36. return Status.NoInit;
  37. }
  38. if (slot < 0 || slot >= Core.Slots.Length || !Core.IsOwnedByProducerLocked(slot))
  39. {
  40. return Status.BadValue;
  41. }
  42. graphicBuffer.Set(Core.Slots[slot].GraphicBuffer);
  43. Core.Slots[slot].RequestBufferCalled = true;
  44. return Status.Success;
  45. }
  46. }
  47. public override Status SetBufferCount(int bufferCount)
  48. {
  49. IConsumerListener listener = null;
  50. lock (Core.Lock)
  51. {
  52. if (Core.IsAbandoned)
  53. {
  54. return Status.NoInit;
  55. }
  56. if (bufferCount > BufferSlotArray.NumBufferSlots)
  57. {
  58. return Status.BadValue;
  59. }
  60. for (int slot = 0; slot < Core.Slots.Length; slot++)
  61. {
  62. if (Core.Slots[slot].BufferState == BufferState.Dequeued)
  63. {
  64. return Status.BadValue;
  65. }
  66. }
  67. if (bufferCount == 0)
  68. {
  69. Core.OverrideMaxBufferCount = 0;
  70. Core.SignalDequeueEvent();
  71. return Status.Success;
  72. }
  73. int minBufferSlots = Core.GetMinMaxBufferCountLocked(false);
  74. if (bufferCount < minBufferSlots)
  75. {
  76. return Status.BadValue;
  77. }
  78. int preallocatedBufferCount = GetPreallocatedBufferCountLocked();
  79. if (preallocatedBufferCount <= 0)
  80. {
  81. Core.Queue.Clear();
  82. Core.FreeAllBuffersLocked();
  83. }
  84. else if (preallocatedBufferCount < bufferCount)
  85. {
  86. Logger.Error?.Print(LogClass.SurfaceFlinger, "Not enough buffers. Try with more pre-allocated buffers");
  87. return Status.Success;
  88. }
  89. Core.OverrideMaxBufferCount = bufferCount;
  90. Core.SignalDequeueEvent();
  91. Core.SignalWaitBufferFreeEvent();
  92. listener = Core.ConsumerListener;
  93. }
  94. listener?.OnBuffersReleased();
  95. return Status.Success;
  96. }
  97. public override Status DequeueBuffer(out int slot,
  98. out AndroidFence fence,
  99. bool async,
  100. uint width,
  101. uint height,
  102. PixelFormat format,
  103. uint usage)
  104. {
  105. if ((width == 0 && height != 0) || (height == 0 && width != 0))
  106. {
  107. slot = BufferSlotArray.InvalidBufferSlot;
  108. fence = AndroidFence.NoFence;
  109. return Status.BadValue;
  110. }
  111. Status returnFlags = Status.Success;
  112. bool attachedByConsumer = false;
  113. lock (Core.Lock)
  114. {
  115. if (format == PixelFormat.Unknown)
  116. {
  117. format = Core.DefaultBufferFormat;
  118. }
  119. usage |= Core.ConsumerUsageBits;
  120. Status status = WaitForFreeSlotThenRelock(async, out slot, out returnFlags);
  121. if (status != Status.Success)
  122. {
  123. slot = BufferSlotArray.InvalidBufferSlot;
  124. fence = AndroidFence.NoFence;
  125. return status;
  126. }
  127. if (slot == BufferSlotArray.InvalidBufferSlot)
  128. {
  129. fence = AndroidFence.NoFence;
  130. Logger.Error?.Print(LogClass.SurfaceFlinger, "No available buffer slots");
  131. return Status.Busy;
  132. }
  133. attachedByConsumer = Core.Slots[slot].AttachedByConsumer;
  134. if (width == 0 || height == 0)
  135. {
  136. width = (uint)Core.DefaultWidth;
  137. height = (uint)Core.DefaultHeight;
  138. }
  139. GraphicBuffer graphicBuffer = Core.Slots[slot].GraphicBuffer.Object;
  140. if (Core.Slots[slot].GraphicBuffer.IsNull
  141. || graphicBuffer.Width != width
  142. || graphicBuffer.Height != height
  143. || graphicBuffer.Format != format
  144. || (graphicBuffer.Usage & usage) != usage)
  145. {
  146. if (!Core.Slots[slot].IsPreallocated)
  147. {
  148. slot = BufferSlotArray.InvalidBufferSlot;
  149. fence = AndroidFence.NoFence;
  150. return Status.NoMemory;
  151. }
  152. else
  153. {
  154. Logger.Error?.Print(LogClass.SurfaceFlinger,
  155. $"Preallocated buffer mismatch - slot {slot}\n" +
  156. $"available: Width = {graphicBuffer.Width} Height = {graphicBuffer.Height} Format = {graphicBuffer.Format} Usage = {graphicBuffer.Usage:x} " +
  157. $"requested: Width = {width} Height = {height} Format = {format} Usage = {usage:x}");
  158. slot = BufferSlotArray.InvalidBufferSlot;
  159. fence = AndroidFence.NoFence;
  160. return Status.NoInit;
  161. }
  162. }
  163. Core.Slots[slot].BufferState = BufferState.Dequeued;
  164. Core.UpdateMaxBufferCountCachedLocked(slot);
  165. fence = Core.Slots[slot].Fence;
  166. Core.Slots[slot].Fence = AndroidFence.NoFence;
  167. Core.Slots[slot].QueueTime = TimeSpanType.Zero;
  168. Core.Slots[slot].PresentationTime = TimeSpanType.Zero;
  169. Core.CheckSystemEventsLocked(Core.GetMaxBufferCountLocked(async));
  170. }
  171. if (attachedByConsumer)
  172. {
  173. returnFlags |= Status.BufferNeedsReallocation;
  174. }
  175. return returnFlags;
  176. }
  177. public override Status DetachBuffer(int slot)
  178. {
  179. lock (Core.Lock)
  180. {
  181. if (Core.IsAbandoned)
  182. {
  183. return Status.NoInit;
  184. }
  185. if (slot < 0 || slot >= Core.Slots.Length || !Core.IsOwnedByProducerLocked(slot))
  186. {
  187. return Status.BadValue;
  188. }
  189. if (!Core.Slots[slot].RequestBufferCalled)
  190. {
  191. Logger.Error?.Print(LogClass.SurfaceFlinger, $"Slot {slot} was detached without requesting a buffer");
  192. return Status.BadValue;
  193. }
  194. Core.FreeBufferLocked(slot);
  195. Core.SignalDequeueEvent();
  196. return Status.Success;
  197. }
  198. }
  199. public override Status DetachNextBuffer(out AndroidStrongPointer<GraphicBuffer> graphicBuffer, out AndroidFence fence)
  200. {
  201. lock (Core.Lock)
  202. {
  203. Core.WaitWhileAllocatingLocked();
  204. if (Core.IsAbandoned)
  205. {
  206. graphicBuffer = default;
  207. fence = AndroidFence.NoFence;
  208. return Status.NoInit;
  209. }
  210. int nextBufferSlot = BufferSlotArray.InvalidBufferSlot;
  211. for (int slot = 0; slot < Core.Slots.Length; slot++)
  212. {
  213. if (Core.Slots[slot].BufferState == BufferState.Free && !Core.Slots[slot].GraphicBuffer.IsNull)
  214. {
  215. if (nextBufferSlot == BufferSlotArray.InvalidBufferSlot || Core.Slots[slot].FrameNumber < Core.Slots[nextBufferSlot].FrameNumber)
  216. {
  217. nextBufferSlot = slot;
  218. }
  219. }
  220. }
  221. if (nextBufferSlot == BufferSlotArray.InvalidBufferSlot)
  222. {
  223. graphicBuffer = default;
  224. fence = AndroidFence.NoFence;
  225. return Status.NoMemory;
  226. }
  227. graphicBuffer = Core.Slots[nextBufferSlot].GraphicBuffer;
  228. fence = Core.Slots[nextBufferSlot].Fence;
  229. Core.FreeBufferLocked(nextBufferSlot);
  230. return Status.Success;
  231. }
  232. }
  233. public override Status AttachBuffer(out int slot, AndroidStrongPointer<GraphicBuffer> graphicBuffer)
  234. {
  235. lock (Core.Lock)
  236. {
  237. Core.WaitWhileAllocatingLocked();
  238. Status status = WaitForFreeSlotThenRelock(false, out slot, out Status returnFlags);
  239. if (status != Status.Success)
  240. {
  241. return status;
  242. }
  243. if (slot == BufferSlotArray.InvalidBufferSlot)
  244. {
  245. Logger.Error?.Print(LogClass.SurfaceFlinger, "No available buffer slots");
  246. return Status.Busy;
  247. }
  248. Core.UpdateMaxBufferCountCachedLocked(slot);
  249. Core.Slots[slot].GraphicBuffer.Set(graphicBuffer);
  250. Core.Slots[slot].BufferState = BufferState.Dequeued;
  251. Core.Slots[slot].Fence = AndroidFence.NoFence;
  252. Core.Slots[slot].RequestBufferCalled = true;
  253. return returnFlags;
  254. }
  255. }
  256. public override Status QueueBuffer(int slot, ref QueueBufferInput input, out QueueBufferOutput output)
  257. {
  258. output = default;
  259. switch (input.ScalingMode)
  260. {
  261. case NativeWindowScalingMode.Freeze:
  262. case NativeWindowScalingMode.ScaleToWindow:
  263. case NativeWindowScalingMode.ScaleCrop:
  264. case NativeWindowScalingMode.Unknown:
  265. case NativeWindowScalingMode.NoScaleCrop:
  266. break;
  267. default:
  268. return Status.BadValue;
  269. }
  270. BufferItem item = new BufferItem();
  271. IConsumerListener frameAvailableListener = null;
  272. IConsumerListener frameReplaceListener = null;
  273. lock (Core.Lock)
  274. {
  275. if (Core.IsAbandoned)
  276. {
  277. return Status.NoInit;
  278. }
  279. int maxBufferCount = Core.GetMaxBufferCountLocked(input.Async != 0);
  280. if (input.Async != 0 && Core.OverrideMaxBufferCount != 0 && Core.OverrideMaxBufferCount < maxBufferCount)
  281. {
  282. return Status.BadValue;
  283. }
  284. if (slot < 0 || slot >= Core.Slots.Length || !Core.IsOwnedByProducerLocked(slot))
  285. {
  286. return Status.BadValue;
  287. }
  288. if (!Core.Slots[slot].RequestBufferCalled)
  289. {
  290. Logger.Error?.Print(LogClass.SurfaceFlinger, $"Slot {slot} was queued without requesting a buffer");
  291. return Status.BadValue;
  292. }
  293. input.Crop.Intersect(Core.Slots[slot].GraphicBuffer.Object.ToRect(), out Rect croppedRect);
  294. if (croppedRect != input.Crop)
  295. {
  296. return Status.BadValue;
  297. }
  298. Core.Slots[slot].Fence = input.Fence;
  299. Core.Slots[slot].BufferState = BufferState.Queued;
  300. Core.FrameCounter++;
  301. Core.Slots[slot].FrameNumber = Core.FrameCounter;
  302. Core.Slots[slot].QueueTime = TimeSpanType.FromTimeSpan(_tickSource.ElapsedTime);
  303. Core.Slots[slot].PresentationTime = TimeSpanType.Zero;
  304. item.AcquireCalled = Core.Slots[slot].AcquireCalled;
  305. item.Crop = input.Crop;
  306. item.Transform = input.Transform;
  307. item.TransformToDisplayInverse = (input.Transform & NativeWindowTransform.InverseDisplay) == NativeWindowTransform.InverseDisplay;
  308. item.ScalingMode = input.ScalingMode;
  309. item.Timestamp = input.Timestamp;
  310. item.IsAutoTimestamp = input.IsAutoTimestamp != 0;
  311. item.SwapInterval = input.SwapInterval;
  312. item.FrameNumber = Core.FrameCounter;
  313. item.Slot = slot;
  314. item.Fence = input.Fence;
  315. item.IsDroppable = Core.DequeueBufferCannotBlock || input.Async != 0;
  316. item.GraphicBuffer.Set(Core.Slots[slot].GraphicBuffer);
  317. item.GraphicBuffer.Object.IncrementNvMapHandleRefCount(Core.Owner);
  318. Core.BufferHistoryPosition = (Core.BufferHistoryPosition + 1) % BufferQueueCore.BufferHistoryArraySize;
  319. Core.BufferHistory[Core.BufferHistoryPosition] = new BufferInfo
  320. {
  321. FrameNumber = Core.FrameCounter,
  322. QueueTime = Core.Slots[slot].QueueTime,
  323. State = BufferState.Queued
  324. };
  325. _stickyTransform = input.StickyTransform;
  326. if (Core.Queue.Count == 0)
  327. {
  328. Core.Queue.Add(item);
  329. frameAvailableListener = Core.ConsumerListener;
  330. }
  331. else
  332. {
  333. BufferItem frontItem = Core.Queue[0];
  334. if (frontItem.IsDroppable)
  335. {
  336. if (Core.StillTracking(ref frontItem))
  337. {
  338. Core.Slots[slot].BufferState = BufferState.Free;
  339. Core.Slots[slot].FrameNumber = 0;
  340. }
  341. Core.Queue.RemoveAt(0);
  342. Core.Queue.Insert(0, item);
  343. frameReplaceListener = Core.ConsumerListener;
  344. }
  345. else
  346. {
  347. Core.Queue.Add(item);
  348. frameAvailableListener = Core.ConsumerListener;
  349. }
  350. }
  351. Core.BufferHasBeenQueued = true;
  352. Core.SignalDequeueEvent();
  353. Core.CheckSystemEventsLocked(maxBufferCount);
  354. output = new QueueBufferOutput
  355. {
  356. Width = (uint)Core.DefaultWidth,
  357. Height = (uint)Core.DefaultHeight,
  358. TransformHint = Core.TransformHint,
  359. NumPendingBuffers = (uint)Core.Queue.Count
  360. };
  361. if ((input.StickyTransform & 8) != 0)
  362. {
  363. output.TransformHint |= NativeWindowTransform.ReturnFrameNumber;
  364. output.FrameNumber = Core.Slots[slot].FrameNumber;
  365. }
  366. _callbackTicket = _nextCallbackTicket++;
  367. }
  368. lock (_callbackLock)
  369. {
  370. while (_callbackTicket != _currentCallbackTicket)
  371. {
  372. Monitor.Wait(_callbackLock);
  373. }
  374. frameAvailableListener?.OnFrameAvailable(ref item);
  375. frameReplaceListener?.OnFrameReplaced(ref item);
  376. _currentCallbackTicket++;
  377. Monitor.PulseAll(_callbackLock);
  378. }
  379. Core.SignalQueueEvent();
  380. return Status.Success;
  381. }
  382. public override void CancelBuffer(int slot, ref AndroidFence fence)
  383. {
  384. lock (Core.Lock)
  385. {
  386. if (Core.IsAbandoned || slot < 0 || slot >= Core.Slots.Length || !Core.IsOwnedByProducerLocked(slot))
  387. {
  388. return;
  389. }
  390. Core.Slots[slot].BufferState = BufferState.Free;
  391. Core.Slots[slot].FrameNumber = 0;
  392. Core.Slots[slot].Fence = fence;
  393. Core.SignalDequeueEvent();
  394. Core.SignalWaitBufferFreeEvent();
  395. }
  396. }
  397. public override Status Query(NativeWindowAttribute what, out int outValue)
  398. {
  399. lock (Core.Lock)
  400. {
  401. if (Core.IsAbandoned)
  402. {
  403. outValue = 0;
  404. return Status.NoInit;
  405. }
  406. switch (what)
  407. {
  408. case NativeWindowAttribute.Width:
  409. outValue = Core.DefaultWidth;
  410. return Status.Success;
  411. case NativeWindowAttribute.Height:
  412. outValue = Core.DefaultHeight;
  413. return Status.Success;
  414. case NativeWindowAttribute.Format:
  415. outValue = (int)Core.DefaultBufferFormat;
  416. return Status.Success;
  417. case NativeWindowAttribute.MinUnqueuedBuffers:
  418. outValue = Core.GetMinUndequeuedBufferCountLocked(false);
  419. return Status.Success;
  420. case NativeWindowAttribute.ConsumerRunningBehind:
  421. outValue = Core.Queue.Count > 1 ? 1 : 0;
  422. return Status.Success;
  423. case NativeWindowAttribute.ConsumerUsageBits:
  424. outValue = (int)Core.ConsumerUsageBits;
  425. return Status.Success;
  426. case NativeWindowAttribute.MaxBufferCountAsync:
  427. outValue = Core.GetMaxBufferCountLocked(true);
  428. return Status.Success;
  429. default:
  430. outValue = 0;
  431. return Status.BadValue;
  432. }
  433. }
  434. }
  435. public override Status Connect(IProducerListener listener, NativeWindowApi api, bool producerControlledByApp, out QueueBufferOutput output)
  436. {
  437. output = new QueueBufferOutput();
  438. lock (Core.Lock)
  439. {
  440. if (Core.IsAbandoned || Core.ConsumerListener == null)
  441. {
  442. return Status.NoInit;
  443. }
  444. if (Core.ConnectedApi != NativeWindowApi.NoApi)
  445. {
  446. return Status.BadValue;
  447. }
  448. Core.BufferHasBeenQueued = false;
  449. Core.DequeueBufferCannotBlock = Core.ConsumerControlledByApp && producerControlledByApp;
  450. switch (api)
  451. {
  452. case NativeWindowApi.NVN:
  453. case NativeWindowApi.CPU:
  454. case NativeWindowApi.Media:
  455. case NativeWindowApi.Camera:
  456. Core.ProducerListener = listener;
  457. Core.ConnectedApi = api;
  458. output.Width = (uint)Core.DefaultWidth;
  459. output.Height = (uint)Core.DefaultHeight;
  460. output.TransformHint = Core.TransformHint;
  461. output.NumPendingBuffers = (uint)Core.Queue.Count;
  462. if (NxSettings.Settings.TryGetValue("nv!nvn_no_vsync_capability", out object noVSyncCapability) && (bool)noVSyncCapability)
  463. {
  464. output.TransformHint |= NativeWindowTransform.NoVSyncCapability;
  465. }
  466. return Status.Success;
  467. default:
  468. return Status.BadValue;
  469. }
  470. }
  471. }
  472. public override Status Disconnect(NativeWindowApi api)
  473. {
  474. IProducerListener producerListener = null;
  475. Status status = Status.BadValue;
  476. lock (Core.Lock)
  477. {
  478. Core.WaitWhileAllocatingLocked();
  479. if (Core.IsAbandoned)
  480. {
  481. return Status.Success;
  482. }
  483. switch (api)
  484. {
  485. case NativeWindowApi.NVN:
  486. case NativeWindowApi.CPU:
  487. case NativeWindowApi.Media:
  488. case NativeWindowApi.Camera:
  489. if (Core.ConnectedApi == api)
  490. {
  491. Core.Queue.Clear();
  492. Core.FreeAllBuffersLocked();
  493. Core.SignalDequeueEvent();
  494. producerListener = Core.ProducerListener;
  495. Core.ProducerListener = null;
  496. Core.ConnectedApi = NativeWindowApi.NoApi;
  497. Core.SignalWaitBufferFreeEvent();
  498. Core.SignalFrameAvailableEvent();
  499. status = Status.Success;
  500. }
  501. break;
  502. }
  503. }
  504. producerListener?.OnBufferReleased();
  505. return status;
  506. }
  507. private int GetPreallocatedBufferCountLocked()
  508. {
  509. int bufferCount = 0;
  510. for (int i = 0; i < Core.Slots.Length; i++)
  511. {
  512. if (Core.Slots[i].IsPreallocated)
  513. {
  514. bufferCount++;
  515. }
  516. }
  517. return bufferCount;
  518. }
  519. public override Status SetPreallocatedBuffer(int slot, AndroidStrongPointer<GraphicBuffer> graphicBuffer)
  520. {
  521. if (slot < 0 || slot >= Core.Slots.Length)
  522. {
  523. return Status.BadValue;
  524. }
  525. lock (Core.Lock)
  526. {
  527. Core.Slots[slot].BufferState = BufferState.Free;
  528. Core.Slots[slot].Fence = AndroidFence.NoFence;
  529. Core.Slots[slot].RequestBufferCalled = false;
  530. Core.Slots[slot].AcquireCalled = false;
  531. Core.Slots[slot].NeedsCleanupOnRelease = false;
  532. Core.Slots[slot].IsPreallocated = !graphicBuffer.IsNull;
  533. Core.Slots[slot].FrameNumber = 0;
  534. Core.Slots[slot].GraphicBuffer.Set(graphicBuffer);
  535. if (!Core.Slots[slot].GraphicBuffer.IsNull)
  536. {
  537. Core.Slots[slot].GraphicBuffer.Object.Buffer.Usage &= (int)Core.ConsumerUsageBits;
  538. }
  539. Core.OverrideMaxBufferCount = GetPreallocatedBufferCountLocked();
  540. Core.UseAsyncBuffer = false;
  541. if (!graphicBuffer.IsNull)
  542. {
  543. // NOTE: Nintendo set the default width, height and format from the GraphicBuffer..
  544. // This is entirely wrong and should only be controlled by the consumer...
  545. Core.DefaultWidth = graphicBuffer.Object.Width;
  546. Core.DefaultHeight = graphicBuffer.Object.Height;
  547. Core.DefaultBufferFormat = graphicBuffer.Object.Format;
  548. }
  549. else
  550. {
  551. bool allBufferFreed = true;
  552. for (int i = 0; i < Core.Slots.Length; i++)
  553. {
  554. if (!Core.Slots[i].GraphicBuffer.IsNull)
  555. {
  556. allBufferFreed = false;
  557. break;
  558. }
  559. }
  560. if (allBufferFreed)
  561. {
  562. Core.Queue.Clear();
  563. Core.FreeAllBuffersLocked();
  564. Core.SignalDequeueEvent();
  565. Core.SignalWaitBufferFreeEvent();
  566. Core.SignalFrameAvailableEvent();
  567. return Status.Success;
  568. }
  569. }
  570. Core.SignalDequeueEvent();
  571. Core.SignalWaitBufferFreeEvent();
  572. return Status.Success;
  573. }
  574. }
  575. private Status WaitForFreeSlotThenRelock(bool async, out int freeSlot, out Status returnStatus)
  576. {
  577. bool tryAgain = true;
  578. freeSlot = BufferSlotArray.InvalidBufferSlot;
  579. returnStatus = Status.Success;
  580. while (tryAgain)
  581. {
  582. if (Core.IsAbandoned)
  583. {
  584. freeSlot = BufferSlotArray.InvalidBufferSlot;
  585. return Status.NoInit;
  586. }
  587. int maxBufferCount = Core.GetMaxBufferCountLocked(async);
  588. if (async && Core.OverrideMaxBufferCount != 0 && Core.OverrideMaxBufferCount < maxBufferCount)
  589. {
  590. freeSlot = BufferSlotArray.InvalidBufferSlot;
  591. return Status.BadValue;
  592. }
  593. if (maxBufferCount < Core.MaxBufferCountCached)
  594. {
  595. for (int slot = maxBufferCount; slot < Core.MaxBufferCountCached; slot++)
  596. {
  597. if (Core.Slots[slot].BufferState == BufferState.Free && !Core.Slots[slot].GraphicBuffer.IsNull && !Core.Slots[slot].IsPreallocated)
  598. {
  599. Core.FreeBufferLocked(slot);
  600. returnStatus |= Status.ReleaseAllBuffers;
  601. }
  602. }
  603. }
  604. freeSlot = BufferSlotArray.InvalidBufferSlot;
  605. int dequeuedCount = 0;
  606. int acquiredCount = 0;
  607. for (int slot = 0; slot < maxBufferCount; slot++)
  608. {
  609. switch (Core.Slots[slot].BufferState)
  610. {
  611. case BufferState.Acquired:
  612. acquiredCount++;
  613. break;
  614. case BufferState.Dequeued:
  615. dequeuedCount++;
  616. break;
  617. case BufferState.Free:
  618. if (freeSlot == BufferSlotArray.InvalidBufferSlot || Core.Slots[slot].FrameNumber < Core.Slots[freeSlot].FrameNumber)
  619. {
  620. freeSlot = slot;
  621. }
  622. break;
  623. default:
  624. break;
  625. }
  626. }
  627. // The producer SHOULD call SetBufferCount otherwise it's not allowed to dequeue multiple buffers.
  628. if (Core.OverrideMaxBufferCount == 0 && dequeuedCount > 0)
  629. {
  630. return Status.InvalidOperation;
  631. }
  632. if (Core.BufferHasBeenQueued)
  633. {
  634. int newUndequeuedCount = maxBufferCount - (dequeuedCount + 1);
  635. int minUndequeuedCount = Core.GetMinUndequeuedBufferCountLocked(async);
  636. if (newUndequeuedCount < minUndequeuedCount)
  637. {
  638. Logger.Error?.Print(LogClass.SurfaceFlinger, $"Min undequeued buffer count ({minUndequeuedCount}) exceeded (dequeued = {dequeuedCount} undequeued = {newUndequeuedCount})");
  639. return Status.InvalidOperation;
  640. }
  641. }
  642. bool tooManyBuffers = Core.Queue.Count > maxBufferCount;
  643. tryAgain = freeSlot == BufferSlotArray.InvalidBufferSlot || tooManyBuffers;
  644. if (tryAgain)
  645. {
  646. if (async || (Core.DequeueBufferCannotBlock && acquiredCount < Core.MaxAcquiredBufferCount))
  647. {
  648. Core.CheckSystemEventsLocked(maxBufferCount);
  649. return Status.WouldBlock;
  650. }
  651. Core.WaitDequeueEvent();
  652. if (!Core.Active)
  653. {
  654. break;
  655. }
  656. }
  657. }
  658. return Status.Success;
  659. }
  660. protected override KReadableEvent GetWaitBufferFreeEvent()
  661. {
  662. return Core.GetWaitBufferFreeEvent();
  663. }
  664. public override Status GetBufferHistory(int bufferHistoryCount, out Span<BufferInfo> bufferInfos)
  665. {
  666. if (bufferHistoryCount <= 0)
  667. {
  668. bufferInfos = Span<BufferInfo>.Empty;
  669. return Status.BadValue;
  670. }
  671. lock (Core.Lock)
  672. {
  673. bufferHistoryCount = Math.Min(bufferHistoryCount, Core.BufferHistory.Length);
  674. BufferInfo[] result = new BufferInfo[bufferHistoryCount];
  675. uint position = Core.BufferHistoryPosition;
  676. for (uint i = 0; i < bufferHistoryCount; i++)
  677. {
  678. result[i] = Core.BufferHistory[(position - i) % Core.BufferHistory.Length];
  679. position--;
  680. }
  681. bufferInfos = result;
  682. return Status.Success;
  683. }
  684. }
  685. }
  686. }