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); } } }
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(); } }
public void Wait(GpuContext gpuContext, NvFence fence) { Fence = fence; State = NvHostEventState.Waiting; _waiterInformation = gpuContext.Synchronization.RegisterCallbackOnSyncpoint(Fence.Id, Fence.Value, GpuSignaled); }
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(); } }
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); }
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); }
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); }
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); }
public void AddFence(NvFence fence) { NvFences[FenceCount++] = fence; }
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); }
private NvInternalResult SyncptReadMax(ref NvFence arguments) { return(SyncptReadMinOrMax(ref arguments, max: true)); }