mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-07-26 06:07:11 +02:00
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();
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 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,9 +1424,41 @@ 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>
|
||||
|
|
|
@ -112,6 +112,17 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
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>
|
||||
/// Sets the scale of all output render targets (they should all have the same scale).
|
||||
/// </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>
|
||||
/// Submits all pending buffer updates to the GPU.
|
||||
/// </summary>
|
||||
|
|
|
@ -247,6 +247,12 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||
return _oldSpecState.GraphicsState.ViewportTransformDisable;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryYNegateEnabled()
|
||||
{
|
||||
return _oldSpecState.GraphicsState.YNegateEnabled;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
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 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";
|
||||
|
@ -140,6 +140,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||
/// </summary>
|
||||
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>
|
||||
|
@ -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,
|
||||
|
|
|
@ -113,6 +113,13 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||
return _state.GraphicsState.AttributeTypes[location];
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryEarlyZForce()
|
||||
{
|
||||
_state.SpecializationState?.RecordEarlyZForce();
|
||||
return _state.GraphicsState.EarlyZForce;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public AttributeType QueryFragmentOutputType(int location)
|
||||
{
|
||||
|
@ -275,19 +282,18 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||
return _state.TransformFeedbackDescriptors[bufferIndex].Stride;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryEarlyZForce()
|
||||
{
|
||||
_state.SpecializationState?.RecordEarlyZForce();
|
||||
return _state.GraphicsState.EarlyZForce;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryViewportTransformDisable()
|
||||
{
|
||||
return _state.GraphicsState.ViewportTransformDisable;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryYNegateEnabled()
|
||||
{
|
||||
return _state.GraphicsState.YNegateEnabled;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RegisterTexture(int handle, int cbufSlot)
|
||||
{
|
||||
|
|
|
@ -97,6 +97,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||
/// </summary>
|
||||
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>
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue