State and cache optimization (#27)

* WIP pipeline/depth state cache rework

* Fix some issues

* Fix some more default values

* Reduce allocations for state changes

* fix helpershader stuff

* explanation comment

* fix depth bias
This commit is contained in:
riperiperi 2024-06-28 21:14:53 +01:00 committed by Isaac Marovitz
parent 9d26aa8d06
commit e02df72323
14 changed files with 1142 additions and 565 deletions

View file

@ -25,6 +25,8 @@ namespace Ryujinx.Graphics.Metal
private readonly IProgram _programDepthStencilClear;
private readonly IProgram _programStrideChange;
private readonly EncoderState _helperShaderState = new();
public HelperShader(MTLDevice device, MetalRenderer renderer, Pipeline pipeline)
{
_device = device;
@ -80,8 +82,7 @@ namespace Ryujinx.Graphics.Metal
bool linearFilter,
bool clear = false)
{
// Save current state
_pipeline.SaveAndResetState();
_pipeline.SwapState(_helperShaderState);
const int RegionBufferSize = 16;
@ -141,8 +142,14 @@ namespace Ryujinx.Graphics.Metal
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
_pipeline.Draw(4, 1, 0, 0);
// Cleanup
if (clear)
{
_pipeline.SetClearLoadAction(false);
}
// Restore previous state
_pipeline.RestoreState();
_pipeline.SwapState(null);
}
public unsafe void DrawTexture(
@ -152,7 +159,11 @@ namespace Ryujinx.Graphics.Metal
Extents2DF dstRegion)
{
// Save current state
_pipeline.SaveState();
var state = _pipeline.SavePredrawState();
_pipeline.SetFaceCulling(false, Face.Front);
_pipeline.SetStencilTest(new StencilTestDescriptor());
_pipeline.SetDepthTest(new DepthTestDescriptor());
const int RegionBufferSize = 16;
@ -204,7 +215,7 @@ namespace Ryujinx.Graphics.Metal
_renderer.BufferManager.Delete(bufferHandle);
// Restore previous state
_pipeline.RestoreState();
_pipeline.RestorePredrawState(state);
}
public void ConvertI8ToI16(CommandBufferScoped cbs, BufferHolder src, BufferHolder dst, int srcOffset, int size)
@ -229,7 +240,7 @@ namespace Ryujinx.Graphics.Metal
const int ParamsBufferSize = 16;
// Save current state
_pipeline.SaveAndResetState();
_pipeline.SwapState(_helperShaderState);
Span<int> shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)];
@ -252,7 +263,7 @@ namespace Ryujinx.Graphics.Metal
_pipeline.DispatchCompute(1 + elems / ConvertElementsPerWorkgroup, 1, 1, 64, 1, 1);
// Restore previous state
_pipeline.RestoreState();
_pipeline.SwapState(null);
}
public unsafe void ClearColor(
@ -262,8 +273,14 @@ namespace Ryujinx.Graphics.Metal
int dstWidth,
int dstHeight)
{
// Keep original scissor
DirtyFlags clearFlags = DirtyFlags.All & (~DirtyFlags.Scissors);
// Save current state
_pipeline.SaveState();
EncoderState originalState = _pipeline.SwapState(_helperShaderState, clearFlags);
// Inherit some state without fully recreating render pipeline.
RenderTargetCopy save = _helperShaderState.InheritForClear(originalState, false, index);
const int ClearColorBufferSize = 16;
@ -286,7 +303,7 @@ namespace Ryujinx.Graphics.Metal
1f);
_pipeline.SetProgram(_programsColorClear[index]);
_pipeline.SetBlendState(index, new BlendDescriptor(false, new ColorF(0f, 0f, 0f, 1f), BlendOp.Add, BlendFactor.One, BlendFactor.Zero, BlendOp.Add, BlendFactor.One, BlendFactor.Zero));
_pipeline.SetBlendState(index, new BlendDescriptor());
_pipeline.SetFaceCulling(false, Face.Front);
_pipeline.SetDepthTest(new DepthTestDescriptor(false, false, CompareOp.Always));
_pipeline.SetRenderTargetColorMasks([componentMask]);
@ -295,7 +312,9 @@ namespace Ryujinx.Graphics.Metal
_pipeline.Draw(4, 1, 0, 0);
// Restore previous state
_pipeline.RestoreState();
_pipeline.SwapState(null, clearFlags);
_helperShaderState.Restore(save);
}
public unsafe void ClearDepthStencil(
@ -306,8 +325,15 @@ namespace Ryujinx.Graphics.Metal
int dstWidth,
int dstHeight)
{
// Keep original scissor
DirtyFlags clearFlags = DirtyFlags.All & (~DirtyFlags.Scissors);
var helperScissors = _helperShaderState.Scissors;
// Save current state
_pipeline.SaveState();
EncoderState originalState = _pipeline.SwapState(_helperShaderState, clearFlags);
// Inherit some state without fully recreating render pipeline.
RenderTargetCopy save = _helperShaderState.InheritForClear(originalState, true);
const int ClearDepthBufferSize = 16;
@ -334,8 +360,14 @@ namespace Ryujinx.Graphics.Metal
_pipeline.SetStencilTest(CreateStencilTestDescriptor(stencilMask != 0, stencilValue, 0xFF, stencilMask));
_pipeline.Draw(4, 1, 0, 0);
// Cleanup
_pipeline.SetDepthTest(new DepthTestDescriptor(false, false, CompareOp.Always));
_pipeline.SetStencilTest(CreateStencilTestDescriptor(false));
// Restore previous state
_pipeline.RestoreState();
_pipeline.SwapState(null, clearFlags);
_helperShaderState.Restore(save);
}
private static StencilTestDescriptor CreateStencilTestDescriptor(