Initial tessellation shader support (#2534)

* Initial tessellation shader support

* Nits

* Re-arrange built-in table

* This is not needed anymore

* PR feedback
This commit is contained in:
gdkchan 2021-10-18 18:38:04 -03:00 committed by GitHub
parent 7603dbe3c8
commit d512ce122c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
42 changed files with 775 additions and 148 deletions

View file

@ -129,7 +129,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
_state.State.SetTexHeaderPoolCMaximumIndex,
_state.State.SetBindlessTextureConstantBufferSlotSelect,
false,
PrimitiveTopology.Points);
PrimitiveTopology.Points,
default);
ShaderBundle cs = memoryManager.Physical.ShaderCache.GetComputeShader(
_channel,

View file

@ -72,6 +72,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
nameof(ThreedClassState.VertexBufferState),
nameof(ThreedClassState.VertexBufferEndAddress)),
new StateUpdateCallbackEntry(UpdateTessellationState,
nameof(ThreedClassState.TessOuterLevel),
nameof(ThreedClassState.TessInnerLevel),
nameof(ThreedClassState.PatchVertices)),
new StateUpdateCallbackEntry(UpdateTfBufferState, nameof(ThreedClassState.TfBufferState)),
new StateUpdateCallbackEntry(UpdateUserClipState, nameof(ThreedClassState.ClipDistanceEnable)),
@ -100,6 +105,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
nameof(ThreedClassState.ViewportExtents),
nameof(ThreedClassState.YControl)),
new StateUpdateCallbackEntry(UpdatePolygonMode,
nameof(ThreedClassState.PolygonModeFront),
nameof(ThreedClassState.PolygonModeBack)),
new StateUpdateCallbackEntry(UpdateDepthBiasState,
nameof(ThreedClassState.DepthBiasState),
nameof(ThreedClassState.DepthBiasFactor),
@ -259,6 +268,17 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
}
}
/// <summary>
/// Updates tessellation state based on the guest GPU state.
/// </summary>
private void UpdateTessellationState()
{
_context.Renderer.Pipeline.SetPatchParameters(
_state.State.PatchVertices,
_state.State.TessOuterLevel.ToSpan(),
_state.State.TessInnerLevel.ToSpan());
}
/// <summary>
/// Updates transform feedback buffer state based on the guest GPU state.
/// </summary>
@ -544,6 +564,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_context.Renderer.Pipeline.SetViewports(0, viewports);
}
/// <summary>
/// Updates polygon mode state based on current GPU state.
/// </summary>
private void UpdatePolygonMode()
{
_context.Renderer.Pipeline.SetPolygonMode(_state.State.PolygonModeFront, _state.State.PolygonModeBack);
}
/// <summary>
/// Updates host depth bias (also called polygon offset) state based on current GPU state.
/// </summary>
@ -949,7 +977,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_state.State.TexturePoolState.MaximumId,
(int)_state.State.TextureBufferIndex,
_state.State.EarlyZForce,
_drawState.Topology);
_drawState.Topology,
_state.State.TessMode);
ShaderBundle gs = _channel.MemoryManager.Physical.ShaderCache.GetGraphicsShader(ref _state.State, _channel, gas, addresses);

View file

@ -3,6 +3,7 @@ using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Engine.InlineToMemory;
using Ryujinx.Graphics.Gpu.Engine.Types;
using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Graphics.Shader;
using System;
namespace Ryujinx.Graphics.Gpu.Engine.Threed
@ -19,6 +20,43 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
Fragment
}
/// <summary>
/// Tessellation mode.
/// </summary>
struct TessMode
{
#pragma warning disable CS0649
public uint Packed;
#pragma warning restore CS0649
/// <summary>
/// Unpacks the tessellation abstract patch type.
/// </summary>
/// <returns>Abtract patch type</returns>
public TessPatchType UnpackPatchType()
{
return (TessPatchType)(Packed & 3);
}
/// <summary>
/// Unpacks the spacing between tessellated vertices of the patch.
/// </summary>
/// <returns>Spacing between tessellated vertices</returns>
public TessSpacing UnpackSpacing()
{
return (TessSpacing)((Packed >> 4) & 3);
}
/// <summary>
/// Unpacks the primitive winding order.
/// </summary>
/// <returns>True if clockwise, false if counter-clockwise</returns>
public bool UnpackCw()
{
return (Packed & (1 << 8)) != 0;
}
}
/// <summary>
/// Transform feedback buffer state.
/// </summary>
@ -661,7 +699,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
public Boolean32 EarlyZForce;
public fixed uint Reserved214[45];
public uint SyncpointAction;
public fixed uint Reserved2CC[44];
public fixed uint Reserved2CC[21];
public TessMode TessMode;
public Array4<float> TessOuterLevel;
public Array2<float> TessInnerLevel;
public fixed uint Reserved33C[16];
public Boolean32 RasterizeEnable;
public Array4<TfBufferState> TfBufferState;
public fixed uint Reserved400[192];
@ -679,9 +721,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
public float ClearDepthValue;
public fixed uint ReservedD94[3];
public uint ClearStencilValue;
public fixed uint ReservedDA4[7];
public fixed uint ReservedDA4[2];
public PolygonMode PolygonModeFront;
public PolygonMode PolygonModeBack;
public Boolean32 PolygonSmoothEnable;
public fixed uint ReservedDB8[2];
public DepthBiasState DepthBiasState;
public fixed uint ReservedDCC[5];
public int PatchVertices;
public fixed uint ReservedDD0[4];
public uint TextureBarrier;
public fixed uint ReservedDE4[7];
public Array16<ScissorState> ScissorState;

View file

@ -349,6 +349,26 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache
return flags;
}
/// <summary>
/// Packs the tessellation parameters from the gpu accessor.
/// </summary>
/// <param name="gpuAccessor">The gpu accessor</param>
/// <returns>The packed tessellation parameters</returns>
private static byte GetTessellationModePacked(IGpuAccessor gpuAccessor)
{
byte value;
value = (byte)((int)gpuAccessor.QueryTessPatchType() & 3);
value |= (byte)(((int)gpuAccessor.QueryTessSpacing() & 3) << 2);
if (gpuAccessor.QueryTessCw())
{
value |= 0x10;
}
return value;
}
/// <summary>
/// Create a new instance of <see cref="GuestGpuAccessorHeader"/> from an gpu accessor.
/// </summary>
@ -364,6 +384,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache
ComputeLocalMemorySize = gpuAccessor.QueryComputeLocalMemorySize(),
ComputeSharedMemorySize = gpuAccessor.QueryComputeSharedMemorySize(),
PrimitiveTopology = gpuAccessor.QueryPrimitiveTopology(),
TessellationModePacked = GetTessellationModePacked(gpuAccessor),
StateFlags = GetGpuStateFlags(gpuAccessor)
};
}

View file

@ -49,10 +49,15 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
/// </summary>
public InputTopology PrimitiveTopology;
/// <summary>
/// Tessellation parameters (packed to fit on a byte).
/// </summary>
public byte TessellationModePacked;
/// <summary>
/// Unused/reserved.
/// </summary>
public ushort Reserved2;
public byte Reserved2;
/// <summary>
/// GPU boolean state that can influence shader compilation.

View file

@ -134,6 +134,33 @@ namespace Ryujinx.Graphics.Gpu.Shader
return _header.PrimitiveTopology;
}
/// <summary>
/// Queries the tessellation evaluation shader primitive winding order.
/// </summary>
/// <returns>True if the primitive winding order is clockwise, false if counter-clockwise</returns>
public bool QueryTessCw()
{
return (_header.TessellationModePacked & 0x10) != 0;
}
/// <summary>
/// Queries the tessellation evaluation shader abstract patch type.
/// </summary>
/// <returns>Abstract patch type</returns>
public TessPatchType QueryTessPatchType()
{
return (TessPatchType)(_header.TessellationModePacked & 3);
}
/// <summary>
/// Queries the tessellation evaluation shader spacing between tessellated vertices of the patch.
/// </summary>
/// <returns>Spacing between tessellated vertices of the patch</returns>
public TessSpacing QueryTessSpacing()
{
return (TessSpacing)((_header.TessellationModePacked >> 2) & 3);
}
/// <summary>
/// Gets the texture descriptor for a given texture on the pool.
/// </summary>

View file

@ -168,10 +168,31 @@ namespace Ryujinx.Graphics.Gpu.Shader
PrimitiveTopology.TriangleFan => InputTopology.Triangles,
PrimitiveTopology.TrianglesAdjacency or
PrimitiveTopology.TriangleStripAdjacency => InputTopology.TrianglesAdjacency,
_ => InputTopology.Points,
PrimitiveTopology.Patches => _state.TessellationMode.UnpackPatchType() == TessPatchType.Isolines
? InputTopology.Lines
: InputTopology.Triangles,
_ => InputTopology.Points
};
}
/// <summary>
/// Queries the tessellation evaluation shader primitive winding order.
/// </summary>
/// <returns>True if the primitive winding order is clockwise, false if counter-clockwise</returns>
public bool QueryTessCw() => _state.TessellationMode.UnpackCw();
/// <summary>
/// Queries the tessellation evaluation shader abstract patch type.
/// </summary>
/// <returns>Abstract patch type</returns>
public TessPatchType QueryTessPatchType() => _state.TessellationMode.UnpackPatchType();
/// <summary>
/// Queries the tessellation evaluation shader spacing between tessellated vertices of the patch.
/// </summary>
/// <returns>Spacing between tessellated vertices of the patch</returns>
public TessSpacing QueryTessSpacing() => _state.TessellationMode.UnpackSpacing();
/// <summary>
/// Gets the texture descriptor for a given texture on the pool.
/// </summary>

View file

@ -1,4 +1,5 @@
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Engine.Threed;
namespace Ryujinx.Graphics.Gpu.Shader
{
@ -32,6 +33,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary>
public PrimitiveTopology Topology { get; }
/// <summary>
/// Tessellation mode.
/// </summary>
public TessMode TessellationMode { get; }
/// <summary>
/// Creates a new instance of the GPU accessor state.
/// </summary>
@ -40,18 +46,21 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <param name="textureBufferIndex">Constant buffer slot where the texture handles are located</param>
/// <param name="earlyZForce">Early Z force enable</param>
/// <param name="topology">Primitive topology</param>
/// <param name="tessellationMode">Tessellation mode</param>
public GpuAccessorState(
ulong texturePoolGpuVa,
int texturePoolMaximumId,
int textureBufferIndex,
bool earlyZForce,
PrimitiveTopology topology)
PrimitiveTopology topology,
TessMode tessellationMode)
{
TexturePoolGpuVa = texturePoolGpuVa;
TexturePoolMaximumId = texturePoolMaximumId;
TextureBufferIndex = textureBufferIndex;
EarlyZForce = earlyZForce;
Topology = topology;
TessellationMode = tessellationMode;
}
}
}

View file

@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <summary>
/// Version of the codegen (to be changed when codegen or guest format change).
/// </summary>
private const ulong ShaderCodeGenVersion = 2702;
private const ulong ShaderCodeGenVersion = 2534;
// Progress reporting helpers
private volatile int _shaderCount;