From 3b444f0ea36538435c23455ddd83eeeddcf1c8d0 Mon Sep 17 00:00:00 2001 From: gdk Date: Thu, 7 Apr 2022 20:01:13 -0300 Subject: [PATCH] SPIR-V: Geometry shader passthrough support --- .../CodeGen/Spirv/Declarations.cs | 26 +++++++++++++++++ .../CodeGen/Spirv/SpirvGenerator.cs | 6 ++++ .../StructuredIr/StructuredProgramContext.cs | 29 +++++++++++++++++++ .../VulkanInitialization.cs | 3 +- 4 files changed, 63 insertions(+), 1 deletion(-) diff --git a/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs index 349a376f4..e011725bf 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs @@ -385,6 +385,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv var spvType = context.TypePointer(StorageClass.Input, attrType); var spvVar = context.Variable(spvType, StorageClass.Input); + if (context.Config.PassthroughAttributes != 0) + { + context.Decorate(spvVar, Decoration.PassthroughNV); + } + context.Decorate(spvVar, Decoration.Location, (LiteralInteger)0); context.AddGlobalVariable(spvVar); @@ -483,10 +488,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input; var attrType = context.GetType(attrInfo.Type, attrInfo.Length); + bool builtInPassthrough = false; if (context.Config.Stage == ShaderStage.Geometry && !isOutAttr && (!attrInfo.IsBuiltin || AttributeInfo.IsArrayBuiltIn(attr))) { attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)context.InputVertices)); + + if (context.Config.GpPassthrough) + { + builtInPassthrough = true; + } } var spvType = context.TypePointer(storageClass, attrType); @@ -497,6 +508,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv context.Decorate(spvVar, Decoration.Patch); } + if (builtInPassthrough) + { + context.Decorate(spvVar, Decoration.PassthroughNV); + } + if (attrInfo.IsBuiltin) { context.Decorate(spvVar, Decoration.BuiltIn, (LiteralInteger)GetBuiltIn(context, attrInfo.BaseValue)); @@ -525,6 +541,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv if (!isOutAttr) { + if (!perPatch && (context.Config.PassthroughAttributes & (1 << location)) != 0) + { + context.Decorate(spvVar, Decoration.PassthroughNV); + } + switch (iq) { case PixelImap.Constant: @@ -585,6 +606,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv } else { + if ((context.Config.PassthroughAttributes & (1 << location)) != 0) + { + context.Decorate(spvVar, Decoration.PassthroughNV); + } + switch (iq) { case PixelImap.Constant: diff --git a/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs b/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs index 352e1aa65..666fcc42e 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs @@ -69,6 +69,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv else if (config.Stage == ShaderStage.Geometry) { context.AddCapability(Capability.Geometry); + + if (config.GpPassthrough) + { + context.AddExtension("SPV_NV_geometry_shader_passthrough"); + context.AddCapability(Capability.GeometryShaderPassthroughNV); + } } else if (config.Stage == ShaderStage.TessellationControl || config.Stage == ShaderStage.TessellationEvaluation) { diff --git a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramContext.cs b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramContext.cs index 19c4ad461..6dc1e85cf 100644 --- a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramContext.cs +++ b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramContext.cs @@ -2,6 +2,7 @@ using Ryujinx.Graphics.Shader.IntermediateRepresentation; using Ryujinx.Graphics.Shader.Translation; using System.Collections.Generic; using System.Linq; +using System.Numerics; using static Ryujinx.Graphics.Shader.StructuredIr.AstHelper; @@ -35,6 +36,34 @@ namespace Ryujinx.Graphics.Shader.StructuredIr Info = new StructuredProgramInfo(); Config = config; + + if (config.GpPassthrough) + { + int passthroughAttributes = config.PassthroughAttributes; + while (passthroughAttributes != 0) + { + int index = BitOperations.TrailingZeroCount(passthroughAttributes); + + int attrBase = AttributeConsts.UserAttributeBase + index * 16; + Info.Inputs.Add(attrBase); + Info.Inputs.Add(attrBase + 4); + Info.Inputs.Add(attrBase + 8); + Info.Inputs.Add(attrBase + 12); + + passthroughAttributes &= ~(1 << index); + } + + Info.Inputs.Add(AttributeConsts.PositionX); + Info.Inputs.Add(AttributeConsts.PositionY); + Info.Inputs.Add(AttributeConsts.PositionZ); + Info.Inputs.Add(AttributeConsts.PositionW); + Info.Inputs.Add(AttributeConsts.PointSize); + + for (int i = 0; i < 8; i++) + { + Info.Inputs.Add(AttributeConsts.ClipDistance0 + i * 4); + } + } } public void EnterFunction( diff --git a/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs b/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs index 68aad266c..8d116eb2b 100644 --- a/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs +++ b/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs @@ -32,7 +32,8 @@ namespace Ryujinx.Graphics.Vulkan "VK_EXT_fragment_shader_interlock", "VK_EXT_index_type_uint8", "VK_EXT_robustness2", - "VK_EXT_shader_subgroup_ballot" + "VK_EXT_shader_subgroup_ballot", + "VK_NV_geometry_shader_passthrough" }; private static readonly string[] _excludedMessages = new string[]