aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs')
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs287
1 files changed, 177 insertions, 110 deletions
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
index 2f5d4fc5..ccbccca1 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
@@ -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>