diff options
Diffstat (limited to 'src/Ryujinx.Graphics.Shader')
9 files changed, 77 insertions, 13 deletions
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs index 2370b49f..2a45e23d 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs @@ -188,10 +188,19 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl context.AppendLine(); } - if (context.Config.Stage == ShaderStage.Fragment && context.Config.GpuAccessor.QueryEarlyZForce()) + if (context.Config.Stage == ShaderStage.Fragment) { - context.AppendLine("layout(early_fragment_tests) in;"); - context.AppendLine(); + if (context.Config.GpuAccessor.QueryEarlyZForce()) + { + context.AppendLine("layout (early_fragment_tests) in;"); + context.AppendLine(); + } + + if (context.Config.Properties.OriginUpperLeft) + { + context.AppendLine("layout (origin_upper_left) in vec4 gl_FragCoord;"); + context.AppendLine(); + } } if ((info.HelperFunctionsMask & HelperFunctionsMask.MultiplyHighS32) != 0) diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs index c8fcd75a..21797975 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs @@ -251,7 +251,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv } else if (context.Config.Stage == ShaderStage.Fragment) { - context.AddExecutionMode(spvFunc, context.Config.Options.TargetApi == TargetApi.Vulkan + context.AddExecutionMode(spvFunc, context.Config.Properties.OriginUpperLeft ? ExecutionMode.OriginUpperLeft : ExecutionMode.OriginLowerLeft); diff --git a/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs b/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs index 1c2b2809..a47791d3 100644 --- a/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs +++ b/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs @@ -179,6 +179,15 @@ namespace Ryujinx.Graphics.Shader } /// <summary> + /// Queries if host state forces early depth testing. + /// </summary> + /// <returns>True if early depth testing is forced</returns> + bool QueryEarlyZForce() + { + return false; + } + + /// <summary> /// Queries whenever the current draw has written the base vertex and base instance into Constant Buffer 0. /// </summary> /// <returns>True if the shader translator can assume that the constant buffer contains the base IDs, false otherwise</returns> @@ -534,19 +543,19 @@ namespace Ryujinx.Graphics.Shader } /// <summary> - /// Queries if host state forces early depth testing. + /// Queries if host state disables the viewport transform. /// </summary> - /// <returns>True if early depth testing is forced</returns> - bool QueryEarlyZForce() + /// <returns>True if the viewport transform is disabled</returns> + bool QueryViewportTransformDisable() { return false; } /// <summary> - /// Queries if host state disables the viewport transform. + /// Queries Y negate enable state. /// </summary> - /// <returns>True if the viewport transform is disabled</returns> - bool QueryViewportTransformDisable() + /// <returns>True if Y negate of the fragment coordinates is enabled, false otherwise</returns> + bool QueryYNegateEnabled() { return false; } diff --git a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs index 1876847c..c7bd0fd6 100644 --- a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs +++ b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs @@ -161,6 +161,18 @@ namespace Ryujinx.Graphics.Shader.Instructions // FragCoord X/Y must be divided by the render target scale, if resolution scaling is active, // because the shader code is not expecting scaled values. res = context.FPDivide(res, context.Load(StorageKind.ConstantBuffer, SupportBuffer.Binding, Const((int)SupportBufferField.RenderScale), Const(0))); + + if (op.Imm10 == AttributeConsts.PositionY && context.Config.Options.TargetApi != TargetApi.OpenGL) + { + // If YNegate is enabled, we need to flip the fragment coordinates vertically, unless + // the API supports changing the origin (only OpenGL does). + if (context.Config.GpuAccessor.QueryYNegateEnabled()) + { + Operand viewportHeight = context.Load(StorageKind.ConstantBuffer, 0, Const((int)SupportBufferField.ViewportSize), Const(1)); + + res = context.FPSubtract(viewportHeight, res); + } + } } else if (op.Imm10 == AttributeConsts.FrontFacing && context.Config.GpuAccessor.QueryHostHasFrontFacingBug()) { diff --git a/src/Ryujinx.Graphics.Shader/ShaderProgramInfo.cs b/src/Ryujinx.Graphics.Shader/ShaderProgramInfo.cs index e87769bb..f9776afc 100644 --- a/src/Ryujinx.Graphics.Shader/ShaderProgramInfo.cs +++ b/src/Ryujinx.Graphics.Shader/ShaderProgramInfo.cs @@ -13,6 +13,7 @@ namespace Ryujinx.Graphics.Shader public ShaderIdentification Identification { get; } public int GpLayerInputAttribute { get; } public ShaderStage Stage { get; } + public bool UsesFragCoord { get; } public bool UsesInstanceId { get; } public bool UsesDrawParameters { get; } public bool UsesRtLayer { get; } @@ -27,6 +28,7 @@ namespace Ryujinx.Graphics.Shader ShaderIdentification identification, int gpLayerInputAttribute, ShaderStage stage, + bool usesFragCoord, bool usesInstanceId, bool usesDrawParameters, bool usesRtLayer, @@ -41,6 +43,7 @@ namespace Ryujinx.Graphics.Shader Identification = identification; GpLayerInputAttribute = gpLayerInputAttribute; Stage = stage; + UsesFragCoord = usesFragCoord; UsesInstanceId = usesInstanceId; UsesDrawParameters = usesDrawParameters; UsesRtLayer = usesRtLayer; diff --git a/src/Ryujinx.Graphics.Shader/StructuredIr/ShaderProperties.cs b/src/Ryujinx.Graphics.Shader/StructuredIr/ShaderProperties.cs index 048a260a..b7e379c6 100644 --- a/src/Ryujinx.Graphics.Shader/StructuredIr/ShaderProperties.cs +++ b/src/Ryujinx.Graphics.Shader/StructuredIr/ShaderProperties.cs @@ -18,6 +18,8 @@ namespace Ryujinx.Graphics.Shader.StructuredIr public IReadOnlyDictionary<int, MemoryDefinition> LocalMemories => _localMemories; public IReadOnlyDictionary<int, MemoryDefinition> SharedMemories => _sharedMemories; + public readonly bool OriginUpperLeft; + public ShaderProperties() { _constantBuffers = new Dictionary<int, BufferDefinition>(); @@ -28,6 +30,11 @@ namespace Ryujinx.Graphics.Shader.StructuredIr _sharedMemories = new Dictionary<int, MemoryDefinition>(); } + public ShaderProperties(bool originUpperLeft) : this() + { + OriginUpperLeft = originUpperLeft; + } + public void AddOrUpdateConstantBuffer(int binding, BufferDefinition definition) { _constantBuffers[binding] = definition; diff --git a/src/Ryujinx.Graphics.Shader/SupportBuffer.cs b/src/Ryujinx.Graphics.Shader/SupportBuffer.cs index 24a99345..0b7a2edd 100644 --- a/src/Ryujinx.Graphics.Shader/SupportBuffer.cs +++ b/src/Ryujinx.Graphics.Shader/SupportBuffer.cs @@ -19,6 +19,7 @@ namespace Ryujinx.Graphics.Shader FragmentAlphaTest, FragmentIsBgra, ViewportInverse, + ViewportSize, FragmentRenderScaleCount, RenderScale, } @@ -33,6 +34,7 @@ namespace Ryujinx.Graphics.Shader public static readonly int FragmentAlphaTestOffset; public static readonly int FragmentIsBgraOffset; public static readonly int ViewportInverseOffset; + public static readonly int ViewportSizeOffset; public static readonly int FragmentRenderScaleCountOffset; public static readonly int GraphicsRenderScaleOffset; public static readonly int ComputeRenderScaleOffset; @@ -56,6 +58,7 @@ namespace Ryujinx.Graphics.Shader FragmentAlphaTestOffset = OffsetOf(ref instance, ref instance.FragmentAlphaTest); FragmentIsBgraOffset = OffsetOf(ref instance, ref instance.FragmentIsBgra); ViewportInverseOffset = OffsetOf(ref instance, ref instance.ViewportInverse); + ViewportSizeOffset = OffsetOf(ref instance, ref instance.ViewportSize); FragmentRenderScaleCountOffset = OffsetOf(ref instance, ref instance.FragmentRenderScaleCount); GraphicsRenderScaleOffset = OffsetOf(ref instance, ref instance.RenderScale); ComputeRenderScaleOffset = GraphicsRenderScaleOffset + FieldSize; @@ -68,6 +71,7 @@ namespace Ryujinx.Graphics.Shader new StructureField(AggregateType.U32, "s_alpha_test"), new StructureField(AggregateType.Array | AggregateType.U32, "s_is_bgra", FragmentIsBgraCount), new StructureField(AggregateType.Vector4 | AggregateType.FP32, "s_viewport_inverse"), + new StructureField(AggregateType.Vector4 | AggregateType.FP32, "s_viewport_size"), new StructureField(AggregateType.S32, "s_frag_scale_count"), new StructureField(AggregateType.Array | AggregateType.FP32, "s_render_scale", RenderScaleMaxCount), }); @@ -76,6 +80,7 @@ namespace Ryujinx.Graphics.Shader public Vector4<int> FragmentAlphaTest; public Array8<Vector4<int>> FragmentIsBgra; public Vector4<float> ViewportInverse; + public Vector4<float> ViewportSize; public Vector4<int> FragmentRenderScaleCount; // Render scale max count: 1 + 64 + 8. First scale is fragment output scale, others are textures/image inputs. diff --git a/src/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs b/src/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs index c92d0583..6cb57238 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs @@ -429,6 +429,11 @@ namespace Ryujinx.Graphics.Shader.Translation return context.Add(Instruction.FP32 | Instruction.SquareRoot, Local(), a); } + public static Operand FPSubtract(this EmitterContext context, Operand a, Operand b, Instruction fpType = Instruction.FP32) + { + return context.Add(fpType | Instruction.Subtract, Local(), a, b); + } + public static Operand FPTruncate(this EmitterContext context, Operand a, Instruction fpType = Instruction.FP32) { return context.Add(fpType | Instruction.Truncate, Local(), a); diff --git a/src/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/src/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs index 5741d028..27b46867 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs @@ -123,7 +123,20 @@ namespace Ryujinx.Graphics.Shader.Translation UsedInputAttributesPerPatch = new HashSet<int>(); UsedOutputAttributesPerPatch = new HashSet<int>(); - ResourceManager = new ResourceManager(stage, gpuAccessor, new ShaderProperties()); + ShaderProperties properties; + + switch (stage) + { + case ShaderStage.Fragment: + bool originUpperLeft = options.TargetApi == TargetApi.Vulkan || gpuAccessor.QueryYNegateEnabled(); + properties = new ShaderProperties(originUpperLeft); + break; + default: + properties = new ShaderProperties(); + break; + } + + ResourceManager = new ResourceManager(stage, gpuAccessor, properties); if (!gpuAccessor.QueryHostSupportsTransformFeedback() && gpuAccessor.QueryTransformFeedbackEnabled()) { @@ -135,7 +148,7 @@ namespace Ryujinx.Graphics.Shader.Translation BufferDefinition tfeInfoBuffer = new(BufferLayout.Std430, 1, Constants.TfeInfoBinding, "tfe_info", tfeInfoStruct); - Properties.AddOrUpdateStorageBuffer(Constants.TfeInfoBinding, tfeInfoBuffer); + properties.AddOrUpdateStorageBuffer(Constants.TfeInfoBinding, tfeInfoBuffer); StructureType tfeDataStruct = new(new StructureField[] { @@ -146,7 +159,7 @@ namespace Ryujinx.Graphics.Shader.Translation { int binding = Constants.TfeBufferBaseBinding + i; BufferDefinition tfeDataBuffer = new(BufferLayout.Std430, 1, binding, $"tfe_data{i}", tfeDataStruct); - Properties.AddOrUpdateStorageBuffer(binding, tfeDataBuffer); + properties.AddOrUpdateStorageBuffer(binding, tfeDataBuffer); } } } @@ -615,6 +628,7 @@ namespace Ryujinx.Graphics.Shader.Translation identification, GpLayerInputAttribute, Stage, + UsedFeatures.HasFlag(FeatureFlags.FragCoordXY), UsedFeatures.HasFlag(FeatureFlags.InstanceId), UsedFeatures.HasFlag(FeatureFlags.DrawParameters), UsedFeatures.HasFlag(FeatureFlags.RtLayer), |