Move solution and projects to src
This commit is contained in:
331
src/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs
Normal file
331
src/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs
Normal file
@@ -0,0 +1,331 @@
|
||||
using Ryujinx.Graphics.Device;
|
||||
using Ryujinx.Graphics.Gpu.Engine.Compute;
|
||||
using Ryujinx.Graphics.Gpu.Engine.Dma;
|
||||
using Ryujinx.Graphics.Gpu.Engine.InlineToMemory;
|
||||
using Ryujinx.Graphics.Gpu.Engine.Threed;
|
||||
using Ryujinx.Graphics.Gpu.Engine.Twod;
|
||||
using Ryujinx.Graphics.Gpu.Memory;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a GPU General Purpose FIFO command processor.
|
||||
/// </summary>
|
||||
class GPFifoProcessor
|
||||
{
|
||||
private const int MacrosCount = 0x80;
|
||||
private const int MacroIndexMask = MacrosCount - 1;
|
||||
|
||||
private const int LoadInlineDataMethodOffset = 0x6d;
|
||||
private const int UniformBufferUpdateDataMethodOffset = 0x8e4;
|
||||
|
||||
private readonly GpuChannel _channel;
|
||||
|
||||
/// <summary>
|
||||
/// Channel memory manager.
|
||||
/// </summary>
|
||||
public MemoryManager MemoryManager => _channel.MemoryManager;
|
||||
|
||||
/// <summary>
|
||||
/// 3D Engine.
|
||||
/// </summary>
|
||||
public ThreedClass ThreedClass => _3dClass;
|
||||
|
||||
/// <summary>
|
||||
/// Internal GPFIFO state.
|
||||
/// </summary>
|
||||
private struct DmaState
|
||||
{
|
||||
public int Method;
|
||||
public int SubChannel;
|
||||
public int MethodCount;
|
||||
public bool NonIncrementing;
|
||||
public bool IncrementOnce;
|
||||
}
|
||||
|
||||
private DmaState _state;
|
||||
|
||||
private readonly ThreedClass _3dClass;
|
||||
private readonly ComputeClass _computeClass;
|
||||
private readonly InlineToMemoryClass _i2mClass;
|
||||
private readonly TwodClass _2dClass;
|
||||
private readonly DmaClass _dmaClass;
|
||||
|
||||
private readonly GPFifoClass _fifoClass;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the GPU General Purpose FIFO command processor.
|
||||
/// </summary>
|
||||
/// <param name="context">GPU context</param>
|
||||
/// <param name="channel">Channel that the GPFIFO processor belongs to</param>
|
||||
public GPFifoProcessor(GpuContext context, GpuChannel channel)
|
||||
{
|
||||
_channel = channel;
|
||||
|
||||
_fifoClass = new GPFifoClass(context, this);
|
||||
_3dClass = new ThreedClass(context, channel, _fifoClass);
|
||||
_computeClass = new ComputeClass(context, channel, _3dClass);
|
||||
_i2mClass = new InlineToMemoryClass(context, channel);
|
||||
_2dClass = new TwodClass(channel);
|
||||
_dmaClass = new DmaClass(context, channel, _3dClass);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes a command buffer.
|
||||
/// </summary>
|
||||
/// <param name="baseGpuVa">Base GPU virtual address of the command buffer</param>
|
||||
/// <param name="commandBuffer">Command buffer</param>
|
||||
public void Process(ulong baseGpuVa, ReadOnlySpan<int> commandBuffer)
|
||||
{
|
||||
for (int index = 0; index < commandBuffer.Length; index++)
|
||||
{
|
||||
int command = commandBuffer[index];
|
||||
|
||||
ulong gpuVa = baseGpuVa + (ulong)index * 4;
|
||||
|
||||
if (_state.MethodCount != 0)
|
||||
{
|
||||
if (TryFastI2mBufferUpdate(commandBuffer, ref index))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Send(gpuVa, _state.Method, command, _state.SubChannel, _state.MethodCount <= 1);
|
||||
|
||||
if (!_state.NonIncrementing)
|
||||
{
|
||||
_state.Method++;
|
||||
}
|
||||
|
||||
if (_state.IncrementOnce)
|
||||
{
|
||||
_state.NonIncrementing = true;
|
||||
}
|
||||
|
||||
_state.MethodCount--;
|
||||
}
|
||||
else
|
||||
{
|
||||
CompressedMethod meth = Unsafe.As<int, CompressedMethod>(ref command);
|
||||
|
||||
if (TryFastUniformBufferUpdate(meth, commandBuffer, index))
|
||||
{
|
||||
index += meth.MethodCount;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (meth.SecOp)
|
||||
{
|
||||
case SecOp.IncMethod:
|
||||
case SecOp.NonIncMethod:
|
||||
case SecOp.OneInc:
|
||||
_state.Method = meth.MethodAddress;
|
||||
_state.SubChannel = meth.MethodSubchannel;
|
||||
_state.MethodCount = meth.MethodCount;
|
||||
_state.IncrementOnce = meth.SecOp == SecOp.OneInc;
|
||||
_state.NonIncrementing = meth.SecOp == SecOp.NonIncMethod;
|
||||
break;
|
||||
case SecOp.ImmdDataMethod:
|
||||
Send(gpuVa, meth.MethodAddress, meth.ImmdData, meth.MethodSubchannel, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_3dClass.FlushUboDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to perform a fast Inline-to-Memory data update.
|
||||
/// If successful, all data will be copied at once, and <see cref="DmaState.MethodCount"/>
|
||||
/// command buffer entries will be consumed.
|
||||
/// </summary>
|
||||
/// <param name="commandBuffer">Command buffer where the data is contained</param>
|
||||
/// <param name="offset">Offset at <paramref name="commandBuffer"/> where the data is located, auto-incremented on success</param>
|
||||
/// <returns>True if the fast copy was successful, false otherwise</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool TryFastI2mBufferUpdate(ReadOnlySpan<int> commandBuffer, ref int offset)
|
||||
{
|
||||
if (_state.Method == LoadInlineDataMethodOffset && _state.NonIncrementing && _state.SubChannel <= 2)
|
||||
{
|
||||
int availableCount = commandBuffer.Length - offset;
|
||||
int consumeCount = Math.Min(_state.MethodCount, availableCount);
|
||||
|
||||
var data = commandBuffer.Slice(offset, consumeCount);
|
||||
|
||||
if (_state.SubChannel == 0)
|
||||
{
|
||||
_3dClass.LoadInlineData(data);
|
||||
}
|
||||
else if (_state.SubChannel == 1)
|
||||
{
|
||||
_computeClass.LoadInlineData(data);
|
||||
}
|
||||
else /* if (_state.SubChannel == 2) */
|
||||
{
|
||||
_i2mClass.LoadInlineData(data);
|
||||
}
|
||||
|
||||
offset += consumeCount - 1;
|
||||
_state.MethodCount -= consumeCount;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to perform a fast constant buffer data update.
|
||||
/// If successful, all data will be copied at once, and <see cref="CompressedMethod.MethodCount"/> + 1
|
||||
/// command buffer entries will be consumed.
|
||||
/// </summary>
|
||||
/// <param name="meth">Compressed method to be checked</param>
|
||||
/// <param name="commandBuffer">Command buffer where <paramref name="meth"/> is contained</param>
|
||||
/// <param name="offset">Offset at <paramref name="commandBuffer"/> where <paramref name="meth"/> is located</param>
|
||||
/// <returns>True if the fast copy was successful, false otherwise</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool TryFastUniformBufferUpdate(CompressedMethod meth, ReadOnlySpan<int> commandBuffer, int offset)
|
||||
{
|
||||
int availableCount = commandBuffer.Length - offset;
|
||||
|
||||
if (meth.MethodAddress == UniformBufferUpdateDataMethodOffset &&
|
||||
meth.MethodCount < availableCount &&
|
||||
meth.SecOp == SecOp.NonIncMethod)
|
||||
{
|
||||
_3dClass.ConstantBufferUpdate(commandBuffer.Slice(offset + 1, meth.MethodCount));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a uncompressed method for processing by the graphics pipeline.
|
||||
/// </summary>
|
||||
/// <param name="gpuVa">GPU virtual address where the command word is located</param>
|
||||
/// <param name="meth">Method to be processed</param>
|
||||
private void Send(ulong gpuVa, int offset, int argument, int subChannel, bool isLastCall)
|
||||
{
|
||||
if (offset < 0x60)
|
||||
{
|
||||
_fifoClass.Write(offset * 4, argument);
|
||||
}
|
||||
else if (offset < 0xe00)
|
||||
{
|
||||
offset *= 4;
|
||||
|
||||
switch (subChannel)
|
||||
{
|
||||
case 0:
|
||||
_3dClass.Write(offset, argument);
|
||||
break;
|
||||
case 1:
|
||||
_computeClass.Write(offset, argument);
|
||||
break;
|
||||
case 2:
|
||||
_i2mClass.Write(offset, argument);
|
||||
break;
|
||||
case 3:
|
||||
_2dClass.Write(offset, argument);
|
||||
break;
|
||||
case 4:
|
||||
_dmaClass.Write(offset, argument);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
IDeviceState state = subChannel switch
|
||||
{
|
||||
0 => _3dClass,
|
||||
3 => _2dClass,
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (state != null)
|
||||
{
|
||||
int macroIndex = (offset >> 1) & MacroIndexMask;
|
||||
|
||||
if ((offset & 1) != 0)
|
||||
{
|
||||
_fifoClass.MmePushArgument(macroIndex, gpuVa, argument);
|
||||
}
|
||||
else
|
||||
{
|
||||
_fifoClass.MmeStart(macroIndex, argument);
|
||||
}
|
||||
|
||||
if (isLastCall)
|
||||
{
|
||||
_fifoClass.CallMme(macroIndex, state);
|
||||
|
||||
_3dClass.PerformDeferredDraws();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes data directly to the state of the specified class.
|
||||
/// </summary>
|
||||
/// <param name="classId">ID of the class to write the data into</param>
|
||||
/// <param name="offset">State offset in bytes</param>
|
||||
/// <param name="value">Value to be written</param>
|
||||
public void Write(ClassId classId, int offset, int value)
|
||||
{
|
||||
switch (classId)
|
||||
{
|
||||
case ClassId.Threed:
|
||||
_3dClass.Write(offset, value);
|
||||
break;
|
||||
case ClassId.Compute:
|
||||
_computeClass.Write(offset, value);
|
||||
break;
|
||||
case ClassId.InlineToMemory:
|
||||
_i2mClass.Write(offset, value);
|
||||
break;
|
||||
case ClassId.Twod:
|
||||
_2dClass.Write(offset, value);
|
||||
break;
|
||||
case ClassId.Dma:
|
||||
_dmaClass.Write(offset, value);
|
||||
break;
|
||||
case ClassId.GPFifo:
|
||||
_fifoClass.Write(offset, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the shadow ram control value of all sub-channels.
|
||||
/// </summary>
|
||||
/// <param name="control">New shadow ram control value</param>
|
||||
public void SetShadowRamControl(int control)
|
||||
{
|
||||
_3dClass.SetShadowRamControl(control);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forces a full host state update by marking all state as modified,
|
||||
/// and also requests all GPU resources in use to be rebound.
|
||||
/// </summary>
|
||||
public void ForceAllDirty()
|
||||
{
|
||||
_3dClass.ForceStateDirty();
|
||||
_channel.BufferManager.Rebind();
|
||||
_channel.TextureManager.Rebind();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform any deferred draws.
|
||||
/// </summary>
|
||||
public void PerformDeferredDraws()
|
||||
{
|
||||
_3dClass.PerformDeferredDraws();
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user