From d512ce122cb1c9a7fe7cb40d3f85d642ee37f897 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Mon, 18 Oct 2021 18:38:04 -0300 Subject: Initial tessellation shader support (#2534) * Initial tessellation shader support * Nits * Re-arrange built-in table * This is not needed anymore * PR feedback --- .../Engine/Compute/ComputeClass.cs | 3 +- Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs | 31 ++++++++++++- .../Engine/Threed/ThreedClassState.cs | 53 ++++++++++++++++++++-- Ryujinx.Graphics.Gpu/Shader/Cache/CacheHelper.cs | 21 +++++++++ .../Cache/Definition/GuestGpuAccessorHeader.cs | 7 ++- Ryujinx.Graphics.Gpu/Shader/CachedGpuAccessor.cs | 27 +++++++++++ Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs | 23 +++++++++- Ryujinx.Graphics.Gpu/Shader/GpuAccessorState.cs | 11 ++++- Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs | 2 +- 9 files changed, 169 insertions(+), 9 deletions(-) (limited to 'Ryujinx.Graphics.Gpu') diff --git a/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs b/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs index 8469f1ae..00015c40 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs @@ -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, diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs index f9d16803..4a5633c9 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs @@ -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 } } + /// + /// Updates tessellation state based on the guest GPU state. + /// + private void UpdateTessellationState() + { + _context.Renderer.Pipeline.SetPatchParameters( + _state.State.PatchVertices, + _state.State.TessOuterLevel.ToSpan(), + _state.State.TessInnerLevel.ToSpan()); + } + /// /// Updates transform feedback buffer state based on the guest GPU state. /// @@ -544,6 +564,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed _context.Renderer.Pipeline.SetViewports(0, viewports); } + /// + /// Updates polygon mode state based on current GPU state. + /// + private void UpdatePolygonMode() + { + _context.Renderer.Pipeline.SetPolygonMode(_state.State.PolygonModeFront, _state.State.PolygonModeBack); + } + /// /// Updates host depth bias (also called polygon offset) state based on current GPU state. /// @@ -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); diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs index a6392e3d..58bc0957 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs @@ -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 } + /// + /// Tessellation mode. + /// + struct TessMode + { +#pragma warning disable CS0649 + public uint Packed; +#pragma warning restore CS0649 + + /// + /// Unpacks the tessellation abstract patch type. + /// + /// Abtract patch type + public TessPatchType UnpackPatchType() + { + return (TessPatchType)(Packed & 3); + } + + /// + /// Unpacks the spacing between tessellated vertices of the patch. + /// + /// Spacing between tessellated vertices + public TessSpacing UnpackSpacing() + { + return (TessSpacing)((Packed >> 4) & 3); + } + + /// + /// Unpacks the primitive winding order. + /// + /// True if clockwise, false if counter-clockwise + public bool UnpackCw() + { + return (Packed & (1 << 8)) != 0; + } + } + /// /// Transform feedback buffer state. /// @@ -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 TessOuterLevel; + public Array2 TessInnerLevel; + public fixed uint Reserved33C[16]; public Boolean32 RasterizeEnable; public Array4 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; diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/CacheHelper.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/CacheHelper.cs index 33da42db..09107346 100644 --- a/Ryujinx.Graphics.Gpu/Shader/Cache/CacheHelper.cs +++ b/Ryujinx.Graphics.Gpu/Shader/Cache/CacheHelper.cs @@ -349,6 +349,26 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache return flags; } + /// + /// Packs the tessellation parameters from the gpu accessor. + /// + /// The gpu accessor + /// The packed tessellation parameters + 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; + } + /// /// Create a new instance of from an gpu accessor. /// @@ -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) }; } diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestGpuAccessorHeader.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestGpuAccessorHeader.cs index 610b2da1..2e044750 100644 --- a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestGpuAccessorHeader.cs +++ b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/GuestGpuAccessorHeader.cs @@ -49,10 +49,15 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition /// public InputTopology PrimitiveTopology; + /// + /// Tessellation parameters (packed to fit on a byte). + /// + public byte TessellationModePacked; + /// /// Unused/reserved. /// - public ushort Reserved2; + public byte Reserved2; /// /// GPU boolean state that can influence shader compilation. diff --git a/Ryujinx.Graphics.Gpu/Shader/CachedGpuAccessor.cs b/Ryujinx.Graphics.Gpu/Shader/CachedGpuAccessor.cs index 3a52b2fe..21d08823 100644 --- a/Ryujinx.Graphics.Gpu/Shader/CachedGpuAccessor.cs +++ b/Ryujinx.Graphics.Gpu/Shader/CachedGpuAccessor.cs @@ -134,6 +134,33 @@ namespace Ryujinx.Graphics.Gpu.Shader return _header.PrimitiveTopology; } + /// + /// Queries the tessellation evaluation shader primitive winding order. + /// + /// True if the primitive winding order is clockwise, false if counter-clockwise + public bool QueryTessCw() + { + return (_header.TessellationModePacked & 0x10) != 0; + } + + /// + /// Queries the tessellation evaluation shader abstract patch type. + /// + /// Abstract patch type + public TessPatchType QueryTessPatchType() + { + return (TessPatchType)(_header.TessellationModePacked & 3); + } + + /// + /// Queries the tessellation evaluation shader spacing between tessellated vertices of the patch. + /// + /// Spacing between tessellated vertices of the patch + public TessSpacing QueryTessSpacing() + { + return (TessSpacing)((_header.TessellationModePacked >> 2) & 3); + } + /// /// Gets the texture descriptor for a given texture on the pool. /// diff --git a/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs b/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs index 50e24b97..64604a99 100644 --- a/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs +++ b/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs @@ -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 }; } + /// + /// Queries the tessellation evaluation shader primitive winding order. + /// + /// True if the primitive winding order is clockwise, false if counter-clockwise + public bool QueryTessCw() => _state.TessellationMode.UnpackCw(); + + /// + /// Queries the tessellation evaluation shader abstract patch type. + /// + /// Abstract patch type + public TessPatchType QueryTessPatchType() => _state.TessellationMode.UnpackPatchType(); + + /// + /// Queries the tessellation evaluation shader spacing between tessellated vertices of the patch. + /// + /// Spacing between tessellated vertices of the patch + public TessSpacing QueryTessSpacing() => _state.TessellationMode.UnpackSpacing(); + /// /// Gets the texture descriptor for a given texture on the pool. /// diff --git a/Ryujinx.Graphics.Gpu/Shader/GpuAccessorState.cs b/Ryujinx.Graphics.Gpu/Shader/GpuAccessorState.cs index 8d817113..ebbf3b69 100644 --- a/Ryujinx.Graphics.Gpu/Shader/GpuAccessorState.cs +++ b/Ryujinx.Graphics.Gpu/Shader/GpuAccessorState.cs @@ -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 /// public PrimitiveTopology Topology { get; } + /// + /// Tessellation mode. + /// + public TessMode TessellationMode { get; } + /// /// Creates a new instance of the GPU accessor state. /// @@ -40,18 +46,21 @@ namespace Ryujinx.Graphics.Gpu.Shader /// Constant buffer slot where the texture handles are located /// Early Z force enable /// Primitive topology + /// Tessellation mode 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; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs index e69e7dcb..f2180820 100644 --- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs +++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs @@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Shader /// /// Version of the codegen (to be changed when codegen or guest format change). /// - private const ulong ShaderCodeGenVersion = 2702; + private const ulong ShaderCodeGenVersion = 2534; // Progress reporting helpers private volatile int _shaderCount; -- cgit v1.2.3