diff options
| author | riperiperi <rhy3756547@hotmail.com> | 2022-12-04 17:41:17 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-12-04 18:41:17 +0100 |
| commit | 9ac66336a216644a1b671e7949702d2e749838d2 (patch) | |
| tree | 549cb9cfd9f8f88f45a1064bafa57800eb241728 /Ryujinx.Graphics.Gpu/Shader | |
| parent | 4965681e069eeedc5272030b131c2a45e6131e61 (diff) | |
GPU: Use lazy checks for specialization state (#4004)
* GPU: Use lazy checks for specialization state
This PR adds a new class, the SpecializationStateUpdater, that allows elements of specialization state to be updated individually, and signal the state is checked when it changes between draws, instead of building and checking it on every draw. This also avoids building spec state when
Most state updates have been moved behind the shader state update, so that their specialization state updates make it in before shaders are fetched.
Downside: Fields in GpuChannelGraphicsState are no longer readonly. To counteract copies that might be caused this I pass it as `ref` when possible, though maybe `in` would be better? Not really sure about the quirks of `in` and the difference probably won't show on a benchmark.
The result is around 2 extra FPS on SMO in the usual spot. Not much right now, but it will remove costs when we're doing more expensive specialization checks, such as fragment output type specialization for macos. It may also help more on other games with more draws.
* Address Feedback
* Oops
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Shader')
6 files changed, 59 insertions, 36 deletions
diff --git a/Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs b/Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs index 511f4c23..e5e48626 100644 --- a/Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs +++ b/Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs @@ -15,62 +15,62 @@ namespace Ryujinx.Graphics.Gpu.Shader /// <summary> /// Early Z force enable. /// </summary> - public readonly bool EarlyZForce; + public bool EarlyZForce; /// <summary> /// Primitive topology of current draw. /// </summary> - public readonly PrimitiveTopology Topology; + public PrimitiveTopology Topology; /// <summary> /// Tessellation mode. /// </summary> - public readonly TessMode TessellationMode; + public TessMode TessellationMode; /// <summary> /// Indicates whether alpha-to-coverage is enabled. /// </summary> - public readonly bool AlphaToCoverageEnable; + public bool AlphaToCoverageEnable; /// <summary> /// Indicates whether alpha-to-coverage dithering is enabled. /// </summary> - public readonly bool AlphaToCoverageDitherEnable; + public bool AlphaToCoverageDitherEnable; /// <summary> /// Indicates whether the viewport transform is disabled. /// </summary> - public readonly bool ViewportTransformDisable; + public bool ViewportTransformDisable; /// <summary> /// Depth mode zero to one or minus one to one. /// </summary> - public readonly bool DepthMode; + public bool DepthMode; /// <summary> /// Indicates if the point size is set on the shader or is fixed. /// </summary> - public readonly bool ProgramPointSizeEnable; + public bool ProgramPointSizeEnable; /// <summary> /// Point size used if <see cref="ProgramPointSizeEnable" /> is false. /// </summary> - public readonly float PointSize; + public float PointSize; /// <summary> /// Indicates whether alpha test is enabled. /// </summary> - public readonly bool AlphaTestEnable; + public bool AlphaTestEnable; /// <summary> /// When alpha test is enabled, indicates the comparison that decides if the fragment should be discarded. /// </summary> - public readonly CompareOp AlphaTestCompare; + public CompareOp AlphaTestCompare; /// <summary> /// When alpha test is enabled, indicates the value to compare with the fragment output alpha. /// </summary> - public readonly float AlphaTestReference; + public float AlphaTestReference; /// <summary> /// Type of the vertex attributes consumed by the shader. @@ -80,12 +80,12 @@ namespace Ryujinx.Graphics.Gpu.Shader /// <summary> /// Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0. /// </summary> - public readonly bool HasConstantBufferDrawParameters; + public bool HasConstantBufferDrawParameters; /// <summary> /// Indicates that any storage buffer use is unaligned. /// </summary> - public readonly bool HasUnalignedStorageBuffer; + public bool HasUnalignedStorageBuffer; /// <summary> /// Creates a new GPU graphics state. diff --git a/Ryujinx.Graphics.Gpu/Shader/GpuChannelPoolState.cs b/Ryujinx.Graphics.Gpu/Shader/GpuChannelPoolState.cs index 0b36227a..b894c57e 100644 --- a/Ryujinx.Graphics.Gpu/Shader/GpuChannelPoolState.cs +++ b/Ryujinx.Graphics.Gpu/Shader/GpuChannelPoolState.cs @@ -1,9 +1,11 @@ +using System; + namespace Ryujinx.Graphics.Gpu.Shader { /// <summary> /// State used by the <see cref="GpuAccessor"/>. /// </summary> - struct GpuChannelPoolState + struct GpuChannelPoolState : IEquatable<GpuChannelPoolState> { /// <summary> /// GPU virtual address of the texture pool. @@ -32,5 +34,17 @@ namespace Ryujinx.Graphics.Gpu.Shader TexturePoolMaximumId = texturePoolMaximumId; TextureBufferIndex = textureBufferIndex; } + + /// <summary> + /// Check if the pool states are equal. + /// </summary> + /// <param name="other">Pool state to compare with</param> + /// <returns>True if they are equal, false otherwise</returns> + public bool Equals(GpuChannelPoolState other) + { + return TexturePoolGpuVa == other.TexturePoolGpuVa && + TexturePoolMaximumId == other.TexturePoolMaximumId && + TextureBufferIndex == other.TextureBufferIndex; + } } }
\ No newline at end of file diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs index 3eaab79f..23b213b4 100644 --- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs +++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs @@ -300,16 +300,16 @@ namespace Ryujinx.Graphics.Gpu.Shader ref ThreedClassState state, ref ProgramPipelineState pipeline, GpuChannel channel, - GpuChannelPoolState poolState, - GpuChannelGraphicsState graphicsState, + ref GpuChannelPoolState poolState, + ref GpuChannelGraphicsState graphicsState, ShaderAddresses addresses) { - if (_gpPrograms.TryGetValue(addresses, out var gpShaders) && IsShaderEqual(channel, poolState, graphicsState, gpShaders, addresses)) + if (_gpPrograms.TryGetValue(addresses, out var gpShaders) && IsShaderEqual(channel, ref poolState, ref graphicsState, gpShaders, addresses)) { return gpShaders; } - if (_graphicsShaderCache.TryFind(channel, poolState, graphicsState, addresses, out gpShaders, out var cachedGuestCode)) + if (_graphicsShaderCache.TryFind(channel, ref poolState, ref graphicsState, addresses, out gpShaders, out var cachedGuestCode)) { _gpPrograms[addresses] = gpShaders; return gpShaders; @@ -498,7 +498,7 @@ namespace Ryujinx.Graphics.Gpu.Shader { if (IsShaderEqual(channel.MemoryManager, cpShader.Shaders[0], gpuVa)) { - return cpShader.SpecializationState.MatchesCompute(channel, poolState, computeState, true); + return cpShader.SpecializationState.MatchesCompute(channel, ref poolState, computeState, true); } return false; @@ -515,8 +515,8 @@ namespace Ryujinx.Graphics.Gpu.Shader /// <returns>True if the code is different, false otherwise</returns> private static bool IsShaderEqual( GpuChannel channel, - GpuChannelPoolState poolState, - GpuChannelGraphicsState graphicsState, + ref GpuChannelPoolState poolState, + ref GpuChannelGraphicsState graphicsState, CachedShaderProgram gpShaders, ShaderAddresses addresses) { @@ -536,7 +536,7 @@ namespace Ryujinx.Graphics.Gpu.Shader bool usesDrawParameters = gpShaders.Shaders[1]?.Info.UsesDrawParameters ?? false; - return gpShaders.SpecializationState.MatchesGraphics(channel, poolState, graphicsState, usesDrawParameters, true); + return gpShaders.SpecializationState.MatchesGraphics(channel, ref poolState, ref graphicsState, usesDrawParameters, true); } /// <summary> diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCacheHashTable.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCacheHashTable.cs index 3d74e53a..e35c06b1 100644 --- a/Ryujinx.Graphics.Gpu/Shader/ShaderCacheHashTable.cs +++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCacheHashTable.cs @@ -215,8 +215,8 @@ namespace Ryujinx.Graphics.Gpu.Shader /// <returns>True if a cached host program was found, false otherwise</returns> public bool TryFind( GpuChannel channel, - GpuChannelPoolState poolState, - GpuChannelGraphicsState graphicsState, + ref GpuChannelPoolState poolState, + ref GpuChannelGraphicsState graphicsState, ShaderAddresses addresses, out CachedShaderProgram program, out CachedGraphicsGuestCode guestCode) @@ -236,7 +236,7 @@ namespace Ryujinx.Graphics.Gpu.Shader if (found && _shaderPrograms.TryGetValue(idTable, out ShaderSpecializationList specList)) { - return specList.TryFindForGraphics(channel, poolState, graphicsState, out program); + return specList.TryFindForGraphics(channel, ref poolState, ref graphicsState, out program); } return false; diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationList.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationList.cs index cb6ab49a..7d61332e 100644 --- a/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationList.cs +++ b/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationList.cs @@ -29,15 +29,15 @@ namespace Ryujinx.Graphics.Gpu.Shader /// <returns>True if a compatible program is found, false otherwise</returns> public bool TryFindForGraphics( GpuChannel channel, - GpuChannelPoolState poolState, - GpuChannelGraphicsState graphicsState, + ref GpuChannelPoolState poolState, + ref GpuChannelGraphicsState graphicsState, out CachedShaderProgram program) { foreach (var entry in _entries) { bool usesDrawParameters = entry.Shaders[1]?.Info.UsesDrawParameters ?? false; - if (entry.SpecializationState.MatchesGraphics(channel, poolState, graphicsState, usesDrawParameters, true)) + if (entry.SpecializationState.MatchesGraphics(channel, ref poolState, ref graphicsState, usesDrawParameters, true)) { program = entry; return true; @@ -60,7 +60,7 @@ namespace Ryujinx.Graphics.Gpu.Shader { foreach (var entry in _entries) { - if (entry.SpecializationState.MatchesCompute(channel, poolState, computeState, true)) + if (entry.SpecializationState.MatchesCompute(channel, ref poolState, computeState, true)) { program = entry; return true; diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs index 8f931507..14f64bbf 100644 --- a/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs +++ b/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs @@ -393,6 +393,15 @@ namespace Ryujinx.Graphics.Gpu.Shader } /// <summary> + /// Checks if primitive topology was queried by the shader. + /// </summary> + /// <returns>True if queried, false otherwise</returns> + public bool IsPrimitiveTopologyQueried() + { + return _queriedState.HasFlag(QueriedStateFlags.PrimitiveTopology); + } + + /// <summary> /// Checks if a given texture was registerd on this specialization state. /// </summary> /// <param name="stageIndex">Shader stage where the texture is used</param> @@ -486,8 +495,8 @@ namespace Ryujinx.Graphics.Gpu.Shader /// <returns>True if the state matches, false otherwise</returns> public bool MatchesGraphics( GpuChannel channel, - GpuChannelPoolState poolState, - GpuChannelGraphicsState graphicsState, + ref GpuChannelPoolState poolState, + ref GpuChannelGraphicsState graphicsState, bool usesDrawParameters, bool checkTextures) { @@ -536,7 +545,7 @@ namespace Ryujinx.Graphics.Gpu.Shader return false; } - return Matches(channel, poolState, checkTextures, isCompute: false); + return Matches(channel, ref poolState, checkTextures, isCompute: false); } /// <summary> @@ -547,14 +556,14 @@ namespace Ryujinx.Graphics.Gpu.Shader /// <param name="computeState">Compute state</param> /// <param name="checkTextures">Indicates whether texture descriptors should be checked</param> /// <returns>True if the state matches, false otherwise</returns> - public bool MatchesCompute(GpuChannel channel, GpuChannelPoolState poolState, GpuChannelComputeState computeState, bool checkTextures) + public bool MatchesCompute(GpuChannel channel, ref GpuChannelPoolState poolState, GpuChannelComputeState computeState, bool checkTextures) { if (computeState.HasUnalignedStorageBuffer != ComputeState.HasUnalignedStorageBuffer) { return false; } - return Matches(channel, poolState, checkTextures, isCompute: true); + return Matches(channel, ref poolState, checkTextures, isCompute: true); } /// <summary> @@ -618,7 +627,7 @@ namespace Ryujinx.Graphics.Gpu.Shader /// <param name="checkTextures">Indicates whether texture descriptors should be checked</param> /// <param name="isCompute">Indicates whenever the check is requested by the 3D or compute engine</param> /// <returns>True if the state matches, false otherwise</returns> - private bool Matches(GpuChannel channel, GpuChannelPoolState poolState, bool checkTextures, bool isCompute) + private bool Matches(GpuChannel channel, ref GpuChannelPoolState poolState, bool checkTextures, bool isCompute) { int constantBufferUsePerStageMask = _constantBufferUsePerStage; |
