From 791bf22109b90eca79fe1bf934074809661a6c86 Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
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<PipelineShaderStageCreateInfo> Stages;
         public PipelineLayout PipelineLayout;
         public SpecData SpecializationData;
@@ -319,6 +320,7 @@ namespace Ryujinx.Graphics.Vulkan
 
         public void Initialize()
         {
+            HasTessellationControlShader = false;
             Stages = new NativeArray<PipelineShaderStageCreateInfo>(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;