From 791bf22109b90eca79fe1bf934074809661a6c86 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sat, 6 Apr 2024 13:25:51 -0300 Subject: [PATCH] Vulkan: Skip draws when patches topology is used without a tessellation shader (#6508) --- src/Ryujinx.Graphics.Vulkan/PipelineBase.cs | 1 + src/Ryujinx.Graphics.Vulkan/PipelineState.cs | 11 +++++++++++ src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs | 2 ++ 3 files changed, 14 insertions(+) diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs index 2bcab51436..d5169a6884 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs @@ -981,6 +981,7 @@ namespace Ryujinx.Graphics.Vulkan _bindingBarriersDirty = true; _newState.PipelineLayout = internalProgram.PipelineLayout; + _newState.HasTessellationControlShader = internalProgram.HasTessellationControlShader; _newState.StagesCount = (uint)stages.Length; stages.CopyTo(_newState.Stages.AsSpan()[..stages.Length]); diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineState.cs b/src/Ryujinx.Graphics.Vulkan/PipelineState.cs index 25fd7168fb..49c12b3768 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineState.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineState.cs @@ -311,6 +311,7 @@ namespace Ryujinx.Graphics.Vulkan set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFBF) | ((value ? 1UL : 0UL) << 6); } + public bool HasTessellationControlShader; public NativeArray Stages; public PipelineLayout PipelineLayout; public SpecData SpecializationData; @@ -319,6 +320,7 @@ namespace Ryujinx.Graphics.Vulkan public void Initialize() { + HasTessellationControlShader = false; Stages = new NativeArray(Constants.MaxShaderStages); AdvancedBlendSrcPreMultiplied = true; @@ -419,6 +421,15 @@ namespace Ryujinx.Graphics.Vulkan PVertexBindingDescriptions = pVertexBindingDescriptions, }; + // Using patches topology without a tessellation shader is invalid. + // If we find such a case, return null pipeline to skip the draw. + if (Topology == PrimitiveTopology.PatchList && !HasTessellationControlShader) + { + program.AddGraphicsPipeline(ref Internal, null); + + return null; + } + bool primitiveRestartEnable = PrimitiveRestartEnable; bool topologySupportsRestart; diff --git a/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs b/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs index e4ea0e4e61..b2be541bf7 100644 --- a/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs +++ b/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs @@ -21,6 +21,7 @@ namespace Ryujinx.Graphics.Vulkan public bool HasMinimalLayout { get; } public bool UsePushDescriptors { get; } public bool IsCompute { get; } + public bool HasTessellationControlShader => (Stages & (1u << 3)) != 0; public uint Stages { get; } @@ -461,6 +462,7 @@ namespace Ryujinx.Graphics.Vulkan stages[i] = _shaders[i].GetInfo(); } + pipeline.HasTessellationControlShader = HasTessellationControlShader; pipeline.StagesCount = (uint)_shaders.Length; pipeline.PipelineLayout = PipelineLayout;