0
0
Fork 0
mirror of https://github.com/ryujinx-mirror/ryujinx.git synced 2024-12-23 00:45:46 +00:00

Implement Viewport Transform Disable (#3328)

* Initial implementation (no specialization)

* Use specialization

* Fix render scale, increase code gen version

* Revert accidental change

* Address Feedback
This commit is contained in:
riperiperi 2022-05-12 14:47:13 +01:00 committed by GitHub
parent 92ca1cb0cb
commit 43b4b34376
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 200 additions and 26 deletions

View file

@ -94,7 +94,7 @@ namespace Ryujinx.Graphics.GAL
void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs); void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs);
void SetVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers); void SetVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers);
void SetViewports(int first, ReadOnlySpan<Viewport> viewports); void SetViewports(int first, ReadOnlySpan<Viewport> viewports, bool disableTransform);
void TextureBarrier(); void TextureBarrier();
void TextureBarrierTiled(); void TextureBarrierTiled();

View file

@ -9,17 +9,19 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands
public CommandType CommandType => CommandType.SetViewports; public CommandType CommandType => CommandType.SetViewports;
private int _first; private int _first;
private SpanRef<Viewport> _viewports; 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; _first = first;
_viewports = viewports; _viewports = viewports;
_disableTransform = disableTransform;
} }
public static void Run(ref SetViewportsCommand command, ThreadedRenderer threaded, IRenderer renderer) public static void Run(ref SetViewportsCommand command, ThreadedRenderer threaded, IRenderer renderer)
{ {
ReadOnlySpan<Viewport> viewports = command._viewports.Get(threaded); 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); command._viewports.Dispose(threaded);
} }
} }

View file

@ -304,9 +304,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand(); _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(); _renderer.QueueCommand();
} }

View file

@ -72,6 +72,13 @@ namespace Ryujinx.Graphics.GAL
UpdateGenericField(SupportBuffer.FragmentIsBgraOffset, data, Data.FragmentIsBgra.ToSpan(), offset, count); 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() public void Commit()
{ {
if (_startOffset != -1) if (_startOffset != -1)

View file

@ -113,7 +113,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
nameof(ThreedClassState.DepthMode), nameof(ThreedClassState.DepthMode),
nameof(ThreedClassState.ViewportTransform), nameof(ThreedClassState.ViewportTransform),
nameof(ThreedClassState.ViewportExtents), nameof(ThreedClassState.ViewportExtents),
nameof(ThreedClassState.YControl)), nameof(ThreedClassState.YControl),
nameof(ThreedClassState.ViewportTransformEnable)),
new StateUpdateCallbackEntry(UpdatePolygonMode, new StateUpdateCallbackEntry(UpdatePolygonMode,
nameof(ThreedClassState.PolygonModeFront), nameof(ThreedClassState.PolygonModeFront),
@ -200,7 +201,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
// of the shader for the new state. // of the shader for the new state.
if (_shaderSpecState != null) if (_shaderSpecState != null)
{ {
if (!_shaderSpecState.MatchesGraphics(_channel, GetPoolState())) if (!_shaderSpecState.MatchesGraphics(_channel, GetPoolState(), GetGraphicsState()))
{ {
ForceShaderUpdate(); ForceShaderUpdate();
} }
@ -568,6 +569,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
var yControl = _state.State.YControl; var yControl = _state.State.YControl;
var face = _state.State.FaceState; var face = _state.State.FaceState;
bool disableTransform = _state.State.ViewportTransformEnable == 0;
UpdateFrontFace(yControl, face.FrontFace); UpdateFrontFace(yControl, face.FrontFace);
UpdateDepthMode(); UpdateDepthMode();
@ -577,6 +580,17 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
for (int index = 0; index < Constants.TotalViewports; index++) 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 transform = ref _state.State.ViewportTransform[index];
ref var extents = ref _state.State.ViewportExtents[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); 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> /// <summary>
@ -1194,7 +1208,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
return new GpuChannelGraphicsState( return new GpuChannelGraphicsState(
_state.State.EarlyZForce, _state.State.EarlyZForce,
_drawState.Topology, _drawState.Topology,
_state.State.TessMode); _state.State.TessMode,
_state.State.ViewportTransformEnable == 0);
} }
/// <summary> /// <summary>

View file

@ -166,7 +166,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache
GpuChannelGraphicsState graphicsState = new GpuChannelGraphicsState( GpuChannelGraphicsState graphicsState = new GpuChannelGraphicsState(
accessorHeader.StateFlags.HasFlag(GuestGpuStateFlags.EarlyZForce), accessorHeader.StateFlags.HasFlag(GuestGpuStateFlags.EarlyZForce),
topology, topology,
tessMode); tessMode,
false);
TransformFeedbackDescriptor[] tfdNew = null; TransformFeedbackDescriptor[] tfdNew = null;

View file

@ -185,6 +185,12 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
return _oldSpecState.GraphicsState.EarlyZForce; return _oldSpecState.GraphicsState.EarlyZForce;
} }
/// <inheritdoc/>
public bool QueryViewportTransformDisable()
{
return _oldSpecState.GraphicsState.ViewportTransformDisable;
}
/// <inheritdoc/> /// <inheritdoc/>
public void RegisterTexture(int handle, int cbufSlot) public void RegisterTexture(int handle, int cbufSlot)
{ {

View file

@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
private const ushort FileFormatVersionMajor = 1; private const ushort FileFormatVersionMajor = 1;
private const ushort FileFormatVersionMinor = 1; private const ushort FileFormatVersionMinor = 1;
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor; 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 SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data"; private const string SharedDataFileName = "shared.data";

View file

@ -217,6 +217,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
return _state.GraphicsState.EarlyZForce; return _state.GraphicsState.EarlyZForce;
} }
/// <inheritdoc/>
public bool QueryViewportTransformDisable()
{
return _state.GraphicsState.ViewportTransformDisable;
}
/// <inheritdoc/> /// <inheritdoc/>
public void RegisterTexture(int handle, int cbufSlot) public void RegisterTexture(int handle, int cbufSlot)
{ {

View file

@ -25,17 +25,24 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary> /// </summary>
public readonly TessMode TessellationMode; public readonly TessMode TessellationMode;
/// <summary>
/// Indicates whenever the viewport transform is disabled.
/// </summary>
public readonly bool ViewportTransformDisable;
/// <summary> /// <summary>
/// Creates a new GPU graphics state. /// Creates a new GPU graphics state.
/// </summary> /// </summary>
/// <param name="earlyZForce">Early Z force enable</param> /// <param name="earlyZForce">Early Z force enable</param>
/// <param name="topology">Primitive topology</param> /// <param name="topology">Primitive topology</param>
/// <param name="tessellationMode">Tessellation mode</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; EarlyZForce = earlyZForce;
Topology = topology; Topology = topology;
TessellationMode = tessellationMode; TessellationMode = tessellationMode;
ViewportTransformDisable = viewportTransformDisable;
} }
} }
} }

View file

@ -249,12 +249,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
GpuChannelGraphicsState graphicsState, GpuChannelGraphicsState graphicsState,
ShaderAddresses addresses) 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; 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; _gpPrograms[addresses] = gpShaders;
return gpShaders; return gpShaders;
@ -429,12 +429,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary> /// </summary>
/// <param name="channel">GPU channel using the shader</param> /// <param name="channel">GPU channel using the shader</param>
/// <param name="poolState">GPU channel state to verify shader compatibility</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="gpShaders">Cached graphics shaders</param>
/// <param name="addresses">GPU virtual addresses of all enabled shader stages</param> /// <param name="addresses">GPU virtual addresses of all enabled shader stages</param>
/// <returns>True if the code is different, false otherwise</returns> /// <returns>True if the code is different, false otherwise</returns>
private static bool IsShaderEqual( private static bool IsShaderEqual(
GpuChannel channel, GpuChannel channel,
GpuChannelPoolState poolState, GpuChannelPoolState poolState,
GpuChannelGraphicsState graphicsState,
CachedShaderProgram gpShaders, CachedShaderProgram gpShaders,
ShaderAddresses addresses) 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> /// <summary>

View file

@ -208,6 +208,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </remarks> /// </remarks>
/// <param name="channel">GPU channel</param> /// <param name="channel">GPU channel</param>
/// <param name="poolState">Texture pool state</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="addresses">Guest addresses of the shaders to find</param>
/// <param name="program">Cached host program for the given state, if found</param> /// <param name="program">Cached host program for the given state, if found</param>
/// <param name="guestCode">Cached guest code, if any found</param> /// <param name="guestCode">Cached guest code, if any found</param>
@ -215,6 +216,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
public bool TryFind( public bool TryFind(
GpuChannel channel, GpuChannel channel,
GpuChannelPoolState poolState, GpuChannelPoolState poolState,
GpuChannelGraphicsState graphicsState,
ShaderAddresses addresses, ShaderAddresses addresses,
out CachedShaderProgram program, out CachedShaderProgram program,
out CachedGraphicsGuestCode guestCode) out CachedGraphicsGuestCode guestCode)
@ -234,7 +236,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
if (found && _shaderPrograms.TryGetValue(idTable, out ShaderSpecializationList specList)) 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; return false;

View file

@ -24,13 +24,18 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary> /// </summary>
/// <param name="channel">GPU channel</param> /// <param name="channel">GPU channel</param>
/// <param name="poolState">Texture pool state</param> /// <param name="poolState">Texture pool state</param>
/// <param name="graphicsState">Graphics state</param>
/// <param name="program">Cached program, if found</param> /// <param name="program">Cached program, if found</param>
/// <returns>True if a compatible program is found, false otherwise</returns> /// <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) foreach (var entry in _entries)
{ {
if (entry.SpecializationState.MatchesGraphics(channel, poolState)) if (entry.SpecializationState.MatchesGraphics(channel, poolState, graphicsState))
{ {
program = entry; program = entry;
return true; return true;

View file

@ -395,9 +395,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary> /// </summary>
/// <param name="channel">GPU channel</param> /// <param name="channel">GPU channel</param>
/// <param name="poolState">Texture pool state</param> /// <param name="poolState">Texture pool state</param>
/// <param name="graphicsState">Graphics state</param>
/// <returns>True if the state matches, false otherwise</returns> /// <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); return Matches(channel, poolState, isCompute: false);
} }

View file

@ -1266,7 +1266,7 @@ namespace Ryujinx.Graphics.OpenGL
_vertexArray.SetVertexBuffers(vertexBuffers); _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 _viewportArray, viewports.Length * 4);
Array.Resize(ref _depthRangeArray, viewports.Length * 2); Array.Resize(ref _depthRangeArray, viewports.Length * 2);
@ -1305,6 +1305,19 @@ namespace Ryujinx.Graphics.OpenGL
GL.ViewportArray(first, viewports.Length, viewportArray); GL.ViewportArray(first, viewports.Length, viewportArray);
GL.DepthRangeArray(first, viewports.Length, depthRangeArray); 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() public void TextureBarrier()

View file

@ -249,7 +249,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
context.AppendLine(); context.AppendLine();
} }
} }
else if (isFragment) else if (isFragment || context.Config.Stage == ShaderStage.Vertex)
{ {
DeclareSupportUniformBlock(context, context.Config.Stage, 0); 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) private static void DeclareSupportUniformBlock(CodeGenContext context, ShaderStage stage, int scaleElements)
{ {
bool isFragment = stage == ShaderStage.Fragment; bool needsSupportBlock = stage == ShaderStage.Fragment ||
if (!isFragment && scaleElements == 0) (context.Config.LastInVertexPipeline && context.Config.GpuAccessor.QueryViewportTransformDisable());
if (!needsSupportBlock && scaleElements == 0)
{ {
return; return;
} }
@ -630,6 +632,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
case ShaderStage.Vertex: case ShaderStage.Vertex:
context.AppendLine($"uint {DefaultNames.SupportBlockAlphaTestName};"); context.AppendLine($"uint {DefaultNames.SupportBlockAlphaTestName};");
context.AppendLine($"bool {DefaultNames.SupportBlockIsBgraName}[{SupportBuffer.FragmentIsBgraCount}];"); context.AppendLine($"bool {DefaultNames.SupportBlockIsBgraName}[{SupportBuffer.FragmentIsBgraCount}];");
context.AppendLine($"vec4 {DefaultNames.SupportBlockViewportInverse};");
context.AppendLine($"int {DefaultNames.SupportBlockFragmentScaleCount};"); context.AppendLine($"int {DefaultNames.SupportBlockFragmentScaleCount};");
break; break;
case ShaderStage.Compute: case ShaderStage.Compute:

View file

@ -18,6 +18,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
public const string SupportBlockName = "support_block"; public const string SupportBlockName = "support_block";
public const string SupportBlockAlphaTestName = "s_alpha_test"; public const string SupportBlockAlphaTestName = "s_alpha_test";
public const string SupportBlockIsBgraName = "s_is_bgra"; 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 SupportBlockFragmentScaleCount = "s_frag_scale_count";
public const string SupportBlockRenderScaleName = "s_render_scale"; public const string SupportBlockRenderScaleName = "s_render_scale";

View file

@ -84,7 +84,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
{ AttributeConsts.FragmentOutputIsBgraBase + 16, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[4]", VariableType.Bool) }, { AttributeConsts.FragmentOutputIsBgraBase + 16, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[4]", VariableType.Bool) },
{ AttributeConsts.FragmentOutputIsBgraBase + 20, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[5]", VariableType.Bool) }, { AttributeConsts.FragmentOutputIsBgraBase + 20, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[5]", VariableType.Bool) },
{ AttributeConsts.FragmentOutputIsBgraBase + 24, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[6]", 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; private Dictionary<AstOperand, string> _locals;

View file

@ -329,6 +329,15 @@ namespace Ryujinx.Graphics.Shader
return false; return false;
} }
/// <summary>
/// Queries if host state disables the viewport transform.
/// </summary>
/// <returns>True if the viewport transform is disabled</returns>
bool QueryViewportTransformDisable()
{
return false;
}
/// <summary> /// <summary>
/// Registers a texture used by the shader. /// Registers a texture used by the shader.
/// </summary> /// </summary>

View file

@ -206,7 +206,33 @@ namespace Ryujinx.Graphics.Shader.Instructions
if (emit) 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) if (cut)

View file

@ -18,6 +18,7 @@ namespace Ryujinx.Graphics.Shader
public static int FragmentAlphaTestOffset; public static int FragmentAlphaTestOffset;
public static int FragmentIsBgraOffset; public static int FragmentIsBgraOffset;
public static int ViewportInverseOffset;
public static int FragmentRenderScaleCountOffset; public static int FragmentRenderScaleCountOffset;
public static int GraphicsRenderScaleOffset; public static int GraphicsRenderScaleOffset;
public static int ComputeRenderScaleOffset; public static int ComputeRenderScaleOffset;
@ -40,6 +41,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);
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;
@ -47,6 +49,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<int> FragmentRenderScaleCount; public Vector4<int> FragmentRenderScaleCount;
// Render scale max count: 1 + 32 + 8. First scale is fragment output scale, others are textures/image inputs. // Render scale max count: 1 + 32 + 8. First scale is fragment output scale, others are textures/image inputs.

View file

@ -67,6 +67,9 @@ namespace Ryujinx.Graphics.Shader.Translation
public const int FragmentOutputIsBgraBase = 0x1000100; public const int FragmentOutputIsBgraBase = 0x1000100;
public const int FragmentOutputIsBgraEnd = FragmentOutputIsBgraBase + 8 * 4; 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 ThreadIdX = 0x2000000;
public const int ThreadIdY = 0x2000004; public const int ThreadIdY = 0x2000004;
public const int ThreadIdZ = 0x2000008; public const int ThreadIdZ = 0x2000008;

View file

@ -154,9 +154,56 @@ namespace Ryujinx.Graphics.Shader.Translation
return label; 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() 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) if (Config.OmapDepth)
{ {

View file

@ -14,6 +14,7 @@ namespace Ryujinx.Graphics.Shader.Translation
public ShaderStage Stage { get; } public ShaderStage Stage { get; }
public bool GpPassthrough { get; } public bool GpPassthrough { get; }
public bool LastInVertexPipeline { get; private set; }
public int ThreadsPerInputPrimitive { get; } public int ThreadsPerInputPrimitive { get; }
@ -135,6 +136,7 @@ namespace Ryujinx.Graphics.Shader.Translation
OmapSampleMask = header.OmapSampleMask; OmapSampleMask = header.OmapSampleMask;
OmapDepth = header.OmapDepth; OmapDepth = header.OmapDepth;
TransformFeedbackEnabled = gpuAccessor.QueryTransformFeedbackEnabled(); TransformFeedbackEnabled = gpuAccessor.QueryTransformFeedbackEnabled();
LastInVertexPipeline = header.Stage < ShaderStage.Fragment;
} }
public int GetDepthRegister() public int GetDepthRegister()
@ -274,6 +276,11 @@ namespace Ryujinx.Graphics.Shader.Translation
NextInputAttributesPerPatchComponents = config.ThisInputAttributesPerPatchComponents; NextInputAttributesPerPatchComponents = config.ThisInputAttributesPerPatchComponents;
NextUsesFixedFuncAttributes = config.UsedFeatures.HasFlag(FeatureFlags.FixedFuncAttr); NextUsesFixedFuncAttributes = config.UsedFeatures.HasFlag(FeatureFlags.FixedFuncAttr);
MergeOutputUserAttributes(config.UsedInputAttributes, config.UsedInputAttributesPerPatch); MergeOutputUserAttributes(config.UsedInputAttributes, config.UsedInputAttributesPerPatch);
if (config.Stage != ShaderStage.Fragment)
{
LastInVertexPipeline = false;
}
} }
public void MergeOutputUserAttributes(int mask, int maskPerPatch) public void MergeOutputUserAttributes(int mask, int maskPerPatch)