aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorriperiperi <rhy3756547@hotmail.com>2024-01-25 18:29:53 +0000
committerGitHub <noreply@github.com>2024-01-25 19:29:53 +0100
commit795539bc821dd51ff7fb2b1f2c851881b168b03d (patch)
tree8a995ea3e9173c221ce1f4650b26f99c43c38341 /src
parentdd2e851e95e586bf65829da7cdb9e82014db36de (diff)
Vulkan: Use staging buffer for temporary constants (#6168)1.1.1127
* 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.
Diffstat (limited to 'src')
-rw-r--r--src/Ryujinx.Graphics.Vulkan/BufferHolder.cs8
-rw-r--r--src/Ryujinx.Graphics.Vulkan/BufferManager.cs50
-rw-r--r--src/Ryujinx.Graphics.Vulkan/Effects/FsrScalingFilter.cs19
-rw-r--r--src/Ryujinx.Graphics.Vulkan/Effects/FxaaPostProcessingEffect.cs8
-rw-r--r--src/Ryujinx.Graphics.Vulkan/Effects/SmaaPostProcessingEffect.cs9
-rw-r--r--src/Ryujinx.Graphics.Vulkan/HelperShader.cs92
-rw-r--r--src/Ryujinx.Graphics.Vulkan/StagingBuffer.cs23
7 files changed, 126 insertions, 83 deletions
diff --git a/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs b/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs
index bdd5d385..3673ee5a 100644
--- a/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs
+++ b/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs
@@ -4,6 +4,7 @@ using Silk.NET.Vulkan;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Threading;
using VkBuffer = Silk.NET.Vulkan.Buffer;
using VkFormat = Silk.NET.Vulkan.Format;
@@ -384,7 +385,7 @@ namespace Ryujinx.Graphics.Vulkan
var baseData = new Span<byte>((void*)(_map + offset), size);
var modData = _pendingData.AsSpan(offset, size);
- StagingBufferReserved? newMirror = _gd.BufferManager.StagingBuffer.TryReserveData(cbs, size, (int)_gd.Capabilities.MinResourceAlignment);
+ StagingBufferReserved? newMirror = _gd.BufferManager.StagingBuffer.TryReserveData(cbs, size);
if (newMirror != null)
{
@@ -838,6 +839,11 @@ namespace Ryujinx.Graphics.Vulkan
}
}
+ public unsafe void SetDataUnchecked<T>(int offset, ReadOnlySpan<T> data) where T : unmanaged
+ {
+ SetDataUnchecked(offset, MemoryMarshal.AsBytes(data));
+ }
+
public void SetDataInline(CommandBufferScoped cbs, Action endRenderPass, int dstOffset, ReadOnlySpan<byte> data)
{
if (!TryPushData(cbs, endRenderPass, dstOffset, data))
diff --git a/src/Ryujinx.Graphics.Vulkan/BufferManager.cs b/src/Ryujinx.Graphics.Vulkan/BufferManager.cs
index e9ac9884..33289a0e 100644
--- a/src/Ryujinx.Graphics.Vulkan/BufferManager.cs
+++ b/src/Ryujinx.Graphics.Vulkan/BufferManager.cs
@@ -9,6 +9,36 @@ using VkFormat = Silk.NET.Vulkan.Format;
namespace Ryujinx.Graphics.Vulkan
{
+ readonly struct ScopedTemporaryBuffer : IDisposable
+ {
+ private readonly BufferManager _bufferManager;
+ private readonly bool _isReserved;
+
+ public readonly BufferRange Range;
+ public readonly BufferHolder Holder;
+
+ public BufferHandle Handle => Range.Handle;
+ public int Offset => Range.Offset;
+
+ public ScopedTemporaryBuffer(BufferManager bufferManager, BufferHolder holder, BufferHandle handle, int offset, int size, bool isReserved)
+ {
+ _bufferManager = bufferManager;
+
+ Range = new BufferRange(handle, offset, size);
+ Holder = holder;
+
+ _isReserved = isReserved;
+ }
+
+ public void Dispose()
+ {
+ if (!_isReserved)
+ {
+ _bufferManager.Delete(Range.Handle);
+ }
+ }
+ }
+
class BufferManager : IDisposable
{
public const MemoryPropertyFlags DefaultBufferMemoryFlags =
@@ -238,6 +268,23 @@ namespace Ryujinx.Graphics.Vulkan
return Unsafe.As<ulong, BufferHandle>(ref handle64);
}
+ public ScopedTemporaryBuffer ReserveOrCreate(VulkanRenderer gd, CommandBufferScoped cbs, int size)
+ {
+ StagingBufferReserved? result = StagingBuffer.TryReserveData(cbs, size);
+
+ if (result.HasValue)
+ {
+ return new ScopedTemporaryBuffer(this, result.Value.Buffer, StagingBuffer.Handle, result.Value.Offset, result.Value.Size, true);
+ }
+ else
+ {
+ // Create a temporary buffer.
+ BufferHandle handle = CreateWithHandle(gd, size, out BufferHolder holder);
+
+ return new ScopedTemporaryBuffer(this, holder, handle, 0, size, false);
+ }
+ }
+
public unsafe MemoryRequirements GetHostImportedUsageRequirements(VulkanRenderer gd)
{
var usage = HostImportedBufferUsageFlags;
@@ -635,13 +682,14 @@ namespace Ryujinx.Graphics.Vulkan
{
if (disposing)
{
+ StagingBuffer.Dispose();
+
foreach (BufferHolder buffer in _buffers)
{
buffer.Dispose();
}
_buffers.Clear();
- StagingBuffer.Dispose();
}
}
diff --git a/src/Ryujinx.Graphics.Vulkan/Effects/FsrScalingFilter.cs b/src/Ryujinx.Graphics.Vulkan/Effects/FsrScalingFilter.cs
index 23acdcf8..5c0fc468 100644
--- a/src/Ryujinx.Graphics.Vulkan/Effects/FsrScalingFilter.cs
+++ b/src/Ryujinx.Graphics.Vulkan/Effects/FsrScalingFilter.cs
@@ -142,19 +142,18 @@ namespace Ryujinx.Graphics.Vulkan.Effects
};
int rangeSize = dimensionsBuffer.Length * sizeof(float);
- var bufferHandle = _renderer.BufferManager.CreateWithHandle(_renderer, rangeSize);
- _renderer.BufferManager.SetData(bufferHandle, 0, dimensionsBuffer);
+ using var buffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, rangeSize);
+ buffer.Holder.SetDataUnchecked(buffer.Offset, dimensionsBuffer);
- ReadOnlySpan<float> sharpeningBuffer = stackalloc float[] { 1.5f - (Level * 0.01f * 1.5f) };
- var sharpeningBufferHandle = _renderer.BufferManager.CreateWithHandle(_renderer, sizeof(float));
- _renderer.BufferManager.SetData(sharpeningBufferHandle, 0, sharpeningBuffer);
+ ReadOnlySpan<float> sharpeningBufferData = stackalloc float[] { 1.5f - (Level * 0.01f * 1.5f) };
+ using var sharpeningBuffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, sizeof(float));
+ sharpeningBuffer.Holder.SetDataUnchecked(sharpeningBuffer.Offset, sharpeningBufferData);
int threadGroupWorkRegionDim = 16;
int dispatchX = (width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
- var bufferRanges = new BufferRange(bufferHandle, 0, rangeSize);
- _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, bufferRanges) });
+ _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) });
_pipeline.SetImage(0, _intermediaryTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
_pipeline.ComputeBarrier();
@@ -162,16 +161,12 @@ namespace Ryujinx.Graphics.Vulkan.Effects
// Sharpening pass
_pipeline.SetProgram(_sharpeningProgram);
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, _intermediaryTexture, _sampler);
- var sharpeningRange = new BufferRange(sharpeningBufferHandle, 0, sizeof(float));
- _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(4, sharpeningRange) });
+ _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(4, sharpeningBuffer.Range) });
_pipeline.SetImage(0, destinationTexture);
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
_pipeline.ComputeBarrier();
_pipeline.Finish();
-
- _renderer.BufferManager.Delete(bufferHandle);
- _renderer.BufferManager.Delete(sharpeningBufferHandle);
}
}
}
diff --git a/src/Ryujinx.Graphics.Vulkan/Effects/FxaaPostProcessingEffect.cs b/src/Ryujinx.Graphics.Vulkan/Effects/FxaaPostProcessingEffect.cs
index 67e461e5..a7dd8eee 100644
--- a/src/Ryujinx.Graphics.Vulkan/Effects/FxaaPostProcessingEffect.cs
+++ b/src/Ryujinx.Graphics.Vulkan/Effects/FxaaPostProcessingEffect.cs
@@ -66,12 +66,11 @@ namespace Ryujinx.Graphics.Vulkan.Effects
ReadOnlySpan<float> resolutionBuffer = stackalloc float[] { view.Width, view.Height };
int rangeSize = resolutionBuffer.Length * sizeof(float);
- var bufferHandle = _renderer.BufferManager.CreateWithHandle(_renderer, rangeSize);
+ using var buffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, rangeSize);
- _renderer.BufferManager.SetData(bufferHandle, 0, resolutionBuffer);
+ buffer.Holder.SetDataUnchecked(buffer.Offset, resolutionBuffer);
- var bufferRanges = new BufferRange(bufferHandle, 0, rangeSize);
- _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, bufferRanges) });
+ _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) });
var dispatchX = BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize);
var dispatchY = BitUtils.DivRoundUp(view.Height, IPostProcessingEffect.LocalGroupSize);
@@ -79,7 +78,6 @@ namespace Ryujinx.Graphics.Vulkan.Effects
_pipeline.SetImage(0, _texture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
- _renderer.BufferManager.Delete(bufferHandle);
_pipeline.ComputeBarrier();
_pipeline.Finish();
diff --git a/src/Ryujinx.Graphics.Vulkan/Effects/SmaaPostProcessingEffect.cs b/src/Ryujinx.Graphics.Vulkan/Effects/SmaaPostProcessingEffect.cs
index c521f227..802b73b8 100644
--- a/src/Ryujinx.Graphics.Vulkan/Effects/SmaaPostProcessingEffect.cs
+++ b/src/Ryujinx.Graphics.Vulkan/Effects/SmaaPostProcessingEffect.cs
@@ -215,11 +215,10 @@ namespace Ryujinx.Graphics.Vulkan.Effects
ReadOnlySpan<float> resolutionBuffer = stackalloc float[] { view.Width, view.Height };
int rangeSize = resolutionBuffer.Length * sizeof(float);
- var bufferHandle = _renderer.BufferManager.CreateWithHandle(_renderer, rangeSize);
+ using var buffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, rangeSize);
- _renderer.BufferManager.SetData(bufferHandle, 0, resolutionBuffer);
- var bufferRanges = new BufferRange(bufferHandle, 0, rangeSize);
- _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, bufferRanges) });
+ buffer.Holder.SetDataUnchecked(buffer.Offset, resolutionBuffer);
+ _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) });
_pipeline.SetImage(0, _edgeOutputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
_pipeline.ComputeBarrier();
@@ -245,8 +244,6 @@ namespace Ryujinx.Graphics.Vulkan.Effects
_pipeline.Finish();
- _renderer.BufferManager.Delete(bufferHandle);
-
return _outputTexture;
}
diff --git a/src/Ryujinx.Graphics.Vulkan/HelperShader.cs b/src/Ryujinx.Graphics.Vulkan/HelperShader.cs
index deaf8162..ce84f752 100644
--- a/src/Ryujinx.Graphics.Vulkan/HelperShader.cs
+++ b/src/Ryujinx.Graphics.Vulkan/HelperShader.cs
@@ -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(
diff --git a/src/Ryujinx.Graphics.Vulkan/StagingBuffer.cs b/src/Ryujinx.Graphics.Vulkan/StagingBuffer.cs
index 3a02a28d..90a47bb6 100644
--- a/src/Ryujinx.Graphics.Vulkan/StagingBuffer.cs
+++ b/src/Ryujinx.Graphics.Vulkan/StagingBuffer.cs
@@ -1,5 +1,6 @@
using Ryujinx.Common;
using Ryujinx.Common.Logging;
+using Ryujinx.Graphics.GAL;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -29,6 +30,9 @@ namespace Ryujinx.Graphics.Vulkan
private readonly VulkanRenderer _gd;
private readonly BufferHolder _buffer;
+ private readonly int _resourceAlignment;
+
+ public readonly BufferHandle Handle;
private readonly struct PendingCopy
{
@@ -48,9 +52,10 @@ namespace Ryujinx.Graphics.Vulkan
public StagingBuffer(VulkanRenderer gd, BufferManager bufferManager)
{
_gd = gd;
- _buffer = bufferManager.Create(gd, BufferSize);
+ Handle = bufferManager.CreateWithHandle(gd, BufferSize, out _buffer);
_pendingCopies = new Queue<PendingCopy>();
_freeSize = BufferSize;
+ _resourceAlignment = (int)gd.Capabilities.MinResourceAlignment;
}
public void PushData(CommandBufferPool cbp, CommandBufferScoped? cbs, Action endRenderPass, BufferHolder dst, int dstOffset, ReadOnlySpan<byte> data)
@@ -197,7 +202,7 @@ namespace Ryujinx.Graphics.Vulkan
/// Reserve a range on the staging buffer for the current command buffer and upload data to it.
/// </summary>
/// <param name="cbs">Command buffer to reserve the data on</param>
- /// <param name="data">The data to upload</param>
+ /// <param name="size">The minimum size the reserved data requires</param>
/// <param name="alignment">The required alignment for the buffer offset</param>
/// <returns>The reserved range of the staging buffer</returns>
public unsafe StagingBufferReserved? TryReserveData(CommandBufferScoped cbs, int size, int alignment)
@@ -223,6 +228,18 @@ namespace Ryujinx.Graphics.Vulkan
return ReserveDataImpl(cbs, size, alignment);
}
+ /// <summary>
+ /// Reserve a range on the staging buffer for the current command buffer and upload data to it.
+ /// Uses the most permissive byte alignment.
+ /// </summary>
+ /// <param name="cbs">Command buffer to reserve the data on</param>
+ /// <param name="size">The minimum size the reserved data requires</param>
+ /// <returns>The reserved range of the staging buffer</returns>
+ public unsafe StagingBufferReserved? TryReserveData(CommandBufferScoped cbs, int size)
+ {
+ return TryReserveData(cbs, size, _resourceAlignment);
+ }
+
private bool WaitFreeCompleted(CommandBufferPool cbp)
{
if (_pendingCopies.TryPeek(out var pc))
@@ -263,7 +280,7 @@ namespace Ryujinx.Graphics.Vulkan
{
if (disposing)
{
- _buffer.Dispose();
+ _gd.BufferManager.Delete(Handle);
while (_pendingCopies.TryDequeue(out var pc))
{