Fix incorrect fragment origin when YNegate is enabled (#4673)
* 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
This commit is contained in:
parent
eb528ae0f0
commit
f95b7c5877
17 changed files with 207 additions and 26 deletions
|
@ -342,5 +342,19 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
Signal();
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
|
|
||||||
private ProgramPipelineState _pipeline;
|
private ProgramPipelineState _pipeline;
|
||||||
|
|
||||||
|
private bool _fsReadsFragCoord;
|
||||||
private bool _vsUsesDrawParameters;
|
private bool _vsUsesDrawParameters;
|
||||||
private bool _vtgWritesRtLayer;
|
private bool _vtgWritesRtLayer;
|
||||||
private byte _vsClipDistancesWritten;
|
private byte _vsClipDistancesWritten;
|
||||||
|
@ -692,12 +693,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
var face = _state.State.FaceState;
|
var face = _state.State.FaceState;
|
||||||
|
|
||||||
bool disableTransform = _state.State.ViewportTransformEnable == 0;
|
bool disableTransform = _state.State.ViewportTransformEnable == 0;
|
||||||
|
bool yNegate = yControl.HasFlag(YControl.NegateY);
|
||||||
|
|
||||||
UpdateFrontFace(yControl, face.FrontFace);
|
UpdateFrontFace(yControl, face.FrontFace);
|
||||||
UpdateDepthMode();
|
UpdateDepthMode();
|
||||||
|
|
||||||
bool flipY = yControl.HasFlag(YControl.NegateY);
|
|
||||||
|
|
||||||
Span<Viewport> viewports = stackalloc Viewport[Constants.TotalViewports];
|
Span<Viewport> viewports = stackalloc Viewport[Constants.TotalViewports];
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalViewports; index++)
|
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 scaleX = MathF.Abs(transform.ScaleX);
|
||||||
float scaleY = transform.ScaleY;
|
float scaleY = transform.ScaleY;
|
||||||
|
|
||||||
if (flipY)
|
if (yNegate)
|
||||||
{
|
{
|
||||||
scaleY = -scaleY;
|
scaleY = -scaleY;
|
||||||
}
|
}
|
||||||
|
@ -771,8 +771,17 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
_channel.TextureManager.RenderTargetScale,
|
_channel.TextureManager.RenderTargetScale,
|
||||||
disableTransform);
|
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.SetViewportTransformDisable(disableTransform);
|
||||||
_currentSpecState.SetDepthMode(GetDepthMode() == DepthMode.MinusOneToOne);
|
_currentSpecState.SetDepthMode(GetDepthMode() == DepthMode.MinusOneToOne);
|
||||||
|
_currentSpecState.SetYNegateEnabled(yNegate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1415,9 +1424,41 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
_currentProgramInfo[stageIndex] = info;
|
_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);
|
_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>
|
/// <summary>
|
||||||
/// Updates bindings consumed by the shader on the texture and buffer managers.
|
/// Updates bindings consumed by the shader on the texture and buffer managers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -112,6 +112,17 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
MarkDirty(SupportBuffer.ViewportInverseOffset, SupportBuffer.FieldSize);
|
MarkDirty(SupportBuffer.ViewportInverseOffset, SupportBuffer.FieldSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <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>
|
/// <summary>
|
||||||
/// Sets the scale of all output render targets (they should all have the same scale).
|
/// Sets the scale of all output render targets (they should all have the same scale).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -192,6 +203,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>
|
/// <summary>
|
||||||
/// Submits all pending buffer updates to the GPU.
|
/// Submits all pending buffer updates to the GPU.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -247,6 +247,12 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||||
return _oldSpecState.GraphicsState.ViewportTransformDisable;
|
return _oldSpecState.GraphicsState.ViewportTransformDisable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool QueryYNegateEnabled()
|
||||||
|
{
|
||||||
|
return _oldSpecState.GraphicsState.YNegateEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void RegisterTexture(int handle, int cbufSlot)
|
public void RegisterTexture(int handle, int cbufSlot)
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||||
private const ushort FileFormatVersionMajor = 1;
|
private const ushort FileFormatVersionMajor = 1;
|
||||||
private const ushort FileFormatVersionMinor = 2;
|
private const ushort FileFormatVersionMinor = 2;
|
||||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
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 SharedTocFileName = "shared.toc";
|
||||||
private const string SharedDataFileName = "shared.data";
|
private const string SharedDataFileName = "shared.data";
|
||||||
|
@ -140,6 +140,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ShaderStage Stage;
|
public ShaderStage Stage;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates if the fragment shader accesses the fragment coordinate built-in variable.
|
||||||
|
/// </summary>
|
||||||
|
public bool UsesFragCoord;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates if the shader accesses the Instance ID built-in variable.
|
/// Indicates if the shader accesses the Instance ID built-in variable.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -781,6 +786,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||||
ShaderIdentification.None,
|
ShaderIdentification.None,
|
||||||
0,
|
0,
|
||||||
dataInfo.Stage,
|
dataInfo.Stage,
|
||||||
|
dataInfo.UsesFragCoord,
|
||||||
dataInfo.UsesInstanceId,
|
dataInfo.UsesInstanceId,
|
||||||
dataInfo.UsesDrawParameters,
|
dataInfo.UsesDrawParameters,
|
||||||
dataInfo.UsesRtLayer,
|
dataInfo.UsesRtLayer,
|
||||||
|
@ -807,6 +813,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||||
TexturesCount = (ushort)info.Textures.Count,
|
TexturesCount = (ushort)info.Textures.Count,
|
||||||
ImagesCount = (ushort)info.Images.Count,
|
ImagesCount = (ushort)info.Images.Count,
|
||||||
Stage = info.Stage,
|
Stage = info.Stage,
|
||||||
|
UsesFragCoord = info.UsesFragCoord,
|
||||||
UsesInstanceId = info.UsesInstanceId,
|
UsesInstanceId = info.UsesInstanceId,
|
||||||
UsesDrawParameters = info.UsesDrawParameters,
|
UsesDrawParameters = info.UsesDrawParameters,
|
||||||
UsesRtLayer = info.UsesRtLayer,
|
UsesRtLayer = info.UsesRtLayer,
|
||||||
|
|
|
@ -113,6 +113,13 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
return _state.GraphicsState.AttributeTypes[location];
|
return _state.GraphicsState.AttributeTypes[location];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool QueryEarlyZForce()
|
||||||
|
{
|
||||||
|
_state.SpecializationState?.RecordEarlyZForce();
|
||||||
|
return _state.GraphicsState.EarlyZForce;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public AttributeType QueryFragmentOutputType(int location)
|
public AttributeType QueryFragmentOutputType(int location)
|
||||||
{
|
{
|
||||||
|
@ -275,19 +282,18 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
return _state.TransformFeedbackDescriptors[bufferIndex].Stride;
|
return _state.TransformFeedbackDescriptors[bufferIndex].Stride;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public bool QueryEarlyZForce()
|
|
||||||
{
|
|
||||||
_state.SpecializationState?.RecordEarlyZForce();
|
|
||||||
return _state.GraphicsState.EarlyZForce;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool QueryViewportTransformDisable()
|
public bool QueryViewportTransformDisable()
|
||||||
{
|
{
|
||||||
return _state.GraphicsState.ViewportTransformDisable;
|
return _state.GraphicsState.ViewportTransformDisable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool QueryYNegateEnabled()
|
||||||
|
{
|
||||||
|
return _state.GraphicsState.YNegateEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void RegisterTexture(int handle, int cbufSlot)
|
public void RegisterTexture(int handle, int cbufSlot)
|
||||||
{
|
{
|
||||||
|
|
|
@ -97,6 +97,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool DualSourceBlendEnable;
|
public bool DualSourceBlendEnable;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates whether Y negate of the fragment coordinates is enabled.
|
||||||
|
/// </summary>
|
||||||
|
public bool YNegateEnabled;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new GPU graphics state.
|
/// Creates a new GPU graphics state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -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="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="hasUnalignedStorageBuffer">Indicates that any storage buffer use is unaligned</param>
|
||||||
/// <param name="fragmentOutputTypes">Type of the fragment shader outputs</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(
|
public GpuChannelGraphicsState(
|
||||||
bool earlyZForce,
|
bool earlyZForce,
|
||||||
PrimitiveTopology topology,
|
PrimitiveTopology topology,
|
||||||
|
@ -134,7 +140,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
bool hasConstantBufferDrawParameters,
|
bool hasConstantBufferDrawParameters,
|
||||||
bool hasUnalignedStorageBuffer,
|
bool hasUnalignedStorageBuffer,
|
||||||
ref Array8<AttributeType> fragmentOutputTypes,
|
ref Array8<AttributeType> fragmentOutputTypes,
|
||||||
bool dualSourceBlendEnable)
|
bool dualSourceBlendEnable,
|
||||||
|
bool yNegateEnabled)
|
||||||
{
|
{
|
||||||
EarlyZForce = earlyZForce;
|
EarlyZForce = earlyZForce;
|
||||||
Topology = topology;
|
Topology = topology;
|
||||||
|
@ -153,6 +160,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
HasUnalignedStorageBuffer = hasUnalignedStorageBuffer;
|
HasUnalignedStorageBuffer = hasUnalignedStorageBuffer;
|
||||||
FragmentOutputTypes = fragmentOutputTypes;
|
FragmentOutputTypes = fragmentOutputTypes;
|
||||||
DualSourceBlendEnable = dualSourceBlendEnable;
|
DualSourceBlendEnable = dualSourceBlendEnable;
|
||||||
|
YNegateEnabled = yNegateEnabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -540,6 +540,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (graphicsState.YNegateEnabled != GraphicsState.YNegateEnabled)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return Matches(channel, ref poolState, checkTextures, isCompute: false);
|
return Matches(channel, ref poolState, checkTextures, isCompute: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -188,10 +188,19 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
context.AppendLine();
|
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;");
|
if (context.Config.GpuAccessor.QueryEarlyZForce())
|
||||||
context.AppendLine();
|
{
|
||||||
|
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)
|
if ((info.HelperFunctionsMask & HelperFunctionsMask.MultiplyHighS32) != 0)
|
||||||
|
|
|
@ -251,7 +251,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
}
|
}
|
||||||
else if (context.Config.Stage == ShaderStage.Fragment)
|
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.OriginUpperLeft
|
||||||
: ExecutionMode.OriginLowerLeft);
|
: ExecutionMode.OriginLowerLeft);
|
||||||
|
|
||||||
|
|
|
@ -178,6 +178,15 @@ namespace Ryujinx.Graphics.Shader
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queries if host state forces early depth testing.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if early depth testing is forced</returns>
|
||||||
|
bool QueryEarlyZForce()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queries whenever the current draw has written the base vertex and base instance into Constant Buffer 0.
|
/// Queries whenever the current draw has written the base vertex and base instance into Constant Buffer 0.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -534,19 +543,19 @@ namespace Ryujinx.Graphics.Shader
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queries if host state forces early depth testing.
|
/// Queries if host state disables the viewport transform.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True if early depth testing is forced</returns>
|
/// <returns>True if the viewport transform is disabled</returns>
|
||||||
bool QueryEarlyZForce()
|
bool QueryViewportTransformDisable()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queries if host state disables the viewport transform.
|
/// Queries Y negate enable state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True if the viewport transform is disabled</returns>
|
/// <returns>True if Y negate of the fragment coordinates is enabled, false otherwise</returns>
|
||||||
bool QueryViewportTransformDisable()
|
bool QueryYNegateEnabled()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
// 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.
|
// 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)));
|
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())
|
else if (op.Imm10 == AttributeConsts.FrontFacing && context.Config.GpuAccessor.QueryHostHasFrontFacingBug())
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,6 +13,7 @@ namespace Ryujinx.Graphics.Shader
|
||||||
public ShaderIdentification Identification { get; }
|
public ShaderIdentification Identification { get; }
|
||||||
public int GpLayerInputAttribute { get; }
|
public int GpLayerInputAttribute { get; }
|
||||||
public ShaderStage Stage { get; }
|
public ShaderStage Stage { get; }
|
||||||
|
public bool UsesFragCoord { get; }
|
||||||
public bool UsesInstanceId { get; }
|
public bool UsesInstanceId { get; }
|
||||||
public bool UsesDrawParameters { get; }
|
public bool UsesDrawParameters { get; }
|
||||||
public bool UsesRtLayer { get; }
|
public bool UsesRtLayer { get; }
|
||||||
|
@ -27,6 +28,7 @@ namespace Ryujinx.Graphics.Shader
|
||||||
ShaderIdentification identification,
|
ShaderIdentification identification,
|
||||||
int gpLayerInputAttribute,
|
int gpLayerInputAttribute,
|
||||||
ShaderStage stage,
|
ShaderStage stage,
|
||||||
|
bool usesFragCoord,
|
||||||
bool usesInstanceId,
|
bool usesInstanceId,
|
||||||
bool usesDrawParameters,
|
bool usesDrawParameters,
|
||||||
bool usesRtLayer,
|
bool usesRtLayer,
|
||||||
|
@ -41,6 +43,7 @@ namespace Ryujinx.Graphics.Shader
|
||||||
Identification = identification;
|
Identification = identification;
|
||||||
GpLayerInputAttribute = gpLayerInputAttribute;
|
GpLayerInputAttribute = gpLayerInputAttribute;
|
||||||
Stage = stage;
|
Stage = stage;
|
||||||
|
UsesFragCoord = usesFragCoord;
|
||||||
UsesInstanceId = usesInstanceId;
|
UsesInstanceId = usesInstanceId;
|
||||||
UsesDrawParameters = usesDrawParameters;
|
UsesDrawParameters = usesDrawParameters;
|
||||||
UsesRtLayer = usesRtLayer;
|
UsesRtLayer = usesRtLayer;
|
||||||
|
|
|
@ -18,6 +18,8 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
public IReadOnlyDictionary<int, MemoryDefinition> LocalMemories => _localMemories;
|
public IReadOnlyDictionary<int, MemoryDefinition> LocalMemories => _localMemories;
|
||||||
public IReadOnlyDictionary<int, MemoryDefinition> SharedMemories => _sharedMemories;
|
public IReadOnlyDictionary<int, MemoryDefinition> SharedMemories => _sharedMemories;
|
||||||
|
|
||||||
|
public readonly bool OriginUpperLeft;
|
||||||
|
|
||||||
public ShaderProperties()
|
public ShaderProperties()
|
||||||
{
|
{
|
||||||
_constantBuffers = new Dictionary<int, BufferDefinition>();
|
_constantBuffers = new Dictionary<int, BufferDefinition>();
|
||||||
|
@ -28,6 +30,11 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
_sharedMemories = new Dictionary<int, MemoryDefinition>();
|
_sharedMemories = new Dictionary<int, MemoryDefinition>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ShaderProperties(bool originUpperLeft) : this()
|
||||||
|
{
|
||||||
|
OriginUpperLeft = originUpperLeft;
|
||||||
|
}
|
||||||
|
|
||||||
public void AddOrUpdateConstantBuffer(int binding, BufferDefinition definition)
|
public void AddOrUpdateConstantBuffer(int binding, BufferDefinition definition)
|
||||||
{
|
{
|
||||||
_constantBuffers[binding] = definition;
|
_constantBuffers[binding] = definition;
|
||||||
|
|
|
@ -19,6 +19,7 @@ namespace Ryujinx.Graphics.Shader
|
||||||
FragmentAlphaTest,
|
FragmentAlphaTest,
|
||||||
FragmentIsBgra,
|
FragmentIsBgra,
|
||||||
ViewportInverse,
|
ViewportInverse,
|
||||||
|
ViewportSize,
|
||||||
FragmentRenderScaleCount,
|
FragmentRenderScaleCount,
|
||||||
RenderScale,
|
RenderScale,
|
||||||
}
|
}
|
||||||
|
@ -33,6 +34,7 @@ namespace Ryujinx.Graphics.Shader
|
||||||
public static readonly int FragmentAlphaTestOffset;
|
public static readonly int FragmentAlphaTestOffset;
|
||||||
public static readonly int FragmentIsBgraOffset;
|
public static readonly int FragmentIsBgraOffset;
|
||||||
public static readonly int ViewportInverseOffset;
|
public static readonly int ViewportInverseOffset;
|
||||||
|
public static readonly int ViewportSizeOffset;
|
||||||
public static readonly int FragmentRenderScaleCountOffset;
|
public static readonly int FragmentRenderScaleCountOffset;
|
||||||
public static readonly int GraphicsRenderScaleOffset;
|
public static readonly int GraphicsRenderScaleOffset;
|
||||||
public static readonly int ComputeRenderScaleOffset;
|
public static readonly int ComputeRenderScaleOffset;
|
||||||
|
@ -56,6 +58,7 @@ namespace Ryujinx.Graphics.Shader
|
||||||
FragmentAlphaTestOffset = OffsetOf(ref instance, ref instance.FragmentAlphaTest);
|
FragmentAlphaTestOffset = OffsetOf(ref instance, ref instance.FragmentAlphaTest);
|
||||||
FragmentIsBgraOffset = OffsetOf(ref instance, ref instance.FragmentIsBgra);
|
FragmentIsBgraOffset = OffsetOf(ref instance, ref instance.FragmentIsBgra);
|
||||||
ViewportInverseOffset = OffsetOf(ref instance, ref instance.ViewportInverse);
|
ViewportInverseOffset = OffsetOf(ref instance, ref instance.ViewportInverse);
|
||||||
|
ViewportSizeOffset = OffsetOf(ref instance, ref instance.ViewportSize);
|
||||||
FragmentRenderScaleCountOffset = OffsetOf(ref instance, ref instance.FragmentRenderScaleCount);
|
FragmentRenderScaleCountOffset = OffsetOf(ref instance, ref instance.FragmentRenderScaleCount);
|
||||||
GraphicsRenderScaleOffset = OffsetOf(ref instance, ref instance.RenderScale);
|
GraphicsRenderScaleOffset = OffsetOf(ref instance, ref instance.RenderScale);
|
||||||
ComputeRenderScaleOffset = GraphicsRenderScaleOffset + FieldSize;
|
ComputeRenderScaleOffset = GraphicsRenderScaleOffset + FieldSize;
|
||||||
|
@ -68,6 +71,7 @@ namespace Ryujinx.Graphics.Shader
|
||||||
new StructureField(AggregateType.U32, "s_alpha_test"),
|
new StructureField(AggregateType.U32, "s_alpha_test"),
|
||||||
new StructureField(AggregateType.Array | AggregateType.U32, "s_is_bgra", FragmentIsBgraCount),
|
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_inverse"),
|
||||||
|
new StructureField(AggregateType.Vector4 | AggregateType.FP32, "s_viewport_size"),
|
||||||
new StructureField(AggregateType.S32, "s_frag_scale_count"),
|
new StructureField(AggregateType.S32, "s_frag_scale_count"),
|
||||||
new StructureField(AggregateType.Array | AggregateType.FP32, "s_render_scale", RenderScaleMaxCount),
|
new StructureField(AggregateType.Array | AggregateType.FP32, "s_render_scale", RenderScaleMaxCount),
|
||||||
});
|
});
|
||||||
|
@ -76,6 +80,7 @@ namespace Ryujinx.Graphics.Shader
|
||||||
public Vector4<int> FragmentAlphaTest;
|
public Vector4<int> FragmentAlphaTest;
|
||||||
public Array8<Vector4<int>> FragmentIsBgra;
|
public Array8<Vector4<int>> FragmentIsBgra;
|
||||||
public Vector4<float> ViewportInverse;
|
public Vector4<float> ViewportInverse;
|
||||||
|
public Vector4<float> ViewportSize;
|
||||||
public Vector4<int> FragmentRenderScaleCount;
|
public Vector4<int> FragmentRenderScaleCount;
|
||||||
|
|
||||||
// Render scale max count: 1 + 64 + 8. First scale is fragment output scale, others are textures/image inputs.
|
// Render scale max count: 1 + 64 + 8. First scale is fragment output scale, others are textures/image inputs.
|
||||||
|
|
|
@ -429,6 +429,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
return context.Add(Instruction.FP32 | Instruction.SquareRoot, Local(), a);
|
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)
|
public static Operand FPTruncate(this EmitterContext context, Operand a, Instruction fpType = Instruction.FP32)
|
||||||
{
|
{
|
||||||
return context.Add(fpType | Instruction.Truncate, Local(), a);
|
return context.Add(fpType | Instruction.Truncate, Local(), a);
|
||||||
|
|
|
@ -123,7 +123,20 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
UsedInputAttributesPerPatch = new HashSet<int>();
|
UsedInputAttributesPerPatch = new HashSet<int>();
|
||||||
UsedOutputAttributesPerPatch = 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())
|
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);
|
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[]
|
StructureType tfeDataStruct = new(new StructureField[]
|
||||||
{
|
{
|
||||||
|
@ -146,7 +159,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
{
|
{
|
||||||
int binding = Constants.TfeBufferBaseBinding + i;
|
int binding = Constants.TfeBufferBaseBinding + i;
|
||||||
BufferDefinition tfeDataBuffer = new(BufferLayout.Std430, 1, binding, $"tfe_data{i}", tfeDataStruct);
|
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,
|
identification,
|
||||||
GpLayerInputAttribute,
|
GpLayerInputAttribute,
|
||||||
Stage,
|
Stage,
|
||||||
|
UsedFeatures.HasFlag(FeatureFlags.FragCoordXY),
|
||||||
UsedFeatures.HasFlag(FeatureFlags.InstanceId),
|
UsedFeatures.HasFlag(FeatureFlags.InstanceId),
|
||||||
UsedFeatures.HasFlag(FeatureFlags.DrawParameters),
|
UsedFeatures.HasFlag(FeatureFlags.DrawParameters),
|
||||||
UsedFeatures.HasFlag(FeatureFlags.RtLayer),
|
UsedFeatures.HasFlag(FeatureFlags.RtLayer),
|
||||||
|
|
Reference in a new issue