0
0
Fork 0
mirror of https://github.com/ryujinx-mirror/ryujinx.git synced 2024-10-19 23:41:41 +00:00
ryujinx-fork/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostCtrl/Types/NvHostEvent.cs
Thog 644de99e86
Implement GPU syncpoints (#980)
* Implement GPU syncpoints

This adds support for GPU syncpoints on the GPU backend & nvservices.

Everything that was implemented here is based on my researches,
hardware testing of the GM20B and reversing of nvservices (8.1.0).

Thanks to @fincs for the informations about some behaviours of the pusher
and for the initial informations about syncpoints.

* syncpoint: address gdkchan's comments

* Add some missing logic to handle SubmitGpfifo correctly

* Handle the NV event API correctly

* evnt => hostEvent

* Finish addressing gdkchan's comments

* nvservices: write the output buffer even when an error is returned

* dma pusher: Implemnet prefetch barrier

lso fix when the commands should be prefetch.

* Partially fix prefetch barrier

* Add a missing syncpoint check in QueryEvent of NvHostSyncPt

* Address Ac_K's comments and fix GetSyncpoint for ChannelResourcePolicy == Channel

* fix SyncptWait & SyncptWaitEx cmds logic

* Address ripinperi's comments

* Address gdkchan's comments

* Move user event management to the control channel

* Fix mm implementation, nvdec works again

* Address ripinperi's comments

* Address gdkchan's comments

* Implement nvhost-ctrl close accurately + make nvservices dispose channels when stopping the emulator

* Fix typo in MultiMediaOperationType
2020-04-19 11:25:57 +10:00

101 lines
No EOL
2.8 KiB
C#

using Ryujinx.Graphics.Gpu;
using Ryujinx.Graphics.Gpu.Synchronization;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Nv.Types;
using System;
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;
public NvHostEvent(NvHostSyncpt syncpointManager, uint eventId, Horizon system)
{
Fence.Id = 0;
State = NvHostEventState.Available;
Event = new KEvent(system);
_eventId = eventId;
_syncpointManager = syncpointManager;
}
public void Reset()
{
Fence.Id = NvFence.InvalidSyncPointId;
Fence.Value = 0;
State = NvHostEventState.Available;
}
private void Signal()
{
NvHostEventState oldState = State;
State = NvHostEventState.Signaling;
if (oldState == NvHostEventState.Waiting)
{
Event.WritableEvent.Signal();
}
State = NvHostEventState.Signaled;
}
private void GpuSignaled()
{
Signal();
}
public void Cancel(GpuContext gpuContext)
{
if (_waiterInformation != null)
{
gpuContext.Synchronization.UnregisterCallback(Fence.Id, _waiterInformation);
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 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();
}
}
}