Separate GPU engines (part 2/2) (#2440)

* 3D engine now uses DeviceState too, plus new state modification tracking

* Remove old methods code

* Remove GpuState and friends

* Optimize DeviceState, force inline some functions

* This change was not supposed to go in

* Proper channel initialization

* Optimize state read/write methods even more

* Fix debug build

* Do not dirty state if the write is redundant

* The YControl register should dirty either the viewport or front face state too, to update the host origin

* Avoid redundant vertex buffer updates

* Move state and get rid of the Ryujinx.Graphics.Gpu.State namespace

* Comments and nits

* Fix rebase

* PR feedback

* Move changed = false to improve codegen

* PR feedback

* Carry RyuJIT a bit more
This commit is contained in:
gdkchan
2021-07-11 17:20:40 -03:00
committed by GitHub
parent b5190f1681
commit 40b21cc3c4
111 changed files with 5262 additions and 4020 deletions

View File

@ -0,0 +1,130 @@
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Engine.Types;
using Ryujinx.Graphics.Gpu.Memory;
namespace Ryujinx.Graphics.Gpu.Engine.Threed
{
/// <summary>
/// Helper methods used for conditional rendering.
/// </summary>
static class ConditionalRendering
{
/// <summary>
/// Checks if draws and clears should be performed, according
/// to currently set conditional rendering conditions.
/// </summary>
/// <param name="context">GPU context</param>
/// <param name="memoryManager">Memory manager bound to the channel currently executing</param>
/// <param name="address">Conditional rendering buffer address</param>
/// <param name="condition">Conditional rendering condition</param>
/// <returns>True if rendering is enabled, false otherwise</returns>
public static ConditionalRenderEnabled GetRenderEnable(GpuContext context, MemoryManager memoryManager, GpuVa address, Condition condition)
{
switch (condition)
{
case Condition.Always:
return ConditionalRenderEnabled.True;
case Condition.Never:
return ConditionalRenderEnabled.False;
case Condition.ResultNonZero:
return CounterNonZero(context, memoryManager, address.Pack());
case Condition.Equal:
return CounterCompare(context, memoryManager, address.Pack(), true);
case Condition.NotEqual:
return CounterCompare(context, memoryManager, address.Pack(), false);
}
Logger.Warning?.Print(LogClass.Gpu, $"Invalid conditional render condition \"{condition}\".");
return ConditionalRenderEnabled.True;
}
/// <summary>
/// Checks if the counter value at a given GPU memory address is non-zero.
/// </summary>
/// <param name="context">GPU context</param>
/// <param name="memoryManager">Memory manager bound to the channel currently executing</param>
/// <param name="gpuVa">GPU virtual address of the counter value</param>
/// <returns>True if the value is not zero, false otherwise. Returns host if handling with host conditional rendering</returns>
private static ConditionalRenderEnabled CounterNonZero(GpuContext context, MemoryManager memoryManager, ulong gpuVa)
{
ICounterEvent evt = memoryManager.CounterCache.FindEvent(gpuVa);
if (evt == null)
{
return ConditionalRenderEnabled.False;
}
if (context.Renderer.Pipeline.TryHostConditionalRendering(evt, 0L, false))
{
return ConditionalRenderEnabled.Host;
}
else
{
evt.Flush();
return (memoryManager.Read<ulong>(gpuVa) != 0) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False;
}
}
/// <summary>
/// Checks if the counter at a given GPU memory address passes a specified equality comparison.
/// </summary>
/// <param name="context">GPU context</param>
/// <param name="memoryManager">Memory manager bound to the channel currently executing</param>
/// <param name="gpuVa">GPU virtual address</param>
/// <param name="isEqual">True to check if the values are equal, false to check if they are not equal</param>
/// <returns>True if the condition is met, false otherwise. Returns host if handling with host conditional rendering</returns>
private static ConditionalRenderEnabled CounterCompare(GpuContext context, MemoryManager memoryManager, ulong gpuVa, bool isEqual)
{
ICounterEvent evt = FindEvent(memoryManager.CounterCache, gpuVa);
ICounterEvent evt2 = FindEvent(memoryManager.CounterCache, gpuVa + 16);
bool useHost;
if (evt != null && evt2 == null)
{
useHost = context.Renderer.Pipeline.TryHostConditionalRendering(evt, memoryManager.Read<ulong>(gpuVa + 16), isEqual);
}
else if (evt == null && evt2 != null)
{
useHost = context.Renderer.Pipeline.TryHostConditionalRendering(evt2, memoryManager.Read<ulong>(gpuVa), isEqual);
}
else if (evt != null && evt2 != null)
{
useHost = context.Renderer.Pipeline.TryHostConditionalRendering(evt, evt2, isEqual);
}
else
{
useHost = false;
}
if (useHost)
{
return ConditionalRenderEnabled.Host;
}
else
{
evt?.Flush();
evt2?.Flush();
ulong x = memoryManager.Read<ulong>(gpuVa);
ulong y = memoryManager.Read<ulong>(gpuVa + 16);
return (isEqual ? x == y : x != y) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False;
}
}
/// <summary>
/// Tries to find a counter that is supposed to be written at the specified address,
/// returning the related event.
/// </summary>
/// <param name="counterCache">GPU counter cache to search on</param>
/// <param name="gpuVa">GPU virtual address where the counter is supposed to be written</param>
/// <returns>The counter event, or null if not present</returns>
private static ICounterEvent FindEvent(CounterCache counterCache, ulong gpuVa)
{
return counterCache.FindEvent(gpuVa);
}
}
}

View File

@ -0,0 +1,173 @@
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Gpu.Engine.Threed
{
/// <summary>
/// Constant buffer updater.
/// </summary>
class ConstantBufferUpdater
{
private readonly GpuChannel _channel;
private readonly DeviceStateWithShadow<ThreedClassState> _state;
// State associated with direct uniform buffer updates.
// This state is used to attempt to batch together consecutive updates.
private ulong _ubBeginCpuAddress = 0;
private ulong _ubFollowUpAddress = 0;
private ulong _ubByteCount = 0;
/// <summary>
/// Creates a new instance of the constant buffer updater.
/// </summary>
/// <param name="channel">GPU channel</param>
/// <param name="state">Channel state</param>
public ConstantBufferUpdater(GpuChannel channel, DeviceStateWithShadow<ThreedClassState> state)
{
_channel = channel;
_state = state;
}
/// <summary>
/// Binds a uniform buffer for the vertex shader stage.
/// </summary>
/// <param name="argument">Method call argument</param>
public void BindVertex(int argument)
{
Bind(argument, ShaderType.Vertex);
}
/// <summary>
/// Binds a uniform buffer for the tessellation control shader stage.
/// </summary>
/// <param name="argument">Method call argument</param>
public void BindTessControl(int argument)
{
Bind(argument, ShaderType.TessellationControl);
}
/// <summary>
/// Binds a uniform buffer for the tessellation evaluation shader stage.
/// </summary>
/// <param name="argument">Method call argument</param>
public void BindTessEvaluation(int argument)
{
Bind(argument, ShaderType.TessellationEvaluation);
}
/// <summary>
/// Binds a uniform buffer for the geometry shader stage.
/// </summary>
/// <param name="argument">Method call argument</param>
public void BindGeometry(int argument)
{
Bind(argument, ShaderType.Geometry);
}
/// <summary>
/// Binds a uniform buffer for the fragment shader stage.
/// </summary>
/// <param name="argument">Method call argument</param>
public void BindFragment(int argument)
{
Bind(argument, ShaderType.Fragment);
}
/// <summary>
/// Binds a uniform buffer for the specified shader stage.
/// </summary>
/// <param name="argument">Method call argument</param>
/// <param name="type">Shader stage that will access the uniform buffer</param>
private void Bind(int argument, ShaderType type)
{
bool enable = (argument & 1) != 0;
int index = (argument >> 4) & 0x1f;
FlushUboDirty();
if (enable)
{
var uniformBuffer = _state.State.UniformBufferState;
ulong address = uniformBuffer.Address.Pack();
_channel.BufferManager.SetGraphicsUniformBuffer((int)type, index, address, (uint)uniformBuffer.Size);
}
else
{
_channel.BufferManager.SetGraphicsUniformBuffer((int)type, index, 0, 0);
}
}
/// <summary>
/// Flushes any queued UBO updates.
/// </summary>
public void FlushUboDirty()
{
if (_ubFollowUpAddress != 0)
{
var memoryManager = _channel.MemoryManager;
memoryManager.Physical.BufferCache.ForceDirty(memoryManager, _ubFollowUpAddress - _ubByteCount, _ubByteCount);
_ubFollowUpAddress = 0;
}
}
/// <summary>
/// Updates the uniform buffer data with inline data.
/// </summary>
/// <param name="argument">New uniform buffer data word</param>
public void Update(int argument)
{
var uniformBuffer = _state.State.UniformBufferState;
ulong address = uniformBuffer.Address.Pack() + (uint)uniformBuffer.Offset;
if (_ubFollowUpAddress != address)
{
FlushUboDirty();
_ubByteCount = 0;
_ubBeginCpuAddress = _channel.MemoryManager.Translate(address);
}
var byteData = MemoryMarshal.Cast<int, byte>(MemoryMarshal.CreateSpan(ref argument, 1));
_channel.MemoryManager.Physical.WriteUntracked(_ubBeginCpuAddress + _ubByteCount, byteData);
_ubFollowUpAddress = address + 4;
_ubByteCount += 4;
_state.State.UniformBufferState.Offset += 4;
}
/// <summary>
/// Updates the uniform buffer data with inline data.
/// </summary>
/// <param name="data">Data to be written to the uniform buffer</param>
public void Update(ReadOnlySpan<int> data)
{
var uniformBuffer = _state.State.UniformBufferState;
ulong address = uniformBuffer.Address.Pack() + (uint)uniformBuffer.Offset;
ulong size = (ulong)data.Length * 4;
if (_ubFollowUpAddress != address)
{
FlushUboDirty();
_ubByteCount = 0;
_ubBeginCpuAddress = _channel.MemoryManager.Translate(address);
}
var byteData = MemoryMarshal.Cast<int, byte>(data);
_channel.MemoryManager.Physical.WriteUntracked(_ubBeginCpuAddress + _ubByteCount, byteData);
_ubFollowUpAddress = address + size;
_ubByteCount += size;
_state.State.UniformBufferState.Offset += data.Length * 4;
}
}
}

View File

@ -0,0 +1,410 @@
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Engine.Types;
using System.Text;
namespace Ryujinx.Graphics.Gpu.Engine.Threed
{
/// <summary>
/// Draw manager.
/// </summary>
class DrawManager
{
private readonly GpuContext _context;
private readonly GpuChannel _channel;
private readonly DeviceStateWithShadow<ThreedClassState> _state;
private readonly DrawState _drawState;
private bool _instancedDrawPending;
private bool _instancedIndexed;
private int _instancedFirstIndex;
private int _instancedFirstVertex;
private int _instancedFirstInstance;
private int _instancedIndexCount;
private int _instancedDrawStateFirst;
private int _instancedDrawStateCount;
private int _instanceIndex;
/// <summary>
/// Creates a new instance of the draw manager.
/// </summary>
/// <param name="context">GPU context</param>
/// <param name="channel">GPU channel</param>
/// <param name="state">Channel state</param>
/// <param name="drawState">Draw state</param>
public DrawManager(GpuContext context, GpuChannel channel, DeviceStateWithShadow<ThreedClassState> state, DrawState drawState)
{
_context = context;
_channel = channel;
_state = state;
_drawState = drawState;
}
/// <summary>
/// Pushes four 8-bit index buffer elements.
/// </summary>
/// <param name="argument">Method call argument</param>
public void VbElementU8(int argument)
{
_drawState.IbStreamer.VbElementU8(_context.Renderer, argument);
}
/// <summary>
/// Pushes two 16-bit index buffer elements.
/// </summary>
/// <param name="argument">Method call argument</param>
public void VbElementU16(int argument)
{
_drawState.IbStreamer.VbElementU16(_context.Renderer, argument);
}
/// <summary>
/// Pushes one 32-bit index buffer element.
/// </summary>
/// <param name="argument">Method call argument</param>
public void VbElementU32(int argument)
{
_drawState.IbStreamer.VbElementU32(_context.Renderer, argument);
}
/// <summary>
/// Finishes the draw call.
/// This draws geometry on the bound buffers based on the current GPU state.
/// </summary>
/// <param name="engine">3D engine where this method is being called</param>
/// <param name="argument">Method call argument</param>
public void DrawEnd(ThreedClass engine, int argument)
{
DrawEnd(engine, _state.State.IndexBufferState.First, (int)_state.State.IndexBufferCount);
}
/// <summary>
/// Finishes the draw call.
/// This draws geometry on the bound buffers based on the current GPU state.
/// </summary>
/// <param name="engine">3D engine where this method is being called</param>
/// <param name="firstIndex">Index of the first index buffer element used on the draw</param>
/// <param name="indexCount">Number of index buffer elements used on the draw</param>
private void DrawEnd(ThreedClass engine, int firstIndex, int indexCount)
{
ConditionalRenderEnabled renderEnable = ConditionalRendering.GetRenderEnable(
_context,
_channel.MemoryManager,
_state.State.RenderEnableAddress,
_state.State.RenderEnableCondition);
if (renderEnable == ConditionalRenderEnabled.False || _instancedDrawPending)
{
if (renderEnable == ConditionalRenderEnabled.False)
{
PerformDeferredDraws();
}
_drawState.DrawIndexed = false;
if (renderEnable == ConditionalRenderEnabled.Host)
{
_context.Renderer.Pipeline.EndHostConditionalRendering();
}
return;
}
_drawState.FirstIndex = firstIndex;
_drawState.IndexCount = indexCount;
engine.UpdateState();
bool instanced = _drawState.VsUsesInstanceId || _drawState.IsAnyVbInstanced;
if (instanced)
{
_instancedDrawPending = true;
_instancedIndexed = _drawState.DrawIndexed;
_instancedFirstIndex = firstIndex;
_instancedFirstVertex = (int)_state.State.FirstVertex;
_instancedFirstInstance = (int)_state.State.FirstInstance;
_instancedIndexCount = indexCount;
var drawState = _state.State.VertexBufferDrawState;
_instancedDrawStateFirst = drawState.First;
_instancedDrawStateCount = drawState.Count;
_drawState.DrawIndexed = false;
if (renderEnable == ConditionalRenderEnabled.Host)
{
_context.Renderer.Pipeline.EndHostConditionalRendering();
}
return;
}
int firstInstance = (int)_state.State.FirstInstance;
int inlineIndexCount = _drawState.IbStreamer.GetAndResetInlineIndexCount();
if (inlineIndexCount != 0)
{
int firstVertex = (int)_state.State.FirstVertex;
BufferRange br = new BufferRange(_drawState.IbStreamer.GetInlineIndexBuffer(), 0, inlineIndexCount * 4);
_channel.BufferManager.SetIndexBuffer(br, IndexType.UInt);
_context.Renderer.Pipeline.DrawIndexed(inlineIndexCount, 1, firstIndex, firstVertex, firstInstance);
}
else if (_drawState.DrawIndexed)
{
int firstVertex = (int)_state.State.FirstVertex;
_context.Renderer.Pipeline.DrawIndexed(indexCount, 1, firstIndex, firstVertex, firstInstance);
}
else
{
var drawState = _state.State.VertexBufferDrawState;
_context.Renderer.Pipeline.Draw(drawState.Count, 1, drawState.First, firstInstance);
}
_drawState.DrawIndexed = false;
if (renderEnable == ConditionalRenderEnabled.Host)
{
_context.Renderer.Pipeline.EndHostConditionalRendering();
}
}
/// <summary>
/// Starts draw.
/// This sets primitive type and instanced draw parameters.
/// </summary>
/// <param name="argument">Method call argument</param>
public void DrawBegin(int argument)
{
bool incrementInstance = (argument & (1 << 26)) != 0;
bool resetInstance = (argument & (1 << 27)) == 0;
if (_state.State.PrimitiveTypeOverrideEnable)
{
PrimitiveTypeOverride typeOverride = _state.State.PrimitiveTypeOverride;
DrawBegin(incrementInstance, resetInstance, typeOverride.Convert());
}
else
{
PrimitiveType type = (PrimitiveType)(argument & 0xffff);
DrawBegin(incrementInstance, resetInstance, type.Convert());
}
}
/// <summary>
/// Starts draw.
/// This sets primitive type and instanced draw parameters.
/// </summary>
/// <param name="incrementInstance">Indicates if the current instance should be incremented</param>
/// <param name="resetInstance">Indicates if the current instance should be set to zero</param>
/// <param name="topology">Primitive topology</param>
private void DrawBegin(bool incrementInstance, bool resetInstance, PrimitiveTopology topology)
{
if (incrementInstance)
{
_instanceIndex++;
}
else if (resetInstance)
{
PerformDeferredDraws();
_instanceIndex = 0;
}
_context.Renderer.Pipeline.SetPrimitiveTopology(topology);
_drawState.Topology = topology;
}
/// <summary>
/// Sets the index buffer count.
/// This also sets internal state that indicates that the next draw is an indexed draw.
/// </summary>
/// <param name="argument">Method call argument</param>
public void SetIndexBufferCount(int argument)
{
_drawState.DrawIndexed = true;
}
/// <summary>
/// Performs a indexed draw with a low number of index buffer elements.
/// </summary>
/// <param name="engine">3D engine where this method is being called</param>
/// <param name="argument">Method call argument</param>
public void DrawIndexedSmall(ThreedClass engine, int argument)
{
DrawIndexedSmall(engine, argument, false);
}
/// <summary>
/// Performs a indexed draw with a low number of index buffer elements.
/// </summary>
/// <param name="engine">3D engine where this method is being called</param>
/// <param name="argument">Method call argument</param>
public void DrawIndexedSmall2(ThreedClass engine, int argument)
{
DrawIndexedSmall(engine, argument);
}
/// <summary>
/// Performs a indexed draw with a low number of index buffer elements,
/// while also pre-incrementing the current instance value.
/// </summary>
/// <param name="engine">3D engine where this method is being called</param>
/// <param name="argument">Method call argument</param>
public void DrawIndexedSmallIncInstance(ThreedClass engine, int argument)
{
DrawIndexedSmall(engine, argument, true);
}
/// <summary>
/// Performs a indexed draw with a low number of index buffer elements,
/// while also pre-incrementing the current instance value.
/// </summary>
/// <param name="engine">3D engine where this method is being called</param>
/// <param name="argument">Method call argument</param>
public void DrawIndexedSmallIncInstance2(ThreedClass engine, int argument)
{
DrawIndexedSmallIncInstance(engine, argument);
}
/// <summary>
/// Performs a indexed draw with a low number of index buffer elements,
/// while optionally also pre-incrementing the current instance value.
/// </summary>
/// <param name="engine">3D engine where this method is being called</param>
/// <param name="argument">Method call argument</param>
/// <param name="instanced">True to increment the current instance value, false otherwise</param>
private void DrawIndexedSmall(ThreedClass engine, int argument, bool instanced)
{
PrimitiveTypeOverride typeOverride = _state.State.PrimitiveTypeOverride;
DrawBegin(instanced, !instanced, typeOverride.Convert());
int firstIndex = argument & 0xffff;
int indexCount = (argument >> 16) & 0xfff;
bool oldDrawIndexed = _drawState.DrawIndexed;
_drawState.DrawIndexed = true;
DrawEnd(engine, firstIndex, indexCount);
_drawState.DrawIndexed = oldDrawIndexed;
}
/// <summary>
/// Perform any deferred draws.
/// This is used for instanced draws.
/// Since each instance is a separate draw, we defer the draw and accumulate the instance count.
/// Once we detect the last instanced draw, then we perform the host instanced draw,
/// with the accumulated instance count.
/// </summary>
public void PerformDeferredDraws()
{
// Perform any pending instanced draw.
if (_instancedDrawPending)
{
_instancedDrawPending = false;
if (_instancedIndexed)
{
_context.Renderer.Pipeline.DrawIndexed(
_instancedIndexCount,
_instanceIndex + 1,
_instancedFirstIndex,
_instancedFirstVertex,
_instancedFirstInstance);
}
else
{
_context.Renderer.Pipeline.Draw(
_instancedDrawStateCount,
_instanceIndex + 1,
_instancedDrawStateFirst,
_instancedFirstInstance);
}
}
}
/// <summary>
/// Clears the current color and depth-stencil buffers.
/// Which buffers should be cleared is also specified on the argument.
/// </summary>
/// <param name="engine">3D engine where this method is being called</param>
/// <param name="argument">Method call argument</param>
public void Clear(ThreedClass engine, int argument)
{
ConditionalRenderEnabled renderEnable = ConditionalRendering.GetRenderEnable(
_context,
_channel.MemoryManager,
_state.State.RenderEnableAddress,
_state.State.RenderEnableCondition);
if (renderEnable == ConditionalRenderEnabled.False)
{
return;
}
// Scissor and rasterizer discard also affect clears.
engine.UpdateState((1UL << StateUpdater.RasterizerStateIndex) | (1UL << StateUpdater.ScissorStateIndex));
int index = (argument >> 6) & 0xf;
engine.UpdateRenderTargetState(useControl: false, singleUse: index);
_channel.TextureManager.UpdateRenderTargets();
bool clearDepth = (argument & 1) != 0;
bool clearStencil = (argument & 2) != 0;
uint componentMask = (uint)((argument >> 2) & 0xf);
if (componentMask != 0)
{
var clearColor = _state.State.ClearColors;
ColorF color = new ColorF(clearColor.Red, clearColor.Green, clearColor.Blue, clearColor.Alpha);
_context.Renderer.Pipeline.ClearRenderTargetColor(index, componentMask, color);
}
if (clearDepth || clearStencil)
{
float depthValue = _state.State.ClearDepthValue;
int stencilValue = (int)_state.State.ClearStencilValue;
int stencilMask = 0;
if (clearStencil)
{
stencilMask = _state.State.StencilTestState.FrontMask;
}
_context.Renderer.Pipeline.ClearRenderTargetDepthStencil(
depthValue,
clearDepth,
stencilValue,
stencilMask);
}
engine.UpdateRenderTargetState(useControl: true);
if (renderEnable == ConditionalRenderEnabled.Host)
{
_context.Renderer.Pipeline.EndHostConditionalRendering();
}
}
}
}

View File

@ -0,0 +1,45 @@
using Ryujinx.Graphics.GAL;
namespace Ryujinx.Graphics.Gpu.Engine.Threed
{
/// <summary>
/// Draw state.
/// </summary>
class DrawState
{
/// <summary>
/// First index to be used for the draw on the index buffer.
/// </summary>
public int FirstIndex;
/// <summary>
/// Number of indices to be used for the draw on the index buffer.
/// </summary>
public int IndexCount;
/// <summary>
/// Indicates if the next draw will be a indexed draw.
/// </summary>
public bool DrawIndexed;
/// <summary>
/// Indicates if any of the currently used vertex shaders reads the instance ID.
/// </summary>
public bool VsUsesInstanceId;
/// <summary>
/// Indicates if any of the currently used vertex buffers is instanced.
/// </summary>
public bool IsAnyVbInstanced;
/// <summary>
/// Primitive topology for the next draw.
/// </summary>
public PrimitiveTopology Topology;
/// <summary>
/// Index buffer data streamer for inline index buffer updates, such as those used in legacy OpenGL.
/// </summary>
public IbStreamer IbStreamer = new IbStreamer();
}
}

View File

@ -0,0 +1,142 @@
using Ryujinx.Common;
using Ryujinx.Graphics.GAL;
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Gpu.Engine.Threed
{
/// <summary>
/// Holds inline index buffer state.
/// The inline index buffer data is sent to the GPU through the command buffer.
/// </summary>
struct IbStreamer
{
private BufferHandle _inlineIndexBuffer;
private int _inlineIndexBufferSize;
private int _inlineIndexCount;
/// <summary>
/// Indicates if any index buffer data has been pushed.
/// </summary>
public bool HasInlineIndexData => _inlineIndexCount != 0;
/// <summary>
/// Gets the handle for the host buffer currently holding the inline index buffer data.
/// </summary>
/// <returns>Host buffer handle</returns>
public BufferHandle GetInlineIndexBuffer()
{
return _inlineIndexBuffer;
}
/// <summary>
/// Gets the number of elements on the current inline index buffer,
/// while also reseting it to zero for the next draw.
/// </summary>
/// <returns>Inline index bufffer count</returns>
public int GetAndResetInlineIndexCount()
{
int temp = _inlineIndexCount;
_inlineIndexCount = 0;
return temp;
}
/// <summary>
/// Pushes four 8-bit index buffer elements.
/// </summary>
/// <param name="renderer">Host renderer</param>
/// <param name="argument">Method call argument</param>
public void VbElementU8(IRenderer renderer, int argument)
{
byte i0 = (byte)argument;
byte i1 = (byte)(argument >> 8);
byte i2 = (byte)(argument >> 16);
byte i3 = (byte)(argument >> 24);
Span<uint> data = stackalloc uint[4];
data[0] = i0;
data[1] = i1;
data[2] = i2;
data[3] = i3;
int offset = _inlineIndexCount * 4;
renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast<uint, byte>(data));
_inlineIndexCount += 4;
}
/// <summary>
/// Pushes two 16-bit index buffer elements.
/// </summary>
/// <param name="renderer">Host renderer</param>
/// <param name="argument">Method call argument</param>
public void VbElementU16(IRenderer renderer, int argument)
{
ushort i0 = (ushort)argument;
ushort i1 = (ushort)(argument >> 16);
Span<uint> data = stackalloc uint[2];
data[0] = i0;
data[1] = i1;
int offset = _inlineIndexCount * 4;
renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast<uint, byte>(data));
_inlineIndexCount += 2;
}
/// <summary>
/// Pushes one 32-bit index buffer element.
/// </summary>
/// <param name="renderer">Host renderer</param>
/// <param name="argument">Method call argument</param>
public void VbElementU32(IRenderer renderer, int argument)
{
uint i0 = (uint)argument;
Span<uint> data = stackalloc uint[1];
data[0] = i0;
int offset = _inlineIndexCount++ * 4;
renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast<uint, byte>(data));
}
/// <summary>
/// Gets the handle of a buffer large enough to hold the data that will be written to <paramref name="offset"/>.
/// </summary>
/// <param name="renderer">Host renderer</param>
/// <param name="offset">Offset where the data will be written</param>
/// <returns>Buffer handle</returns>
private BufferHandle GetInlineIndexBuffer(IRenderer renderer, int offset)
{
// Calculate a reasonable size for the buffer that can fit all the data,
// and that also won't require frequent resizes if we need to push more data.
int size = BitUtils.AlignUp(offset + 0x10, 0x200);
if (_inlineIndexBuffer == BufferHandle.Null)
{
_inlineIndexBuffer = renderer.CreateBuffer(size);
_inlineIndexBufferSize = size;
}
else if (_inlineIndexBufferSize < size)
{
BufferHandle oldBuffer = _inlineIndexBuffer;
int oldSize = _inlineIndexBufferSize;
_inlineIndexBuffer = renderer.CreateBuffer(size);
_inlineIndexBufferSize = size;
renderer.Pipeline.CopyBuffer(oldBuffer, _inlineIndexBuffer, 0, 0, oldSize);
renderer.DeleteBuffer(oldBuffer);
}
return _inlineIndexBuffer;
}
}
}

View File

@ -0,0 +1,222 @@
using Ryujinx.Common;
using Ryujinx.Graphics.GAL;
namespace Ryujinx.Graphics.Gpu.Engine.Threed
{
/// <summary>
/// Semaphore updater.
/// </summary>
class SemaphoreUpdater
{
private const int NsToTicksFractionNumerator = 384;
private const int NsToTicksFractionDenominator = 625;
/// <summary>
/// GPU semaphore operation.
/// </summary>
private enum SemaphoreOperation
{
Release = 0,
Acquire = 1,
Counter = 2
}
/// <summary>
/// Counter type for GPU counter reset.
/// </summary>
private enum ResetCounterType
{
SamplesPassed = 1,
ZcullStats = 2,
TransformFeedbackPrimitivesWritten = 0x10,
InputVertices = 0x12,
InputPrimitives = 0x13,
VertexShaderInvocations = 0x15,
TessControlShaderInvocations = 0x16,
TessEvaluationShaderInvocations = 0x17,
TessEvaluationShaderPrimitives = 0x18,
GeometryShaderInvocations = 0x1a,
GeometryShaderPrimitives = 0x1b,
ClipperInputPrimitives = 0x1c,
ClipperOutputPrimitives = 0x1d,
FragmentShaderInvocations = 0x1e,
PrimitivesGenerated = 0x1f
}
/// <summary>
/// Counter type for GPU counter reporting.
/// </summary>
private enum ReportCounterType
{
Zero = 0,
InputVertices = 1,
InputPrimitives = 3,
VertexShaderInvocations = 5,
GeometryShaderInvocations = 7,
GeometryShaderPrimitives = 9,
ZcullStats0 = 0xa,
TransformFeedbackPrimitivesWritten = 0xb,
ZcullStats1 = 0xc,
ZcullStats2 = 0xe,
ClipperInputPrimitives = 0xf,
ZcullStats3 = 0x10,
ClipperOutputPrimitives = 0x11,
PrimitivesGenerated = 0x12,
FragmentShaderInvocations = 0x13,
SamplesPassed = 0x15,
TransformFeedbackOffset = 0x1a,
TessControlShaderInvocations = 0x1b,
TessEvaluationShaderInvocations = 0x1d,
TessEvaluationShaderPrimitives = 0x1f
}
private readonly GpuContext _context;
private readonly GpuChannel _channel;
private readonly DeviceStateWithShadow<ThreedClassState> _state;
/// <summary>
/// Creates a new instance of the semaphore updater.
/// </summary>
/// <param name="context">GPU context</param>
/// <param name="channel">GPU channel</param>
/// <param name="state">Channel state</param>
public SemaphoreUpdater(GpuContext context, GpuChannel channel, DeviceStateWithShadow<ThreedClassState> state)
{
_context = context;
_channel = channel;
_state = state;
}
/// <summary>
/// Resets the value of an internal GPU counter back to zero.
/// </summary>
/// <param name="argument">Method call argument</param>
public void ResetCounter(int argument)
{
ResetCounterType type = (ResetCounterType)argument;
switch (type)
{
case ResetCounterType.SamplesPassed:
_context.Renderer.ResetCounter(CounterType.SamplesPassed);
break;
case ResetCounterType.PrimitivesGenerated:
_context.Renderer.ResetCounter(CounterType.PrimitivesGenerated);
break;
case ResetCounterType.TransformFeedbackPrimitivesWritten:
_context.Renderer.ResetCounter(CounterType.TransformFeedbackPrimitivesWritten);
break;
}
}
/// <summary>
/// Writes a GPU counter to guest memory.
/// </summary>
/// <param name="argument">Method call argument</param>
public void Report(int argument)
{
SemaphoreOperation op = (SemaphoreOperation)(argument & 3);
ReportCounterType type = (ReportCounterType)((argument >> 23) & 0x1f);
switch (op)
{
case SemaphoreOperation.Release: ReleaseSemaphore(); break;
case SemaphoreOperation.Counter: ReportCounter(type); break;
}
}
/// <summary>
/// Writes (or Releases) a GPU semaphore value to guest memory.
/// </summary>
private void ReleaseSemaphore()
{
_channel.MemoryManager.Write(_state.State.SemaphoreAddress.Pack(), _state.State.SemaphorePayload);
_context.AdvanceSequence();
}
/// <summary>
/// Packed GPU counter data (including GPU timestamp) in memory.
/// </summary>
private struct CounterData
{
public ulong Counter;
public ulong Timestamp;
}
/// <summary>
/// Writes a GPU counter to guest memory.
/// This also writes the current timestamp value.
/// </summary>
/// <param name="type">Counter to be written to memory</param>
private void ReportCounter(ReportCounterType type)
{
ulong gpuVa = _state.State.SemaphoreAddress.Pack();
ulong ticks = ConvertNanosecondsToTicks((ulong)PerformanceCounter.ElapsedNanoseconds);
if (GraphicsConfig.FastGpuTime)
{
// Divide by some amount to report time as if operations were performed faster than they really are.
// This can prevent some games from switching to a lower resolution because rendering is too slow.
ticks /= 256;
}
ICounterEvent counter = null;
void resultHandler(object evt, ulong result)
{
CounterData counterData = new CounterData
{
Counter = result,
Timestamp = ticks
};
if (counter?.Invalid != true)
{
_channel.MemoryManager.Write(gpuVa, counterData);
}
}
switch (type)
{
case ReportCounterType.Zero:
resultHandler(null, 0);
break;
case ReportCounterType.SamplesPassed:
counter = _context.Renderer.ReportCounter(CounterType.SamplesPassed, resultHandler);
break;
case ReportCounterType.PrimitivesGenerated:
counter = _context.Renderer.ReportCounter(CounterType.PrimitivesGenerated, resultHandler);
break;
case ReportCounterType.TransformFeedbackPrimitivesWritten:
counter = _context.Renderer.ReportCounter(CounterType.TransformFeedbackPrimitivesWritten, resultHandler);
break;
}
_channel.MemoryManager.CounterCache.AddOrUpdate(gpuVa, counter);
}
/// <summary>
/// Converts a nanoseconds timestamp value to Maxwell time ticks.
/// </summary>
/// <remarks>
/// The frequency is 614400000 Hz.
/// </remarks>
/// <param name="nanoseconds">Timestamp in nanoseconds</param>
/// <returns>Maxwell ticks</returns>
private static ulong ConvertNanosecondsToTicks(ulong nanoseconds)
{
// We need to divide first to avoid overflows.
// We fix up the result later by calculating the difference and adding
// that to the result.
ulong divided = nanoseconds / NsToTicksFractionDenominator;
ulong rounded = divided * NsToTicksFractionDenominator;
ulong errorBias = (nanoseconds - rounded) * NsToTicksFractionNumerator / NsToTicksFractionDenominator;
return divided * NsToTicksFractionNumerator + errorBias;
}
}
}

View File

@ -0,0 +1,166 @@
using Ryujinx.Graphics.Device;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Gpu.Engine.Threed
{
/// <summary>
/// State update callback entry, with the callback function and associated field names.
/// </summary>
struct StateUpdateCallbackEntry
{
/// <summary>
/// Callback function, to be called if the register was written as the state needs to be updated.
/// </summary>
public Action Callback { get; }
/// <summary>
/// Name of the state fields (registers) associated with the callback function.
/// </summary>
public string[] FieldNames { get; }
/// <summary>
/// Creates a new state update callback entry.
/// </summary>
/// <param name="callback">Callback function, to be called if the register was written as the state needs to be updated</param>
/// <param name="fieldNames">Name of the state fields (registers) associated with the callback function</param>
public StateUpdateCallbackEntry(Action callback, params string[] fieldNames)
{
Callback = callback;
FieldNames = fieldNames;
}
}
/// <summary>
/// GPU state update tracker.
/// </summary>
/// <typeparam name="TState">State type</typeparam>
class StateUpdateTracker<TState>
{
private const int BlockSize = 0xe00;
private const int RegisterSize = sizeof(uint);
private readonly byte[] _registerToGroupMapping;
private readonly Action[] _callbacks;
private ulong _dirtyMask;
/// <summary>
/// Creates a new instance of the state update tracker.
/// </summary>
/// <param name="entries">Update tracker callback entries</param>
public StateUpdateTracker(StateUpdateCallbackEntry[] entries)
{
_registerToGroupMapping = new byte[BlockSize];
_callbacks = new Action[entries.Length];
var fieldToDelegate = new Dictionary<string, int>();
for (int entryIndex = 0; entryIndex < entries.Length; entryIndex++)
{
var entry = entries[entryIndex];
foreach (var fieldName in entry.FieldNames)
{
fieldToDelegate.Add(fieldName, entryIndex);
}
_callbacks[entryIndex] = entry.Callback;
}
var fields = typeof(TState).GetFields();
int offset = 0;
for (int fieldIndex = 0; fieldIndex < fields.Length; fieldIndex++)
{
var field = fields[fieldIndex];
int sizeOfField = SizeCalculator.SizeOf(field.FieldType);
if (fieldToDelegate.TryGetValue(field.Name, out int entryIndex))
{
for (int i = 0; i < ((sizeOfField + 3) & ~3); i += 4)
{
_registerToGroupMapping[(offset + i) / RegisterSize] = (byte)(entryIndex + 1);
}
}
offset += sizeOfField;
}
Debug.Assert(offset == Unsafe.SizeOf<TState>());
}
/// <summary>
/// Sets a register as modified.
/// </summary>
/// <param name="offset">Register offset in bytes</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetDirty(int offset)
{
uint index = (uint)offset / RegisterSize;
if (index < BlockSize)
{
int groupIndex = Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_registerToGroupMapping), (IntPtr)index);
if (groupIndex != 0)
{
groupIndex--;
_dirtyMask |= 1UL << groupIndex;
}
}
}
/// <summary>
/// Forces a register group as dirty, by index.
/// </summary>
/// <param name="groupIndex">Index of the group to be dirtied</param>
public void ForceDirty(int groupIndex)
{
if ((uint)groupIndex >= _callbacks.Length)
{
throw new ArgumentOutOfRangeException(nameof(groupIndex));
}
_dirtyMask |= 1UL << groupIndex;
}
/// <summary>
/// Forces all register groups as dirty, triggering a full update on the next call to <see cref="Update"/>.
/// </summary>
public void SetAllDirty()
{
Debug.Assert(_callbacks.Length <= sizeof(ulong) * 8);
_dirtyMask = ulong.MaxValue >> ((sizeof(ulong) * 8) - _callbacks.Length);
}
/// <summary>
/// Check all the groups specified by <paramref name="checkMask"/> for modification, and update if modified.
/// </summary>
/// <param name="checkMask">Mask, where each bit set corresponds to a group index that should be checked</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update(ulong checkMask)
{
ulong mask = _dirtyMask & checkMask;
if (mask == 0)
{
return;
}
do
{
int groupIndex = BitOperations.TrailingZeroCount(mask);
_callbacks[groupIndex]();
mask &= ~(1UL << groupIndex);
}
while (mask != 0);
_dirtyMask &= ~checkMask;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,428 @@
using Ryujinx.Graphics.Device;
using Ryujinx.Graphics.Gpu.Engine.InlineToMemory;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace Ryujinx.Graphics.Gpu.Engine.Threed
{
/// <summary>
/// Represents a 3D engine class.
/// </summary>
class ThreedClass : IDeviceState
{
private readonly GpuContext _context;
private readonly DeviceStateWithShadow<ThreedClassState> _state;
private readonly InlineToMemoryClass _i2mClass;
private readonly DrawManager _drawManager;
private readonly SemaphoreUpdater _semaphoreUpdater;
private readonly ConstantBufferUpdater _cbUpdater;
private readonly StateUpdater _stateUpdater;
/// <summary>
/// Creates a new instance of the 3D engine class.
/// </summary>
/// <param name="context">GPU context</param>
/// <param name="channel">GPU channel</param>
public ThreedClass(GpuContext context, GpuChannel channel)
{
_context = context;
_state = new DeviceStateWithShadow<ThreedClassState>(new Dictionary<string, RwCallback>
{
{ nameof(ThreedClassState.LaunchDma), new RwCallback(LaunchDma, null) },
{ nameof(ThreedClassState.LoadInlineData), new RwCallback(LoadInlineData, null) },
{ nameof(ThreedClassState.SyncpointAction), new RwCallback(IncrementSyncpoint, null) },
{ nameof(ThreedClassState.TextureBarrier), new RwCallback(TextureBarrier, null) },
{ nameof(ThreedClassState.TextureBarrierTiled), new RwCallback(TextureBarrierTiled, null) },
{ nameof(ThreedClassState.VbElementU8), new RwCallback(VbElementU8, null) },
{ nameof(ThreedClassState.VbElementU16), new RwCallback(VbElementU16, null) },
{ nameof(ThreedClassState.VbElementU32), new RwCallback(VbElementU32, null) },
{ nameof(ThreedClassState.ResetCounter), new RwCallback(ResetCounter, null) },
{ nameof(ThreedClassState.RenderEnableCondition), new RwCallback(null, Zero) },
{ nameof(ThreedClassState.DrawEnd), new RwCallback(DrawEnd, null) },
{ nameof(ThreedClassState.DrawBegin), new RwCallback(DrawBegin, null) },
{ nameof(ThreedClassState.DrawIndexedSmall), new RwCallback(DrawIndexedSmall, null) },
{ nameof(ThreedClassState.DrawIndexedSmall2), new RwCallback(DrawIndexedSmall2, null) },
{ nameof(ThreedClassState.DrawIndexedSmallIncInstance), new RwCallback(DrawIndexedSmallIncInstance, null) },
{ nameof(ThreedClassState.DrawIndexedSmallIncInstance2), new RwCallback(DrawIndexedSmallIncInstance2, null) },
{ nameof(ThreedClassState.IndexBufferCount), new RwCallback(SetIndexBufferCount, null) },
{ nameof(ThreedClassState.Clear), new RwCallback(Clear, null) },
{ nameof(ThreedClassState.SemaphoreControl), new RwCallback(Report, null) },
{ nameof(ThreedClassState.SetFalcon04), new RwCallback(SetFalcon04, null) },
{ nameof(ThreedClassState.UniformBufferUpdateData), new RwCallback(ConstantBufferUpdate, null) },
{ nameof(ThreedClassState.UniformBufferBindVertex), new RwCallback(ConstantBufferBindVertex, null) },
{ nameof(ThreedClassState.UniformBufferBindTessControl), new RwCallback(ConstantBufferBindTessControl, null) },
{ nameof(ThreedClassState.UniformBufferBindTessEvaluation), new RwCallback(ConstantBufferBindTessEvaluation, null) },
{ nameof(ThreedClassState.UniformBufferBindGeometry), new RwCallback(ConstantBufferBindGeometry, null) },
{ nameof(ThreedClassState.UniformBufferBindFragment), new RwCallback(ConstantBufferBindFragment, null) }
});
_i2mClass = new InlineToMemoryClass(context, channel, initializeState: false);
var drawState = new DrawState();
_drawManager = new DrawManager(context, channel, _state, drawState);
_semaphoreUpdater = new SemaphoreUpdater(context, channel, _state);
_cbUpdater = new ConstantBufferUpdater(channel, _state);
_stateUpdater = new StateUpdater(context, channel, _state, drawState);
// This defaults to "always", even without any register write.
// Reads just return 0, regardless of what was set there.
_state.State.RenderEnableCondition = Condition.Always;
}
/// <summary>
/// Reads data from the class registers.
/// </summary>
/// <param name="offset">Register byte offset</param>
/// <returns>Data at the specified offset</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int Read(int offset) => _state.Read(offset);
/// <summary>
/// Writes data to the class registers.
/// </summary>
/// <param name="offset">Register byte offset</param>
/// <param name="data">Data to be written</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Write(int offset, int data)
{
_state.WriteWithRedundancyCheck(offset, data, out bool valueChanged);
if (valueChanged)
{
_stateUpdater.SetDirty(offset);
}
}
/// <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)
{
_state.State.SetMmeShadowRamControl = (uint)control;
}
/// <summary>
/// Updates current host state for all registers modified since the last call to this method.
/// </summary>
public void UpdateState()
{
_cbUpdater.FlushUboDirty();
_stateUpdater.Update();
}
/// <summary>
/// Updates current host state for all registers modified since the last call to this method.
/// </summary>
/// <param name="mask">Mask where each bit set indicates that the respective state group index should be checked</param>
public void UpdateState(ulong mask)
{
_stateUpdater.Update(mask);
}
/// <summary>
/// Updates render targets (color and depth-stencil buffers) based on current render target state.
/// </summary>
/// <param name="useControl">Use draw buffers information from render target control register</param>
/// <param name="singleUse">If this is not -1, it indicates that only the given indexed target will be used.</param>
public void UpdateRenderTargetState(bool useControl, int singleUse = -1)
{
_stateUpdater.UpdateRenderTargetState(useControl, singleUse);
}
/// <summary>
/// Marks the entire state as dirty, forcing a full host state update before the next draw.
/// </summary>
public void ForceStateDirty()
{
_stateUpdater.SetAllDirty();
}
/// <summary>
/// Forces the shaders to be rebound on the next draw.
/// </summary>
public void ForceShaderUpdate()
{
_stateUpdater.ForceShaderUpdate();
}
/// <summary>
/// Flushes any queued UBO updates.
/// </summary>
public void FlushUboDirty()
{
_cbUpdater.FlushUboDirty();
}
/// <summary>
/// Perform any deferred draws.
/// </summary>
public void PerformDeferredDraws()
{
_drawManager.PerformDeferredDraws();
}
/// <summary>
/// Updates the currently bound constant buffer.
/// </summary>
/// <param name="data">Data to be written to the buffer</param>
public void ConstantBufferUpdate(ReadOnlySpan<int> data)
{
_cbUpdater.Update(data);
}
/// <summary>
/// Launches the Inline-to-Memory DMA copy operation.
/// </summary>
/// <param name="argument">Method call argument</param>
private void LaunchDma(int argument)
{
_i2mClass.LaunchDma(ref Unsafe.As<ThreedClassState, InlineToMemoryClassState>(ref _state.State), argument);
}
/// <summary>
/// Pushes a word of data to the Inline-to-Memory engine.
/// </summary>
/// <param name="argument">Method call argument</param>
private void LoadInlineData(int argument)
{
_i2mClass.LoadInlineData(argument);
}
/// <summary>
/// Performs an incrementation on a syncpoint.
/// </summary>
/// <param name="argument">Method call argument</param>
public void IncrementSyncpoint(int argument)
{
uint syncpointId = (uint)argument & 0xFFFF;
_context.CreateHostSyncIfNeeded();
_context.Renderer.UpdateCounters(); // Poll the query counters, the game may want an updated result.
_context.Synchronization.IncrementSyncpoint(syncpointId);
}
/// <summary>
/// Issues a texture barrier.
/// This waits until previous texture writes from the GPU to finish, before
/// performing new operations with said textures.
/// </summary>
/// <param name="argument">Method call argument (unused)</param>
private void TextureBarrier(int argument)
{
_context.Renderer.Pipeline.TextureBarrier();
}
/// <summary>
/// Issues a texture barrier.
/// This waits until previous texture writes from the GPU to finish, before
/// performing new operations with said textures.
/// This performs a per-tile wait, it is only valid if both the previous write
/// and current access has the same access patterns.
/// This may be faster than the regular barrier on tile-based rasterizers.
/// </summary>
/// <param name="argument">Method call argument (unused)</param>
private void TextureBarrierTiled(int argument)
{
_context.Renderer.Pipeline.TextureBarrierTiled();
}
/// <summary>
/// Pushes four 8-bit index buffer elements.
/// </summary>
/// <param name="argument">Method call argument</param>
private void VbElementU8(int argument)
{
_drawManager.VbElementU8(argument);
}
/// <summary>
/// Pushes two 16-bit index buffer elements.
/// </summary>
/// <param name="argument">Method call argument</param>
private void VbElementU16(int argument)
{
_drawManager.VbElementU16(argument);
}
/// <summary>
/// Pushes one 32-bit index buffer element.
/// </summary>
/// <param name="argument">Method call argument</param>
private void VbElementU32(int argument)
{
_drawManager.VbElementU32(argument);
}
/// <summary>
/// Resets the value of an internal GPU counter back to zero.
/// </summary>
/// <param name="argument">Method call argument</param>
private void ResetCounter(int argument)
{
_semaphoreUpdater.ResetCounter(argument);
}
/// <summary>
/// Finishes the draw call.
/// This draws geometry on the bound buffers based on the current GPU state.
/// </summary>
/// <param name="argument">Method call argument</param>
private void DrawEnd(int argument)
{
_drawManager.DrawEnd(this, argument);
}
/// <summary>
/// Starts draw.
/// This sets primitive type and instanced draw parameters.
/// </summary>
/// <param name="argument">Method call argument</param>
private void DrawBegin(int argument)
{
_drawManager.DrawBegin(argument);
}
/// <summary>
/// Sets the index buffer count.
/// This also sets internal state that indicates that the next draw is an indexed draw.
/// </summary>
/// <param name="argument">Method call argument</param>
private void SetIndexBufferCount(int argument)
{
_drawManager.SetIndexBufferCount(argument);
}
/// <summary>
/// Performs a indexed draw with a low number of index buffer elements.
/// </summary>
/// <param name="argument">Method call argument</param>
private void DrawIndexedSmall(int argument)
{
_drawManager.DrawIndexedSmall(this, argument);
}
/// <summary>
/// Performs a indexed draw with a low number of index buffer elements.
/// </summary>
/// <param name="argument">Method call argument</param>
private void DrawIndexedSmall2(int argument)
{
_drawManager.DrawIndexedSmall2(this, argument);
}
/// <summary>
/// Performs a indexed draw with a low number of index buffer elements,
/// while also pre-incrementing the current instance value.
/// </summary>
/// <param name="argument">Method call argument</param>
private void DrawIndexedSmallIncInstance(int argument)
{
_drawManager.DrawIndexedSmallIncInstance(this, argument);
}
/// <summary>
/// Performs a indexed draw with a low number of index buffer elements,
/// while also pre-incrementing the current instance value.
/// </summary>
/// <param name="argument">Method call argument</param>
private void DrawIndexedSmallIncInstance2(int argument)
{
_drawManager.DrawIndexedSmallIncInstance2(this, argument);
}
/// <summary>
/// Clears the current color and depth-stencil buffers.
/// Which buffers should be cleared is also specified on the argument.
/// </summary>
/// <param name="argument">Method call argument</param>
private void Clear(int argument)
{
_drawManager.Clear(this, argument);
}
/// <summary>
/// Writes a GPU counter to guest memory.
/// </summary>
/// <param name="argument">Method call argument</param>
private void Report(int argument)
{
_semaphoreUpdater.Report(argument);
}
/// <summary>
/// Performs high-level emulation of Falcon microcode function number "4".
/// </summary>
/// <param name="argument">Method call argument</param>
private void SetFalcon04(int argument)
{
_state.State.SetMmeShadowScratch[0] = 1;
}
/// <summary>
/// Updates the uniform buffer data with inline data.
/// </summary>
/// <param name="argument">New uniform buffer data word</param>
private void ConstantBufferUpdate(int argument)
{
_cbUpdater.Update(argument);
}
/// <summary>
/// Binds a uniform buffer for the vertex shader stage.
/// </summary>
/// <param name="argument">Method call argument</param>
private void ConstantBufferBindVertex(int argument)
{
_cbUpdater.BindVertex(argument);
}
/// <summary>
/// Binds a uniform buffer for the tessellation control shader stage.
/// </summary>
/// <param name="argument">Method call argument</param>
private void ConstantBufferBindTessControl(int argument)
{
_cbUpdater.BindTessControl(argument);
}
/// <summary>
/// Binds a uniform buffer for the tessellation evaluation shader stage.
/// </summary>
/// <param name="argument">Method call argument</param>
private void ConstantBufferBindTessEvaluation(int argument)
{
_cbUpdater.BindTessEvaluation(argument);
}
/// <summary>
/// Binds a uniform buffer for the geometry shader stage.
/// </summary>
/// <param name="argument">Method call argument</param>
private void ConstantBufferBindGeometry(int argument)
{
_cbUpdater.BindGeometry(argument);
}
/// <summary>
/// Binds a uniform buffer for the fragment shader stage.
/// </summary>
/// <param name="argument">Method call argument</param>
private void ConstantBufferBindFragment(int argument)
{
_cbUpdater.BindFragment(argument);
}
/// <summary>
/// Generic register read function that just returns 0.
/// </summary>
/// <returns>Zero</returns>
private static int Zero()
{
return 0;
}
}
}

View File

@ -0,0 +1,861 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Engine.InlineToMemory;
using Ryujinx.Graphics.Gpu.Engine.Types;
using Ryujinx.Graphics.Gpu.Image;
using System;
namespace Ryujinx.Graphics.Gpu.Engine.Threed
{
/// <summary>
/// Shader stage name.
/// </summary>
enum ShaderType
{
Vertex,
TessellationControl,
TessellationEvaluation,
Geometry,
Fragment
}
/// <summary>
/// Transform feedback buffer state.
/// </summary>
struct TfBufferState
{
#pragma warning disable CS0649
public Boolean32 Enable;
public GpuVa Address;
public int Size;
public int Offset;
public uint Padding0;
public uint Padding1;
public uint Padding2;
#pragma warning restore CS0649
}
/// <summary>
/// Transform feedback state.
/// </summary>
struct TfState
{
#pragma warning disable CS0649
public int BufferIndex;
public int VaryingsCount;
public int Stride;
public uint Padding;
#pragma warning restore CS0649
}
/// <summary>
/// Render target color buffer state.
/// </summary>
struct RtColorState
{
#pragma warning disable CS0649
public GpuVa Address;
public int WidthOrStride;
public int Height;
public ColorFormat Format;
public MemoryLayout MemoryLayout;
public int Depth;
public int LayerSize;
public int BaseLayer;
public int Unknown0x24;
public int Padding0;
public int Padding1;
public int Padding2;
public int Padding3;
public int Padding4;
public int Padding5;
#pragma warning restore CS0649
}
/// <summary>
/// Viewport transform parameters, for viewport transformation.
/// </summary>
struct ViewportTransform
{
#pragma warning disable CS0649
public float ScaleX;
public float ScaleY;
public float ScaleZ;
public float TranslateX;
public float TranslateY;
public float TranslateZ;
public uint Swizzle;
public uint SubpixelPrecisionBias;
#pragma warning restore CS0649
/// <summary>
/// Unpacks viewport swizzle of the position X component.
/// </summary>
/// <returns>Swizzle enum value</returns>
public ViewportSwizzle UnpackSwizzleX()
{
return (ViewportSwizzle)(Swizzle & 7);
}
/// <summary>
/// Unpacks viewport swizzle of the position Y component.
/// </summary>
/// <returns>Swizzle enum value</returns>
public ViewportSwizzle UnpackSwizzleY()
{
return (ViewportSwizzle)((Swizzle >> 4) & 7);
}
/// <summary>
/// Unpacks viewport swizzle of the position Z component.
/// </summary>
/// <returns>Swizzle enum value</returns>
public ViewportSwizzle UnpackSwizzleZ()
{
return (ViewportSwizzle)((Swizzle >> 8) & 7);
}
/// <summary>
/// Unpacks viewport swizzle of the position W component.
/// </summary>
/// <returns>Swizzle enum value</returns>
public ViewportSwizzle UnpackSwizzleW()
{
return (ViewportSwizzle)((Swizzle >> 12) & 7);
}
}
/// <summary>
/// Viewport extents for viewport clipping, also includes depth range.
/// </summary>
struct ViewportExtents
{
#pragma warning disable CS0649
public ushort X;
public ushort Width;
public ushort Y;
public ushort Height;
public float DepthNear;
public float DepthFar;
#pragma warning restore CS0649
}
/// <summary>
/// Draw state for non-indexed draws.
/// </summary>
struct VertexBufferDrawState
{
#pragma warning disable CS0649
public int First;
public int Count;
#pragma warning restore CS0649
}
/// <summary>
/// Color buffer clear color.
/// </summary>
struct ClearColors
{
#pragma warning disable CS0649
public float Red;
public float Green;
public float Blue;
public float Alpha;
#pragma warning restore CS0649
}
/// <summary>
/// Depth bias (also called polygon offset) parameters.
/// </summary>
struct DepthBiasState
{
#pragma warning disable CS0649
public Boolean32 PointEnable;
public Boolean32 LineEnable;
public Boolean32 FillEnable;
#pragma warning restore CS0649
}
/// <summary>
/// Scissor state.
/// </summary>
struct ScissorState
{
#pragma warning disable CS0649
public Boolean32 Enable;
public ushort X1;
public ushort X2;
public ushort Y1;
public ushort Y2;
public uint Padding;
#pragma warning restore CS0649
}
/// <summary>
/// Stencil test masks for back tests.
/// </summary>
struct StencilBackMasks
{
#pragma warning disable CS0649
public int FuncRef;
public int Mask;
public int FuncMask;
#pragma warning restore CS0649
}
/// <summary>
/// Render target depth-stencil buffer state.
/// </summary>
struct RtDepthStencilState
{
#pragma warning disable CS0649
public GpuVa Address;
public ZetaFormat Format;
public MemoryLayout MemoryLayout;
public int LayerSize;
#pragma warning restore CS0649
}
/// <summary>
/// Screen scissor state.
/// </summary>
struct ScreenScissorState
{
#pragma warning disable CS0649
public ushort X;
public ushort Width;
public ushort Y;
public ushort Height;
#pragma warning restore CS0649
}
/// <summary>
/// Vertex buffer attribute state.
/// </summary>
struct VertexAttribState
{
#pragma warning disable CS0649
public uint Attribute;
#pragma warning restore CS0649
/// <summary>
/// Unpacks the index of the vertex buffer this attribute belongs to.
/// </summary>
/// <returns>Vertex buffer index</returns>
public int UnpackBufferIndex()
{
return (int)(Attribute & 0x1f);
}
/// <summary>
/// Unpacks the attribute constant flag.
/// </summary>
/// <returns>True if the attribute is constant, false otherwise</returns>
public bool UnpackIsConstant()
{
return (Attribute & 0x40) != 0;
}
/// <summary>
/// Unpacks the offset, in bytes, of the attribute on the vertex buffer.
/// </summary>
/// <returns>Attribute offset in bytes</returns>
public int UnpackOffset()
{
return (int)((Attribute >> 7) & 0x3fff);
}
/// <summary>
/// Unpacks the Maxwell attribute format integer.
/// </summary>
/// <returns>Attribute format integer</returns>
public uint UnpackFormat()
{
return Attribute & 0x3fe00000;
}
}
/// <summary>
/// Render target draw buffers control.
/// </summary>
struct RtControl
{
#pragma warning disable CS0649
public uint Packed;
#pragma warning restore CS0649
/// <summary>
/// Unpacks the number of active draw buffers.
/// </summary>
/// <returns>Number of active draw buffers</returns>
public int UnpackCount()
{
return (int)(Packed & 0xf);
}
/// <summary>
/// Unpacks the color attachment index for a given draw buffer.
/// </summary>
/// <param name="index">Index of the draw buffer</param>
/// <returns>Attachment index</returns>
public int UnpackPermutationIndex(int index)
{
return (int)((Packed >> (4 + index * 3)) & 7);
}
}
/// <summary>
/// 3D, 2D or 1D texture size.
/// </summary>
struct Size3D
{
#pragma warning disable CS0649
public int Width;
public int Height;
public int Depth;
#pragma warning restore CS0649
}
/// <summary>
/// Stencil front test state and masks.
/// </summary>
struct StencilTestState
{
#pragma warning disable CS0649
public Boolean32 Enable;
public StencilOp FrontSFail;
public StencilOp FrontDpFail;
public StencilOp FrontDpPass;
public CompareOp FrontFunc;
public int FrontFuncRef;
public int FrontFuncMask;
public int FrontMask;
#pragma warning restore CS0649
}
/// <summary>
/// Screen Y control register.
/// </summary>
[Flags]
enum YControl
{
NegateY = 1 << 0,
TriangleRastFlip = 1 << 4
}
/// <summary>
/// Condition for conditional rendering.
/// </summary>
enum Condition
{
Never,
Always,
ResultNonZero,
Equal,
NotEqual
}
/// <summary>
/// Texture or sampler pool state.
/// </summary>
struct PoolState
{
#pragma warning disable CS0649
public GpuVa Address;
public int MaximumId;
#pragma warning restore CS0649
}
/// <summary>
/// Stencil back test state.
/// </summary>
struct StencilBackTestState
{
#pragma warning disable CS0649
public Boolean32 TwoSided;
public StencilOp BackSFail;
public StencilOp BackDpFail;
public StencilOp BackDpPass;
public CompareOp BackFunc;
#pragma warning restore CS0649
}
/// <summary>
/// Primitive restart state.
/// </summary>
struct PrimitiveRestartState
{
#pragma warning disable CS0649
public Boolean32 Enable;
public int Index;
#pragma warning restore CS0649
}
/// <summary>
/// GPU index buffer state.
/// This is used on indexed draws.
/// </summary>
struct IndexBufferState
{
#pragma warning disable CS0649
public GpuVa Address;
public GpuVa EndAddress;
public IndexType Type;
public int First;
#pragma warning restore CS0649
}
/// <summary>
/// Face culling and orientation parameters.
/// </summary>
struct FaceState
{
#pragma warning disable CS0649
public Boolean32 CullEnable;
public FrontFace FrontFace;
public Face CullFace;
#pragma warning restore CS0649
}
/// <summary>
/// View volume clip control.
/// </summary>
[Flags]
enum ViewVolumeClipControl
{
ForceDepthRangeZeroToOne = 1 << 0,
DepthClampDisabled = 1 << 11
}
/// <summary>
/// Logical operation state.
/// </summary>
struct LogicalOpState
{
#pragma warning disable CS0649
public Boolean32 Enable;
public LogicalOp LogicalOp;
#pragma warning restore CS0649
}
/// <summary>
/// Render target color buffer mask.
/// This defines which color channels are written to the color buffer.
/// </summary>
struct RtColorMask
{
#pragma warning disable CS0649
public uint Packed;
#pragma warning restore CS0649
/// <summary>
/// Unpacks red channel enable.
/// </summary>
/// <returns>True to write the new red channel color, false to keep the old value</returns>
public bool UnpackRed()
{
return (Packed & 0x1) != 0;
}
/// <summary>
/// Unpacks green channel enable.
/// </summary>
/// <returns>True to write the new green channel color, false to keep the old value</returns>
public bool UnpackGreen()
{
return (Packed & 0x10) != 0;
}
/// <summary>
/// Unpacks blue channel enable.
/// </summary>
/// <returns>True to write the new blue channel color, false to keep the old value</returns>
public bool UnpackBlue()
{
return (Packed & 0x100) != 0;
}
/// <summary>
/// Unpacks alpha channel enable.
/// </summary>
/// <returns>True to write the new alpha channel color, false to keep the old value</returns>
public bool UnpackAlpha()
{
return (Packed & 0x1000) != 0;
}
}
/// <summary>
/// Vertex buffer state.
/// </summary>
struct VertexBufferState
{
#pragma warning disable CS0649
public uint Control;
public GpuVa Address;
public int Divisor;
#pragma warning restore CS0649
/// <summary>
/// Vertex buffer stride, defined as the number of bytes occupied by each vertex in memory.
/// </summary>
/// <returns>Vertex buffer stride</returns>
public int UnpackStride()
{
return (int)(Control & 0xfff);
}
/// <summary>
/// Vertex buffer enable.
/// </summary>
/// <returns>True if the vertex buffer is enabled, false otherwise</returns>
public bool UnpackEnable()
{
return (Control & (1 << 12)) != 0;
}
}
/// <summary>
/// Color buffer blending parameters, shared by all color buffers.
/// </summary>
struct BlendStateCommon
{
#pragma warning disable CS0649
public Boolean32 SeparateAlpha;
public BlendOp ColorOp;
public BlendFactor ColorSrcFactor;
public BlendFactor ColorDstFactor;
public BlendOp AlphaOp;
public BlendFactor AlphaSrcFactor;
public uint Unknown0x1354;
public BlendFactor AlphaDstFactor;
#pragma warning restore CS0649
}
/// <summary>
/// Color buffer blending parameters.
/// </summary>
struct BlendState
{
#pragma warning disable CS0649
public Boolean32 SeparateAlpha;
public BlendOp ColorOp;
public BlendFactor ColorSrcFactor;
public BlendFactor ColorDstFactor;
public BlendOp AlphaOp;
public BlendFactor AlphaSrcFactor;
public BlendFactor AlphaDstFactor;
public uint Padding;
#pragma warning restore CS0649
}
/// <summary>
/// Graphics shader stage state.
/// </summary>
struct ShaderState
{
#pragma warning disable CS0649
public uint Control;
public uint Offset;
public uint Unknown0x8;
public int MaxRegisters;
public ShaderType Type;
public uint Unknown0x14;
public uint Unknown0x18;
public uint Unknown0x1c;
public uint Unknown0x20;
public uint Unknown0x24;
public uint Unknown0x28;
public uint Unknown0x2c;
public uint Unknown0x30;
public uint Unknown0x34;
public uint Unknown0x38;
public uint Unknown0x3c;
#pragma warning restore CS0649
/// <summary>
/// Unpacks shader enable information.
/// Must be ignored for vertex shaders, those are always enabled.
/// </summary>
/// <returns>True if the stage is enabled, false otherwise</returns>
public bool UnpackEnable()
{
return (Control & 1) != 0;
}
}
/// <summary>
/// Uniform buffer state for the uniform buffer currently being modified.
/// </summary>
struct UniformBufferState
{
#pragma warning disable CS0649
public int Size;
public GpuVa Address;
public int Offset;
#pragma warning restore CS0649
}
unsafe struct ThreedClassState : IShadowState
{
#pragma warning disable CS0649
public uint SetObject;
public int SetObjectClassId => (int)((SetObject >> 0) & 0xFFFF);
public int SetObjectEngineId => (int)((SetObject >> 16) & 0x1F);
public fixed uint Reserved04[63];
public uint NoOperation;
public uint SetNotifyA;
public int SetNotifyAAddressUpper => (int)((SetNotifyA >> 0) & 0xFF);
public uint SetNotifyB;
public uint Notify;
public NotifyType NotifyType => (NotifyType)(Notify);
public uint WaitForIdle;
public uint LoadMmeInstructionRamPointer;
public uint LoadMmeInstructionRam;
public uint LoadMmeStartAddressRamPointer;
public uint LoadMmeStartAddressRam;
public uint SetMmeShadowRamControl;
public SetMmeShadowRamControlMode SetMmeShadowRamControlMode => (SetMmeShadowRamControlMode)((SetMmeShadowRamControl >> 0) & 0x3);
public fixed uint Reserved128[2];
public uint SetGlobalRenderEnableA;
public int SetGlobalRenderEnableAOffsetUpper => (int)((SetGlobalRenderEnableA >> 0) & 0xFF);
public uint SetGlobalRenderEnableB;
public uint SetGlobalRenderEnableC;
public int SetGlobalRenderEnableCMode => (int)((SetGlobalRenderEnableC >> 0) & 0x7);
public uint SendGoIdle;
public uint PmTrigger;
public uint PmTriggerWfi;
public fixed uint Reserved148[2];
public uint SetInstrumentationMethodHeader;
public uint SetInstrumentationMethodData;
public fixed uint Reserved158[10];
public uint LineLengthIn;
public uint LineCount;
public uint OffsetOutUpper;
public int OffsetOutUpperValue => (int)((OffsetOutUpper >> 0) & 0xFF);
public uint OffsetOut;
public uint PitchOut;
public uint SetDstBlockSize;
public SetDstBlockSizeWidth SetDstBlockSizeWidth => (SetDstBlockSizeWidth)((SetDstBlockSize >> 0) & 0xF);
public SetDstBlockSizeHeight SetDstBlockSizeHeight => (SetDstBlockSizeHeight)((SetDstBlockSize >> 4) & 0xF);
public SetDstBlockSizeDepth SetDstBlockSizeDepth => (SetDstBlockSizeDepth)((SetDstBlockSize >> 8) & 0xF);
public uint SetDstWidth;
public uint SetDstHeight;
public uint SetDstDepth;
public uint SetDstLayer;
public uint SetDstOriginBytesX;
public int SetDstOriginBytesXV => (int)((SetDstOriginBytesX >> 0) & 0xFFFFF);
public uint SetDstOriginSamplesY;
public int SetDstOriginSamplesYV => (int)((SetDstOriginSamplesY >> 0) & 0xFFFF);
public uint LaunchDma;
public LaunchDmaDstMemoryLayout LaunchDmaDstMemoryLayout => (LaunchDmaDstMemoryLayout)((LaunchDma >> 0) & 0x1);
public LaunchDmaCompletionType LaunchDmaCompletionType => (LaunchDmaCompletionType)((LaunchDma >> 4) & 0x3);
public LaunchDmaInterruptType LaunchDmaInterruptType => (LaunchDmaInterruptType)((LaunchDma >> 8) & 0x3);
public LaunchDmaSemaphoreStructSize LaunchDmaSemaphoreStructSize => (LaunchDmaSemaphoreStructSize)((LaunchDma >> 12) & 0x1);
public bool LaunchDmaReductionEnable => (LaunchDma & 0x2) != 0;
public LaunchDmaReductionOp LaunchDmaReductionOp => (LaunchDmaReductionOp)((LaunchDma >> 13) & 0x7);
public LaunchDmaReductionFormat LaunchDmaReductionFormat => (LaunchDmaReductionFormat)((LaunchDma >> 2) & 0x3);
public bool LaunchDmaSysmembarDisable => (LaunchDma & 0x40) != 0;
public uint LoadInlineData;
public fixed uint Reserved1B8[22];
public Boolean32 EarlyZForce;
public fixed uint Reserved214[45];
public uint SyncpointAction;
public fixed uint Reserved2CC[44];
public Boolean32 RasterizeEnable;
public Array4<TfBufferState> TfBufferState;
public fixed uint Reserved400[192];
public Array4<TfState> TfState;
public fixed uint Reserved740[1];
public Boolean32 TfEnable;
public fixed uint Reserved748[46];
public Array8<RtColorState> RtColorState;
public Array16<ViewportTransform> ViewportTransform;
public Array16<ViewportExtents> ViewportExtents;
public fixed uint ReservedD00[29];
public VertexBufferDrawState VertexBufferDrawState;
public uint DepthMode;
public ClearColors ClearColors;
public float ClearDepthValue;
public fixed uint ReservedD94[3];
public uint ClearStencilValue;
public fixed uint ReservedDA4[7];
public DepthBiasState DepthBiasState;
public fixed uint ReservedDCC[5];
public uint TextureBarrier;
public fixed uint ReservedDE4[7];
public Array16<ScissorState> ScissorState;
public fixed uint ReservedF00[21];
public StencilBackMasks StencilBackMasks;
public fixed uint ReservedF60[5];
public uint InvalidateTextures;
public fixed uint ReservedF78[1];
public uint TextureBarrierTiled;
public fixed uint ReservedF80[4];
public Boolean32 RtColorMaskShared;
public fixed uint ReservedF94[19];
public RtDepthStencilState RtDepthStencilState;
public ScreenScissorState ScreenScissorState;
public fixed uint ReservedFFC[89];
public Array16<VertexAttribState> VertexAttribState;
public fixed uint Reserved11A0[31];
public RtControl RtControl;
public fixed uint Reserved1220[2];
public Size3D RtDepthStencilSize;
public SamplerIndex SamplerIndex;
public fixed uint Reserved1238[37];
public Boolean32 DepthTestEnable;
public fixed uint Reserved12D0[5];
public Boolean32 BlendIndependent;
public Boolean32 DepthWriteEnable;
public Boolean32 AlphaTestEnable;
public fixed uint Reserved12F0[5];
public uint VbElementU8;
public uint Reserved1308;
public CompareOp DepthTestFunc;
public float AlphaTestRef;
public CompareOp AlphaTestFunc;
public uint Reserved1318;
public ColorF BlendConstant;
public fixed uint Reserved132C[4];
public BlendStateCommon BlendStateCommon;
public Boolean32 BlendEnableCommon;
public Array8<Boolean32> BlendEnable;
public StencilTestState StencilTestState;
public fixed uint Reserved13A0[3];
public YControl YControl;
public float LineWidthSmooth;
public float LineWidthAliased;
public fixed uint Reserved13B8[31];
public uint FirstVertex;
public uint FirstInstance;
public fixed uint Reserved143C[53];
public uint ClipDistanceEnable;
public uint Reserved1514;
public float PointSize;
public uint Reserved151C;
public Boolean32 PointSpriteEnable;
public fixed uint Reserved1524[3];
public uint ResetCounter;
public uint Reserved1534;
public Boolean32 RtDepthStencilEnable;
public fixed uint Reserved153C[5];
public GpuVa RenderEnableAddress;
public Condition RenderEnableCondition;
public PoolState SamplerPoolState;
public uint Reserved1568;
public float DepthBiasFactor;
public Boolean32 LineSmoothEnable;
public PoolState TexturePoolState;
public fixed uint Reserved1580[5];
public StencilBackTestState StencilBackTestState;
public fixed uint Reserved15A8[5];
public float DepthBiasUnits;
public fixed uint Reserved15C0[4];
public TextureMsaaMode RtMsaaMode;
public fixed uint Reserved15D4[5];
public uint VbElementU32;
public uint Reserved15EC;
public uint VbElementU16;
public fixed uint Reserved15F4[4];
public uint PointCoordReplace;
public GpuVa ShaderBaseAddress;
public uint Reserved1610;
public uint DrawEnd;
public uint DrawBegin;
public fixed uint Reserved161C[10];
public PrimitiveRestartState PrimitiveRestartState;
public fixed uint Reserved164C[95];
public IndexBufferState IndexBufferState;
public uint IndexBufferCount;
public uint DrawIndexedSmall;
public uint DrawIndexedSmall2;
public uint Reserved17EC;
public uint DrawIndexedSmallIncInstance;
public uint DrawIndexedSmallIncInstance2;
public fixed uint Reserved17F8[33];
public float DepthBiasClamp;
public Array16<Boolean32> VertexBufferInstanced;
public fixed uint Reserved18C0[20];
public Boolean32 VertexProgramPointSize;
public uint Reserved1914;
public FaceState FaceState;
public fixed uint Reserved1924[2];
public uint ViewportTransformEnable;
public fixed uint Reserved1930[3];
public ViewVolumeClipControl ViewVolumeClipControl;
public fixed uint Reserved1940[2];
public Boolean32 PrimitiveTypeOverrideEnable;
public fixed uint Reserved194C[9];
public PrimitiveTypeOverride PrimitiveTypeOverride;
public fixed uint Reserved1974[20];
public LogicalOpState LogicOpState;
public uint Reserved19CC;
public uint Clear;
public fixed uint Reserved19D4[11];
public Array8<RtColorMask> RtColorMask;
public fixed uint Reserved1A20[56];
public GpuVa SemaphoreAddress;
public int SemaphorePayload;
public uint SemaphoreControl;
public fixed uint Reserved1B10[60];
public Array16<VertexBufferState> VertexBufferState;
public fixed uint Reserved1D00[64];
public Array8<BlendState> BlendState;
public Array16<GpuVa> VertexBufferEndAddress;
public fixed uint Reserved1F80[32];
public Array6<ShaderState> ShaderState;
public fixed uint Reserved2180[96];
public uint SetFalcon00;
public uint SetFalcon01;
public uint SetFalcon02;
public uint SetFalcon03;
public uint SetFalcon04;
public uint SetFalcon05;
public uint SetFalcon06;
public uint SetFalcon07;
public uint SetFalcon08;
public uint SetFalcon09;
public uint SetFalcon10;
public uint SetFalcon11;
public uint SetFalcon12;
public uint SetFalcon13;
public uint SetFalcon14;
public uint SetFalcon15;
public uint SetFalcon16;
public uint SetFalcon17;
public uint SetFalcon18;
public uint SetFalcon19;
public uint SetFalcon20;
public uint SetFalcon21;
public uint SetFalcon22;
public uint SetFalcon23;
public uint SetFalcon24;
public uint SetFalcon25;
public uint SetFalcon26;
public uint SetFalcon27;
public uint SetFalcon28;
public uint SetFalcon29;
public uint SetFalcon30;
public uint SetFalcon31;
public UniformBufferState UniformBufferState;
public Array16<uint> UniformBufferUpdateData;
public fixed uint Reserved23D0[16];
public uint UniformBufferBindVertex;
public fixed uint Reserved2414[7];
public uint UniformBufferBindTessControl;
public fixed uint Reserved2434[7];
public uint UniformBufferBindTessEvaluation;
public fixed uint Reserved2454[7];
public uint UniformBufferBindGeometry;
public fixed uint Reserved2474[7];
public uint UniformBufferBindFragment;
public fixed uint Reserved2494[93];
public uint TextureBufferIndex;
public fixed uint Reserved260C[125];
public Array4<Array32<uint>> TfVaryingLocations;
public fixed uint Reserved2A00[640];
public MmeShadowScratch SetMmeShadowScratch;
#pragma warning restore CS0649
}
}