Vulkan: Use staging buffer for temporary constants (#6168)
* Vulkan: Use staging buffer for temporary constants Helper shaders and post processing effects typically need some parameters to tell them what to do, which we pass via constant buffers that are created and destroyed each time. This can vary in cost between different Vulkan drivers. It shows up on profiles on mesa and MoltenVK, so it's worth avoiding. Some games only do it once (BlitColor for present), others multiple times. It's also done for post processing filters and FSR upscaling, which creates two buffers. For mirrors, I added the ability to reserve a range on the staging buffer for use as any type of binding. This PR allows these constant buffers to be instead temporarily allocated on the staging buffer, skipping allocation and buffer management costs entirely. Two temporary allocations do remain: - DrawTexture, because it doesn't have access to the command buffer scope - Index buffer indirect conversion, because one of them is a storage buffer and thus is a little more complicated. There's a small cost in that the uniform buffer takes up more space due to alignment requirements. At worst that's 256 bytes (on a GTX 1070) but more modern GPUs should have a better time. Worth testing across different games and post effects to make sure they still work. * Use temporary buffer for ConvertIndexBufferIndirect * Simplify alignment passing for now * Fix shader params length for CopyIncompatibleFormats * Set data for helpershaders without overlap checks The data is in the staging buffer, so its usage range is guarded using that.
This commit is contained in:
parent
dd2e851e95
commit
795539bc82
7 changed files with 126 additions and 83 deletions
|
@ -430,11 +430,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
(region[2], region[3]) = (region[3], region[2]);
|
||||
}
|
||||
|
||||
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, RegionBufferSize);
|
||||
using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, RegionBufferSize);
|
||||
|
||||
gd.BufferManager.SetData<float>(bufferHandle, 0, region);
|
||||
buffer.Holder.SetDataUnchecked<float>(buffer.Offset, region);
|
||||
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, RegionBufferSize)) });
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, buffer.Range) });
|
||||
|
||||
Span<Viewport> viewports = stackalloc Viewport[1];
|
||||
|
||||
|
@ -490,8 +490,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
}
|
||||
|
||||
_pipeline.Finish(gd, cbs);
|
||||
|
||||
gd.BufferManager.Delete(bufferHandle);
|
||||
}
|
||||
|
||||
private void BlitDepthStencil(
|
||||
|
@ -527,11 +525,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
(region[2], region[3]) = (region[3], region[2]);
|
||||
}
|
||||
|
||||
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, RegionBufferSize);
|
||||
using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, RegionBufferSize);
|
||||
|
||||
gd.BufferManager.SetData<float>(bufferHandle, 0, region);
|
||||
buffer.Holder.SetDataUnchecked<float>(buffer.Offset, region);
|
||||
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, RegionBufferSize)) });
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, buffer.Range) });
|
||||
|
||||
Span<Viewport> viewports = stackalloc Viewport[1];
|
||||
|
||||
|
@ -582,8 +580,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
}
|
||||
|
||||
_pipeline.Finish(gd, cbs);
|
||||
|
||||
gd.BufferManager.Delete(bufferHandle);
|
||||
}
|
||||
|
||||
private static TextureView CreateDepthOrStencilView(TextureView depthStencilTexture, DepthStencilMode depthStencilMode)
|
||||
|
@ -681,11 +677,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
_pipeline.SetCommandBuffer(cbs);
|
||||
|
||||
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ClearColorBufferSize);
|
||||
using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ClearColorBufferSize);
|
||||
|
||||
gd.BufferManager.SetData(bufferHandle, 0, clearColor);
|
||||
buffer.Holder.SetDataUnchecked(buffer.Offset, clearColor);
|
||||
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, ClearColorBufferSize)) });
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, buffer.Range) });
|
||||
|
||||
Span<Viewport> viewports = stackalloc Viewport[1];
|
||||
|
||||
|
@ -721,8 +717,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
||||
_pipeline.Draw(4, 1, 0, 0);
|
||||
_pipeline.Finish();
|
||||
|
||||
gd.BufferManager.Delete(bufferHandle);
|
||||
}
|
||||
|
||||
public void Clear(
|
||||
|
@ -745,11 +739,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
_pipeline.SetCommandBuffer(cbs);
|
||||
|
||||
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ClearColorBufferSize);
|
||||
using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ClearColorBufferSize);
|
||||
|
||||
gd.BufferManager.SetData<float>(bufferHandle, 0, stackalloc float[] { depthValue });
|
||||
buffer.Holder.SetDataUnchecked<float>(buffer.Offset, stackalloc float[] { depthValue });
|
||||
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, ClearColorBufferSize)) });
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, buffer.Range) });
|
||||
|
||||
Span<Viewport> viewports = stackalloc Viewport[1];
|
||||
|
||||
|
@ -771,8 +765,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_pipeline.SetStencilTest(CreateStencilTestDescriptor(stencilMask != 0, stencilValue, 0xff, stencilMask));
|
||||
_pipeline.Draw(4, 1, 0, 0);
|
||||
_pipeline.Finish();
|
||||
|
||||
gd.BufferManager.Delete(bufferHandle);
|
||||
}
|
||||
|
||||
public void DrawTexture(
|
||||
|
@ -878,13 +870,13 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
shaderParams[2] = size;
|
||||
shaderParams[3] = srcOffset;
|
||||
|
||||
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize);
|
||||
using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize);
|
||||
|
||||
gd.BufferManager.SetData<int>(bufferHandle, 0, shaderParams);
|
||||
buffer.Holder.SetDataUnchecked<int>(buffer.Offset, shaderParams);
|
||||
|
||||
_pipeline.SetCommandBuffer(cbs);
|
||||
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) });
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, buffer.Range) });
|
||||
|
||||
Span<Auto<DisposableBuffer>> sbRanges = new Auto<DisposableBuffer>[2];
|
||||
|
||||
|
@ -896,8 +888,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_pipeline.SetProgram(_programStrideChange);
|
||||
_pipeline.DispatchCompute(1 + elems / ConvertElementsPerWorkgroup, 1, 1);
|
||||
|
||||
gd.BufferManager.Delete(bufferHandle);
|
||||
|
||||
_pipeline.Finish(gd, cbs);
|
||||
}
|
||||
else
|
||||
|
@ -1025,7 +1015,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
{
|
||||
const int ParamsBufferSize = 4;
|
||||
|
||||
Span<int> shaderParams = stackalloc int[sizeof(int)];
|
||||
Span<int> shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)];
|
||||
|
||||
int srcBpp = src.Info.BytesPerPixel;
|
||||
int dstBpp = dst.Info.BytesPerPixel;
|
||||
|
@ -1034,9 +1024,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
shaderParams[0] = BitOperations.Log2((uint)ratio);
|
||||
|
||||
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize);
|
||||
using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize);
|
||||
|
||||
gd.BufferManager.SetData<int>(bufferHandle, 0, shaderParams);
|
||||
buffer.Holder.SetDataUnchecked<int>(buffer.Offset, shaderParams);
|
||||
|
||||
TextureView.InsertImageBarrier(
|
||||
gd.Api,
|
||||
|
@ -1064,7 +1054,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
var srcFormat = GetFormat(componentSize, srcBpp / componentSize);
|
||||
var dstFormat = GetFormat(componentSize, dstBpp / componentSize);
|
||||
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) });
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, buffer.Range) });
|
||||
|
||||
for (int l = 0; l < levels; l++)
|
||||
{
|
||||
|
@ -1093,8 +1083,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
}
|
||||
}
|
||||
|
||||
gd.BufferManager.Delete(bufferHandle);
|
||||
|
||||
_pipeline.Finish(gd, cbs);
|
||||
|
||||
TextureView.InsertImageBarrier(
|
||||
|
@ -1128,9 +1116,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
(shaderParams[0], shaderParams[1]) = GetSampleCountXYLog2(samples);
|
||||
(shaderParams[2], shaderParams[3]) = GetSampleCountXYLog2((int)TextureStorage.ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)samples));
|
||||
|
||||
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize);
|
||||
using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize);
|
||||
|
||||
gd.BufferManager.SetData<int>(bufferHandle, 0, shaderParams);
|
||||
buffer.Holder.SetDataUnchecked<int>(buffer.Offset, shaderParams);
|
||||
|
||||
TextureView.InsertImageBarrier(
|
||||
gd.Api,
|
||||
|
@ -1147,7 +1135,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
1);
|
||||
|
||||
_pipeline.SetCommandBuffer(cbs);
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) });
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, buffer.Range) });
|
||||
|
||||
if (isDepthOrStencil)
|
||||
{
|
||||
|
@ -1226,8 +1214,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
}
|
||||
}
|
||||
|
||||
gd.BufferManager.Delete(bufferHandle);
|
||||
|
||||
_pipeline.Finish(gd, cbs);
|
||||
|
||||
TextureView.InsertImageBarrier(
|
||||
|
@ -1261,9 +1247,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
(shaderParams[0], shaderParams[1]) = GetSampleCountXYLog2(samples);
|
||||
(shaderParams[2], shaderParams[3]) = GetSampleCountXYLog2((int)TextureStorage.ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)samples));
|
||||
|
||||
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize);
|
||||
using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize);
|
||||
|
||||
gd.BufferManager.SetData<int>(bufferHandle, 0, shaderParams);
|
||||
buffer.Holder.SetDataUnchecked<int>(buffer.Offset, shaderParams);
|
||||
|
||||
TextureView.InsertImageBarrier(
|
||||
gd.Api,
|
||||
|
@ -1299,7 +1285,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_pipeline.SetViewports(viewports);
|
||||
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
||||
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) });
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, buffer.Range) });
|
||||
|
||||
if (isDepthOrStencil)
|
||||
{
|
||||
|
@ -1364,8 +1350,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
}
|
||||
}
|
||||
|
||||
gd.BufferManager.Delete(bufferHandle);
|
||||
|
||||
_pipeline.Finish(gd, cbs);
|
||||
|
||||
TextureView.InsertImageBarrier(
|
||||
|
@ -1616,10 +1600,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
pattern.OffsetIndex.CopyTo(shaderParams[..pattern.OffsetIndex.Length]);
|
||||
|
||||
var patternBufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize, out var patternBuffer);
|
||||
using var patternScoped = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize);
|
||||
var patternBuffer = patternScoped.Holder;
|
||||
var patternBufferAuto = patternBuffer.GetBuffer();
|
||||
|
||||
gd.BufferManager.SetData<int>(patternBufferHandle, 0, shaderParams);
|
||||
patternBuffer.SetDataUnchecked<int>(patternScoped.Offset, shaderParams);
|
||||
|
||||
_pipeline.SetCommandBuffer(cbs);
|
||||
|
||||
|
@ -1635,7 +1620,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
indirectDataSize);
|
||||
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, drawCountBufferAligned) });
|
||||
_pipeline.SetStorageBuffers(1, new[] { srcIndirectBuffer.GetBuffer(), dstIndirectBuffer.GetBuffer(), patternBuffer.GetBuffer() });
|
||||
_pipeline.SetStorageBuffers(1, new[] { srcIndirectBuffer.GetBuffer(), dstIndirectBuffer.GetBuffer() });
|
||||
_pipeline.SetStorageBuffers(stackalloc[] { new BufferAssignment(3, patternScoped.Range) });
|
||||
|
||||
_pipeline.SetProgram(_programConvertIndirectData);
|
||||
_pipeline.DispatchCompute(1, 1, 1);
|
||||
|
@ -1643,12 +1629,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
BufferHolder.InsertBufferBarrier(
|
||||
gd,
|
||||
cbs.CommandBuffer,
|
||||
patternBufferAuto.Get(cbs, ParamsIndirectDispatchOffset, ParamsIndirectDispatchSize).Value,
|
||||
patternBufferAuto.Get(cbs, patternScoped.Offset + ParamsIndirectDispatchOffset, ParamsIndirectDispatchSize).Value,
|
||||
AccessFlags.ShaderWriteBit,
|
||||
AccessFlags.IndirectCommandReadBit,
|
||||
PipelineStageFlags.ComputeShaderBit,
|
||||
PipelineStageFlags.DrawIndirectBit,
|
||||
ParamsIndirectDispatchOffset,
|
||||
patternScoped.Offset + ParamsIndirectDispatchOffset,
|
||||
ParamsIndirectDispatchSize);
|
||||
|
||||
BufferHolder.InsertBufferBarrier(
|
||||
|
@ -1662,11 +1648,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
0,
|
||||
convertedCount * outputIndexSize);
|
||||
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(patternBufferHandle, 0, ParamsBufferSize)) });
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(patternScoped.Handle, patternScoped.Offset, ParamsBufferSize)) });
|
||||
_pipeline.SetStorageBuffers(1, new[] { srcIndexBuffer.GetBuffer(), dstIndexBuffer.GetBuffer() });
|
||||
|
||||
_pipeline.SetProgram(_programConvertIndexBuffer);
|
||||
_pipeline.DispatchComputeIndirect(patternBufferAuto, ParamsIndirectDispatchOffset);
|
||||
_pipeline.DispatchComputeIndirect(patternBufferAuto, patternScoped.Offset + ParamsIndirectDispatchOffset);
|
||||
|
||||
BufferHolder.InsertBufferBarrier(
|
||||
gd,
|
||||
|
@ -1679,8 +1665,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
0,
|
||||
convertedCount * outputIndexSize);
|
||||
|
||||
gd.BufferManager.Delete(patternBufferHandle);
|
||||
|
||||
_pipeline.Finish(gd, cbs);
|
||||
}
|
||||
|
||||
|
@ -1726,13 +1710,13 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
shaderParams[0] = pixelCount;
|
||||
shaderParams[1] = dstOffset;
|
||||
|
||||
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize);
|
||||
using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize);
|
||||
|
||||
gd.BufferManager.SetData<int>(bufferHandle, 0, shaderParams);
|
||||
buffer.Holder.SetDataUnchecked<int>(buffer.Offset, shaderParams);
|
||||
|
||||
_pipeline.SetCommandBuffer(cbs);
|
||||
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) });
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, buffer.Range) });
|
||||
|
||||
Span<Auto<DisposableBuffer>> sbRanges = new Auto<DisposableBuffer>[2];
|
||||
|
||||
|
@ -1744,8 +1728,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_pipeline.SetProgram(_programConvertD32S8ToD24S8);
|
||||
_pipeline.DispatchCompute(1 + inSize / ConvertElementsPerWorkgroup, 1, 1);
|
||||
|
||||
gd.BufferManager.Delete(bufferHandle);
|
||||
|
||||
_pipeline.Finish(gd, cbs);
|
||||
|
||||
BufferHolder.InsertBufferBarrier(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue