diff options
author | gdkchan <gab.dark.100@gmail.com> | 2023-07-29 18:47:03 -0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-29 18:47:03 -0300 |
commit | f95b7c58779f01d9077996da67953d8d9acd058c (patch) | |
tree | b0be466b2e52f966620aa2e0acb4524d28da1b22 | |
parent | eb528ae0f05f057e671eb9e92f44f1caa9bcc84b (diff) |
Fix incorrect fragment origin when YNegate is enabled (#4673)1.1.970
* Fix incorrect fragment origin when YNegate is enabled
* Shader cache version bump
* Do not update support buffer if shader does not read gl_FragCoord
* Pass unscaled viewport size to the support buffer
17 files changed, 205 insertions, 24 deletions
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs index cbf1573c..b2935a5b 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs @@ -342,5 +342,19 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed Signal(); } } + + /// <summary> + /// Sets the Y negate enabled state. + /// </summary> + /// <param name="enabled">True if Y negate of the fragment coordinates is enabled</param> + public void SetYNegateEnabled(bool enabled) + { + if (enabled != _graphics.YNegateEnabled) + { + _graphics.YNegateEnabled = enabled; + + Signal(); + } + } } } diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs index b4f56245..c0c2d5b3 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs @@ -37,6 +37,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed private ProgramPipelineState _pipeline; + private bool _fsReadsFragCoord; private bool _vsUsesDrawParameters; private bool _vtgWritesRtLayer; private byte _vsClipDistancesWritten; @@ -692,12 +693,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed var face = _state.State.FaceState; bool disableTransform = _state.State.ViewportTransformEnable == 0; + bool yNegate = yControl.HasFlag(YControl.NegateY); UpdateFrontFace(yControl, face.FrontFace); UpdateDepthMode(); - bool flipY = yControl.HasFlag(YControl.NegateY); - Span<Viewport> viewports = stackalloc Viewport[Constants.TotalViewports]; for (int index = 0; index < Constants.TotalViewports; index++) @@ -719,7 +719,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed float scaleX = MathF.Abs(transform.ScaleX); float scaleY = transform.ScaleY; - if (flipY) + if (yNegate) { scaleY = -scaleY; } @@ -771,8 +771,17 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed _channel.TextureManager.RenderTargetScale, disableTransform); + // Viewport size is only used on the shader when YNegate is enabled, + // and if the fragment shader accesses gl_FragCoord, + // so there's no need to update it in other cases. + if (yNegate && _fsReadsFragCoord) + { + UpdateSupportBufferViewportSize(); + } + _currentSpecState.SetViewportTransformDisable(disableTransform); _currentSpecState.SetDepthMode(GetDepthMode() == DepthMode.MinusOneToOne); + _currentSpecState.SetYNegateEnabled(yNegate); } /// <summary> @@ -1415,10 +1424,42 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed _currentProgramInfo[stageIndex] = info; } + if (gs.Shaders[5]?.Info.UsesFragCoord == true) + { + // Make sure we update the viewport size on the support buffer if it will be consumed on the new shader. + + if (!_fsReadsFragCoord && _state.State.YControl.HasFlag(YControl.NegateY)) + { + UpdateSupportBufferViewportSize(); + } + + _fsReadsFragCoord = true; + } + else + { + _fsReadsFragCoord = false; + } + _context.Renderer.Pipeline.SetProgram(gs.HostProgram); } /// <summary> + /// Updates the viewport size on the support buffer for fragment shader access. + /// </summary> + private void UpdateSupportBufferViewportSize() + { + ref var transform = ref _state.State.ViewportTransform[0]; + + float scaleX = MathF.Abs(transform.ScaleX); + float scaleY = transform.ScaleY; + + float width = scaleX * 2; + float height = scaleY * 2; + + _context.SupportBufferUpdater.SetViewportSize(width, MathF.Abs(height)); + } + + /// <summary> /// Updates bindings consumed by the shader on the texture and buffer managers. /// </summary> /// <param name="bindings">Bindings for the active shader</param> diff --git a/src/Ryujinx.Graphics.Gpu/Memory/SupportBufferUpdater.cs b/src/Ryujinx.Graphics.Gpu/Memory/SupportBufferUpdater.cs index 50c042fb..b236476e 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/SupportBufferUpdater.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/SupportBufferUpdater.cs @@ -113,6 +113,17 @@ namespace Ryujinx.Graphics.Gpu.Memory } /// <summary> + /// Updates the viewport size vector. + /// </summary> + /// <param name="data">Viewport size vector</param> + private void UpdateViewportSize(Vector4<float> data) + { + _data.ViewportSize = data; + + MarkDirty(SupportBuffer.ViewportSizeOffset, SupportBuffer.FieldSize); + } + + /// <summary> /// Sets the scale of all output render targets (they should all have the same scale). /// </summary> /// <param name="scale">Scale value</param> @@ -193,6 +204,25 @@ namespace Ryujinx.Graphics.Gpu.Memory } /// <summary> + /// Sets the viewport size, used to invert the fragment coordinates Y value. + /// </summary> + /// <param name="viewportWidth">Value used as viewport width</param> + /// <param name="viewportHeight">Value used as viewport height</param> + public void SetViewportSize(float viewportWidth, float viewportHeight) + { + if (_data.ViewportSize.X != viewportWidth || _data.ViewportSize.Y != viewportHeight) + { + UpdateViewportSize(new Vector4<float> + { + X = viewportWidth, + Y = viewportHeight, + Z = 1, + W = 0 + }); + } + } + + /// <summary> /// Submits all pending buffer updates to the GPU. /// </summary> public void Commit() diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs index 7f01aca6..b5f9395e 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs @@ -248,6 +248,12 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache } /// <inheritdoc/> + public bool QueryYNegateEnabled() + { + return _oldSpecState.GraphicsState.YNegateEnabled; + } + + /// <inheritdoc/> public void RegisterTexture(int handle, int cbufSlot) { if (!_oldSpecState.TextureRegistered(_stageIndex, handle, cbufSlot)) diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs index 672b3b8d..4bab165d 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs @@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache private const ushort FileFormatVersionMajor = 1; private const ushort FileFormatVersionMinor = 2; private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor; - private const uint CodeGenVersion = 5266; + private const uint CodeGenVersion = 4675; private const string SharedTocFileName = "shared.toc"; private const string SharedDataFileName = "shared.data"; @@ -141,6 +141,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache public ShaderStage Stage; /// <summary> + /// Indicates if the fragment shader accesses the fragment coordinate built-in variable. + /// </summary> + public bool UsesFragCoord; + + /// <summary> /// Indicates if the shader accesses the Instance ID built-in variable. /// </summary> public bool UsesInstanceId; @@ -781,6 +786,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache ShaderIdentification.None, 0, dataInfo.Stage, + dataInfo.UsesFragCoord, dataInfo.UsesInstanceId, dataInfo.UsesDrawParameters, dataInfo.UsesRtLayer, @@ -807,6 +813,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache TexturesCount = (ushort)info.Textures.Count, ImagesCount = (ushort)info.Images.Count, Stage = info.Stage, + UsesFragCoord = info.UsesFragCoord, UsesInstanceId = info.UsesInstanceId, UsesDrawParameters = info.UsesDrawParameters, UsesRtLayer = info.UsesRtLayer, diff --git a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs index ca9c883e..1fcc93c5 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs @@ -114,6 +114,13 @@ namespace Ryujinx.Graphics.Gpu.Shader } /// <inheritdoc/> + public bool QueryEarlyZForce() + { + _state.SpecializationState?.RecordEarlyZForce(); + return _state.GraphicsState.EarlyZForce; + } + + /// <inheritdoc/> public AttributeType QueryFragmentOutputType(int location) { return _state.GraphicsState.FragmentOutputTypes[location]; @@ -276,16 +283,15 @@ namespace Ryujinx.Graphics.Gpu.Shader } /// <inheritdoc/> - public bool QueryEarlyZForce() + public bool QueryViewportTransformDisable() { - _state.SpecializationState?.RecordEarlyZForce(); - return _state.GraphicsState.EarlyZForce; + return _state.GraphicsState.ViewportTransformDisable; } /// <inheritdoc/> - public bool QueryViewportTransformDisable() + public bool QueryYNegateEnabled() { - return _state.GraphicsState.ViewportTransformDisable; + return _state.GraphicsState.YNegateEnabled; } /// <inheritdoc/> diff --git a/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs b/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs index 544e689a..f392491c 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs @@ -98,6 +98,11 @@ namespace Ryujinx.Graphics.Gpu.Shader public bool DualSourceBlendEnable; /// <summary> + /// Indicates whether Y negate of the fragment coordinates is enabled. + /// </summary> + public bool YNegateEnabled; + + /// <summary> /// Creates a new GPU graphics state. /// </summary> /// <param name="earlyZForce">Early Z force enable</param> @@ -116,7 +121,8 @@ namespace Ryujinx.Graphics.Gpu.Shader /// <param name="hasConstantBufferDrawParameters">Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0</param> /// <param name="hasUnalignedStorageBuffer">Indicates that any storage buffer use is unaligned</param> /// <param name="fragmentOutputTypes">Type of the fragment shader outputs</param> - /// <param name="dualSourceBlendEnable">Type of the vertex attributes consumed by the shader</param> + /// <param name="dualSourceBlendEnable">Indicates whether dual source blend is enabled</param> + /// <param name="yNegateEnabled">Indicates whether Y negate of the fragment coordinates is enabled</param> public GpuChannelGraphicsState( bool earlyZForce, PrimitiveTopology topology, @@ -134,7 +140,8 @@ namespace Ryujinx.Graphics.Gpu.Shader bool hasConstantBufferDrawParameters, bool hasUnalignedStorageBuffer, ref Array8<AttributeType> fragmentOutputTypes, - bool dualSourceBlendEnable) + bool dualSourceBlendEnable, + bool yNegateEnabled) { EarlyZForce = earlyZForce; Topology = topology; @@ -153,6 +160,7 @@ namespace Ryujinx.Graphics.Gpu.Shader HasUnalignedStorageBuffer = hasUnalignedStorageBuffer; FragmentOutputTypes = fragmentOutputTypes; DualSourceBlendEnable = dualSourceBlendEnable; + YNegateEnabled = yNegateEnabled; } } } diff --git a/src/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs b/src/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs index 775bfb2a..b33f96c5 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs @@ -540,6 +540,11 @@ namespace Ryujinx.Graphics.Gpu.Shader return false; } + if (graphicsState.YNegateEnabled != GraphicsState.YNegateEnabled) + { + return false; + } + return Matches(channel, ref poolState, checkTextures, isCompute: false); } 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), |