aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Ryujinx.Graphics.GAL/IPipeline.cs2
-rw-r--r--Ryujinx.Graphics.GAL/Multithreading/Commands/SetViewportsCommand.cs6
-rw-r--r--Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs4
-rw-r--r--Ryujinx.Graphics.GAL/SupportBufferUpdater.cs7
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs23
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/Cache/Migration.cs3
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs6
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs2
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs6
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs9
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs8
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/ShaderCacheHashTable.cs4
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationList.cs9
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs8
-rw-r--r--Ryujinx.Graphics.OpenGL/Pipeline.cs15
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs9
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs1
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs5
-rw-r--r--Ryujinx.Graphics.Shader/IGpuAccessor.cs9
-rw-r--r--Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs28
-rw-r--r--Ryujinx.Graphics.Shader/SupportBuffer.cs3
-rw-r--r--Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs3
-rw-r--r--Ryujinx.Graphics.Shader/Translation/EmitterContext.cs49
-rw-r--r--Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs7
24 files changed, 200 insertions, 26 deletions
diff --git a/Ryujinx.Graphics.GAL/IPipeline.cs b/Ryujinx.Graphics.GAL/IPipeline.cs
index 75c3077e..aec096e7 100644
--- a/Ryujinx.Graphics.GAL/IPipeline.cs
+++ b/Ryujinx.Graphics.GAL/IPipeline.cs
@@ -94,7 +94,7 @@ namespace Ryujinx.Graphics.GAL
void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs);
void SetVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers);
- void SetViewports(int first, ReadOnlySpan<Viewport> viewports);
+ void SetViewports(int first, ReadOnlySpan<Viewport> viewports, bool disableTransform);
void TextureBarrier();
void TextureBarrierTiled();
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetViewportsCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetViewportsCommand.cs
index e11b00e8..b208d9fe 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetViewportsCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetViewportsCommand.cs
@@ -9,17 +9,19 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands
public CommandType CommandType => CommandType.SetViewports;
private int _first;
private SpanRef<Viewport> _viewports;
+ private bool _disableTransform;
- public void Set(int first, SpanRef<Viewport> viewports)
+ public void Set(int first, SpanRef<Viewport> viewports, bool disableTransform)
{
_first = first;
_viewports = viewports;
+ _disableTransform = disableTransform;
}
public static void Run(ref SetViewportsCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ReadOnlySpan<Viewport> viewports = command._viewports.Get(threaded);
- renderer.Pipeline.SetViewports(command._first, viewports);
+ renderer.Pipeline.SetViewports(command._first, viewports, command._disableTransform);
command._viewports.Dispose(threaded);
}
}
diff --git a/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs b/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs
index b6acfaa8..010ee7e6 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs
@@ -304,9 +304,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand();
}
- public void SetViewports(int first, ReadOnlySpan<Viewport> viewports)
+ public void SetViewports(int first, ReadOnlySpan<Viewport> viewports, bool disableTransform)
{
- _renderer.New<SetViewportsCommand>().Set(first, _renderer.CopySpan(viewports));
+ _renderer.New<SetViewportsCommand>().Set(first, _renderer.CopySpan(viewports), disableTransform);
_renderer.QueueCommand();
}
diff --git a/Ryujinx.Graphics.GAL/SupportBufferUpdater.cs b/Ryujinx.Graphics.GAL/SupportBufferUpdater.cs
index cb24bdd7..da7a2461 100644
--- a/Ryujinx.Graphics.GAL/SupportBufferUpdater.cs
+++ b/Ryujinx.Graphics.GAL/SupportBufferUpdater.cs
@@ -72,6 +72,13 @@ namespace Ryujinx.Graphics.GAL
UpdateGenericField(SupportBuffer.FragmentIsBgraOffset, data, Data.FragmentIsBgra.ToSpan(), offset, count);
}
+ public void UpdateViewportInverse(Vector4<float> data)
+ {
+ Data.ViewportInverse = data;
+
+ MarkDirty(SupportBuffer.ViewportInverseOffset, SupportBuffer.FieldSize);
+ }
+
public void Commit()
{
if (_startOffset != -1)
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
index 3bc15a31..d0c3bc5a 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
@@ -113,7 +113,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
nameof(ThreedClassState.DepthMode),
nameof(ThreedClassState.ViewportTransform),
nameof(ThreedClassState.ViewportExtents),
- nameof(ThreedClassState.YControl)),
+ nameof(ThreedClassState.YControl),
+ nameof(ThreedClassState.ViewportTransformEnable)),
new StateUpdateCallbackEntry(UpdatePolygonMode,
nameof(ThreedClassState.PolygonModeFront),
@@ -200,7 +201,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
// of the shader for the new state.
if (_shaderSpecState != null)
{
- if (!_shaderSpecState.MatchesGraphics(_channel, GetPoolState()))
+ if (!_shaderSpecState.MatchesGraphics(_channel, GetPoolState(), GetGraphicsState()))
{
ForceShaderUpdate();
}
@@ -568,6 +569,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
var yControl = _state.State.YControl;
var face = _state.State.FaceState;
+ bool disableTransform = _state.State.ViewportTransformEnable == 0;
+
UpdateFrontFace(yControl, face.FrontFace);
UpdateDepthMode();
@@ -577,6 +580,17 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
for (int index = 0; index < Constants.TotalViewports; index++)
{
+ if (disableTransform)
+ {
+ ref var scissor = ref _state.State.ScreenScissorState;
+
+ float rScale = _channel.TextureManager.RenderTargetScale;
+ var scissorRect = new RectangleF(0, 0, (scissor.X + scissor.Width) * rScale, (scissor.Y + scissor.Height) * rScale);
+
+ viewports[index] = new Viewport(scissorRect, ViewportSwizzle.PositiveX, ViewportSwizzle.PositiveY, ViewportSwizzle.PositiveZ, ViewportSwizzle.PositiveW, 0, 1);
+ continue;
+ }
+
ref var transform = ref _state.State.ViewportTransform[index];
ref var extents = ref _state.State.ViewportExtents[index];
@@ -628,7 +642,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
viewports[index] = new Viewport(region, swizzleX, swizzleY, swizzleZ, swizzleW, depthNear, depthFar);
}
- _context.Renderer.Pipeline.SetViewports(0, viewports);
+ _context.Renderer.Pipeline.SetViewports(0, viewports, disableTransform);
}
/// <summary>
@@ -1194,7 +1208,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
return new GpuChannelGraphicsState(
_state.State.EarlyZForce,
_drawState.Topology,
- _state.State.TessMode);
+ _state.State.TessMode,
+ _state.State.ViewportTransformEnable == 0);
}
/// <summary>
diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/Migration.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/Migration.cs
index 27fac8f3..4de6eff9 100644
--- a/Ryujinx.Graphics.Gpu/Shader/Cache/Migration.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/Cache/Migration.cs
@@ -166,7 +166,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache
GpuChannelGraphicsState graphicsState = new GpuChannelGraphicsState(
accessorHeader.StateFlags.HasFlag(GuestGpuStateFlags.EarlyZForce),
topology,
- tessMode);
+ tessMode,
+ false);
TransformFeedbackDescriptor[] tfdNew = null;
diff --git a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs
index b1c04eac..bc63f714 100644
--- a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs
@@ -186,6 +186,12 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
}
/// <inheritdoc/>
+ public bool QueryViewportTransformDisable()
+ {
+ return _oldSpecState.GraphicsState.ViewportTransformDisable;
+ }
+
+ /// <inheritdoc/>
public void RegisterTexture(int handle, int cbufSlot)
{
if (!_oldSpecState.TextureRegistered(_stageIndex, handle, cbufSlot))
diff --git a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
index 0028e879..5d99957f 100644
--- a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
@@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
private const ushort FileFormatVersionMajor = 1;
private const ushort FileFormatVersionMinor = 1;
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
- private const uint CodeGenVersion = 0;
+ private const uint CodeGenVersion = 1;
private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data";
diff --git a/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs b/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs
index 192467b7..5cd966af 100644
--- a/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs
@@ -218,6 +218,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
}
/// <inheritdoc/>
+ public bool QueryViewportTransformDisable()
+ {
+ return _state.GraphicsState.ViewportTransformDisable;
+ }
+
+ /// <inheritdoc/>
public void RegisterTexture(int handle, int cbufSlot)
{
_state.SpecializationState?.RegisterTexture(_stageIndex, handle, cbufSlot, GetTextureDescriptor(handle, cbufSlot));
diff --git a/Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs b/Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs
index 5eb31db6..92ec117f 100644
--- a/Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs
@@ -26,16 +26,23 @@ namespace Ryujinx.Graphics.Gpu.Shader
public readonly TessMode TessellationMode;
/// <summary>
+ /// Indicates whenever the viewport transform is disabled.
+ /// </summary>
+ public readonly bool ViewportTransformDisable;
+
+ /// <summary>
/// Creates a new GPU graphics state.
/// </summary>
/// <param name="earlyZForce">Early Z force enable</param>
/// <param name="topology">Primitive topology</param>
/// <param name="tessellationMode">Tessellation mode</param>
- public GpuChannelGraphicsState(bool earlyZForce, PrimitiveTopology topology, TessMode tessellationMode)
+ /// <param name="viewportTransformDisable">Indicates whenever the viewport transform is disabled</param>
+ public GpuChannelGraphicsState(bool earlyZForce, PrimitiveTopology topology, TessMode tessellationMode, bool viewportTransformDisable)
{
EarlyZForce = earlyZForce;
Topology = topology;
TessellationMode = tessellationMode;
+ ViewportTransformDisable = viewportTransformDisable;
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
index 03d5ecad..df4b9d12 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
@@ -249,12 +249,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
GpuChannelGraphicsState graphicsState,
ShaderAddresses addresses)
{
- if (_gpPrograms.TryGetValue(addresses, out var gpShaders) && IsShaderEqual(channel, poolState, gpShaders, addresses))
+ if (_gpPrograms.TryGetValue(addresses, out var gpShaders) && IsShaderEqual(channel, poolState, graphicsState, gpShaders, addresses))
{
return gpShaders;
}
- if (_graphicsShaderCache.TryFind(channel, poolState, addresses, out gpShaders, out var cachedGuestCode))
+ if (_graphicsShaderCache.TryFind(channel, poolState, graphicsState, addresses, out gpShaders, out var cachedGuestCode))
{
_gpPrograms[addresses] = gpShaders;
return gpShaders;
@@ -429,12 +429,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary>
/// <param name="channel">GPU channel using the shader</param>
/// <param name="poolState">GPU channel state to verify shader compatibility</param>
+ /// <param name="graphicsState">GPU channel graphics state to verify shader compatibility</param>
/// <param name="gpShaders">Cached graphics shaders</param>
/// <param name="addresses">GPU virtual addresses of all enabled shader stages</param>
/// <returns>True if the code is different, false otherwise</returns>
private static bool IsShaderEqual(
GpuChannel channel,
GpuChannelPoolState poolState,
+ GpuChannelGraphicsState graphicsState,
CachedShaderProgram gpShaders,
ShaderAddresses addresses)
{
@@ -452,7 +454,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
}
}
- return gpShaders.SpecializationState.MatchesGraphics(channel, poolState);
+ return gpShaders.SpecializationState.MatchesGraphics(channel, poolState, graphicsState);
}
/// <summary>
diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCacheHashTable.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCacheHashTable.cs
index 065f9ba9..3d74e53a 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderCacheHashTable.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCacheHashTable.cs
@@ -208,6 +208,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </remarks>
/// <param name="channel">GPU channel</param>
/// <param name="poolState">Texture pool state</param>
+ /// <param name="graphicsState">Graphics state</param>
/// <param name="addresses">Guest addresses of the shaders to find</param>
/// <param name="program">Cached host program for the given state, if found</param>
/// <param name="guestCode">Cached guest code, if any found</param>
@@ -215,6 +216,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
public bool TryFind(
GpuChannel channel,
GpuChannelPoolState poolState,
+ GpuChannelGraphicsState graphicsState,
ShaderAddresses addresses,
out CachedShaderProgram program,
out CachedGraphicsGuestCode guestCode)
@@ -234,7 +236,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
if (found && _shaderPrograms.TryGetValue(idTable, out ShaderSpecializationList specList))
{
- return specList.TryFindForGraphics(channel, poolState, out program);
+ return specList.TryFindForGraphics(channel, poolState, graphicsState, out program);
}
return false;
diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationList.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationList.cs
index 87e08754..e3e57d74 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationList.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationList.cs
@@ -24,13 +24,18 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary>
/// <param name="channel">GPU channel</param>
/// <param name="poolState">Texture pool state</param>
+ /// <param name="graphicsState">Graphics state</param>
/// <param name="program">Cached program, if found</param>
/// <returns>True if a compatible program is found, false otherwise</returns>
- public bool TryFindForGraphics(GpuChannel channel, GpuChannelPoolState poolState, out CachedShaderProgram program)
+ public bool TryFindForGraphics(
+ GpuChannel channel,
+ GpuChannelPoolState poolState,
+ GpuChannelGraphicsState graphicsState,
+ out CachedShaderProgram program)
{
foreach (var entry in _entries)
{
- if (entry.SpecializationState.MatchesGraphics(channel, poolState))
+ if (entry.SpecializationState.MatchesGraphics(channel, poolState, graphicsState))
{
program = entry;
return true;
diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs
index 2bbc3d2c..418c7b1a 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderSpecializationState.cs
@@ -395,9 +395,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary>
/// <param name="channel">GPU channel</param>
/// <param name="poolState">Texture pool state</param>
+ /// <param name="graphicsState">Graphics state</param>
/// <returns>True if the state matches, false otherwise</returns>
- public bool MatchesGraphics(GpuChannel channel, GpuChannelPoolState poolState)
+ public bool MatchesGraphics(GpuChannel channel, GpuChannelPoolState poolState, GpuChannelGraphicsState graphicsState)
{
+ if (graphicsState.ViewportTransformDisable != GraphicsState.ViewportTransformDisable)
+ {
+ return false;
+ }
+
return Matches(channel, poolState, isCompute: false);
}
diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs
index 114fa685..0326f980 100644
--- a/Ryujinx.Graphics.OpenGL/Pipeline.cs
+++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs
@@ -1266,7 +1266,7 @@ namespace Ryujinx.Graphics.OpenGL
_vertexArray.SetVertexBuffers(vertexBuffers);
}
- public void SetViewports(int first, ReadOnlySpan<Viewport> viewports)
+ public void SetViewports(int first, ReadOnlySpan<Viewport> viewports, bool disableTransform)
{
Array.Resize(ref _viewportArray, viewports.Length * 4);
Array.Resize(ref _depthRangeArray, viewports.Length * 2);
@@ -1305,6 +1305,19 @@ namespace Ryujinx.Graphics.OpenGL
GL.ViewportArray(first, viewports.Length, viewportArray);
GL.DepthRangeArray(first, viewports.Length, depthRangeArray);
+
+ float disableTransformF = disableTransform ? 1.0f : 0.0f;
+ if (_supportBuffer.Data.ViewportInverse.W != disableTransformF || disableTransform)
+ {
+ float scale = _renderScale[0].X;
+ _supportBuffer.UpdateViewportInverse(new Vector4<float>
+ {
+ X = scale * 2f / viewports[first].Region.Width,
+ Y = scale * 2f / viewports[first].Region.Height,
+ Z = 1,
+ W = disableTransformF
+ });
+ }
}
public void TextureBarrier()
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
index c955a616..59a7ccdc 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
@@ -249,7 +249,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
context.AppendLine();
}
}
- else if (isFragment)
+ else if (isFragment || context.Config.Stage == ShaderStage.Vertex)
{
DeclareSupportUniformBlock(context, context.Config.Stage, 0);
}
@@ -615,8 +615,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
private static void DeclareSupportUniformBlock(CodeGenContext context, ShaderStage stage, int scaleElements)
{
- bool isFragment = stage == ShaderStage.Fragment;
- if (!isFragment && scaleElements == 0)
+ bool needsSupportBlock = stage == ShaderStage.Fragment ||
+ (context.Config.LastInVertexPipeline && context.Config.GpuAccessor.QueryViewportTransformDisable());
+
+ if (!needsSupportBlock && scaleElements == 0)
{
return;
}
@@ -630,6 +632,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
case ShaderStage.Vertex:
context.AppendLine($"uint {DefaultNames.SupportBlockAlphaTestName};");
context.AppendLine($"bool {DefaultNames.SupportBlockIsBgraName}[{SupportBuffer.FragmentIsBgraCount}];");
+ context.AppendLine($"vec4 {DefaultNames.SupportBlockViewportInverse};");
context.AppendLine($"int {DefaultNames.SupportBlockFragmentScaleCount};");
break;
case ShaderStage.Compute:
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs
index 76203522..3ab4814c 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs
@@ -18,6 +18,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
public const string SupportBlockName = "support_block";
public const string SupportBlockAlphaTestName = "s_alpha_test";
public const string SupportBlockIsBgraName = "s_is_bgra";
+ public const string SupportBlockViewportInverse = "s_viewport_inverse";
public const string SupportBlockFragmentScaleCount = "s_frag_scale_count";
public const string SupportBlockRenderScaleName = "s_render_scale";
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
index 2d6607ad..334c744d 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
@@ -84,7 +84,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
{ AttributeConsts.FragmentOutputIsBgraBase + 16, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[4]", VariableType.Bool) },
{ AttributeConsts.FragmentOutputIsBgraBase + 20, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[5]", VariableType.Bool) },
{ AttributeConsts.FragmentOutputIsBgraBase + 24, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[6]", VariableType.Bool) },
- { AttributeConsts.FragmentOutputIsBgraBase + 28, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[7]", VariableType.Bool) }
+ { AttributeConsts.FragmentOutputIsBgraBase + 28, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[7]", VariableType.Bool) },
+
+ { AttributeConsts.SupportBlockViewInverseX, new BuiltInAttribute($"{DefaultNames.SupportBlockViewportInverse}.x", VariableType.F32) },
+ { AttributeConsts.SupportBlockViewInverseY, new BuiltInAttribute($"{DefaultNames.SupportBlockViewportInverse}.y", VariableType.F32) }
};
private Dictionary<AstOperand, string> _locals;
diff --git a/Ryujinx.Graphics.Shader/IGpuAccessor.cs b/Ryujinx.Graphics.Shader/IGpuAccessor.cs
index 9c624d90..180fc187 100644
--- a/Ryujinx.Graphics.Shader/IGpuAccessor.cs
+++ b/Ryujinx.Graphics.Shader/IGpuAccessor.cs
@@ -330,6 +330,15 @@ namespace Ryujinx.Graphics.Shader
}
/// <summary>
+ /// Queries if host state disables the viewport transform.
+ /// </summary>
+ /// <returns>True if the viewport transform is disabled</returns>
+ bool QueryViewportTransformDisable()
+ {
+ return false;
+ }
+
+ /// <summary>
/// Registers a texture used by the shader.
/// </summary>
/// <param name="handle">Texture handle word offset</param>
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs
index 1cdb3842..6ce2e537 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs
@@ -206,7 +206,33 @@ namespace Ryujinx.Graphics.Shader.Instructions
if (emit)
{
- context.EmitVertex();
+ if (context.Config.LastInVertexPipeline)
+ {
+ context.PrepareForVertexReturn(out var tempXLocal, out var tempYLocal, out var tempZLocal);
+
+ context.EmitVertex();
+
+ // Restore output position value before transformation.
+
+ if (tempXLocal != null)
+ {
+ context.Copy(Attribute(AttributeConsts.PositionX), tempXLocal);
+ }
+
+ if (tempYLocal != null)
+ {
+ context.Copy(Attribute(AttributeConsts.PositionY), tempYLocal);
+ }
+
+ if (tempZLocal != null)
+ {
+ context.Copy(Attribute(AttributeConsts.PositionZ), tempZLocal);
+ }
+ }
+ else
+ {
+ context.EmitVertex();
+ }
}
if (cut)
diff --git a/Ryujinx.Graphics.Shader/SupportBuffer.cs b/Ryujinx.Graphics.Shader/SupportBuffer.cs
index 47a47ea6..28a48c2a 100644
--- a/Ryujinx.Graphics.Shader/SupportBuffer.cs
+++ b/Ryujinx.Graphics.Shader/SupportBuffer.cs
@@ -18,6 +18,7 @@ namespace Ryujinx.Graphics.Shader
public static int FragmentAlphaTestOffset;
public static int FragmentIsBgraOffset;
+ public static int ViewportInverseOffset;
public static int FragmentRenderScaleCountOffset;
public static int GraphicsRenderScaleOffset;
public static int ComputeRenderScaleOffset;
@@ -40,6 +41,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);
FragmentRenderScaleCountOffset = OffsetOf(ref instance, ref instance.FragmentRenderScaleCount);
GraphicsRenderScaleOffset = OffsetOf(ref instance, ref instance.RenderScale);
ComputeRenderScaleOffset = GraphicsRenderScaleOffset + FieldSize;
@@ -47,6 +49,7 @@ namespace Ryujinx.Graphics.Shader
public Vector4<int> FragmentAlphaTest;
public Array8<Vector4<int>> FragmentIsBgra;
+ public Vector4<float> ViewportInverse;
public Vector4<int> FragmentRenderScaleCount;
// Render scale max count: 1 + 32 + 8. First scale is fragment output scale, others are textures/image inputs.
diff --git a/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs b/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs
index 370af009..ada60ab9 100644
--- a/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs
+++ b/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs
@@ -67,6 +67,9 @@ namespace Ryujinx.Graphics.Shader.Translation
public const int FragmentOutputIsBgraBase = 0x1000100;
public const int FragmentOutputIsBgraEnd = FragmentOutputIsBgraBase + 8 * 4;
+ public const int SupportBlockViewInverseX = 0x1000200;
+ public const int SupportBlockViewInverseY = 0x1000204;
+
public const int ThreadIdX = 0x2000000;
public const int ThreadIdY = 0x2000004;
public const int ThreadIdZ = 0x2000008;
diff --git a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
index 775f1217..ba3b551d 100644
--- a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
+++ b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
@@ -154,9 +154,56 @@ namespace Ryujinx.Graphics.Shader.Translation
return label;
}
+ public void PrepareForVertexReturn()
+ {
+ if (Config.GpuAccessor.QueryViewportTransformDisable())
+ {
+ Operand x = Attribute(AttributeConsts.PositionX | AttributeConsts.LoadOutputMask);
+ Operand y = Attribute(AttributeConsts.PositionY | AttributeConsts.LoadOutputMask);
+ Operand xScale = Attribute(AttributeConsts.SupportBlockViewInverseX);
+ Operand yScale = Attribute(AttributeConsts.SupportBlockViewInverseY);
+ Operand negativeOne = ConstF(-1.0f);
+
+ this.Copy(Attribute(AttributeConsts.PositionX), this.FPFusedMultiplyAdd(x, xScale, negativeOne));
+ this.Copy(Attribute(AttributeConsts.PositionY), this.FPFusedMultiplyAdd(y, yScale, negativeOne));
+ }
+ }
+
+ public void PrepareForVertexReturn(out Operand oldXLocal, out Operand oldYLocal, out Operand oldZLocal)
+ {
+ if (Config.GpuAccessor.QueryViewportTransformDisable())
+ {
+ oldXLocal = Local();
+ this.Copy(oldXLocal, Attribute(AttributeConsts.PositionX | AttributeConsts.LoadOutputMask));
+ oldYLocal = Local();
+ this.Copy(oldYLocal, Attribute(AttributeConsts.PositionY | AttributeConsts.LoadOutputMask));
+ }
+ else
+ {
+ oldXLocal = null;
+ oldYLocal = null;
+ }
+
+ // Will be used by Vulkan backend for depth mode emulation.
+ oldZLocal = null;
+
+ PrepareForVertexReturn();
+ }
+
public void PrepareForReturn()
{
- if (!IsNonMain && Config.Stage == ShaderStage.Fragment)
+ if (IsNonMain)
+ {
+ return;
+ }
+
+ if (Config.LastInVertexPipeline &&
+ (Config.Stage == ShaderStage.Vertex || Config.Stage == ShaderStage.TessellationEvaluation) &&
+ (Config.Options.Flags & TranslationFlags.VertexA) == 0)
+ {
+ PrepareForVertexReturn();
+ }
+ else if (Config.Stage == ShaderStage.Fragment)
{
if (Config.OmapDepth)
{
diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
index 23b8b951..27d72cd5 100644
--- a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
+++ b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
@@ -14,6 +14,7 @@ namespace Ryujinx.Graphics.Shader.Translation
public ShaderStage Stage { get; }
public bool GpPassthrough { get; }
+ public bool LastInVertexPipeline { get; private set; }
public int ThreadsPerInputPrimitive { get; }
@@ -135,6 +136,7 @@ namespace Ryujinx.Graphics.Shader.Translation
OmapSampleMask = header.OmapSampleMask;
OmapDepth = header.OmapDepth;
TransformFeedbackEnabled = gpuAccessor.QueryTransformFeedbackEnabled();
+ LastInVertexPipeline = header.Stage < ShaderStage.Fragment;
}
public int GetDepthRegister()
@@ -274,6 +276,11 @@ namespace Ryujinx.Graphics.Shader.Translation
NextInputAttributesPerPatchComponents = config.ThisInputAttributesPerPatchComponents;
NextUsesFixedFuncAttributes = config.UsedFeatures.HasFlag(FeatureFlags.FixedFuncAttr);
MergeOutputUserAttributes(config.UsedInputAttributes, config.UsedInputAttributesPerPatch);
+
+ if (config.Stage != ShaderStage.Fragment)
+ {
+ LastInVertexPipeline = false;
+ }
}
public void MergeOutputUserAttributes(int mask, int maskPerPatch)