Restride vertex buffer when stride causes attributes to misalign in Vulkan. (#3679)
* Vertex Buffer Alignment part 1 * Update CacheByRange * Add Stride Change compute shader, fix storage buffers in helpers * An AMD exclusive * Reword * Change rules - stride conversion when attrs misalign * Fix stupid mistake * Fix background pipeline compile * Improve a few things. * Fix some feedback * Address Feedback (the shader binary didn't change when i changed the source to use the subgroup size) * Fix bug where rewritten buffer would be disposed instantly.
This commit is contained in:
parent
ee1825219b
commit
c6d82209ab
18 changed files with 1069 additions and 120 deletions
|
@ -16,6 +16,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
private readonly IProgram _programColorBlit;
|
||||
private readonly IProgram _programColorBlitClearAlpha;
|
||||
private readonly IProgram _programColorClear;
|
||||
private readonly IProgram _programStrideChange;
|
||||
|
||||
public HelperShader(VulkanRenderer gd, Device device)
|
||||
{
|
||||
|
@ -39,14 +40,14 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
_programColorBlit = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Glsl),
|
||||
new ShaderSource(ShaderBinaries.ColorBlitFragmentShaderSource, fragmentBindings, ShaderStage.Fragment, TargetLanguage.Glsl),
|
||||
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ShaderBinaries.ColorBlitFragmentShaderSource, fragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
});
|
||||
|
||||
_programColorBlitClearAlpha = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Glsl),
|
||||
new ShaderSource(ShaderBinaries.ColorBlitClearAlphaFragmentShaderSource, fragmentBindings, ShaderStage.Fragment, TargetLanguage.Glsl),
|
||||
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ShaderBinaries.ColorBlitClearAlphaFragmentShaderSource, fragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
});
|
||||
|
||||
var fragmentBindings2 = new ShaderBindings(
|
||||
|
@ -57,8 +58,19 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
_programColorClear = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Glsl),
|
||||
new ShaderSource(ShaderBinaries.ColorClearFragmentShaderSource, fragmentBindings2, ShaderStage.Fragment, TargetLanguage.Glsl),
|
||||
new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||
new ShaderSource(ShaderBinaries.ColorClearFragmentShaderSource, fragmentBindings2, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||
});
|
||||
|
||||
var strideChangeBindings = new ShaderBindings(
|
||||
new[] { 0 },
|
||||
new[] { 1, 2 },
|
||||
Array.Empty<int>(),
|
||||
Array.Empty<int>());
|
||||
|
||||
_programStrideChange = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ShaderBinaries.ChangeBufferStrideShaderSource, strideChangeBindings, ShaderStage.Compute, TargetLanguage.Spirv),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -163,7 +175,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_pipeline.SetViewports(viewports, false);
|
||||
_pipeline.SetPrimitiveTopology(GAL.PrimitiveTopology.TriangleStrip);
|
||||
_pipeline.Draw(4, 1, 0, 0);
|
||||
_pipeline.Finish();
|
||||
_pipeline.Finish(gd, cbs);
|
||||
|
||||
gd.BufferManager.Delete(bufferHandle);
|
||||
}
|
||||
|
@ -291,45 +303,100 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
public unsafe void ConvertI8ToI16(VulkanRenderer gd, CommandBufferScoped cbs, BufferHolder src, BufferHolder dst, int srcOffset, int size)
|
||||
{
|
||||
// TODO: Do this with a compute shader?
|
||||
var srcBuffer = src.GetBuffer().Get(cbs, srcOffset, size).Value;
|
||||
var dstBuffer = dst.GetBuffer().Get(cbs, 0, size * 2).Value;
|
||||
ChangeStride(gd, cbs, src, dst, srcOffset, size, 1, 2);
|
||||
}
|
||||
|
||||
gd.Api.CmdFillBuffer(cbs.CommandBuffer, dstBuffer, 0, Vk.WholeSize, 0);
|
||||
public unsafe void ChangeStride(VulkanRenderer gd, CommandBufferScoped cbs, BufferHolder src, BufferHolder dst, int srcOffset, int size, int stride, int newStride)
|
||||
{
|
||||
bool supportsUint8 = gd.Capabilities.SupportsShaderInt8;
|
||||
|
||||
var bufferCopy = new BufferCopy[size];
|
||||
int elems = size / stride;
|
||||
int newSize = elems * newStride;
|
||||
|
||||
for (ulong i = 0; i < (ulong)size; i++)
|
||||
{
|
||||
bufferCopy[i] = new BufferCopy((ulong)srcOffset + i, i * 2, 1);
|
||||
}
|
||||
var srcBufferAuto = src.GetBuffer();
|
||||
var dstBufferAuto = dst.GetBuffer();
|
||||
|
||||
var srcBuffer = srcBufferAuto.Get(cbs, srcOffset, size).Value;
|
||||
var dstBuffer = dstBufferAuto.Get(cbs, 0, newSize).Value;
|
||||
|
||||
var access = supportsUint8 ? AccessFlags.AccessShaderWriteBit : AccessFlags.AccessTransferWriteBit;
|
||||
var stage = supportsUint8 ? PipelineStageFlags.PipelineStageComputeShaderBit : PipelineStageFlags.PipelineStageTransferBit;
|
||||
|
||||
BufferHolder.InsertBufferBarrier(
|
||||
gd,
|
||||
cbs.CommandBuffer,
|
||||
dstBuffer,
|
||||
BufferHolder.DefaultAccessFlags,
|
||||
AccessFlags.AccessTransferWriteBit,
|
||||
access,
|
||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
||||
PipelineStageFlags.PipelineStageTransferBit,
|
||||
stage,
|
||||
0,
|
||||
size * 2);
|
||||
newSize);
|
||||
|
||||
fixed (BufferCopy* pBufferCopy = bufferCopy)
|
||||
if (supportsUint8)
|
||||
{
|
||||
gd.Api.CmdCopyBuffer(cbs.CommandBuffer, srcBuffer, dstBuffer, (uint)size, pBufferCopy);
|
||||
const int ParamsBufferSize = 16;
|
||||
|
||||
Span<int> shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)];
|
||||
|
||||
shaderParams[0] = stride;
|
||||
shaderParams[1] = newStride;
|
||||
shaderParams[2] = size;
|
||||
shaderParams[3] = srcOffset;
|
||||
|
||||
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize, false);
|
||||
|
||||
gd.BufferManager.SetData<int>(bufferHandle, 0, shaderParams);
|
||||
|
||||
_pipeline.SetCommandBuffer(cbs);
|
||||
|
||||
Span<BufferRange> cbRanges = stackalloc BufferRange[1];
|
||||
|
||||
cbRanges[0] = new BufferRange(bufferHandle, 0, ParamsBufferSize);
|
||||
|
||||
_pipeline.SetUniformBuffers(0, cbRanges);
|
||||
|
||||
Span<Auto<DisposableBuffer>> sbRanges = new Auto<DisposableBuffer>[2];
|
||||
|
||||
sbRanges[0] = srcBufferAuto;
|
||||
sbRanges[1] = dstBufferAuto;
|
||||
|
||||
_pipeline.SetStorageBuffers(1, sbRanges);
|
||||
|
||||
_pipeline.SetProgram(_programStrideChange);
|
||||
_pipeline.DispatchCompute(1, 1, 1);
|
||||
|
||||
gd.BufferManager.Delete(bufferHandle);
|
||||
|
||||
_pipeline.Finish(gd, cbs);
|
||||
}
|
||||
else
|
||||
{
|
||||
gd.Api.CmdFillBuffer(cbs.CommandBuffer, dstBuffer, 0, Vk.WholeSize, 0);
|
||||
|
||||
var bufferCopy = new BufferCopy[elems];
|
||||
|
||||
for (ulong i = 0; i < (ulong)elems; i++)
|
||||
{
|
||||
bufferCopy[i] = new BufferCopy((ulong)srcOffset + i * (ulong)stride, i * (ulong)newStride, (ulong)stride);
|
||||
}
|
||||
|
||||
fixed (BufferCopy* pBufferCopy = bufferCopy)
|
||||
{
|
||||
gd.Api.CmdCopyBuffer(cbs.CommandBuffer, srcBuffer, dstBuffer, (uint)elems, pBufferCopy);
|
||||
}
|
||||
}
|
||||
|
||||
BufferHolder.InsertBufferBarrier(
|
||||
gd,
|
||||
cbs.CommandBuffer,
|
||||
dstBuffer,
|
||||
AccessFlags.AccessTransferWriteBit,
|
||||
access,
|
||||
BufferHolder.DefaultAccessFlags,
|
||||
PipelineStageFlags.PipelineStageTransferBit,
|
||||
stage,
|
||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
||||
0,
|
||||
size * 2);
|
||||
newSize);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue