示例#1
0
 public BufferSlot()
 {
     GraphicBuffer    = new AndroidStrongPointer <GraphicBuffer>();
     BufferState      = BufferState.Free;
     QueueTime        = TimeSpanType.Zero;
     PresentationTime = TimeSpanType.Zero;
 }
示例#2
0
        public override Status AttachBuffer(out int slot, AndroidStrongPointer <GraphicBuffer> graphicBuffer)
        {
            lock (Core.Lock)
            {
                Status status = WaitForFreeSlotThenRelock(false, out slot, out Status returnFlags);

                if (status != Status.Success)
                {
                    return(status);
                }

                if (slot == BufferSlotArray.InvalidBufferSlot)
                {
                    Logger.PrintError(LogClass.SurfaceFlinger, "No available buffer slots");

                    return(Status.Busy);
                }

                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);
            }
        }
示例#3
0
        public void WriteStrongPointer <T>(ref AndroidStrongPointer <T> value) where T : unmanaged, IFlattenable
        {
            WriteBoolean(!value.IsNull);

            if (!value.IsNull)
            {
                WriteFlattenable <T>(ref value.Object);
            }
        }
示例#4
0
        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.PrintError(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);
        }
示例#5
0
        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);
        }
示例#6
0
        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);
        }
示例#7
0
        public BufferItem()
        {
            GraphicBuffer             = new AndroidStrongPointer <GraphicBuffer>();
            Transform                 = NativeWindowTransform.None;
            ScalingMode               = NativeWindowScalingMode.Freeze;
            Timestamp                 = 0;
            IsAutoTimestamp           = false;
            FrameNumber               = 0;
            Slot                      = BufferSlotArray.InvalidBufferSlot;
            IsDroppable               = false;
            AcquireCalled             = false;
            TransformToDisplayInverse = false;
            SwapInterval              = 1;
            Fence                     = AndroidFence.NoFence;

            Crop = new Rect();
            Crop.MakeInvalid();
        }
示例#8
0
        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);
        }
示例#9
0
        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);
            }
        }
示例#10
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 abstract Status RequestBuffer(int slot, out AndroidStrongPointer <GraphicBuffer> graphicBuffer);
示例#12
0
 public void Set(AndroidStrongPointer <T> other)
 {
     Object     = other.Object;
     _hasObject = other._hasObject;
 }
示例#13
0
 public Slot()
 {
     GraphicBuffer = new AndroidStrongPointer <GraphicBuffer>();
 }
        public void OnTransact(uint code, uint flags, Parcel inputParcel, Parcel outputParcel)
        {
            Status            status = Status.Success;
            int               slot;
            AndroidFence      fence;
            QueueBufferInput  queueInput;
            QueueBufferOutput queueOutput;
            NativeWindowApi   api;

            AndroidStrongPointer <GraphicBuffer> graphicBuffer;
            AndroidStrongPointer <AndroidFence>  strongFence;

            switch ((TransactionCode)code)
            {
            case TransactionCode.RequestBuffer:
                slot = inputParcel.ReadInt32();

                status = RequestBuffer(slot, out graphicBuffer);

                outputParcel.WriteStrongPointer(ref graphicBuffer);

                outputParcel.WriteStatus(status);

                break;

            case TransactionCode.SetBufferCount:
                int bufferCount = inputParcel.ReadInt32();

                status = SetBufferCount(bufferCount);

                outputParcel.WriteStatus(status);

                break;

            case TransactionCode.DequeueBuffer:
                bool        async  = inputParcel.ReadBoolean();
                uint        width  = inputParcel.ReadUInt32();
                uint        height = inputParcel.ReadUInt32();
                PixelFormat format = inputParcel.ReadUnmanagedType <PixelFormat>();
                uint        usage  = inputParcel.ReadUInt32();

                status      = DequeueBuffer(out int dequeueSlot, out fence, async, width, height, format, usage);
                strongFence = new AndroidStrongPointer <AndroidFence>(fence);

                outputParcel.WriteInt32(dequeueSlot);
                outputParcel.WriteStrongPointer(ref strongFence);

                outputParcel.WriteStatus(status);

                break;

            case TransactionCode.DetachBuffer:
                slot = inputParcel.ReadInt32();

                status = DetachBuffer(slot);

                outputParcel.WriteStatus(status);

                break;

            case TransactionCode.DetachNextBuffer:
                status      = DetachNextBuffer(out graphicBuffer, out fence);
                strongFence = new AndroidStrongPointer <AndroidFence>(fence);

                outputParcel.WriteStrongPointer(ref graphicBuffer);
                outputParcel.WriteStrongPointer(ref strongFence);

                outputParcel.WriteStatus(status);

                break;

            case TransactionCode.AttachBuffer:
                graphicBuffer = inputParcel.ReadStrongPointer <GraphicBuffer>();

                status = AttachBuffer(out slot, graphicBuffer);

                outputParcel.WriteInt32(slot);

                outputParcel.WriteStatus(status);

                break;

            case TransactionCode.QueueBuffer:
                slot       = inputParcel.ReadInt32();
                queueInput = inputParcel.ReadFlattenable <QueueBufferInput>();

                status = QueueBuffer(slot, ref queueInput, out queueOutput);

                outputParcel.WriteUnmanagedType(ref queueOutput);

                outputParcel.WriteStatus(status);

                break;

            case TransactionCode.CancelBuffer:
                slot  = inputParcel.ReadInt32();
                fence = inputParcel.ReadFlattenable <AndroidFence>();

                CancelBuffer(slot, ref fence);

                outputParcel.WriteStatus(Status.Success);

                break;

            case TransactionCode.Query:
                NativeWindowAttribute what = inputParcel.ReadUnmanagedType <NativeWindowAttribute>();

                status = Query(what, out int outValue);

                outputParcel.WriteInt32(outValue);

                outputParcel.WriteStatus(status);

                break;

            case TransactionCode.Connect:
                bool hasListener = inputParcel.ReadBoolean();

                IProducerListener listener = null;

                if (hasListener)
                {
                    throw new NotImplementedException("Connect with a strong binder listener isn't implemented");
                }

                api = inputParcel.ReadUnmanagedType <NativeWindowApi>();

                bool producerControlledByApp = inputParcel.ReadBoolean();

                status = Connect(listener, api, producerControlledByApp, out queueOutput);

                outputParcel.WriteUnmanagedType(ref queueOutput);

                outputParcel.WriteStatus(status);

                break;

            case TransactionCode.Disconnect:
                api = inputParcel.ReadUnmanagedType <NativeWindowApi>();

                status = Disconnect(api);

                outputParcel.WriteStatus(status);

                break;

            case TransactionCode.SetPreallocatedBuffer:
                slot = inputParcel.ReadInt32();

                graphicBuffer = inputParcel.ReadStrongPointer <GraphicBuffer>();

                status = SetPreallocatedBuffer(slot, graphicBuffer);

                outputParcel.WriteStatus(status);

                break;

            default:
                throw new NotImplementedException($"Transaction {(TransactionCode)code} not implemented");
            }

            if (status != Status.Success)
            {
                Logger.PrintError(LogClass.SurfaceFlinger, $"Error returned by transaction {(TransactionCode)code}: {status}");
            }
        }
 public abstract Status SetPreallocatedBuffer(int slot, AndroidStrongPointer <GraphicBuffer> graphicBuffer);
 public abstract Status AttachBuffer(out int slot, AndroidStrongPointer <GraphicBuffer> graphicBuffer);
示例#17
0
        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);
            }
        }
示例#18
0
        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].FrameNumber           = 0;

                Core.Slots[slot].GraphicBuffer.Set(graphicBuffer);

                if (!Core.Slots[slot].GraphicBuffer.IsNull)
                {
                    Core.Slots[slot].GraphicBuffer.Object.Buffer.Usage &= (int)Core.ConsumerUsageBits;
                }

                int bufferCount = 0;

                for (int i = 0; i < Core.Slots.Length; i++)
                {
                    if (!Core.Slots[i].GraphicBuffer.IsNull)
                    {
                        bufferCount++;
                    }
                }

                Core.OverrideMaxBufferCount = bufferCount;
                Core.UseAsyncBuffer         = false;

                bool cleared = 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
                {
                    foreach (BufferItem item in Core.Queue)
                    {
                        if (item.Slot >= BufferSlotArray.NumBufferSlots)
                        {
                            Core.Queue.Clear();
                            Core.FreeAllBuffersLocked();
                            Core.SignalDequeueEvent();
                            Core.SignalWaitBufferFreeEvent();
                            Core.SignalFrameAvailableEvent();

                            cleared = true;

                            break;
                        }
                    }
                }

                // The dequeue event must not be signaled two times in case of clean up,
                // but for some reason, it still signals the wait buffer free event two times...
                if (!cleared)
                {
                    Core.SignalDequeueEvent();
                }

                Core.SignalWaitBufferFreeEvent();

                return(Status.Success);
            }
        }
 public abstract Status DetachNextBuffer(out AndroidStrongPointer <GraphicBuffer> graphicBuffer, out AndroidFence fence);
示例#20
0
 public BufferSlot()
 {
     GraphicBuffer = new AndroidStrongPointer <GraphicBuffer>();
     BufferState   = BufferState.Free;
 }