public BufferSlot() { GraphicBuffer = new AndroidStrongPointer <GraphicBuffer>(); BufferState = BufferState.Free; QueueTime = TimeSpanType.Zero; PresentationTime = TimeSpanType.Zero; }
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); } }
public void WriteStrongPointer <T>(ref AndroidStrongPointer <T> value) where T : unmanaged, IFlattenable { WriteBoolean(!value.IsNull); if (!value.IsNull) { WriteFlattenable <T>(ref value.Object); } }
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); }
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 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); }
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(); }
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); }
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 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);
public void Set(AndroidStrongPointer <T> other) { Object = other.Object; _hasObject = other._hasObject; }
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);
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); } }
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);
public BufferSlot() { GraphicBuffer = new AndroidStrongPointer <GraphicBuffer>(); BufferState = BufferState.Free; }