BufferQueueProducer.cs 28 KB

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