BufferQueueProducer.cs 26 KB

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