0
0
Fork 0
This repository has been archived on 2024-10-12. You can view files and clone it, but cannot push or open issues or pull requests.
ryujinx-final/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEvent.cs
mageven a33dc2f491
Improved Logger (#1292)
* Logger class changes only

Now compile-time checking is possible with the help of Nullable Value
types.

* Misc formatting

* Manual optimizations

PrintGuestLog
PrintGuestStackTrace
Surfaceflinger DequeueBuffer

* Reduce SendVibrationXX log level to Debug

* Add Notice log level

This level is always enabled and used to print system info, etc...
Also, rewrite LogColor to switch expression as colors are static

* Unify unhandled exception event handlers

* Print enabled LogLevels during init

* Re-add App Exit disposes in proper order

nit: switch case spacing

* Revert PrintGuestStackTrace to Info logs due to #1407

PrintGuestStackTrace is now called in some critical error handlers
so revert to old behavior as KThread isn't part of Guest.

* Batch replace Logger statements
2020-08-04 01:32:53 +02:00

162 lines
No EOL
5 KiB
C#

using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Gpu;
using Ryujinx.Graphics.Gpu.Synchronization;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Nv.Types;
using System;
using System.Threading;
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl
{
class NvHostEvent : IDisposable
{
public NvFence Fence;
public NvHostEventState State;
public KEvent Event;
private uint _eventId;
private NvHostSyncpt _syncpointManager;
private SyncpointWaiterHandle _waiterInformation;
private NvFence _previousFailingFence;
private uint _failingCount;
public object Lock = new object();
/// <summary>
/// Max failing count until waiting on CPU.
/// FIXME: This seems enough for most of the cases, reduce if needed.
/// </summary>
private const uint FailingCountMax = 2;
public NvHostEvent(NvHostSyncpt syncpointManager, uint eventId, Horizon system)
{
Fence.Id = 0;
State = NvHostEventState.Available;
Event = new KEvent(system.KernelContext);
_eventId = eventId;
_syncpointManager = syncpointManager;
ResetFailingState();
}
private void ResetFailingState()
{
_previousFailingFence.Id = NvFence.InvalidSyncPointId;
_previousFailingFence.Value = 0;
_failingCount = 0;
}
private void Signal()
{
lock (Lock)
{
NvHostEventState oldState = State;
State = NvHostEventState.Signaling;
if (oldState == NvHostEventState.Waiting)
{
Event.WritableEvent.Signal();
}
State = NvHostEventState.Signaled;
}
}
private void GpuSignaled()
{
lock (Lock)
{
ResetFailingState();
Signal();
}
}
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 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.Warning?.Print(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 string DumpState(GpuContext gpuContext)
{
string res = $"\nNvHostEvent {_eventId}:\n";
res += $"\tState: {State}\n";
if (State == NvHostEventState.Waiting)
{
res += "\tFence:\n";
res += $"\t\tId : {Fence.Id}\n";
res += $"\t\tThreshold : {Fence.Value}\n";
res += $"\t\tCurrent Value : {gpuContext.Synchronization.GetSyncpointValue(Fence.Id)}\n";
res += $"\t\tWaiter Valid : {_waiterInformation != null}\n";
}
return res;
}
public void Dispose()
{
Event.ReadableEvent.DecrementReferenceCount();
Event.WritableEvent.DecrementReferenceCount();
}
}
}