Add XML documentation to Ryujinx.Graphics.Gpu
This commit is contained in:
parent
4a4e2f7c72
commit
f7bcc884e4
10 changed files with 355 additions and 30 deletions
|
@ -1,5 +1,8 @@
|
||||||
namespace Ryujinx.Graphics.Gpu
|
namespace Ryujinx.Graphics.Gpu
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// GPU engine class ID.
|
||||||
|
/// </summary>
|
||||||
enum ClassId
|
enum ClassId
|
||||||
{
|
{
|
||||||
Engine2D = 0x902d,
|
Engine2D = 0x902d,
|
||||||
|
|
|
@ -1,14 +1,48 @@
|
||||||
namespace Ryujinx.Graphics.Gpu
|
namespace Ryujinx.Graphics.Gpu
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Common Maxwell GPU constants.
|
||||||
|
/// </summary>
|
||||||
static class Constants
|
static class Constants
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Maximum number of compute uniform buffers.
|
||||||
|
/// </summary>
|
||||||
public const int TotalCpUniformBuffers = 8;
|
public const int TotalCpUniformBuffers = 8;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maximum number of compute storage buffers (this is a API limitation).
|
||||||
|
/// </summary>
|
||||||
public const int TotalCpStorageBuffers = 16;
|
public const int TotalCpStorageBuffers = 16;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maximum number of graphics uniform buffers.
|
||||||
|
/// </summary>
|
||||||
public const int TotalGpUniformBuffers = 18;
|
public const int TotalGpUniformBuffers = 18;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maximum number of graphics storage buffers (this is a API limitation).
|
||||||
|
/// </summary>
|
||||||
public const int TotalGpStorageBuffers = 16;
|
public const int TotalGpStorageBuffers = 16;
|
||||||
public const int TotalRenderTargets = 8;
|
|
||||||
public const int TotalShaderStages = 5;
|
/// <summary>
|
||||||
public const int TotalVertexBuffers = 16;
|
/// Maximum number of render target color buffers.
|
||||||
public const int TotalViewports = 8;
|
/// </summary>
|
||||||
|
public const int TotalRenderTargets = 8;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of shader stages.
|
||||||
|
/// </summary>
|
||||||
|
public const int TotalShaderStages = 5;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maximum number of vertex buffers.
|
||||||
|
/// </summary>
|
||||||
|
public const int TotalVertexBuffers = 16;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maximum number of viewports.
|
||||||
|
/// </summary>
|
||||||
|
public const int TotalViewports = 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,6 +3,9 @@ using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu
|
namespace Ryujinx.Graphics.Gpu
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// GPU DMA pusher, used to push commands to the GPU.
|
||||||
|
/// </summary>
|
||||||
public class DmaPusher
|
public class DmaPusher
|
||||||
{
|
{
|
||||||
private ConcurrentQueue<ulong> _ibBuffer;
|
private ConcurrentQueue<ulong> _ibBuffer;
|
||||||
|
@ -10,6 +13,9 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
private ulong _dmaPut;
|
private ulong _dmaPut;
|
||||||
private ulong _dmaGet;
|
private ulong _dmaGet;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Internal GPFIFO state.
|
||||||
|
/// </summary>
|
||||||
private struct DmaState
|
private struct DmaState
|
||||||
{
|
{
|
||||||
public int Method;
|
public int Method;
|
||||||
|
@ -34,6 +40,10 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
private AutoResetEvent _event;
|
private AutoResetEvent _event;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the GPU DMA pusher.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">GPU context that the pusher belongs to</param>
|
||||||
internal DmaPusher(GpuContext context)
|
internal DmaPusher(GpuContext context)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
|
@ -45,6 +55,10 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
_event = new AutoResetEvent(false);
|
_event = new AutoResetEvent(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pushes a GPFIFO entry.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entry">GPFIFO entry</param>
|
||||||
public void Push(ulong entry)
|
public void Push(ulong entry)
|
||||||
{
|
{
|
||||||
_ibBuffer.Enqueue(entry);
|
_ibBuffer.Enqueue(entry);
|
||||||
|
@ -52,16 +66,27 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
_event.Set();
|
_event.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Waits until commands are pushed to the FIFO.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if commands were received, false if wait timed out</returns>
|
||||||
public bool WaitForCommands()
|
public bool WaitForCommands()
|
||||||
{
|
{
|
||||||
return _event.WaitOne(8);
|
return _event.WaitOne(8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processes commands pushed to the FIFO.
|
||||||
|
/// </summary>
|
||||||
public void DispatchCalls()
|
public void DispatchCalls()
|
||||||
{
|
{
|
||||||
while (Step());
|
while (Step());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processes a single command on the FIFO.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
private bool Step()
|
private bool Step()
|
||||||
{
|
{
|
||||||
if (_dmaGet != _dmaPut)
|
if (_dmaGet != _dmaPut)
|
||||||
|
@ -162,6 +187,10 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets current non-immediate method call state.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="word">Compressed method word</param>
|
||||||
private void SetNonImmediateState(int word)
|
private void SetNonImmediateState(int word)
|
||||||
{
|
{
|
||||||
_state.Method = (word >> 0) & 0x1fff;
|
_state.Method = (word >> 0) & 0x1fff;
|
||||||
|
@ -169,6 +198,10 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
_state.MethodCount = (word >> 16) & 0x1fff;
|
_state.MethodCount = (word >> 16) & 0x1fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Forwards the method call to GPU engines.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="argument">Call argument</param>
|
||||||
private void CallMethod(int argument)
|
private void CallMethod(int argument)
|
||||||
{
|
{
|
||||||
_context.Fifo.CallMethod(new MethodParams(
|
_context.Fifo.CallMethod(new MethodParams(
|
||||||
|
|
|
@ -5,30 +5,68 @@ using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu
|
namespace Ryujinx.Graphics.Gpu
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// GPU emulation context.
|
||||||
|
/// </summary>
|
||||||
public class GpuContext
|
public class GpuContext
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Host renderer.
|
||||||
|
/// </summary>
|
||||||
public IRenderer Renderer { get; }
|
public IRenderer Renderer { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Physical memory access (it actually accesses the process memory, not actual physical memory).
|
||||||
|
/// </summary>
|
||||||
internal PhysicalMemory PhysicalMemory { get; private set; }
|
internal PhysicalMemory PhysicalMemory { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GPU memory manager.
|
||||||
|
/// </summary>
|
||||||
public MemoryManager MemoryManager { get; }
|
public MemoryManager MemoryManager { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GPU memory accessor.
|
||||||
|
/// </summary>
|
||||||
internal MemoryAccessor MemoryAccessor { get; }
|
internal MemoryAccessor MemoryAccessor { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GPU engine methods processing.
|
||||||
|
/// </summary>
|
||||||
internal Methods Methods { get; }
|
internal Methods Methods { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GPU commands FIFO.
|
||||||
|
/// </summary>
|
||||||
internal NvGpuFifo Fifo { get; }
|
internal NvGpuFifo Fifo { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DMA pusher.
|
||||||
|
/// </summary>
|
||||||
public DmaPusher DmaPusher { get; }
|
public DmaPusher DmaPusher { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Presentation window.
|
||||||
|
/// </summary>
|
||||||
public Window Window { get; }
|
public Window Window { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Internal sequence number, used to avoid needless resource data updates
|
||||||
|
/// in the middle of a command buffer before synchronizations.
|
||||||
|
/// </summary>
|
||||||
internal int SequenceNumber { get; private set; }
|
internal int SequenceNumber { get; private set; }
|
||||||
|
|
||||||
private readonly Lazy<Capabilities> _caps;
|
private readonly Lazy<Capabilities> _caps;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Host hardware capabilities.
|
||||||
|
/// </summary>
|
||||||
internal Capabilities Capabilities => _caps.Value;
|
internal Capabilities Capabilities => _caps.Value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the GPU emulation context.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="renderer">Host renderer</param>
|
||||||
public GpuContext(IRenderer renderer)
|
public GpuContext(IRenderer renderer)
|
||||||
{
|
{
|
||||||
Renderer = renderer;
|
Renderer = renderer;
|
||||||
|
@ -48,11 +86,20 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
_caps = new Lazy<Capabilities>(Renderer.GetCapabilities);
|
_caps = new Lazy<Capabilities>(Renderer.GetCapabilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Advances internal sequence number.
|
||||||
|
/// This forces the update of any modified GPU resource.
|
||||||
|
/// </summary>
|
||||||
internal void AdvanceSequence()
|
internal void AdvanceSequence()
|
||||||
{
|
{
|
||||||
SequenceNumber++;
|
SequenceNumber++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the process memory manager, after the application process is initialized.
|
||||||
|
/// This is required for any GPU memory access.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cpuMemory">CPU memory manager</param>
|
||||||
public void SetVmm(ARMeilleure.Memory.MemoryManager cpuMemory)
|
public void SetVmm(ARMeilleure.Memory.MemoryManager cpuMemory)
|
||||||
{
|
{
|
||||||
PhysicalMemory = new PhysicalMemory(cpuMemory);
|
PhysicalMemory = new PhysicalMemory(cpuMemory);
|
||||||
|
|
|
@ -1,12 +1,21 @@
|
||||||
namespace Ryujinx.Graphics.Gpu
|
namespace Ryujinx.Graphics.Gpu
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// General GPU and graphics configuration.
|
||||||
|
/// </summary>
|
||||||
public static class GraphicsConfig
|
public static class GraphicsConfig
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base directory used to write shader code dumps.
|
||||||
|
/// Set to null to disable code dumping.
|
||||||
|
/// </summary>
|
||||||
public static string ShadersDumpPath;
|
public static string ShadersDumpPath;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fast GPU time calculates the internal GPU time ticks as if the GPU was capable of
|
||||||
|
/// processing commands almost instantly, instead of using the host timer.
|
||||||
|
/// This can avoid lower resolution on some games when GPU performance is poor.
|
||||||
|
/// </summary>
|
||||||
public static bool FastGpuTime = true;
|
public static bool FastGpuTime = true;
|
||||||
|
|
||||||
public static bool DisableTUpdate;
|
|
||||||
public static bool DisableBUpdate;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,6 +5,9 @@ using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu
|
namespace Ryujinx.Graphics.Gpu
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Macro code interpreter.
|
||||||
|
/// </summary>
|
||||||
class MacroInterpreter
|
class MacroInterpreter
|
||||||
{
|
{
|
||||||
private enum AssignmentOperation
|
private enum AssignmentOperation
|
||||||
|
@ -42,10 +45,6 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
BitwiseNotAnd = 12
|
BitwiseNotAnd = 12
|
||||||
}
|
}
|
||||||
|
|
||||||
private GpuContext _context;
|
|
||||||
|
|
||||||
private NvGpuFifo _pFifo;
|
|
||||||
|
|
||||||
public Queue<int> Fifo { get; private set; }
|
public Queue<int> Fifo { get; private set; }
|
||||||
|
|
||||||
private int[] _gprs;
|
private int[] _gprs;
|
||||||
|
@ -61,16 +60,23 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
private int _pc;
|
private int _pc;
|
||||||
|
|
||||||
public MacroInterpreter(GpuContext context, NvGpuFifo pFifo)
|
/// <summary>
|
||||||
|
/// Creates a new instance of the macro code interpreter.
|
||||||
|
/// </summary>
|
||||||
|
public MacroInterpreter()
|
||||||
{
|
{
|
||||||
_context = context;
|
|
||||||
_pFifo = pFifo;
|
|
||||||
|
|
||||||
Fifo = new Queue<int>();
|
Fifo = new Queue<int>();
|
||||||
|
|
||||||
_gprs = new int[8];
|
_gprs = new int[8];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Executes a macro program until it exits.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mme">Code of the program to execute</param>
|
||||||
|
/// <param name="position">Start position to execute</param>
|
||||||
|
/// <param name="param">Optional argument passed to the program, 0 if not used</param>
|
||||||
|
/// <param name="state">Current GPU state</param>
|
||||||
public void Execute(int[] mme, int position, int param, GpuState state)
|
public void Execute(int[] mme, int position, int param, GpuState state)
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
|
@ -88,6 +94,10 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
Step(mme, state);
|
Step(mme, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets the internal interpreter state.
|
||||||
|
/// Call each time you run a new program.
|
||||||
|
/// </summary>
|
||||||
private void Reset()
|
private void Reset()
|
||||||
{
|
{
|
||||||
for (int index = 0; index < _gprs.Length; index++)
|
for (int index = 0; index < _gprs.Length; index++)
|
||||||
|
@ -101,6 +111,12 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
_carry = false;
|
_carry = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Executes a single instruction of the program.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mme">Program code to execute</param>
|
||||||
|
/// <param name="state">Current GPU state</param>
|
||||||
|
/// <returns>True to continue execution, false if the program exited</returns>
|
||||||
private bool Step(int[] mme, GpuState state)
|
private bool Step(int[] mme, GpuState state)
|
||||||
{
|
{
|
||||||
int baseAddr = _pc - 1;
|
int baseAddr = _pc - 1;
|
||||||
|
@ -226,12 +242,21 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
return !exit;
|
return !exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetches a single operation code from the program code.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mme">Program code</param>
|
||||||
private void FetchOpCode(int[] mme)
|
private void FetchOpCode(int[] mme)
|
||||||
{
|
{
|
||||||
_opCode = _pipeOp;
|
_opCode = _pipeOp;
|
||||||
_pipeOp = mme[_pc++];
|
_pipeOp = mme[_pc++];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the result of the current Arithmetic and Logic unit operation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">Current GPU state</param>
|
||||||
|
/// <returns>Operation result</returns>
|
||||||
private int GetAluResult(GpuState state)
|
private int GetAluResult(GpuState state)
|
||||||
{
|
{
|
||||||
AluOperation op = (AluOperation)(_opCode & 7);
|
AluOperation op = (AluOperation)(_opCode & 7);
|
||||||
|
@ -303,6 +328,13 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
throw new ArgumentException(nameof(_opCode));
|
throw new ArgumentException(nameof(_opCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the result of a Arithmetic and Logic operation using registers.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="aluOp">Arithmetic and Logic unit operation with registers</param>
|
||||||
|
/// <param name="a">First operand value</param>
|
||||||
|
/// <param name="b">Second operand value</param>
|
||||||
|
/// <returns>Operation result</returns>
|
||||||
private int GetAluResult(AluRegOperation aluOp, int a, int b)
|
private int GetAluResult(AluRegOperation aluOp, int a, int b)
|
||||||
{
|
{
|
||||||
switch (aluOp)
|
switch (aluOp)
|
||||||
|
@ -353,43 +385,70 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
throw new ArgumentOutOfRangeException(nameof(aluOp));
|
throw new ArgumentOutOfRangeException(nameof(aluOp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extracts a 32-bits signed integer constant from the current operation code.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
private int GetImm()
|
private int GetImm()
|
||||||
{
|
{
|
||||||
// Note: The immediate is signed, the sign-extension is intended here.
|
// Note: The immediate is signed, the sign-extension is intended here.
|
||||||
return _opCode >> 14;
|
return _opCode >> 14;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the current method address, for method calls.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">Packed address and increment value</param>
|
||||||
private void SetMethAddr(int value)
|
private void SetMethAddr(int value)
|
||||||
{
|
{
|
||||||
_methAddr = (value >> 0) & 0xfff;
|
_methAddr = (value >> 0) & 0xfff;
|
||||||
_methIncr = (value >> 12) & 0x3f;
|
_methIncr = (value >> 12) & 0x3f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the destination register value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">Value to set (usually the operation result)</param>
|
||||||
private void SetDstGpr(int value)
|
private void SetDstGpr(int value)
|
||||||
{
|
{
|
||||||
_gprs[(_opCode >> 8) & 7] = value;
|
_gprs[(_opCode >> 8) & 7] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets first operand value from the respective register.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Operand value</returns>
|
||||||
private int GetGprA()
|
private int GetGprA()
|
||||||
{
|
{
|
||||||
return GetGprValue((_opCode >> 11) & 7);
|
return GetGprValue((_opCode >> 11) & 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets second operand value from the respective register.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Operand value</returns>
|
||||||
private int GetGprB()
|
private int GetGprB()
|
||||||
{
|
{
|
||||||
return GetGprValue((_opCode >> 14) & 7);
|
return GetGprValue((_opCode >> 14) & 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value from a register, or 0 if the R0 register is specified.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">Index of the register</param>
|
||||||
|
/// <returns>Register value</returns>
|
||||||
private int GetGprValue(int index)
|
private int GetGprValue(int index)
|
||||||
{
|
{
|
||||||
return index != 0 ? _gprs[index] : 0;
|
return index != 0 ? _gprs[index] : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetches a call argument from the call argument FIFO.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The call argument, or 0 if the FIFO is empty</returns>
|
||||||
private int FetchParam()
|
private int FetchParam()
|
||||||
{
|
{
|
||||||
int value;
|
if (!Fifo.TryDequeue(out int value))
|
||||||
|
|
||||||
if (!Fifo.TryDequeue(out value))
|
|
||||||
{
|
{
|
||||||
Logger.PrintWarning(LogClass.Gpu, "Macro attempted to fetch an inexistent argument.");
|
Logger.PrintWarning(LogClass.Gpu, "Macro attempted to fetch an inexistent argument.");
|
||||||
|
|
||||||
|
@ -399,11 +458,22 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads data from a GPU register.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">Current GPU state</param>
|
||||||
|
/// <param name="reg">Register offset to read</param>
|
||||||
|
/// <returns>GPU register value</returns>
|
||||||
private int Read(GpuState state, int reg)
|
private int Read(GpuState state, int reg)
|
||||||
{
|
{
|
||||||
return state.Read(reg);
|
return state.Read(reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs a GPU method call.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">Current GPU state</param>
|
||||||
|
/// <param name="value">Call argument</param>
|
||||||
private void Send(GpuState state, int value)
|
private void Send(GpuState state, int value)
|
||||||
{
|
{
|
||||||
MethodParams meth = new MethodParams(_methAddr, value);
|
MethodParams meth = new MethodParams(_methAddr, value);
|
||||||
|
|
|
@ -1,14 +1,42 @@
|
||||||
namespace Ryujinx.Graphics
|
namespace Ryujinx.Graphics
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Method call parameters.
|
||||||
|
/// </summary>
|
||||||
struct MethodParams
|
struct MethodParams
|
||||||
{
|
{
|
||||||
public int Method { get; private set; }
|
/// <summary>
|
||||||
public int Argument { get; private set; }
|
/// Method offset.
|
||||||
public int SubChannel { get; private set; }
|
/// </summary>
|
||||||
public int MethodCount { get; private set; }
|
public int Method { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Method call argument.
|
||||||
|
/// </summary>
|
||||||
|
public int Argument { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sub-channel where the call should be sent.
|
||||||
|
/// </summary>
|
||||||
|
public int SubChannel { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For multiple calls to the same method, this is the remaining calls count.
|
||||||
|
/// </summary>
|
||||||
|
public int MethodCount { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates if the current call is the last one from a batch of calls to the same method.
|
||||||
|
/// </summary>
|
||||||
public bool IsLastCall => MethodCount <= 1;
|
public bool IsLastCall => MethodCount <= 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs the method call parameters structure.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="method">Method offset</param>
|
||||||
|
/// <param name="argument">Method call argument</param>
|
||||||
|
/// <param name="subChannel">Optional sub-channel where the method should be sent (not required for macro calls)</param>
|
||||||
|
/// <param name="methodCount">Optional remaining calls count (not required for macro calls)</param>
|
||||||
public MethodParams(
|
public MethodParams(
|
||||||
int method,
|
int method,
|
||||||
int argument,
|
int argument,
|
||||||
|
|
|
@ -2,6 +2,9 @@ using Ryujinx.Graphics.Gpu.State;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu
|
namespace Ryujinx.Graphics.Gpu
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// GPU commands FIFO.
|
||||||
|
/// </summary>
|
||||||
class NvGpuFifo
|
class NvGpuFifo
|
||||||
{
|
{
|
||||||
private const int MacrosCount = 0x80;
|
private const int MacrosCount = 0x80;
|
||||||
|
@ -13,25 +16,36 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
private GpuContext _context;
|
private GpuContext _context;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cached GPU macro program.
|
||||||
|
/// </summary>
|
||||||
private struct CachedMacro
|
private struct CachedMacro
|
||||||
{
|
{
|
||||||
public int Position { get; private set; }
|
public int Position { get; }
|
||||||
|
|
||||||
private bool _executionPending;
|
private bool _executionPending;
|
||||||
private int _argument;
|
private int _argument;
|
||||||
|
|
||||||
private MacroInterpreter _interpreter;
|
private MacroInterpreter _interpreter;
|
||||||
|
|
||||||
public CachedMacro(GpuContext context, NvGpuFifo fifo, int position)
|
/// <summary>
|
||||||
|
/// Creates a new instance of the GPU cached macro program.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="position">Macro code start position</param>
|
||||||
|
public CachedMacro(int position)
|
||||||
{
|
{
|
||||||
Position = position;
|
Position = position;
|
||||||
|
|
||||||
_executionPending = false;
|
_executionPending = false;
|
||||||
_argument = 0;
|
_argument = 0;
|
||||||
|
|
||||||
_interpreter = new MacroInterpreter(context, fifo);
|
_interpreter = new MacroInterpreter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the first argument for the macro call.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="argument">First argument</param>
|
||||||
public void StartExecution(int argument)
|
public void StartExecution(int argument)
|
||||||
{
|
{
|
||||||
_argument = argument;
|
_argument = argument;
|
||||||
|
@ -39,6 +53,11 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
_executionPending = true;
|
_executionPending = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Starts executing the macro program code.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mme">Program code</param>
|
||||||
|
/// <param name="state">Current GPU state</param>
|
||||||
public void Execute(int[] mme, GpuState state)
|
public void Execute(int[] mme, GpuState state)
|
||||||
{
|
{
|
||||||
if (_executionPending)
|
if (_executionPending)
|
||||||
|
@ -49,6 +68,10 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pushes a argument to the macro call argument FIFO.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="argument">Argument to be pushed</param>
|
||||||
public void PushArgument(int argument)
|
public void PushArgument(int argument)
|
||||||
{
|
{
|
||||||
_interpreter?.Fifo.Enqueue(argument);
|
_interpreter?.Fifo.Enqueue(argument);
|
||||||
|
@ -62,11 +85,24 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
private int[] _mme;
|
private int[] _mme;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GPU sub-channel information.
|
||||||
|
/// </summary>
|
||||||
private class SubChannel
|
private class SubChannel
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Sub-channel GPU state.
|
||||||
|
/// </summary>
|
||||||
public GpuState State { get; }
|
public GpuState State { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Engine bound to the sub-channel.
|
||||||
|
/// </summary>
|
||||||
public ClassId Class { get; set; }
|
public ClassId Class { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the GPU sub-channel.
|
||||||
|
/// </summary>
|
||||||
public SubChannel()
|
public SubChannel()
|
||||||
{
|
{
|
||||||
State = new GpuState();
|
State = new GpuState();
|
||||||
|
@ -75,6 +111,10 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
private SubChannel[] _subChannels;
|
private SubChannel[] _subChannels;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the GPU commands FIFO.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">GPU emulation context</param>
|
||||||
public NvGpuFifo(GpuContext context)
|
public NvGpuFifo(GpuContext context)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
|
@ -93,6 +133,10 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calls a GPU method.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="meth">GPU method call parameters</param>
|
||||||
public void CallMethod(MethodParams meth)
|
public void CallMethod(MethodParams meth)
|
||||||
{
|
{
|
||||||
if ((NvGpuFifoMeth)meth.Method == NvGpuFifoMeth.BindChannel)
|
if ((NvGpuFifoMeth)meth.Method == NvGpuFifoMeth.BindChannel)
|
||||||
|
@ -137,7 +181,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
{
|
{
|
||||||
int position = meth.Argument;
|
int position = meth.Argument;
|
||||||
|
|
||||||
_macros[_currMacroBindIndex++] = new CachedMacro(_context, this, position);
|
_macros[_currMacroBindIndex++] = new CachedMacro(position);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
namespace Ryujinx.Graphics.Gpu
|
namespace Ryujinx.Graphics.Gpu
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// GPU commands FIFO processor commands.
|
||||||
|
/// </summary>
|
||||||
enum NvGpuFifoMeth
|
enum NvGpuFifoMeth
|
||||||
{
|
{
|
||||||
BindChannel = 0,
|
BindChannel = 0,
|
||||||
|
|
|
@ -7,17 +7,45 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
{
|
{
|
||||||
using Texture = Image.Texture;
|
using Texture = Image.Texture;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GPU image presentation window.
|
||||||
|
/// </summary>
|
||||||
public class Window
|
public class Window
|
||||||
{
|
{
|
||||||
private readonly GpuContext _context;
|
private readonly GpuContext _context;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Texture presented on the window.
|
||||||
|
/// </summary>
|
||||||
private struct PresentationTexture
|
private struct PresentationTexture
|
||||||
{
|
{
|
||||||
public TextureInfo Info { get; }
|
/// <summary>
|
||||||
public ImageCrop Crop { get; }
|
/// Texture information.
|
||||||
public Action<object> Callback { get; }
|
/// </summary>
|
||||||
public object UserObj { get; }
|
public TextureInfo Info { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Texture crop region.
|
||||||
|
/// </summary>
|
||||||
|
public ImageCrop Crop { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Texture release callback.
|
||||||
|
/// </summary>
|
||||||
|
public Action<object> Callback { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// User defined object, passed to the release callback.
|
||||||
|
/// </summary>
|
||||||
|
public object UserObj { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the presentation texture.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="info">Information of the texture to be presented</param>
|
||||||
|
/// <param name="crop">Texture crop region</param>
|
||||||
|
/// <param name="callback">Texture release callback</param>
|
||||||
|
/// <param name="userObj">User defined object passed to the release callback, can be used to identify the texture</param>
|
||||||
public PresentationTexture(
|
public PresentationTexture(
|
||||||
TextureInfo info,
|
TextureInfo info,
|
||||||
ImageCrop crop,
|
ImageCrop crop,
|
||||||
|
@ -33,6 +61,10 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
private readonly ConcurrentQueue<PresentationTexture> _frameQueue;
|
private readonly ConcurrentQueue<PresentationTexture> _frameQueue;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the GPU presentation window.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">GPU emulation context</param>
|
||||||
public Window(GpuContext context)
|
public Window(GpuContext context)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
|
@ -40,6 +72,23 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
_frameQueue = new ConcurrentQueue<PresentationTexture>();
|
_frameQueue = new ConcurrentQueue<PresentationTexture>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enqueues a frame for presentation.
|
||||||
|
/// This method is thread safe and can be called from any thread.
|
||||||
|
/// When the texture is presented and not needed anymore, the release callback is called.
|
||||||
|
/// It's an error to modify the texture after calling this method, before the release callback is called.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="address">CPU virtual address of the texture data</param>
|
||||||
|
/// <param name="width">Texture width</param>
|
||||||
|
/// <param name="height">Texture height</param>
|
||||||
|
/// <param name="stride">Texture stride for linear texture, should be zero otherwise</param>
|
||||||
|
/// <param name="isLinear">Indicates if the texture is linear, normally false</param>
|
||||||
|
/// <param name="gobBlocksInY">GOB blocks in the Y direction, for block linear textures</param>
|
||||||
|
/// <param name="format">Texture format</param>
|
||||||
|
/// <param name="bytesPerPixel">Texture format bytes per pixel (must match the format)</param>
|
||||||
|
/// <param name="crop">Texture crop region</param>
|
||||||
|
/// <param name="callback">Texture release callback</param>
|
||||||
|
/// <param name="userObj">User defined object passed to the release callback</param>
|
||||||
public void EnqueueFrameThreadSafe(
|
public void EnqueueFrameThreadSafe(
|
||||||
ulong address,
|
ulong address,
|
||||||
int width,
|
int width,
|
||||||
|
@ -74,6 +123,11 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
_frameQueue.Enqueue(new PresentationTexture(info, crop, callback, userObj));
|
_frameQueue.Enqueue(new PresentationTexture(info, crop, callback, userObj));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Presents a texture on the queue.
|
||||||
|
/// If the queue is empty, then no texture is presented.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="swapBuffersCallback">Callback method to call when a new texture should be presented on the screen</param>
|
||||||
public void Present(Action swapBuffersCallback)
|
public void Present(Action swapBuffersCallback)
|
||||||
{
|
{
|
||||||
_context.AdvanceSequence();
|
_context.AdvanceSequence();
|
||||||
|
|
Reference in a new issue