| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867 |
- using Ryujinx.Common.Logging;
- using Ryujinx.HLE.HOS.Kernel.Threading;
- using Ryujinx.HLE.HOS.Services.Settings;
- using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
- using Ryujinx.HLE.HOS.Services.Time.Clock;
- using System;
- using System.Threading;
- namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
- {
- class BufferQueueProducer : IGraphicBufferProducer
- {
- public BufferQueueCore Core { get; }
- private uint _stickyTransform;
- private uint _nextCallbackTicket;
- private uint _currentCallbackTicket;
- private uint _callbackTicket;
- private readonly object _callbackLock = new object();
- public BufferQueueProducer(BufferQueueCore core)
- {
- Core = core;
- _stickyTransform = 0;
- _callbackTicket = 0;
- _nextCallbackTicket = 0;
- _currentCallbackTicket = 0;
- }
- public override Status RequestBuffer(int slot, out AndroidStrongPointer<GraphicBuffer> graphicBuffer)
- {
- graphicBuffer = new AndroidStrongPointer<GraphicBuffer>();
- lock (Core.Lock)
- {
- if (Core.IsAbandoned)
- {
- return Status.NoInit;
- }
- if (slot < 0 || slot >= Core.Slots.Length || !Core.IsOwnedByProducerLocked(slot))
- {
- return Status.BadValue;
- }
- graphicBuffer.Set(Core.Slots[slot].GraphicBuffer);
- Core.Slots[slot].RequestBufferCalled = true;
- return Status.Success;
- }
- }
- public override Status SetBufferCount(int bufferCount)
- {
- IConsumerListener listener = null;
- lock (Core.Lock)
- {
- if (Core.IsAbandoned)
- {
- return Status.NoInit;
- }
- if (bufferCount > BufferSlotArray.NumBufferSlots)
- {
- return Status.BadValue;
- }
- for (int slot = 0; slot < Core.Slots.Length; slot++)
- {
- if (Core.Slots[slot].BufferState == BufferState.Dequeued)
- {
- return Status.BadValue;
- }
- }
- if (bufferCount == 0)
- {
- Core.OverrideMaxBufferCount = 0;
- Core.SignalDequeueEvent();
- return Status.Success;
- }
- int minBufferSlots = Core.GetMinMaxBufferCountLocked(false);
- if (bufferCount < minBufferSlots)
- {
- return Status.BadValue;
- }
- int preallocatedBufferCount = GetPreallocatedBufferCountLocked();
- if (preallocatedBufferCount <= 0)
- {
- Core.Queue.Clear();
- Core.FreeAllBuffersLocked();
- }
- else if (preallocatedBufferCount < bufferCount)
- {
- Logger.Error?.Print(LogClass.SurfaceFlinger, "Not enough buffers. Try with more pre-allocated buffers");
- return Status.Success;
- }
- Core.OverrideMaxBufferCount = bufferCount;
- Core.SignalDequeueEvent();
- Core.SignalWaitBufferFreeEvent();
- listener = Core.ConsumerListener;
- }
- listener?.OnBuffersReleased();
- return Status.Success;
- }
- public override Status DequeueBuffer(out int slot,
- out AndroidFence fence,
- bool async,
- uint width,
- uint height,
- PixelFormat format,
- uint usage)
- {
- if ((width == 0 && height != 0) || (height == 0 && width != 0))
- {
- slot = BufferSlotArray.InvalidBufferSlot;
- fence = AndroidFence.NoFence;
- return Status.BadValue;
- }
- Status returnFlags = Status.Success;
- bool attachedByConsumer = false;
- lock (Core.Lock)
- {
- if (format == PixelFormat.Unknown)
- {
- format = Core.DefaultBufferFormat;
- }
- usage |= Core.ConsumerUsageBits;
- Status status = WaitForFreeSlotThenRelock(async, out slot, out returnFlags);
- if (status != Status.Success)
- {
- slot = BufferSlotArray.InvalidBufferSlot;
- fence = AndroidFence.NoFence;
- return status;
- }
- if (slot == BufferSlotArray.InvalidBufferSlot)
- {
- fence = AndroidFence.NoFence;
- Logger.Error?.Print(LogClass.SurfaceFlinger, "No available buffer slots");
- return Status.Busy;
- }
- attachedByConsumer = Core.Slots[slot].AttachedByConsumer;
- if (width == 0 || height == 0)
- {
- width = (uint)Core.DefaultWidth;
- height = (uint)Core.DefaultHeight;
- }
- GraphicBuffer graphicBuffer = Core.Slots[slot].GraphicBuffer.Object;
- if (Core.Slots[slot].GraphicBuffer.IsNull
- || graphicBuffer.Width != width
- || graphicBuffer.Height != height
- || graphicBuffer.Format != format
- || (graphicBuffer.Usage & usage) != usage)
- {
- if (!Core.Slots[slot].IsPreallocated)
- {
- slot = BufferSlotArray.InvalidBufferSlot;
- fence = AndroidFence.NoFence;
- return Status.NoMemory;
- }
- else
- {
- Logger.Error?.Print(LogClass.SurfaceFlinger,
- $"Preallocated buffer mismatch - slot {slot}\n" +
- $"available: Width = {graphicBuffer.Width} Height = {graphicBuffer.Height} Format = {graphicBuffer.Format} Usage = {graphicBuffer.Usage:x} " +
- $"requested: Width = {width} Height = {height} Format = {format} Usage = {usage:x}");
- slot = BufferSlotArray.InvalidBufferSlot;
- fence = AndroidFence.NoFence;
- return Status.NoInit;
- }
- }
- Core.Slots[slot].BufferState = BufferState.Dequeued;
- Core.UpdateMaxBufferCountCachedLocked(slot);
- fence = Core.Slots[slot].Fence;
- Core.Slots[slot].Fence = AndroidFence.NoFence;
- Core.Slots[slot].QueueTime = TimeSpanType.Zero;
- Core.Slots[slot].PresentationTime = TimeSpanType.Zero;
- Core.CheckSystemEventsLocked(Core.GetMaxBufferCountLocked(async));
- }
- if (attachedByConsumer)
- {
- returnFlags |= Status.BufferNeedsReallocation;
- }
- return returnFlags;
- }
- public override Status DetachBuffer(int slot)
- {
- lock (Core.Lock)
- {
- if (Core.IsAbandoned)
- {
- return Status.NoInit;
- }
- if (slot < 0 || slot >= Core.Slots.Length || !Core.IsOwnedByProducerLocked(slot))
- {
- return Status.BadValue;
- }
- if (!Core.Slots[slot].RequestBufferCalled)
- {
- Logger.Error?.Print(LogClass.SurfaceFlinger, $"Slot {slot} was detached without requesting a buffer");
- return Status.BadValue;
- }
- Core.FreeBufferLocked(slot);
- Core.SignalDequeueEvent();
- return Status.Success;
- }
- }
- public override Status DetachNextBuffer(out AndroidStrongPointer<GraphicBuffer> graphicBuffer, out AndroidFence fence)
- {
- lock (Core.Lock)
- {
- Core.WaitWhileAllocatingLocked();
- if (Core.IsAbandoned)
- {
- graphicBuffer = default;
- fence = AndroidFence.NoFence;
- return Status.NoInit;
- }
- int nextBufferSlot = BufferSlotArray.InvalidBufferSlot;
- for (int slot = 0; slot < Core.Slots.Length; slot++)
- {
- if (Core.Slots[slot].BufferState == BufferState.Free && !Core.Slots[slot].GraphicBuffer.IsNull)
- {
- if (nextBufferSlot == BufferSlotArray.InvalidBufferSlot || Core.Slots[slot].FrameNumber < Core.Slots[nextBufferSlot].FrameNumber)
- {
- nextBufferSlot = slot;
- }
- }
- }
- if (nextBufferSlot == BufferSlotArray.InvalidBufferSlot)
- {
- graphicBuffer = default;
- fence = AndroidFence.NoFence;
- return Status.NoMemory;
- }
- graphicBuffer = Core.Slots[nextBufferSlot].GraphicBuffer;
- fence = Core.Slots[nextBufferSlot].Fence;
- Core.FreeBufferLocked(nextBufferSlot);
- return Status.Success;
- }
- }
- public override Status AttachBuffer(out int slot, AndroidStrongPointer<GraphicBuffer> graphicBuffer)
- {
- lock (Core.Lock)
- {
- Core.WaitWhileAllocatingLocked();
- Status status = WaitForFreeSlotThenRelock(false, out slot, out Status returnFlags);
- if (status != Status.Success)
- {
- return status;
- }
- if (slot == BufferSlotArray.InvalidBufferSlot)
- {
- Logger.Error?.Print(LogClass.SurfaceFlinger, "No available buffer slots");
- return Status.Busy;
- }
- Core.UpdateMaxBufferCountCachedLocked(slot);
- Core.Slots[slot].GraphicBuffer.Set(graphicBuffer);
- Core.Slots[slot].BufferState = BufferState.Dequeued;
- Core.Slots[slot].Fence = AndroidFence.NoFence;
- Core.Slots[slot].RequestBufferCalled = true;
- return returnFlags;
- }
- }
- public override Status QueueBuffer(int slot, ref QueueBufferInput input, out QueueBufferOutput output)
- {
- output = default;
- switch (input.ScalingMode)
- {
- case NativeWindowScalingMode.Freeze:
- case NativeWindowScalingMode.ScaleToWindow:
- case NativeWindowScalingMode.ScaleCrop:
- case NativeWindowScalingMode.Unknown:
- case NativeWindowScalingMode.NoScaleCrop:
- break;
- default:
- return Status.BadValue;
- }
- BufferItem item = new BufferItem();
- IConsumerListener frameAvailableListener = null;
- IConsumerListener frameReplaceListener = null;
- lock (Core.Lock)
- {
- if (Core.IsAbandoned)
- {
- return Status.NoInit;
- }
- int maxBufferCount = Core.GetMaxBufferCountLocked(input.Async != 0);
- if (input.Async != 0 && Core.OverrideMaxBufferCount != 0 && Core.OverrideMaxBufferCount < maxBufferCount)
- {
- return Status.BadValue;
- }
- if (slot < 0 || slot >= Core.Slots.Length || !Core.IsOwnedByProducerLocked(slot))
- {
- return Status.BadValue;
- }
- if (!Core.Slots[slot].RequestBufferCalled)
- {
- Logger.Error?.Print(LogClass.SurfaceFlinger, $"Slot {slot} was queued without requesting a buffer");
- return Status.BadValue;
- }
- input.Crop.Intersect(Core.Slots[slot].GraphicBuffer.Object.ToRect(), out Rect croppedRect);
- if (croppedRect != input.Crop)
- {
- return Status.BadValue;
- }
- Core.Slots[slot].Fence = input.Fence;
- Core.Slots[slot].BufferState = BufferState.Queued;
- Core.FrameCounter++;
- Core.Slots[slot].FrameNumber = Core.FrameCounter;
- Core.Slots[slot].QueueTime = TimeSpanType.FromTimeSpan(ARMeilleure.State.ExecutionContext.ElapsedTime);
- Core.Slots[slot].PresentationTime = TimeSpanType.Zero;
- item.AcquireCalled = Core.Slots[slot].AcquireCalled;
- item.Crop = input.Crop;
- item.Transform = input.Transform;
- item.TransformToDisplayInverse = (input.Transform & NativeWindowTransform.InverseDisplay) == NativeWindowTransform.InverseDisplay;
- item.ScalingMode = input.ScalingMode;
- item.Timestamp = input.Timestamp;
- item.IsAutoTimestamp = input.IsAutoTimestamp != 0;
- item.SwapInterval = input.SwapInterval;
- item.FrameNumber = Core.FrameCounter;
- item.Slot = slot;
- item.Fence = input.Fence;
- item.IsDroppable = Core.DequeueBufferCannotBlock || input.Async != 0;
- item.GraphicBuffer.Set(Core.Slots[slot].GraphicBuffer);
- item.GraphicBuffer.Object.IncrementNvMapHandleRefCount(Core.Owner);
- Core.BufferHistoryPosition = (Core.BufferHistoryPosition + 1) % BufferQueueCore.BufferHistoryArraySize;
- Core.BufferHistory[Core.BufferHistoryPosition] = new BufferInfo
- {
- FrameNumber = Core.FrameCounter,
- QueueTime = Core.Slots[slot].QueueTime,
- State = BufferState.Queued
- };
- _stickyTransform = input.StickyTransform;
- if (Core.Queue.Count == 0)
- {
- Core.Queue.Add(item);
- frameAvailableListener = Core.ConsumerListener;
- }
- else
- {
- BufferItem frontItem = Core.Queue[0];
- if (frontItem.IsDroppable)
- {
- if (Core.StillTracking(ref frontItem))
- {
- Core.Slots[slot].BufferState = BufferState.Free;
- Core.Slots[slot].FrameNumber = 0;
- }
- Core.Queue.RemoveAt(0);
- Core.Queue.Insert(0, item);
- frameReplaceListener = Core.ConsumerListener;
- }
- else
- {
- Core.Queue.Add(item);
- frameAvailableListener = Core.ConsumerListener;
- }
- }
- Core.BufferHasBeenQueued = true;
- Core.SignalDequeueEvent();
- Core.CheckSystemEventsLocked(maxBufferCount);
- output = new QueueBufferOutput
- {
- Width = (uint)Core.DefaultWidth,
- Height = (uint)Core.DefaultHeight,
- TransformHint = Core.TransformHint,
- NumPendingBuffers = (uint)Core.Queue.Count
- };
- if ((input.StickyTransform & 8) != 0)
- {
- output.TransformHint |= NativeWindowTransform.ReturnFrameNumber;
- output.FrameNumber = Core.Slots[slot].FrameNumber;
- }
- _callbackTicket = _nextCallbackTicket++;
- }
- lock (_callbackLock)
- {
- while (_callbackTicket != _currentCallbackTicket)
- {
- Monitor.Wait(_callbackLock);
- }
- frameAvailableListener?.OnFrameAvailable(ref item);
- frameReplaceListener?.OnFrameReplaced(ref item);
- _currentCallbackTicket++;
- Monitor.PulseAll(_callbackLock);
- }
- Core.SignalQueueEvent();
- return Status.Success;
- }
- public override void CancelBuffer(int slot, ref AndroidFence fence)
- {
- lock (Core.Lock)
- {
- if (Core.IsAbandoned || slot < 0 || slot >= Core.Slots.Length || !Core.IsOwnedByProducerLocked(slot))
- {
- return;
- }
- Core.Slots[slot].BufferState = BufferState.Free;
- Core.Slots[slot].FrameNumber = 0;
- Core.Slots[slot].Fence = fence;
- Core.SignalDequeueEvent();
- Core.SignalWaitBufferFreeEvent();
- }
- }
- public override Status Query(NativeWindowAttribute what, out int outValue)
- {
- lock (Core.Lock)
- {
- if (Core.IsAbandoned)
- {
- outValue = 0;
- return Status.NoInit;
- }
- switch (what)
- {
- case NativeWindowAttribute.Width:
- outValue = Core.DefaultWidth;
- return Status.Success;
- case NativeWindowAttribute.Height:
- outValue = Core.DefaultHeight;
- return Status.Success;
- case NativeWindowAttribute.Format:
- outValue = (int)Core.DefaultBufferFormat;
- return Status.Success;
- case NativeWindowAttribute.MinUnqueuedBuffers:
- outValue = Core.GetMinUndequeuedBufferCountLocked(false);
- return Status.Success;
- case NativeWindowAttribute.ConsumerRunningBehind:
- outValue = Core.Queue.Count > 1 ? 1 : 0;
- return Status.Success;
- case NativeWindowAttribute.ConsumerUsageBits:
- outValue = (int)Core.ConsumerUsageBits;
- return Status.Success;
- case NativeWindowAttribute.MaxBufferCountAsync:
- outValue = Core.GetMaxBufferCountLocked(true);
- return Status.Success;
- default:
- outValue = 0;
- return Status.BadValue;
- }
- }
- }
- public override Status Connect(IProducerListener listener, NativeWindowApi api, bool producerControlledByApp, out QueueBufferOutput output)
- {
- output = new QueueBufferOutput();
- lock (Core.Lock)
- {
- if (Core.IsAbandoned || Core.ConsumerListener == null)
- {
- return Status.NoInit;
- }
- if (Core.ConnectedApi != NativeWindowApi.NoApi)
- {
- return Status.BadValue;
- }
- Core.BufferHasBeenQueued = false;
- Core.DequeueBufferCannotBlock = Core.ConsumerControlledByApp && producerControlledByApp;
- switch (api)
- {
- case NativeWindowApi.NVN:
- case NativeWindowApi.CPU:
- case NativeWindowApi.Media:
- case NativeWindowApi.Camera:
- Core.ProducerListener = listener;
- Core.ConnectedApi = api;
- output.Width = (uint)Core.DefaultWidth;
- output.Height = (uint)Core.DefaultHeight;
- output.TransformHint = Core.TransformHint;
- output.NumPendingBuffers = (uint)Core.Queue.Count;
- if (NxSettings.Settings.TryGetValue("nv!nvn_no_vsync_capability", out object noVSyncCapability) && (bool)noVSyncCapability)
- {
- output.TransformHint |= NativeWindowTransform.NoVSyncCapability;
- }
- return Status.Success;
- default:
- return Status.BadValue;
- }
- }
- }
- public override Status Disconnect(NativeWindowApi api)
- {
- IProducerListener producerListener = null;
- Status status = Status.BadValue;
- lock (Core.Lock)
- {
- Core.WaitWhileAllocatingLocked();
- if (Core.IsAbandoned)
- {
- return Status.Success;
- }
- switch (api)
- {
- case NativeWindowApi.NVN:
- case NativeWindowApi.CPU:
- case NativeWindowApi.Media:
- case NativeWindowApi.Camera:
- if (Core.ConnectedApi == api)
- {
- Core.Queue.Clear();
- Core.FreeAllBuffersLocked();
- Core.SignalDequeueEvent();
- producerListener = Core.ProducerListener;
- Core.ProducerListener = null;
- Core.ConnectedApi = NativeWindowApi.NoApi;
- Core.SignalWaitBufferFreeEvent();
- Core.SignalFrameAvailableEvent();
- status = Status.Success;
- }
- break;
- }
- }
- producerListener?.OnBufferReleased();
- return status;
- }
- private int GetPreallocatedBufferCountLocked()
- {
- int bufferCount = 0;
- for (int i = 0; i < Core.Slots.Length; i++)
- {
- if (Core.Slots[i].IsPreallocated)
- {
- bufferCount++;
- }
- }
- return bufferCount;
- }
- public override Status SetPreallocatedBuffer(int slot, AndroidStrongPointer<GraphicBuffer> graphicBuffer)
- {
- if (slot < 0 || slot >= Core.Slots.Length)
- {
- return Status.BadValue;
- }
- lock (Core.Lock)
- {
- Core.Slots[slot].BufferState = BufferState.Free;
- Core.Slots[slot].Fence = AndroidFence.NoFence;
- Core.Slots[slot].RequestBufferCalled = false;
- Core.Slots[slot].AcquireCalled = false;
- Core.Slots[slot].NeedsCleanupOnRelease = false;
- Core.Slots[slot].IsPreallocated = !graphicBuffer.IsNull;
- Core.Slots[slot].FrameNumber = 0;
- Core.Slots[slot].GraphicBuffer.Set(graphicBuffer);
- if (!Core.Slots[slot].GraphicBuffer.IsNull)
- {
- Core.Slots[slot].GraphicBuffer.Object.Buffer.Usage &= (int)Core.ConsumerUsageBits;
- }
- Core.OverrideMaxBufferCount = GetPreallocatedBufferCountLocked();
- Core.UseAsyncBuffer = false;
- if (!graphicBuffer.IsNull)
- {
- // NOTE: Nintendo set the default width, height and format from the GraphicBuffer..
- // This is entirely wrong and should only be controlled by the consumer...
- Core.DefaultWidth = graphicBuffer.Object.Width;
- Core.DefaultHeight = graphicBuffer.Object.Height;
- Core.DefaultBufferFormat = graphicBuffer.Object.Format;
- }
- else
- {
- bool allBufferFreed = true;
- for (int i = 0; i < Core.Slots.Length; i++)
- {
- if (!Core.Slots[i].GraphicBuffer.IsNull)
- {
- allBufferFreed = false;
- break;
- }
- }
- if (allBufferFreed)
- {
- Core.Queue.Clear();
- Core.FreeAllBuffersLocked();
- Core.SignalDequeueEvent();
- Core.SignalWaitBufferFreeEvent();
- Core.SignalFrameAvailableEvent();
- return Status.Success;
- }
- }
- Core.SignalDequeueEvent();
- Core.SignalWaitBufferFreeEvent();
- return Status.Success;
- }
- }
- private Status WaitForFreeSlotThenRelock(bool async, out int freeSlot, out Status returnStatus)
- {
- bool tryAgain = true;
- freeSlot = BufferSlotArray.InvalidBufferSlot;
- returnStatus = Status.Success;
- while (tryAgain)
- {
- if (Core.IsAbandoned)
- {
- freeSlot = BufferSlotArray.InvalidBufferSlot;
- return Status.NoInit;
- }
- int maxBufferCount = Core.GetMaxBufferCountLocked(async);
- if (async && Core.OverrideMaxBufferCount != 0 && Core.OverrideMaxBufferCount < maxBufferCount)
- {
- freeSlot = BufferSlotArray.InvalidBufferSlot;
- return Status.BadValue;
- }
- if (maxBufferCount < Core.MaxBufferCountCached)
- {
- for (int slot = maxBufferCount; slot < Core.MaxBufferCountCached; slot++)
- {
- if (Core.Slots[slot].BufferState == BufferState.Free && !Core.Slots[slot].GraphicBuffer.IsNull && !Core.Slots[slot].IsPreallocated)
- {
- Core.FreeBufferLocked(slot);
- returnStatus |= Status.ReleaseAllBuffers;
- }
- }
- }
- freeSlot = BufferSlotArray.InvalidBufferSlot;
- int dequeuedCount = 0;
- int acquiredCount = 0;
- for (int slot = 0; slot < maxBufferCount; slot++)
- {
- switch (Core.Slots[slot].BufferState)
- {
- case BufferState.Acquired:
- acquiredCount++;
- break;
- case BufferState.Dequeued:
- dequeuedCount++;
- break;
- case BufferState.Free:
- if (freeSlot == BufferSlotArray.InvalidBufferSlot || Core.Slots[slot].FrameNumber < Core.Slots[freeSlot].FrameNumber)
- {
- freeSlot = slot;
- }
- break;
- default:
- break;
- }
- }
- // The producer SHOULD call SetBufferCount otherwise it's not allowed to dequeue multiple buffers.
- if (Core.OverrideMaxBufferCount == 0 && dequeuedCount > 0)
- {
- return Status.InvalidOperation;
- }
- if (Core.BufferHasBeenQueued)
- {
- int newUndequeuedCount = maxBufferCount - (dequeuedCount + 1);
- int minUndequeuedCount = Core.GetMinUndequeuedBufferCountLocked(async);
- if (newUndequeuedCount < minUndequeuedCount)
- {
- Logger.Error?.Print(LogClass.SurfaceFlinger, $"Min undequeued buffer count ({minUndequeuedCount}) exceeded (dequeued = {dequeuedCount} undequeued = {newUndequeuedCount})");
- return Status.InvalidOperation;
- }
- }
- bool tooManyBuffers = Core.Queue.Count > maxBufferCount;
- tryAgain = freeSlot == BufferSlotArray.InvalidBufferSlot || tooManyBuffers;
- if (tryAgain)
- {
- if (async || (Core.DequeueBufferCannotBlock && acquiredCount < Core.MaxAcquiredBufferCount))
- {
- Core.CheckSystemEventsLocked(maxBufferCount);
- return Status.WouldBlock;
- }
- Core.WaitDequeueEvent();
- if (!Core.Active)
- {
- break;
- }
- }
- }
- return Status.Success;
- }
- protected override KReadableEvent GetWaitBufferFreeEvent()
- {
- return Core.GetWaitBufferFreeEvent();
- }
- public override Status GetBufferHistory(int bufferHistoryCount, out Span<BufferInfo> bufferInfos)
- {
- if (bufferHistoryCount <= 0)
- {
- bufferInfos = Span<BufferInfo>.Empty;
- return Status.BadValue;
- }
- lock (Core.Lock)
- {
- bufferHistoryCount = Math.Min(bufferHistoryCount, Core.BufferHistory.Length);
- BufferInfo[] result = new BufferInfo[bufferHistoryCount];
- uint position = Core.BufferHistoryPosition;
- for (uint i = 0; i < bufferHistoryCount; i++)
- {
- result[i] = Core.BufferHistory[(position - i) % Core.BufferHistory.Length];
- position--;
- }
- bufferInfos = result;
- return Status.Success;
- }
- }
- }
- }
|