| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420 |
- using Ryujinx.Common.Logging;
- using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
- using Ryujinx.HLE.HOS.Services.Time.Clock;
- using System;
- namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
- {
- class BufferQueueConsumer
- {
- public BufferQueueCore Core { get; }
- public BufferQueueConsumer(BufferQueueCore core)
- {
- Core = core;
- }
- public Status AcquireBuffer(out BufferItem bufferItem, ulong expectedPresent)
- {
- lock (Core.Lock)
- {
- int numAcquiredBuffers = 0;
- for (int i = 0; i < Core.MaxBufferCountCached; i++)
- {
- if (Core.Slots[i].BufferState == BufferState.Acquired)
- {
- numAcquiredBuffers++;
- }
- }
- if (numAcquiredBuffers > Core.MaxAcquiredBufferCount)
- {
- bufferItem = null;
- Logger.Debug?.Print(LogClass.SurfaceFlinger, $"Max acquired buffer count reached: {numAcquiredBuffers} (max: {Core.MaxAcquiredBufferCount})");
- return Status.InvalidOperation;
- }
- if (Core.Queue.Count == 0)
- {
- bufferItem = null;
- return Status.NoBufferAvailaible;
- }
- if (expectedPresent != 0)
- {
- // TODO: support this for advanced presenting.
- throw new NotImplementedException();
- }
- bufferItem = Core.Queue[0];
- if (Core.StillTracking(ref bufferItem))
- {
- Core.Slots[bufferItem.Slot].AcquireCalled = true;
- Core.Slots[bufferItem.Slot].NeedsCleanupOnRelease = true;
- Core.Slots[bufferItem.Slot].BufferState = BufferState.Acquired;
- Core.Slots[bufferItem.Slot].Fence = AndroidFence.NoFence;
- ulong targetFrameNumber = Core.Slots[bufferItem.Slot].FrameNumber;
- for (int i = 0; i < Core.BufferHistory.Length; i++)
- {
- if (Core.BufferHistory[i].FrameNumber == targetFrameNumber)
- {
- Core.BufferHistory[i].State = BufferState.Acquired;
- break;
- }
- }
- }
- if (bufferItem.AcquireCalled)
- {
- bufferItem.GraphicBuffer.Reset();
- }
- Core.Queue.RemoveAt(0);
- Core.CheckSystemEventsLocked(Core.GetMaxBufferCountLocked(true));
- Core.SignalDequeueEvent();
- }
- return Status.Success;
- }
- public Status DetachBuffer(int slot)
- {
- lock (Core.Lock)
- {
- if (Core.IsAbandoned)
- {
- return Status.NoInit;
- }
- if (slot < 0 || slot >= Core.Slots.Length || !Core.IsOwnedByConsumerLocked(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 Status AttachBuffer(out int slot, ref AndroidStrongPointer<GraphicBuffer> graphicBuffer)
- {
- lock (Core.Lock)
- {
- int numAcquiredBuffers = 0;
- int freeSlot = BufferSlotArray.InvalidBufferSlot;
- for (int i = 0; i < Core.Slots.Length; i++)
- {
- if (Core.Slots[i].BufferState == BufferState.Acquired)
- {
- numAcquiredBuffers++;
- }
- else if (Core.Slots[i].BufferState == BufferState.Free)
- {
- if (freeSlot == BufferSlotArray.InvalidBufferSlot || Core.Slots[i].FrameNumber < Core.Slots[freeSlot].FrameNumber)
- {
- freeSlot = i;
- }
- }
- }
- if (numAcquiredBuffers > Core.MaxAcquiredBufferCount + 1)
- {
- slot = BufferSlotArray.InvalidBufferSlot;
- Logger.Error?.Print(LogClass.SurfaceFlinger, $"Max acquired buffer count reached: {numAcquiredBuffers} (max: {Core.MaxAcquiredBufferCount})");
- return Status.InvalidOperation;
- }
- if (freeSlot == BufferSlotArray.InvalidBufferSlot)
- {
- slot = BufferSlotArray.InvalidBufferSlot;
- return Status.NoMemory;
- }
- Core.UpdateMaxBufferCountCachedLocked(freeSlot);
- slot = freeSlot;
- Core.Slots[slot].GraphicBuffer.Set(graphicBuffer);
- Core.Slots[slot].BufferState = BufferState.Acquired;
- Core.Slots[slot].AttachedByConsumer = true;
- Core.Slots[slot].NeedsCleanupOnRelease = false;
- Core.Slots[slot].Fence = AndroidFence.NoFence;
- Core.Slots[slot].FrameNumber = 0;
- Core.Slots[slot].AcquireCalled = false;
- }
- return Status.Success;
- }
- public Status ReleaseBuffer(int slot, ulong frameNumber, ref AndroidFence fence)
- {
- if (slot < 0 || slot >= Core.Slots.Length)
- {
- return Status.BadValue;
- }
- IProducerListener listener = null;
- lock (Core.Lock)
- {
- if (Core.Slots[slot].FrameNumber != frameNumber)
- {
- return Status.StaleBufferSlot;
- }
- foreach (BufferItem item in Core.Queue)
- {
- if (item.Slot == slot)
- {
- return Status.BadValue;
- }
- }
- if (Core.Slots[slot].BufferState == BufferState.Acquired)
- {
- Core.Slots[slot].BufferState = BufferState.Free;
- Core.Slots[slot].Fence = fence;
- listener = Core.ProducerListener;
- }
- else if (Core.Slots[slot].NeedsCleanupOnRelease)
- {
- Core.Slots[slot].NeedsCleanupOnRelease = false;
- return Status.StaleBufferSlot;
- }
- else
- {
- return Status.BadValue;
- }
- Core.Slots[slot].GraphicBuffer.Object.DecrementNvMapHandleRefCount(Core.Owner);
- Core.CheckSystemEventsLocked(Core.GetMaxBufferCountLocked(true));
- Core.SignalDequeueEvent();
- }
- listener?.OnBufferReleased();
- return Status.Success;
- }
- public Status Connect(IConsumerListener consumerListener, bool controlledByApp)
- {
- if (consumerListener == null)
- {
- return Status.BadValue;
- }
- lock (Core.Lock)
- {
- if (Core.IsAbandoned)
- {
- return Status.NoInit;
- }
- Core.ConsumerListener = consumerListener;
- Core.ConsumerControlledByApp = controlledByApp;
- }
- return Status.Success;
- }
- public Status Disconnect()
- {
- lock (Core.Lock)
- {
- if (!Core.IsConsumerConnectedLocked())
- {
- return Status.BadValue;
- }
- Core.IsAbandoned = true;
- Core.ConsumerListener = null;
- Core.Queue.Clear();
- Core.FreeAllBuffersLocked();
- Core.SignalDequeueEvent();
- }
- return Status.Success;
- }
- public Status GetReleasedBuffers(out ulong slotMask)
- {
- slotMask = 0;
- lock (Core.Lock)
- {
- if (Core.IsAbandoned)
- {
- return Status.BadValue;
- }
- for (int slot = 0; slot < Core.Slots.Length; slot++)
- {
- if (!Core.Slots[slot].AcquireCalled)
- {
- slotMask |= 1UL << slot;
- }
- }
- for (int i = 0; i < Core.Queue.Count; i++)
- {
- if (Core.Queue[i].AcquireCalled)
- {
- slotMask &= ~(1UL << i);
- }
- }
- }
- return Status.Success;
- }
- public Status SetDefaultBufferSize(uint width, uint height)
- {
- if (width == 0 || height == 0)
- {
- return Status.BadValue;
- }
- lock (Core.Lock)
- {
- Core.DefaultWidth = (int)width;
- Core.DefaultHeight = (int)height;
- }
- return Status.Success;
- }
- public Status SetDefaultMaxBufferCount(int bufferMaxCount)
- {
- lock (Core.Lock)
- {
- return Core.SetDefaultMaxBufferCountLocked(bufferMaxCount);
- }
- }
- public Status DisableAsyncBuffer()
- {
- lock (Core.Lock)
- {
- if (Core.IsConsumerConnectedLocked())
- {
- return Status.InvalidOperation;
- }
- Core.UseAsyncBuffer = false;
- }
- return Status.Success;
- }
- public Status SetMaxAcquiredBufferCount(int maxAcquiredBufferCount)
- {
- if (maxAcquiredBufferCount < 0 || maxAcquiredBufferCount > BufferSlotArray.MaxAcquiredBuffers)
- {
- return Status.BadValue;
- }
- lock (Core.Lock)
- {
- if (Core.IsProducerConnectedLocked())
- {
- return Status.InvalidOperation;
- }
- Core.MaxAcquiredBufferCount = maxAcquiredBufferCount;
- }
- return Status.Success;
- }
- public Status SetDefaultBufferFormat(PixelFormat defaultFormat)
- {
- lock (Core.Lock)
- {
- Core.DefaultBufferFormat = defaultFormat;
- }
- return Status.Success;
- }
- public Status SetConsumerUsageBits(uint usage)
- {
- lock (Core.Lock)
- {
- Core.ConsumerUsageBits = usage;
- }
- return Status.Success;
- }
- public Status SetTransformHint(NativeWindowTransform transformHint)
- {
- lock (Core.Lock)
- {
- Core.TransformHint = transformHint;
- }
- return Status.Success;
- }
- public Status SetPresentTime(int slot, ulong frameNumber, TimeSpanType presentationTime)
- {
- if (slot < 0 || slot >= Core.Slots.Length)
- {
- return Status.BadValue;
- }
- lock (Core.Lock)
- {
- if (Core.Slots[slot].FrameNumber != frameNumber)
- {
- return Status.StaleBufferSlot;
- }
- if (Core.Slots[slot].PresentationTime.NanoSeconds == 0)
- {
- Core.Slots[slot].PresentationTime = presentationTime;
- }
- for (int i = 0; i < Core.BufferHistory.Length; i++)
- {
- if (Core.BufferHistory[i].FrameNumber == frameNumber)
- {
- Core.BufferHistory[i].PresentationTime = presentationTime;
- break;
- }
- }
- }
- return Status.Success;
- }
- }
- }
|