Esempio n. 1
0
        public bool Wait(GpuContext gpuContext, NvFence fence)
        {
            lock (Lock)
            {
                Fence = fence;
                State = NvHostEventState.Waiting;

                // NOTE: nvservices code should always wait on the GPU side.
                //       If we do this, we may get an abort or undefined behaviour when the GPU processing thread is blocked for a long period (for example, during shader compilation).
                //       The reason for this is that the NVN code will try to wait until giving up.
                //       This is done by trying to wait and signal multiple times until aborting after you are past the timeout.
                //       As such, if it fails too many time, we enforce a wait on the CPU side indefinitely.
                //       This allows to keep GPU and CPU in sync when we are slow.
                if (_failingCount == FailingCountMax)
                {
                    Logger.PrintWarning(LogClass.ServiceNv, "GPU processing thread is too slow, waiting on CPU...");

                    bool timedOut = Fence.Wait(gpuContext, Timeout.InfiniteTimeSpan);

                    GpuSignaled();

                    return(timedOut);
                }
                else
                {
                    _waiterInformation = gpuContext.Synchronization.RegisterCallbackOnSyncpoint(Fence.Id, Fence.Value, GpuSignaled);

                    return(true);
                }
            }
        }
Esempio n. 2
0
        public void Cancel(GpuContext gpuContext)
        {
            lock (Lock)
            {
                if (_waiterInformation != null)
                {
                    gpuContext.Synchronization.UnregisterCallback(Fence.Id, _waiterInformation);

                    if (_previousFailingFence.Id == Fence.Id && _previousFailingFence.Value == Fence.Value)
                    {
                        _failingCount++;
                    }
                    else
                    {
                        _failingCount = 1;

                        _previousFailingFence = Fence;
                    }

                    Signal();
                }

                Event.WritableEvent.Clear();
            }
        }
Esempio n. 3
0
        public void Wait(GpuContext gpuContext, NvFence fence)
        {
            Fence = fence;
            State = NvHostEventState.Waiting;

            _waiterInformation = gpuContext.Synchronization.RegisterCallbackOnSyncpoint(Fence.Id, Fence.Value, GpuSignaled);
        }
Esempio n. 4
0
        public void Cancel(GpuContext gpuContext)
        {
            lock (Lock)
            {
                NvHostEventState oldState = State;

                State = NvHostEventState.Cancelling;

                if (oldState == NvHostEventState.Waiting && _waiterInformation != null)
                {
                    gpuContext.Synchronization.UnregisterCallback(Fence.Id, _waiterInformation);
                    _waiterInformation = null;

                    if (_previousFailingFence.Id == Fence.Id && _previousFailingFence.Value == Fence.Value)
                    {
                        _failingCount++;
                    }
                    else
                    {
                        _failingCount = 1;

                        _previousFailingFence = Fence;
                    }
                }

                State = NvHostEventState.Cancelled;

                Event.WritableEvent.Clear();
            }
        }
Esempio n. 5
0
        private static int[] CreateWaitCommandBuffer(NvFence fence)
        {
            int[] result = new int[4];

            // SyncpointValue = fence.Value;
            result[0] = 0x2001001C;
            result[1] = (int)fence.Value;

            // SyncpointAction(fence.id, increment: false, switch_en: true);
            result[2] = 0x2001001D;
            result[3] = (((int)fence.Id << 8) | (0 << 0) | (1 << 4));

            return(result);
        }
Esempio n. 6
0
        private NvInternalResult SyncptReadMinOrMax(ref NvFence arguments, bool max)
        {
            if (arguments.Id >= SynchronizationManager.MaxHardwareSyncpoints)
            {
                return(NvInternalResult.InvalidInput);
            }

            if (max)
            {
                arguments.Value = _device.System.HostSyncpoint.ReadSyncpointMaxValue(arguments.Id);
            }
            else
            {
                arguments.Value = _device.System.HostSyncpoint.ReadSyncpointValue(arguments.Id);
            }

            return(NvInternalResult.Success);
        }
Esempio n. 7
0
        private NvInternalResult SyncptReadMinOrMax(ref NvFence arguments, bool max)
        {
            if (arguments.Id >= NvHostSyncpt.SyncptsCount)
            {
                return(NvInternalResult.InvalidInput);
            }

            if (max)
            {
                arguments.Value = (uint)_syncpt.GetMax((int)arguments.Id);
            }
            else
            {
                arguments.Value = (uint)_syncpt.GetMin((int)arguments.Id);
            }

            return(NvInternalResult.Success);
        }
Esempio n. 8
0
        private int[] CreateIncrementCommandBuffer(ref NvFence fence, SubmitGpfifoFlags flags)
        {
            bool hasWfi = !flags.HasFlag(SubmitGpfifoFlags.SuppressWfi);

            int[] result;

            int offset = 0;

            if (hasWfi)
            {
                result = new int[8];

                // WaitForInterupt(handle)
                result[offset++] = 0x2001001E;
                result[offset++] = 0x0;
            }
            else
            {
                result = new int[6];
            }

            // SyncpointValue = 0x0;
            result[offset++] = 0x2001001C;
            result[offset++] = 0x0;

            // Increment the syncpoint 2 time. (mitigate an hardware bug)

            // SyncpointAction(fence.id, increment: true, switch_en: false);
            result[offset++] = 0x2001001D;
            result[offset++] = (((int)fence.Id << 8) | (1 << 0) | (0 << 4));

            // SyncpointAction(fence.id, increment: true, switch_en: false);
            result[offset++] = 0x2001001D;
            result[offset++] = (((int)fence.Id << 8) | (1 << 0) | (0 << 4));

            return(result);
        }
Esempio n. 9
0
 public void AddFence(NvFence fence)
 {
     NvFences[FenceCount++] = fence;
 }
Esempio n. 10
0
        private NvInternalResult EventWait(ref NvFence fence, ref uint value, int timeout, bool isWaitEventAsyncCmd, bool isWaitEventCmd)
        {
            if (fence.Id >= SynchronizationManager.MaxHardwareSyncpoints)
            {
                return(NvInternalResult.InvalidInput);
            }

            // First try to check if the syncpoint is already expired on the CPU side
            if (_device.System.HostSyncpoint.IsSyncpointExpired(fence.Id, fence.Value))
            {
                value = _device.System.HostSyncpoint.ReadSyncpointMinValue(fence.Id);

                return(NvInternalResult.Success);
            }

            // Try to invalidate the CPU cache and check for expiration again.
            uint newCachedSyncpointValue = _device.System.HostSyncpoint.UpdateMin(fence.Id);

            // Has the fence already expired?
            if (_device.System.HostSyncpoint.IsSyncpointExpired(fence.Id, fence.Value))
            {
                value = newCachedSyncpointValue;

                return(NvInternalResult.Success);
            }

            // If the timeout is 0, directly return.
            if (timeout == 0)
            {
                return(NvInternalResult.TryAgain);
            }

            // The syncpoint value isn't at the fence yet, we need to wait.

            if (!isWaitEventAsyncCmd)
            {
                value = 0;
            }

            NvHostEvent hostEvent;

            NvInternalResult result;

            uint eventIndex;

            lock (_events)
            {
                if (isWaitEventAsyncCmd)
                {
                    eventIndex = value;

                    if (eventIndex >= EventsCount)
                    {
                        return(NvInternalResult.InvalidInput);
                    }

                    hostEvent = _events[eventIndex];
                }
                else
                {
                    hostEvent = GetFreeEventLocked(fence.Id, out eventIndex);
                }

                if (hostEvent != null)
                {
                    lock (hostEvent.Lock)
                    {
                        if (hostEvent.State == NvHostEventState.Available ||
                            hostEvent.State == NvHostEventState.Signaled ||
                            hostEvent.State == NvHostEventState.Cancelled)
                        {
                            bool timedOut = hostEvent.Wait(_device.Gpu, fence);

                            if (timedOut)
                            {
                                if (isWaitEventCmd)
                                {
                                    value = ((fence.Id & 0xfff) << 16) | 0x10000000;
                                }
                                else
                                {
                                    value = fence.Id << 4;
                                }

                                value |= eventIndex;

                                result = NvInternalResult.TryAgain;
                            }
                            else
                            {
                                value = fence.Value;

                                return(NvInternalResult.Success);
                            }
                        }
                        else
                        {
                            Logger.Error?.Print(LogClass.ServiceNv, $"Invalid Event at index {eventIndex} (isWaitEventAsyncCmd: {isWaitEventAsyncCmd}, isWaitEventCmd: {isWaitEventCmd})");

                            if (hostEvent != null)
                            {
                                Logger.Error?.Print(LogClass.ServiceNv, hostEvent.DumpState(_device.Gpu));
                            }

                            result = NvInternalResult.InvalidInput;
                        }
                    }
                }
                else
                {
                    Logger.Error?.Print(LogClass.ServiceNv, $"Invalid Event at index {eventIndex} (isWaitEventAsyncCmd: {isWaitEventAsyncCmd}, isWaitEventCmd: {isWaitEventCmd})");

                    result = NvInternalResult.InvalidInput;
                }
            }

            return(result);
        }
Esempio n. 11
0
 private NvInternalResult SyncptReadMax(ref NvFence arguments)
 {
     return(SyncptReadMinOrMax(ref arguments, max: true));
 }