예제 #1
0
        private void PostFrameBuffer(Layer layer, BufferItem item)
        {
            int frameBufferWidth  = item.GraphicBuffer.Object.Width;
            int frameBufferHeight = item.GraphicBuffer.Object.Height;

            int nvMapHandle = item.GraphicBuffer.Object.Buffer.Surfaces[0].NvMapHandle;

            if (nvMapHandle == 0)
            {
                nvMapHandle = item.GraphicBuffer.Object.Buffer.NvMapId;
            }

            ulong bufferOffset = (ulong)item.GraphicBuffer.Object.Buffer.Surfaces[0].Offset;

            NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(layer.Owner, nvMapHandle);

            ulong frameBufferAddress = map.Address + bufferOffset;

            Format format = ConvertColorFormat(item.GraphicBuffer.Object.Buffer.Surfaces[0].ColorFormat);

            int bytesPerPixel =
                format == Format.B5G6R5Unorm ||
                format == Format.R4G4B4A4Unorm ? 2 : 4;

            int gobBlocksInY = 1 << item.GraphicBuffer.Object.Buffer.Surfaces[0].BlockHeightLog2;

            // Note: Rotation is being ignored.
            Rect cropRect = item.Crop;

            bool flipX = item.Transform.HasFlag(NativeWindowTransform.FlipX);
            bool flipY = item.Transform.HasFlag(NativeWindowTransform.FlipY);

            AspectRatio aspectRatio = _device.Configuration.AspectRatio;
            bool        isStretched = aspectRatio == AspectRatio.Stretched;

            ImageCrop crop = new ImageCrop(
                cropRect.Left,
                cropRect.Right,
                cropRect.Top,
                cropRect.Bottom,
                flipX,
                flipY,
                isStretched,
                aspectRatio.ToFloatX(),
                aspectRatio.ToFloatY());

            TextureCallbackInformation textureCallbackInformation = new TextureCallbackInformation
            {
                Layer = layer,
                Item  = item
            };

            _device.Gpu.Window.EnqueueFrameThreadSafe(
                layer.Owner,
                frameBufferAddress,
                frameBufferWidth,
                frameBufferHeight,
                0,
                false,
                gobBlocksInY,
                format,
                bytesPerPixel,
                crop,
                AcquireBuffer,
                ReleaseBuffer,
                textureCallbackInformation);

            if (item.Fence.FenceCount == 0)
            {
                _device.Gpu.Window.SignalFrameReady();
                _device.Gpu.GPFifo.Interrupt();
            }
            else
            {
                item.Fence.RegisterCallback(_device.Gpu, (x) =>
                {
                    _device.Gpu.Window.SignalFrameReady();
                    _device.Gpu.GPFifo.Interrupt();
                });
            }
        }
예제 #2
0
 public void OnFrameAvailable(ref BufferItem item)
 {
     _device.Statistics.RecordGameFrameTime();
 }
예제 #3
0
 public void OnFrameReplaced(ref BufferItem item)
 {
     _device.Statistics.RecordGameFrameTime();
 }
예제 #4
0
        private void PostFrameBuffer(Layer layer, BufferItem item)
        {
            int frameBufferWidth  = item.GraphicBuffer.Object.Width;
            int frameBufferHeight = item.GraphicBuffer.Object.Height;

            int nvMapHandle = item.GraphicBuffer.Object.Buffer.Surfaces[0].NvMapHandle;

            if (nvMapHandle == 0)
            {
                nvMapHandle = item.GraphicBuffer.Object.Buffer.NvMapId;
            }

            int bufferOffset = item.GraphicBuffer.Object.Buffer.Surfaces[0].Offset;

            NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(layer.Owner, nvMapHandle);

            ulong frameBufferAddress = (ulong)(map.Address + bufferOffset);

            Format format = ConvertColorFormat(item.GraphicBuffer.Object.Buffer.Surfaces[0].ColorFormat);

            int bytesPerPixel =
                format == Format.B5G6R5Unorm ||
                format == Format.R4G4B4A4Unorm ? 2 : 4;

            int gobBlocksInY = 1 << item.GraphicBuffer.Object.Buffer.Surfaces[0].BlockHeightLog2;

            // Note: Rotation is being ignored.
            Rect cropRect = item.Crop;

            bool flipX = item.Transform.HasFlag(NativeWindowTransform.FlipX);
            bool flipY = item.Transform.HasFlag(NativeWindowTransform.FlipY);

            ImageCrop crop = new ImageCrop(
                cropRect.Left,
                cropRect.Right,
                cropRect.Top,
                cropRect.Bottom,
                flipX,
                flipY);

            // Enforce that dequeueBuffer wait for the next vblank
            _vblankFence.NvFences[0].Value++;

            TextureCallbackInformation textureCallbackInformation = new TextureCallbackInformation
            {
                Layer = layer,
                Item  = item,
                Fence = _vblankFence
            };

            _device.Gpu.Window.EnqueueFrameThreadSafe(
                frameBufferAddress,
                frameBufferWidth,
                frameBufferHeight,
                0,
                false,
                gobBlocksInY,
                format,
                bytesPerPixel,
                crop,
                AcquireBuffer,
                ReleaseBuffer,
                textureCallbackInformation);
        }
예제 #5
0
        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.PrintDebug(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);
        }
예제 #6
0
 public virtual void OnFrameReplaced(ref BufferItem item)
 {
     _listener?.OnFrameReplaced(ref item);
 }
예제 #7
0
 public virtual void OnFrameAvailable(ref BufferItem item)
 {
     _listener?.OnFrameAvailable(ref item);
 }
예제 #8
0
        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.PrintError(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
                };

                _callbackTicket = _nextCallbackTicket++;
            }

            lock (_callbackLock)
            {
                while (_callbackTicket != _currentCallbackTicket)
                {
                    Monitor.Wait(_callbackLock);
                }

                frameAvailableListener?.OnFrameAvailable(ref item);
                frameReplaceListener?.OnFrameReplaced(ref item);

                _currentCallbackTicket++;

                Monitor.PulseAll(_callbackLock);
            }

            return(Status.Success);
        }