|
|
@@ -1,4 +1,5 @@
|
|
|
using Ryujinx.Common.Logging;
|
|
|
+using Ryujinx.Common.Memory;
|
|
|
using Ryujinx.Graphics.GAL;
|
|
|
using Ryujinx.Graphics.Gpu.Engine.Types;
|
|
|
using Ryujinx.Graphics.Gpu.Image;
|
|
|
@@ -15,11 +16,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
/// </summary>
|
|
|
class StateUpdater
|
|
|
{
|
|
|
- public const int ShaderStateIndex = 0;
|
|
|
- public const int RasterizerStateIndex = 1;
|
|
|
- public const int ScissorStateIndex = 2;
|
|
|
- public const int VertexBufferStateIndex = 3;
|
|
|
- public const int PrimitiveRestartStateIndex = 4;
|
|
|
+ public const int ShaderStateIndex = 16;
|
|
|
+ public const int RasterizerStateIndex = 15;
|
|
|
+ public const int ScissorStateIndex = 18;
|
|
|
+ public const int VertexBufferStateIndex = 0;
|
|
|
+ public const int PrimitiveRestartStateIndex = 12;
|
|
|
|
|
|
private readonly GpuContext _context;
|
|
|
private readonly GpuChannel _channel;
|
|
|
@@ -31,6 +32,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
private readonly ShaderProgramInfo[] _currentProgramInfo;
|
|
|
private ShaderSpecializationState _shaderSpecState;
|
|
|
|
|
|
+ private ProgramPipelineState _pipeline;
|
|
|
+
|
|
|
private bool _vtgWritesRtLayer;
|
|
|
private byte _vsClipDistancesWritten;
|
|
|
|
|
|
@@ -54,7 +57,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
_drawState = drawState;
|
|
|
_currentProgramInfo = new ShaderProgramInfo[Constants.ShaderStages];
|
|
|
|
|
|
- // ShaderState must be the first, as other state updates depends on information from the currently bound shader.
|
|
|
+ // ShaderState must be updated after other state updates, as pipeline state is sent to the backend when compiling new shaders.
|
|
|
+ // Render target state must appear after shader state as it depends on information from the currently bound shader.
|
|
|
// Rasterizer and scissor states are checked by render target clear, their indexes
|
|
|
// must be updated on the constants "RasterizerStateIndex" and "ScissorStateIndex" if modified.
|
|
|
// The vertex buffer state may be forced dirty when a indexed draw starts, the "VertexBufferStateIndex"
|
|
|
@@ -62,53 +66,39 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
// The order of the other state updates doesn't matter.
|
|
|
_updateTracker = new StateUpdateTracker<ThreedClassState>(new[]
|
|
|
{
|
|
|
- new StateUpdateCallbackEntry(UpdateShaderState,
|
|
|
- nameof(ThreedClassState.ShaderBaseAddress),
|
|
|
- nameof(ThreedClassState.ShaderState)),
|
|
|
-
|
|
|
- new StateUpdateCallbackEntry(UpdateRasterizerState, nameof(ThreedClassState.RasterizeEnable)),
|
|
|
-
|
|
|
- new StateUpdateCallbackEntry(UpdateScissorState,
|
|
|
- nameof(ThreedClassState.ScissorState),
|
|
|
- nameof(ThreedClassState.ScreenScissorState)),
|
|
|
-
|
|
|
new StateUpdateCallbackEntry(UpdateVertexBufferState,
|
|
|
nameof(ThreedClassState.VertexBufferDrawState),
|
|
|
nameof(ThreedClassState.VertexBufferInstanced),
|
|
|
nameof(ThreedClassState.VertexBufferState),
|
|
|
nameof(ThreedClassState.VertexBufferEndAddress)),
|
|
|
|
|
|
- new StateUpdateCallbackEntry(UpdatePrimitiveRestartState,
|
|
|
- nameof(ThreedClassState.PrimitiveRestartDrawArrays),
|
|
|
- nameof(ThreedClassState.PrimitiveRestartState)),
|
|
|
-
|
|
|
- new StateUpdateCallbackEntry(UpdateTessellationState,
|
|
|
- nameof(ThreedClassState.TessOuterLevel),
|
|
|
- nameof(ThreedClassState.TessInnerLevel),
|
|
|
- nameof(ThreedClassState.PatchVertices)),
|
|
|
-
|
|
|
- new StateUpdateCallbackEntry(UpdateTfBufferState, nameof(ThreedClassState.TfBufferState)),
|
|
|
- new StateUpdateCallbackEntry(UpdateUserClipState, nameof(ThreedClassState.ClipDistanceEnable)),
|
|
|
+ new StateUpdateCallbackEntry(UpdateVertexAttribState, nameof(ThreedClassState.VertexAttribState)),
|
|
|
|
|
|
- new StateUpdateCallbackEntry(UpdateRenderTargetState,
|
|
|
- nameof(ThreedClassState.RtColorState),
|
|
|
- nameof(ThreedClassState.RtDepthStencilState),
|
|
|
- nameof(ThreedClassState.RtControl),
|
|
|
- nameof(ThreedClassState.RtDepthStencilSize),
|
|
|
- nameof(ThreedClassState.RtDepthStencilEnable)),
|
|
|
+ new StateUpdateCallbackEntry(UpdateBlendState,
|
|
|
+ nameof(ThreedClassState.BlendIndependent),
|
|
|
+ nameof(ThreedClassState.BlendConstant),
|
|
|
+ nameof(ThreedClassState.BlendStateCommon),
|
|
|
+ nameof(ThreedClassState.BlendEnableCommon),
|
|
|
+ nameof(ThreedClassState.BlendEnable),
|
|
|
+ nameof(ThreedClassState.BlendState)),
|
|
|
|
|
|
- new StateUpdateCallbackEntry(UpdateDepthClampState, nameof(ThreedClassState.ViewVolumeClipControl)),
|
|
|
+ new StateUpdateCallbackEntry(UpdateFaceState, nameof(ThreedClassState.FaceState)),
|
|
|
|
|
|
- new StateUpdateCallbackEntry(UpdateAlphaTestState,
|
|
|
- nameof(ThreedClassState.AlphaTestEnable),
|
|
|
- nameof(ThreedClassState.AlphaTestRef),
|
|
|
- nameof(ThreedClassState.AlphaTestFunc)),
|
|
|
+ new StateUpdateCallbackEntry(UpdateStencilTestState,
|
|
|
+ nameof(ThreedClassState.StencilBackMasks),
|
|
|
+ nameof(ThreedClassState.StencilTestState),
|
|
|
+ nameof(ThreedClassState.StencilBackTestState)),
|
|
|
|
|
|
new StateUpdateCallbackEntry(UpdateDepthTestState,
|
|
|
nameof(ThreedClassState.DepthTestEnable),
|
|
|
nameof(ThreedClassState.DepthWriteEnable),
|
|
|
nameof(ThreedClassState.DepthTestFunc)),
|
|
|
|
|
|
+ new StateUpdateCallbackEntry(UpdateTessellationState,
|
|
|
+ nameof(ThreedClassState.TessOuterLevel),
|
|
|
+ nameof(ThreedClassState.TessInnerLevel),
|
|
|
+ nameof(ThreedClassState.PatchVertices)),
|
|
|
+
|
|
|
new StateUpdateCallbackEntry(UpdateViewportTransform,
|
|
|
nameof(ThreedClassState.DepthMode),
|
|
|
nameof(ThreedClassState.ViewportTransform),
|
|
|
@@ -116,6 +106,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
nameof(ThreedClassState.YControl),
|
|
|
nameof(ThreedClassState.ViewportTransformEnable)),
|
|
|
|
|
|
+ new StateUpdateCallbackEntry(UpdateLogicOpState, nameof(ThreedClassState.LogicOpState)),
|
|
|
+
|
|
|
+ new StateUpdateCallbackEntry(UpdateDepthClampState, nameof(ThreedClassState.ViewVolumeClipControl)),
|
|
|
+
|
|
|
new StateUpdateCallbackEntry(UpdatePolygonMode,
|
|
|
nameof(ThreedClassState.PolygonModeFront),
|
|
|
nameof(ThreedClassState.PolygonModeBack)),
|
|
|
@@ -126,21 +120,46 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
nameof(ThreedClassState.DepthBiasUnits),
|
|
|
nameof(ThreedClassState.DepthBiasClamp)),
|
|
|
|
|
|
- new StateUpdateCallbackEntry(UpdateStencilTestState,
|
|
|
- nameof(ThreedClassState.StencilBackMasks),
|
|
|
- nameof(ThreedClassState.StencilTestState),
|
|
|
- nameof(ThreedClassState.StencilBackTestState)),
|
|
|
+ new StateUpdateCallbackEntry(UpdatePrimitiveRestartState, nameof(ThreedClassState.PrimitiveRestartState)),
|
|
|
+
|
|
|
+ new StateUpdateCallbackEntry(UpdateLineState,
|
|
|
+ nameof(ThreedClassState.LineWidthSmooth),
|
|
|
+ nameof(ThreedClassState.LineSmoothEnable)),
|
|
|
+
|
|
|
+ new StateUpdateCallbackEntry(UpdateRtColorMask,
|
|
|
+ nameof(ThreedClassState.RtColorMaskShared),
|
|
|
+ nameof(ThreedClassState.RtColorMask)),
|
|
|
+
|
|
|
+ new StateUpdateCallbackEntry(UpdateRasterizerState, nameof(ThreedClassState.RasterizeEnable)),
|
|
|
+
|
|
|
+ new StateUpdateCallbackEntry(UpdateShaderState,
|
|
|
+ nameof(ThreedClassState.ShaderBaseAddress),
|
|
|
+ nameof(ThreedClassState.ShaderState)),
|
|
|
+
|
|
|
+ new StateUpdateCallbackEntry(UpdateRenderTargetState,
|
|
|
+ nameof(ThreedClassState.RtColorState),
|
|
|
+ nameof(ThreedClassState.RtDepthStencilState),
|
|
|
+ nameof(ThreedClassState.RtControl),
|
|
|
+ nameof(ThreedClassState.RtDepthStencilSize),
|
|
|
+ nameof(ThreedClassState.RtDepthStencilEnable)),
|
|
|
+
|
|
|
+ new StateUpdateCallbackEntry(UpdateScissorState,
|
|
|
+ nameof(ThreedClassState.ScissorState),
|
|
|
+ nameof(ThreedClassState.ScreenScissorState)),
|
|
|
+
|
|
|
+ new StateUpdateCallbackEntry(UpdateTfBufferState, nameof(ThreedClassState.TfBufferState)),
|
|
|
+ new StateUpdateCallbackEntry(UpdateUserClipState, nameof(ThreedClassState.ClipDistanceEnable)),
|
|
|
+
|
|
|
+ new StateUpdateCallbackEntry(UpdateAlphaTestState,
|
|
|
+ nameof(ThreedClassState.AlphaTestEnable),
|
|
|
+ nameof(ThreedClassState.AlphaTestRef),
|
|
|
+ nameof(ThreedClassState.AlphaTestFunc)),
|
|
|
|
|
|
new StateUpdateCallbackEntry(UpdateSamplerPoolState,
|
|
|
nameof(ThreedClassState.SamplerPoolState),
|
|
|
nameof(ThreedClassState.SamplerIndex)),
|
|
|
|
|
|
new StateUpdateCallbackEntry(UpdateTexturePoolState, nameof(ThreedClassState.TexturePoolState)),
|
|
|
- new StateUpdateCallbackEntry(UpdateVertexAttribState, nameof(ThreedClassState.VertexAttribState)),
|
|
|
-
|
|
|
- new StateUpdateCallbackEntry(UpdateLineState,
|
|
|
- nameof(ThreedClassState.LineWidthSmooth),
|
|
|
- nameof(ThreedClassState.LineSmoothEnable)),
|
|
|
|
|
|
new StateUpdateCallbackEntry(UpdatePointState,
|
|
|
nameof(ThreedClassState.PointSize),
|
|
|
@@ -152,22 +171,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
nameof(ThreedClassState.IndexBufferState),
|
|
|
nameof(ThreedClassState.IndexBufferCount)),
|
|
|
|
|
|
- new StateUpdateCallbackEntry(UpdateFaceState, nameof(ThreedClassState.FaceState)),
|
|
|
-
|
|
|
- new StateUpdateCallbackEntry(UpdateRtColorMask,
|
|
|
- nameof(ThreedClassState.RtColorMaskShared),
|
|
|
- nameof(ThreedClassState.RtColorMask)),
|
|
|
-
|
|
|
- new StateUpdateCallbackEntry(UpdateBlendState,
|
|
|
- nameof(ThreedClassState.BlendIndependent),
|
|
|
- nameof(ThreedClassState.BlendConstant),
|
|
|
- nameof(ThreedClassState.BlendStateCommon),
|
|
|
- nameof(ThreedClassState.BlendEnableCommon),
|
|
|
- nameof(ThreedClassState.BlendEnable),
|
|
|
- nameof(ThreedClassState.BlendState)),
|
|
|
-
|
|
|
- new StateUpdateCallbackEntry(UpdateLogicOpState, nameof(ThreedClassState.LogicOpState)),
|
|
|
-
|
|
|
new StateUpdateCallbackEntry(UpdateMultisampleState,
|
|
|
nameof(ThreedClassState.AlphaToCoverageDitherEnable),
|
|
|
nameof(ThreedClassState.MultisampleControl))
|
|
|
@@ -324,6 +327,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
/// </summary>
|
|
|
private void UpdateTessellationState()
|
|
|
{
|
|
|
+ _pipeline.PatchControlPoints = (uint)_state.State.PatchVertices;
|
|
|
+
|
|
|
_context.Renderer.Pipeline.SetPatchParameters(
|
|
|
_state.State.PatchVertices,
|
|
|
_state.State.TessOuterLevel.ToSpan(),
|
|
|
@@ -356,6 +361,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
private void UpdateRasterizerState()
|
|
|
{
|
|
|
bool enable = _state.State.RasterizeEnable;
|
|
|
+ _pipeline.RasterizerDiscard = !enable;
|
|
|
_context.Renderer.Pipeline.SetRasterizerDiscard(!enable);
|
|
|
}
|
|
|
|
|
|
@@ -497,11 +503,21 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
/// </summary>
|
|
|
public void UpdateScissorState()
|
|
|
{
|
|
|
+ const int MinX = 0;
|
|
|
+ const int MinY = 0;
|
|
|
+ const int MaxW = 0xffff;
|
|
|
+ const int MaxH = 0xffff;
|
|
|
+
|
|
|
+ Span<Rectangle<int>> regions = stackalloc Rectangle<int>[Constants.TotalViewports];
|
|
|
+
|
|
|
for (int index = 0; index < Constants.TotalViewports; index++)
|
|
|
{
|
|
|
ScissorState scissor = _state.State.ScissorState[index];
|
|
|
|
|
|
- bool enable = scissor.Enable && (scissor.X1 != 0 || scissor.Y1 != 0 || scissor.X2 != 0xffff || scissor.Y2 != 0xffff);
|
|
|
+ bool enable = scissor.Enable && (scissor.X1 != MinX ||
|
|
|
+ scissor.Y1 != MinY ||
|
|
|
+ scissor.X2 != MaxW ||
|
|
|
+ scissor.Y2 != MaxH);
|
|
|
|
|
|
if (enable)
|
|
|
{
|
|
|
@@ -531,13 +547,15 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
height = (int)MathF.Ceiling(height * scale);
|
|
|
}
|
|
|
|
|
|
- _context.Renderer.Pipeline.SetScissor(index, true, x, y, width, height);
|
|
|
+ regions[index] = new Rectangle<int>(x, y, width, height);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- _context.Renderer.Pipeline.SetScissor(index, false, 0, 0, 0, 0);
|
|
|
+ regions[index] = new Rectangle<int>(MinX, MinY, MaxW, MaxH);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ _context.Renderer.Pipeline.SetScissors(regions);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
@@ -547,7 +565,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
private void UpdateDepthClampState()
|
|
|
{
|
|
|
ViewVolumeClipControl clip = _state.State.ViewVolumeClipControl;
|
|
|
- _context.Renderer.Pipeline.SetDepthClamp((clip & ViewVolumeClipControl.DepthClampDisabled) == 0);
|
|
|
+ bool clamp = (clip & ViewVolumeClipControl.DepthClampDisabled) == 0;
|
|
|
+
|
|
|
+ _pipeline.DepthClampEnable = clamp;
|
|
|
+ _context.Renderer.Pipeline.SetDepthClamp(clamp);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
@@ -566,10 +587,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
/// </summary>
|
|
|
private void UpdateDepthTestState()
|
|
|
{
|
|
|
- _context.Renderer.Pipeline.SetDepthTest(new DepthTestDescriptor(
|
|
|
+ DepthTestDescriptor descriptor = new DepthTestDescriptor(
|
|
|
_state.State.DepthTestEnable,
|
|
|
_state.State.DepthWriteEnable,
|
|
|
- _state.State.DepthTestFunc));
|
|
|
+ _state.State.DepthTestFunc);
|
|
|
+
|
|
|
+ _pipeline.DepthTest = descriptor;
|
|
|
+ _context.Renderer.Pipeline.SetDepthTest(descriptor);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
@@ -596,7 +620,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
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);
|
|
|
+ var scissorRect = new Rectangle<float>(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;
|
|
|
@@ -633,7 +657,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
height *= scale;
|
|
|
}
|
|
|
|
|
|
- RectangleF region = new RectangleF(x, y, width, height);
|
|
|
+ Rectangle<float> region = new Rectangle<float>(x, y, width, height);
|
|
|
|
|
|
ViewportSwizzle swizzleX = transform.UnpackSwizzleX();
|
|
|
ViewportSwizzle swizzleY = transform.UnpackSwizzleY();
|
|
|
@@ -653,7 +677,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
viewports[index] = new Viewport(region, swizzleX, swizzleY, swizzleZ, swizzleW, depthNear, depthFar);
|
|
|
}
|
|
|
|
|
|
- _context.Renderer.Pipeline.SetViewports(0, viewports, disableTransform);
|
|
|
+ _context.Renderer.Pipeline.SetDepthMode(GetDepthMode());
|
|
|
+ _context.Renderer.Pipeline.SetViewports(viewports, disableTransform);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
@@ -661,37 +686,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
/// </summary>
|
|
|
private void UpdateDepthMode()
|
|
|
{
|
|
|
- ref var transform = ref _state.State.ViewportTransform[0];
|
|
|
- ref var extents = ref _state.State.ViewportExtents[0];
|
|
|
-
|
|
|
- DepthMode depthMode;
|
|
|
-
|
|
|
- if (!float.IsInfinity(extents.DepthNear) &&
|
|
|
- !float.IsInfinity(extents.DepthFar) &&
|
|
|
- (extents.DepthFar - extents.DepthNear) != 0)
|
|
|
- {
|
|
|
- // Try to guess the depth mode being used on the high level API
|
|
|
- // based on current transform.
|
|
|
- // It is setup like so by said APIs:
|
|
|
- // If depth mode is ZeroToOne:
|
|
|
- // TranslateZ = Near
|
|
|
- // ScaleZ = Far - Near
|
|
|
- // If depth mode is MinusOneToOne:
|
|
|
- // TranslateZ = (Near + Far) / 2
|
|
|
- // ScaleZ = (Far - Near) / 2
|
|
|
- // DepthNear/Far are sorted such as that Near is always less than Far.
|
|
|
- depthMode = extents.DepthNear != transform.TranslateZ &&
|
|
|
- extents.DepthFar != transform.TranslateZ
|
|
|
- ? DepthMode.MinusOneToOne
|
|
|
- : DepthMode.ZeroToOne;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- // If we can't guess from the viewport transform, then just use the depth mode register.
|
|
|
- depthMode = (DepthMode)(_state.State.DepthMode & 1);
|
|
|
- }
|
|
|
-
|
|
|
- _context.Renderer.Pipeline.SetDepthMode(depthMode);
|
|
|
+ _context.Renderer.Pipeline.SetDepthMode(GetDepthMode());
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
@@ -719,6 +714,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
enables |= (depthBias.LineEnable ? PolygonModeMask.Line : 0);
|
|
|
enables |= (depthBias.FillEnable ? PolygonModeMask.Fill : 0);
|
|
|
|
|
|
+ _pipeline.BiasEnable = enables;
|
|
|
_context.Renderer.Pipeline.SetDepthBias(enables, factor, units / 2f, clamp);
|
|
|
}
|
|
|
|
|
|
@@ -760,7 +756,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
backMask = test.FrontMask;
|
|
|
}
|
|
|
|
|
|
- _context.Renderer.Pipeline.SetStencilTest(new StencilTestDescriptor(
|
|
|
+ StencilTestDescriptor descriptor = new StencilTestDescriptor(
|
|
|
test.Enable,
|
|
|
test.FrontFunc,
|
|
|
test.FrontSFail,
|
|
|
@@ -775,7 +771,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
backDpFail,
|
|
|
backFuncRef,
|
|
|
backFuncMask,
|
|
|
- backMask));
|
|
|
+ backMask);
|
|
|
+
|
|
|
+ _pipeline.StencilTest = descriptor;
|
|
|
+ _context.Renderer.Pipeline.SetStencilTest(descriptor);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
@@ -844,6 +843,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
format);
|
|
|
}
|
|
|
|
|
|
+ _pipeline.SetVertexAttribs(vertexAttribs);
|
|
|
_context.Renderer.Pipeline.SetVertexAttribs(vertexAttribs);
|
|
|
}
|
|
|
|
|
|
@@ -855,6 +855,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
float width = _state.State.LineWidthSmooth;
|
|
|
bool smooth = _state.State.LineSmoothEnable;
|
|
|
|
|
|
+ _pipeline.LineWidth = width;
|
|
|
_context.Renderer.Pipeline.SetLineParameters(width, smooth);
|
|
|
}
|
|
|
|
|
|
@@ -881,6 +882,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
PrimitiveRestartState primitiveRestart = _state.State.PrimitiveRestartState;
|
|
|
bool enable = primitiveRestart.Enable && (_drawState.DrawIndexed || _state.State.PrimitiveRestartDrawArrays);
|
|
|
|
|
|
+ _pipeline.PrimitiveRestartEnable = enable;
|
|
|
_context.Renderer.Pipeline.SetPrimitiveRestart(enable, primitiveRestart.Index);
|
|
|
}
|
|
|
|
|
|
@@ -927,6 +929,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
|
|
|
if (!vertexBuffer.UnpackEnable())
|
|
|
{
|
|
|
+ _pipeline.VertexBuffers[index] = new BufferPipelineDescriptor(false, 0, 0);
|
|
|
_channel.BufferManager.SetVertexBuffer(index, 0, 0, 0, 0);
|
|
|
|
|
|
continue;
|
|
|
@@ -944,6 +947,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
|
|
|
_drawState.IsAnyVbInstanced |= divisor != 0;
|
|
|
|
|
|
+ ulong vbSize = endAddress.Pack() - address + 1;
|
|
|
ulong size;
|
|
|
|
|
|
if (_drawState.IbStreamer.HasInlineIndexData || _drawState.DrawIndexed || stride == 0 || instanced)
|
|
|
@@ -951,7 +955,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
// This size may be (much) larger than the real vertex buffer size.
|
|
|
// Avoid calculating it this way, unless we don't have any other option.
|
|
|
|
|
|
- size = endAddress.Pack() - address + 1;
|
|
|
+ size = vbSize;
|
|
|
|
|
|
if (stride > 0 && indexTypeSmall && _drawState.DrawIndexed && !instanced)
|
|
|
{
|
|
|
@@ -975,9 +979,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
|
|
|
var drawState = _state.State.VertexBufferDrawState;
|
|
|
|
|
|
- size = (ulong)((firstInstance + drawState.First + drawState.Count) * stride);
|
|
|
+ size = Math.Min(vbSize, (ulong)((firstInstance + drawState.First + drawState.Count) * stride));
|
|
|
}
|
|
|
|
|
|
+ _pipeline.VertexBuffers[index] = new BufferPipelineDescriptor(_channel.MemoryManager.IsMapped(address), stride, divisor);
|
|
|
_channel.BufferManager.SetVertexBuffer(index, address, size, stride, divisor);
|
|
|
}
|
|
|
}
|
|
|
@@ -990,6 +995,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
var yControl = _state.State.YControl;
|
|
|
var face = _state.State.FaceState;
|
|
|
|
|
|
+ _pipeline.CullEnable = face.CullEnable;
|
|
|
+ _pipeline.CullMode = face.CullFace;
|
|
|
_context.Renderer.Pipeline.SetFaceCulling(face.CullEnable, face.CullFace);
|
|
|
|
|
|
UpdateFrontFace(yControl, face.FrontFace);
|
|
|
@@ -1009,6 +1016,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
frontFace = frontFace == FrontFace.CounterClockwise ? FrontFace.Clockwise : FrontFace.CounterClockwise;
|
|
|
}
|
|
|
|
|
|
+ _pipeline.FrontFace = frontFace;
|
|
|
_context.Renderer.Pipeline.SetFrontFace(frontFace);
|
|
|
}
|
|
|
|
|
|
@@ -1034,6 +1042,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
componentMask |= (colorMask.UnpackAlpha() ? 8u : 0u);
|
|
|
|
|
|
componentMasks[index] = componentMask;
|
|
|
+ _pipeline.ColorWriteMask[index] = componentMask;
|
|
|
}
|
|
|
|
|
|
_context.Renderer.Pipeline.SetRenderTargetColorMasks(componentMasks);
|
|
|
@@ -1082,6 +1091,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
blend.AlphaDstFactor);
|
|
|
}
|
|
|
|
|
|
+ _pipeline.BlendDescriptors[index] = descriptor;
|
|
|
_context.Renderer.Pipeline.SetBlendState(index, descriptor);
|
|
|
}
|
|
|
}
|
|
|
@@ -1093,6 +1103,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
{
|
|
|
LogicalOpState logicOpState = _state.State.LogicOpState;
|
|
|
|
|
|
+ _pipeline.SetLogicOpState(logicOpState.Enable, logicOpState.LogicalOp);
|
|
|
_context.Renderer.Pipeline.SetLogicOpState(logicOpState.Enable, logicOpState.LogicalOp);
|
|
|
}
|
|
|
|
|
|
@@ -1138,7 +1149,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
GpuChannelPoolState poolState = GetPoolState();
|
|
|
GpuChannelGraphicsState graphicsState = GetGraphicsState();
|
|
|
|
|
|
- CachedShaderProgram gs = shaderCache.GetGraphicsShader(ref _state.State, _channel, poolState, graphicsState, addresses);
|
|
|
+ CachedShaderProgram gs = shaderCache.GetGraphicsShader(ref _state.State, ref _pipeline, _channel, poolState, graphicsState, addresses);
|
|
|
|
|
|
_shaderSpecState = gs.SpecializationState;
|
|
|
|
|
|
@@ -1245,13 +1256,69 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|
|
/// <returns>Current GPU channel state</returns>
|
|
|
private GpuChannelGraphicsState GetGraphicsState()
|
|
|
{
|
|
|
+ ref var vertexAttribState = ref _state.State.VertexAttribState;
|
|
|
+
|
|
|
+ Array32<AttributeType> attributeTypes = new Array32<AttributeType>();
|
|
|
+
|
|
|
+ for (int location = 0; location < attributeTypes.Length; location++)
|
|
|
+ {
|
|
|
+ attributeTypes[location] = vertexAttribState[location].UnpackType() switch
|
|
|
+ {
|
|
|
+ 3 => AttributeType.Sint,
|
|
|
+ 4 => AttributeType.Uint,
|
|
|
+ _ => AttributeType.Float
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
return new GpuChannelGraphicsState(
|
|
|
_state.State.EarlyZForce,
|
|
|
_drawState.Topology,
|
|
|
_state.State.TessMode,
|
|
|
- _state.State.ViewportTransformEnable == 0,
|
|
|
(_state.State.MultisampleControl & 1) != 0,
|
|
|
- _state.State.AlphaToCoverageDitherEnable);
|
|
|
+ _state.State.AlphaToCoverageDitherEnable,
|
|
|
+ _state.State.ViewportTransformEnable == 0,
|
|
|
+ GetDepthMode() == DepthMode.MinusOneToOne,
|
|
|
+ _state.State.VertexProgramPointSize,
|
|
|
+ _state.State.PointSize,
|
|
|
+ _state.State.AlphaTestEnable,
|
|
|
+ _state.State.AlphaTestFunc,
|
|
|
+ _state.State.AlphaTestRef,
|
|
|
+ ref attributeTypes);
|
|
|
+ }
|
|
|
+
|
|
|
+ private DepthMode GetDepthMode()
|
|
|
+ {
|
|
|
+ ref var transform = ref _state.State.ViewportTransform[0];
|
|
|
+ ref var extents = ref _state.State.ViewportExtents[0];
|
|
|
+
|
|
|
+ DepthMode depthMode;
|
|
|
+
|
|
|
+ if (!float.IsInfinity(extents.DepthNear) &&
|
|
|
+ !float.IsInfinity(extents.DepthFar) &&
|
|
|
+ (extents.DepthFar - extents.DepthNear) != 0)
|
|
|
+ {
|
|
|
+ // Try to guess the depth mode being used on the high level API
|
|
|
+ // based on current transform.
|
|
|
+ // It is setup like so by said APIs:
|
|
|
+ // If depth mode is ZeroToOne:
|
|
|
+ // TranslateZ = Near
|
|
|
+ // ScaleZ = Far - Near
|
|
|
+ // If depth mode is MinusOneToOne:
|
|
|
+ // TranslateZ = (Near + Far) / 2
|
|
|
+ // ScaleZ = (Far - Near) / 2
|
|
|
+ // DepthNear/Far are sorted such as that Near is always less than Far.
|
|
|
+ depthMode = extents.DepthNear != transform.TranslateZ &&
|
|
|
+ extents.DepthFar != transform.TranslateZ
|
|
|
+ ? DepthMode.MinusOneToOne
|
|
|
+ : DepthMode.ZeroToOne;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // If we can't guess from the viewport transform, then just use the depth mode register.
|
|
|
+ depthMode = (DepthMode)(_state.State.DepthMode & 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ return depthMode;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|