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:
parent
92ca1cb0cb
commit
43b4b34376
24 changed files with 200 additions and 26 deletions
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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";
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -206,7 +206,33 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
|
|
||||||
if (emit)
|
if (emit)
|
||||||
{
|
{
|
||||||
|
if (context.Config.LastInVertexPipeline)
|
||||||
|
{
|
||||||
|
context.PrepareForVertexReturn(out var tempXLocal, out var tempYLocal, out var tempZLocal);
|
||||||
|
|
||||||
context.EmitVertex();
|
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)
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Reference in a new issue