Ryujinx/Ryujinx.Graphics.Gpu/Engine/MethodFifo.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

78 lines
2.6 KiB
C#

using Ryujinx.Graphics.Gpu.State;
using System;
using System.Threading;
namespace Ryujinx.Graphics.Gpu.Engine
{
partial class Methods
{
/// <summary>
/// Waits for the GPU to be idle.
/// </summary>
/// <param name="state">Current GPU state</param>
/// <param name="argument">Method call argument</param>
public void WaitForIdle(GpuState state, int argument)
{
PerformDeferredDraws();
_context.Renderer.Pipeline.Barrier();
}
/// <summary>
/// Send macro code/data to the MME.
/// </summary>
/// <param name="state">Current GPU state</param>
/// <param name="argument">Method call argument</param>
public void SendMacroCodeData(GpuState state, int argument)
{
int macroUploadAddress = state.Get<int>(MethodOffset.MacroUploadAddress);
_context.Fifo.SendMacroCodeData(macroUploadAddress++, argument);
state.Write((int)MethodOffset.MacroUploadAddress, macroUploadAddress);
}
/// <summary>
/// Bind a macro index to a position for the MME.
/// </summary>
/// <param name="state">Current GPU state</param>
/// <param name="argument">Method call argument</param>
public void BindMacro(GpuState state, int argument)
{
int macroBindingIndex = state.Get<int>(MethodOffset.MacroBindingIndex);
_context.Fifo.BindMacro(macroBindingIndex++, argument);
state.Write((int)MethodOffset.MacroBindingIndex, macroBindingIndex);
}
public void SetMmeShadowRamControl(GpuState state, int argument)
{
_context.Fifo.SetMmeShadowRamControl((ShadowRamControl)argument);
}
/// <summary>
/// Apply a fence operation on a syncpoint.
/// </summary>
/// <param name="state">Current GPU state</param>
/// <param name="argument">Method call argument</param>
public void FenceAction(GpuState state, int argument)
{
uint threshold = state.Get<uint>(MethodOffset.FenceValue);
FenceActionOperation operation = (FenceActionOperation)(argument & 1);
uint syncpointId = (uint)(argument >> 8) & 0xFF;
if (operation == FenceActionOperation.Acquire)
{
_context.Synchronization.WaitOnSyncpoint(syncpointId, threshold, Timeout.InfiniteTimeSpan);
}
else if (operation == FenceActionOperation.Increment)
{
_context.Synchronization.IncrementSyncpoint(syncpointId);
}
}
}
}