diff options
Diffstat (limited to 'src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/ConsumerBase.cs')
-rw-r--r-- | src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/ConsumerBase.cs | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/ConsumerBase.cs b/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/ConsumerBase.cs new file mode 100644 index 00000000..49fceed9 --- /dev/null +++ b/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/ConsumerBase.cs @@ -0,0 +1,175 @@ +using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types; +using System; + +namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger +{ + class ConsumerBase : IConsumerListener + { + public class Slot + { + public AndroidStrongPointer<GraphicBuffer> GraphicBuffer; + public AndroidFence Fence; + public ulong FrameNumber; + + public Slot() + { + GraphicBuffer = new AndroidStrongPointer<GraphicBuffer>(); + } + } + + protected Slot[] Slots = new Slot[BufferSlotArray.NumBufferSlots]; + + protected bool IsAbandoned; + + protected BufferQueueConsumer Consumer; + + protected readonly object Lock = new object(); + + private IConsumerListener _listener; + + public ConsumerBase(BufferQueueConsumer consumer, bool controlledByApp, IConsumerListener listener) + { + for (int i = 0; i < Slots.Length; i++) + { + Slots[i] = new Slot(); + } + + IsAbandoned = false; + Consumer = consumer; + _listener = listener; + + Status connectStatus = consumer.Connect(this, controlledByApp); + + if (connectStatus != Status.Success) + { + throw new InvalidOperationException(); + } + } + + public virtual void OnBuffersReleased() + { + lock (Lock) + { + if (IsAbandoned) + { + return; + } + + Consumer.GetReleasedBuffers(out ulong slotMask); + + for (int i = 0; i < Slots.Length; i++) + { + if ((slotMask & (1UL << i)) != 0) + { + FreeBufferLocked(i); + } + } + } + } + + public virtual void OnFrameAvailable(ref BufferItem item) + { + _listener?.OnFrameAvailable(ref item); + } + + public virtual void OnFrameReplaced(ref BufferItem item) + { + _listener?.OnFrameReplaced(ref item); + } + + protected virtual void FreeBufferLocked(int slotIndex) + { + Slots[slotIndex].GraphicBuffer.Reset(); + + Slots[slotIndex].Fence = AndroidFence.NoFence; + Slots[slotIndex].FrameNumber = 0; + } + + public void Abandon() + { + lock (Lock) + { + if (!IsAbandoned) + { + AbandonLocked(); + + IsAbandoned = true; + } + } + } + + protected virtual void AbandonLocked() + { + for (int i = 0; i < Slots.Length; i++) + { + FreeBufferLocked(i); + } + + Consumer.Disconnect(); + } + + protected virtual Status AcquireBufferLocked(out BufferItem bufferItem, ulong expectedPresent) + { + Status acquireStatus = Consumer.AcquireBuffer(out bufferItem, expectedPresent); + + if (acquireStatus != Status.Success) + { + return acquireStatus; + } + + if (!bufferItem.GraphicBuffer.IsNull) + { + Slots[bufferItem.Slot].GraphicBuffer.Set(bufferItem.GraphicBuffer.Object); + } + + Slots[bufferItem.Slot].FrameNumber = bufferItem.FrameNumber; + Slots[bufferItem.Slot].Fence = bufferItem.Fence; + + return Status.Success; + } + + protected virtual Status AddReleaseFenceLocked(int slot, ref AndroidStrongPointer<GraphicBuffer> graphicBuffer, ref AndroidFence fence) + { + if (!StillTracking(slot, ref graphicBuffer)) + { + return Status.Success; + } + + Slots[slot].Fence = fence; + + return Status.Success; + } + + protected virtual Status ReleaseBufferLocked(int slot, ref AndroidStrongPointer<GraphicBuffer> graphicBuffer) + { + if (!StillTracking(slot, ref graphicBuffer)) + { + return Status.Success; + } + + Status result = Consumer.ReleaseBuffer(slot, Slots[slot].FrameNumber, ref Slots[slot].Fence); + + if (result == Status.StaleBufferSlot) + { + FreeBufferLocked(slot); + } + + Slots[slot].Fence = AndroidFence.NoFence; + + return result; + } + + protected virtual bool StillTracking(int slotIndex, ref AndroidStrongPointer<GraphicBuffer> graphicBuffer) + { + if (slotIndex < 0 || slotIndex >= Slots.Length) + { + return false; + } + + Slot slot = Slots[slotIndex]; + + // TODO: Check this. On Android, this checks the "handle". I assume NvMapHandle is the handle, but it might not be. + return !slot.GraphicBuffer.IsNull && slot.GraphicBuffer.Object.Buffer.Surfaces[0].NvMapHandle == graphicBuffer.Object.Buffer.Surfaces[0].NvMapHandle; + } + } +} |