forked from Mirror/Ryujinx
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
|
@ -4,6 +4,7 @@ using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using VkBuffer = Silk.NET.Vulkan.Buffer;
|
using VkBuffer = Silk.NET.Vulkan.Buffer;
|
||||||
using VkFormat = Silk.NET.Vulkan.Format;
|
using VkFormat = Silk.NET.Vulkan.Format;
|
||||||
|
@ -384,7 +385,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
var baseData = new Span<byte>((void*)(_map + offset), size);
|
var baseData = new Span<byte>((void*)(_map + offset), size);
|
||||||
var modData = _pendingData.AsSpan(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)
|
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)
|
public void SetDataInline(CommandBufferScoped cbs, Action endRenderPass, int dstOffset, ReadOnlySpan<byte> data)
|
||||||
{
|
{
|
||||||
if (!TryPushData(cbs, endRenderPass, dstOffset, data))
|
if (!TryPushData(cbs, endRenderPass, dstOffset, data))
|
||||||
|
|
|
@ -9,6 +9,36 @@ using VkFormat = Silk.NET.Vulkan.Format;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
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
|
class BufferManager : IDisposable
|
||||||
{
|
{
|
||||||
public const MemoryPropertyFlags DefaultBufferMemoryFlags =
|
public const MemoryPropertyFlags DefaultBufferMemoryFlags =
|
||||||
|
@ -238,6 +268,23 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
return Unsafe.As<ulong, BufferHandle>(ref handle64);
|
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)
|
public unsafe MemoryRequirements GetHostImportedUsageRequirements(VulkanRenderer gd)
|
||||||
{
|
{
|
||||||
var usage = HostImportedBufferUsageFlags;
|
var usage = HostImportedBufferUsageFlags;
|
||||||
|
@ -635,13 +682,14 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
if (disposing)
|
if (disposing)
|
||||||
{
|
{
|
||||||
|
StagingBuffer.Dispose();
|
||||||
|
|
||||||
foreach (BufferHolder buffer in _buffers)
|
foreach (BufferHolder buffer in _buffers)
|
||||||
{
|
{
|
||||||
buffer.Dispose();
|
buffer.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
_buffers.Clear();
|
_buffers.Clear();
|
||||||
StagingBuffer.Dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -142,19 +142,18 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
||||||
};
|
};
|
||||||
|
|
||||||
int rangeSize = dimensionsBuffer.Length * sizeof(float);
|
int rangeSize = dimensionsBuffer.Length * sizeof(float);
|
||||||
var bufferHandle = _renderer.BufferManager.CreateWithHandle(_renderer, rangeSize);
|
using var buffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, rangeSize);
|
||||||
_renderer.BufferManager.SetData(bufferHandle, 0, dimensionsBuffer);
|
buffer.Holder.SetDataUnchecked(buffer.Offset, dimensionsBuffer);
|
||||||
|
|
||||||
ReadOnlySpan<float> sharpeningBuffer = stackalloc float[] { 1.5f - (Level * 0.01f * 1.5f) };
|
ReadOnlySpan<float> sharpeningBufferData = stackalloc float[] { 1.5f - (Level * 0.01f * 1.5f) };
|
||||||
var sharpeningBufferHandle = _renderer.BufferManager.CreateWithHandle(_renderer, sizeof(float));
|
using var sharpeningBuffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, sizeof(float));
|
||||||
_renderer.BufferManager.SetData(sharpeningBufferHandle, 0, sharpeningBuffer);
|
sharpeningBuffer.Holder.SetDataUnchecked(sharpeningBuffer.Offset, sharpeningBufferData);
|
||||||
|
|
||||||
int threadGroupWorkRegionDim = 16;
|
int threadGroupWorkRegionDim = 16;
|
||||||
int dispatchX = (width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
int dispatchX = (width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
||||||
int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
||||||
|
|
||||||
var bufferRanges = new BufferRange(bufferHandle, 0, rangeSize);
|
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) });
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, bufferRanges) });
|
|
||||||
_pipeline.SetImage(0, _intermediaryTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
|
_pipeline.SetImage(0, _intermediaryTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
|
||||||
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
||||||
_pipeline.ComputeBarrier();
|
_pipeline.ComputeBarrier();
|
||||||
|
@ -162,16 +161,12 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
||||||
// Sharpening pass
|
// Sharpening pass
|
||||||
_pipeline.SetProgram(_sharpeningProgram);
|
_pipeline.SetProgram(_sharpeningProgram);
|
||||||
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, _intermediaryTexture, _sampler);
|
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, _intermediaryTexture, _sampler);
|
||||||
var sharpeningRange = new BufferRange(sharpeningBufferHandle, 0, sizeof(float));
|
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(4, sharpeningBuffer.Range) });
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(4, sharpeningRange) });
|
|
||||||
_pipeline.SetImage(0, destinationTexture);
|
_pipeline.SetImage(0, destinationTexture);
|
||||||
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
||||||
_pipeline.ComputeBarrier();
|
_pipeline.ComputeBarrier();
|
||||||
|
|
||||||
_pipeline.Finish();
|
_pipeline.Finish();
|
||||||
|
|
||||||
_renderer.BufferManager.Delete(bufferHandle);
|
|
||||||
_renderer.BufferManager.Delete(sharpeningBufferHandle);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,12 +66,11 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
||||||
|
|
||||||
ReadOnlySpan<float> resolutionBuffer = stackalloc float[] { view.Width, view.Height };
|
ReadOnlySpan<float> resolutionBuffer = stackalloc float[] { view.Width, view.Height };
|
||||||
int rangeSize = resolutionBuffer.Length * sizeof(float);
|
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, buffer.Range) });
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, bufferRanges) });
|
|
||||||
|
|
||||||
var dispatchX = BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize);
|
var dispatchX = BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize);
|
||||||
var dispatchY = BitUtils.DivRoundUp(view.Height, 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.SetImage(0, _texture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
|
||||||
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
||||||
|
|
||||||
_renderer.BufferManager.Delete(bufferHandle);
|
|
||||||
_pipeline.ComputeBarrier();
|
_pipeline.ComputeBarrier();
|
||||||
|
|
||||||
_pipeline.Finish();
|
_pipeline.Finish();
|
||||||
|
|
|
@ -215,11 +215,10 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
||||||
|
|
||||||
ReadOnlySpan<float> resolutionBuffer = stackalloc float[] { view.Width, view.Height };
|
ReadOnlySpan<float> resolutionBuffer = stackalloc float[] { view.Width, view.Height };
|
||||||
int rangeSize = resolutionBuffer.Length * sizeof(float);
|
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, buffer.Range) });
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, bufferRanges) });
|
|
||||||
_pipeline.SetImage(0, _edgeOutputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
|
_pipeline.SetImage(0, _edgeOutputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
|
||||||
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
||||||
_pipeline.ComputeBarrier();
|
_pipeline.ComputeBarrier();
|
||||||
|
@ -245,8 +244,6 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
||||||
|
|
||||||
_pipeline.Finish();
|
_pipeline.Finish();
|
||||||
|
|
||||||
_renderer.BufferManager.Delete(bufferHandle);
|
|
||||||
|
|
||||||
return _outputTexture;
|
return _outputTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -430,11 +430,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
(region[2], region[3]) = (region[3], region[2]);
|
(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];
|
Span<Viewport> viewports = stackalloc Viewport[1];
|
||||||
|
|
||||||
|
@ -490,8 +490,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
|
|
||||||
_pipeline.Finish(gd, cbs);
|
_pipeline.Finish(gd, cbs);
|
||||||
|
|
||||||
gd.BufferManager.Delete(bufferHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BlitDepthStencil(
|
private void BlitDepthStencil(
|
||||||
|
@ -527,11 +525,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
(region[2], region[3]) = (region[3], region[2]);
|
(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];
|
Span<Viewport> viewports = stackalloc Viewport[1];
|
||||||
|
|
||||||
|
@ -582,8 +580,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
|
|
||||||
_pipeline.Finish(gd, cbs);
|
_pipeline.Finish(gd, cbs);
|
||||||
|
|
||||||
gd.BufferManager.Delete(bufferHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TextureView CreateDepthOrStencilView(TextureView depthStencilTexture, DepthStencilMode depthStencilMode)
|
private static TextureView CreateDepthOrStencilView(TextureView depthStencilTexture, DepthStencilMode depthStencilMode)
|
||||||
|
@ -681,11 +677,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
_pipeline.SetCommandBuffer(cbs);
|
_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];
|
Span<Viewport> viewports = stackalloc Viewport[1];
|
||||||
|
|
||||||
|
@ -721,8 +717,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
||||||
_pipeline.Draw(4, 1, 0, 0);
|
_pipeline.Draw(4, 1, 0, 0);
|
||||||
_pipeline.Finish();
|
_pipeline.Finish();
|
||||||
|
|
||||||
gd.BufferManager.Delete(bufferHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear(
|
public void Clear(
|
||||||
|
@ -745,11 +739,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
_pipeline.SetCommandBuffer(cbs);
|
_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];
|
Span<Viewport> viewports = stackalloc Viewport[1];
|
||||||
|
|
||||||
|
@ -771,8 +765,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_pipeline.SetStencilTest(CreateStencilTestDescriptor(stencilMask != 0, stencilValue, 0xff, stencilMask));
|
_pipeline.SetStencilTest(CreateStencilTestDescriptor(stencilMask != 0, stencilValue, 0xff, stencilMask));
|
||||||
_pipeline.Draw(4, 1, 0, 0);
|
_pipeline.Draw(4, 1, 0, 0);
|
||||||
_pipeline.Finish();
|
_pipeline.Finish();
|
||||||
|
|
||||||
gd.BufferManager.Delete(bufferHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DrawTexture(
|
public void DrawTexture(
|
||||||
|
@ -878,13 +870,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
shaderParams[2] = size;
|
shaderParams[2] = size;
|
||||||
shaderParams[3] = srcOffset;
|
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.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];
|
Span<Auto<DisposableBuffer>> sbRanges = new Auto<DisposableBuffer>[2];
|
||||||
|
|
||||||
|
@ -896,8 +888,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_pipeline.SetProgram(_programStrideChange);
|
_pipeline.SetProgram(_programStrideChange);
|
||||||
_pipeline.DispatchCompute(1 + elems / ConvertElementsPerWorkgroup, 1, 1);
|
_pipeline.DispatchCompute(1 + elems / ConvertElementsPerWorkgroup, 1, 1);
|
||||||
|
|
||||||
gd.BufferManager.Delete(bufferHandle);
|
|
||||||
|
|
||||||
_pipeline.Finish(gd, cbs);
|
_pipeline.Finish(gd, cbs);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1025,7 +1015,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
const int ParamsBufferSize = 4;
|
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 srcBpp = src.Info.BytesPerPixel;
|
||||||
int dstBpp = dst.Info.BytesPerPixel;
|
int dstBpp = dst.Info.BytesPerPixel;
|
||||||
|
@ -1034,9 +1024,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
shaderParams[0] = BitOperations.Log2((uint)ratio);
|
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(
|
TextureView.InsertImageBarrier(
|
||||||
gd.Api,
|
gd.Api,
|
||||||
|
@ -1064,7 +1054,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
var srcFormat = GetFormat(componentSize, srcBpp / componentSize);
|
var srcFormat = GetFormat(componentSize, srcBpp / componentSize);
|
||||||
var dstFormat = GetFormat(componentSize, dstBpp / 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++)
|
for (int l = 0; l < levels; l++)
|
||||||
{
|
{
|
||||||
|
@ -1093,8 +1083,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gd.BufferManager.Delete(bufferHandle);
|
|
||||||
|
|
||||||
_pipeline.Finish(gd, cbs);
|
_pipeline.Finish(gd, cbs);
|
||||||
|
|
||||||
TextureView.InsertImageBarrier(
|
TextureView.InsertImageBarrier(
|
||||||
|
@ -1128,9 +1116,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
(shaderParams[0], shaderParams[1]) = GetSampleCountXYLog2(samples);
|
(shaderParams[0], shaderParams[1]) = GetSampleCountXYLog2(samples);
|
||||||
(shaderParams[2], shaderParams[3]) = GetSampleCountXYLog2((int)TextureStorage.ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)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(
|
TextureView.InsertImageBarrier(
|
||||||
gd.Api,
|
gd.Api,
|
||||||
|
@ -1147,7 +1135,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
1);
|
1);
|
||||||
|
|
||||||
_pipeline.SetCommandBuffer(cbs);
|
_pipeline.SetCommandBuffer(cbs);
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) });
|
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, buffer.Range) });
|
||||||
|
|
||||||
if (isDepthOrStencil)
|
if (isDepthOrStencil)
|
||||||
{
|
{
|
||||||
|
@ -1226,8 +1214,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gd.BufferManager.Delete(bufferHandle);
|
|
||||||
|
|
||||||
_pipeline.Finish(gd, cbs);
|
_pipeline.Finish(gd, cbs);
|
||||||
|
|
||||||
TextureView.InsertImageBarrier(
|
TextureView.InsertImageBarrier(
|
||||||
|
@ -1261,9 +1247,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
(shaderParams[0], shaderParams[1]) = GetSampleCountXYLog2(samples);
|
(shaderParams[0], shaderParams[1]) = GetSampleCountXYLog2(samples);
|
||||||
(shaderParams[2], shaderParams[3]) = GetSampleCountXYLog2((int)TextureStorage.ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)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(
|
TextureView.InsertImageBarrier(
|
||||||
gd.Api,
|
gd.Api,
|
||||||
|
@ -1299,7 +1285,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_pipeline.SetViewports(viewports);
|
_pipeline.SetViewports(viewports);
|
||||||
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
_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)
|
if (isDepthOrStencil)
|
||||||
{
|
{
|
||||||
|
@ -1364,8 +1350,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gd.BufferManager.Delete(bufferHandle);
|
|
||||||
|
|
||||||
_pipeline.Finish(gd, cbs);
|
_pipeline.Finish(gd, cbs);
|
||||||
|
|
||||||
TextureView.InsertImageBarrier(
|
TextureView.InsertImageBarrier(
|
||||||
|
@ -1616,10 +1600,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
pattern.OffsetIndex.CopyTo(shaderParams[..pattern.OffsetIndex.Length]);
|
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();
|
var patternBufferAuto = patternBuffer.GetBuffer();
|
||||||
|
|
||||||
gd.BufferManager.SetData<int>(patternBufferHandle, 0, shaderParams);
|
patternBuffer.SetDataUnchecked<int>(patternScoped.Offset, shaderParams);
|
||||||
|
|
||||||
_pipeline.SetCommandBuffer(cbs);
|
_pipeline.SetCommandBuffer(cbs);
|
||||||
|
|
||||||
|
@ -1635,7 +1620,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
indirectDataSize);
|
indirectDataSize);
|
||||||
|
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, drawCountBufferAligned) });
|
_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.SetProgram(_programConvertIndirectData);
|
||||||
_pipeline.DispatchCompute(1, 1, 1);
|
_pipeline.DispatchCompute(1, 1, 1);
|
||||||
|
@ -1643,12 +1629,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
BufferHolder.InsertBufferBarrier(
|
BufferHolder.InsertBufferBarrier(
|
||||||
gd,
|
gd,
|
||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
patternBufferAuto.Get(cbs, ParamsIndirectDispatchOffset, ParamsIndirectDispatchSize).Value,
|
patternBufferAuto.Get(cbs, patternScoped.Offset + ParamsIndirectDispatchOffset, ParamsIndirectDispatchSize).Value,
|
||||||
AccessFlags.ShaderWriteBit,
|
AccessFlags.ShaderWriteBit,
|
||||||
AccessFlags.IndirectCommandReadBit,
|
AccessFlags.IndirectCommandReadBit,
|
||||||
PipelineStageFlags.ComputeShaderBit,
|
PipelineStageFlags.ComputeShaderBit,
|
||||||
PipelineStageFlags.DrawIndirectBit,
|
PipelineStageFlags.DrawIndirectBit,
|
||||||
ParamsIndirectDispatchOffset,
|
patternScoped.Offset + ParamsIndirectDispatchOffset,
|
||||||
ParamsIndirectDispatchSize);
|
ParamsIndirectDispatchSize);
|
||||||
|
|
||||||
BufferHolder.InsertBufferBarrier(
|
BufferHolder.InsertBufferBarrier(
|
||||||
|
@ -1662,11 +1648,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
0,
|
0,
|
||||||
convertedCount * outputIndexSize);
|
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.SetStorageBuffers(1, new[] { srcIndexBuffer.GetBuffer(), dstIndexBuffer.GetBuffer() });
|
||||||
|
|
||||||
_pipeline.SetProgram(_programConvertIndexBuffer);
|
_pipeline.SetProgram(_programConvertIndexBuffer);
|
||||||
_pipeline.DispatchComputeIndirect(patternBufferAuto, ParamsIndirectDispatchOffset);
|
_pipeline.DispatchComputeIndirect(patternBufferAuto, patternScoped.Offset + ParamsIndirectDispatchOffset);
|
||||||
|
|
||||||
BufferHolder.InsertBufferBarrier(
|
BufferHolder.InsertBufferBarrier(
|
||||||
gd,
|
gd,
|
||||||
|
@ -1679,8 +1665,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
0,
|
0,
|
||||||
convertedCount * outputIndexSize);
|
convertedCount * outputIndexSize);
|
||||||
|
|
||||||
gd.BufferManager.Delete(patternBufferHandle);
|
|
||||||
|
|
||||||
_pipeline.Finish(gd, cbs);
|
_pipeline.Finish(gd, cbs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1726,13 +1710,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
shaderParams[0] = pixelCount;
|
shaderParams[0] = pixelCount;
|
||||||
shaderParams[1] = dstOffset;
|
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.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];
|
Span<Auto<DisposableBuffer>> sbRanges = new Auto<DisposableBuffer>[2];
|
||||||
|
|
||||||
|
@ -1744,8 +1728,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_pipeline.SetProgram(_programConvertD32S8ToD24S8);
|
_pipeline.SetProgram(_programConvertD32S8ToD24S8);
|
||||||
_pipeline.DispatchCompute(1 + inSize / ConvertElementsPerWorkgroup, 1, 1);
|
_pipeline.DispatchCompute(1 + inSize / ConvertElementsPerWorkgroup, 1, 1);
|
||||||
|
|
||||||
gd.BufferManager.Delete(bufferHandle);
|
|
||||||
|
|
||||||
_pipeline.Finish(gd, cbs);
|
_pipeline.Finish(gd, cbs);
|
||||||
|
|
||||||
BufferHolder.InsertBufferBarrier(
|
BufferHolder.InsertBufferBarrier(
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Graphics.GAL;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
@ -29,6 +30,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
private readonly VulkanRenderer _gd;
|
private readonly VulkanRenderer _gd;
|
||||||
private readonly BufferHolder _buffer;
|
private readonly BufferHolder _buffer;
|
||||||
|
private readonly int _resourceAlignment;
|
||||||
|
|
||||||
|
public readonly BufferHandle Handle;
|
||||||
|
|
||||||
private readonly struct PendingCopy
|
private readonly struct PendingCopy
|
||||||
{
|
{
|
||||||
|
@ -48,9 +52,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
public StagingBuffer(VulkanRenderer gd, BufferManager bufferManager)
|
public StagingBuffer(VulkanRenderer gd, BufferManager bufferManager)
|
||||||
{
|
{
|
||||||
_gd = gd;
|
_gd = gd;
|
||||||
_buffer = bufferManager.Create(gd, BufferSize);
|
Handle = bufferManager.CreateWithHandle(gd, BufferSize, out _buffer);
|
||||||
_pendingCopies = new Queue<PendingCopy>();
|
_pendingCopies = new Queue<PendingCopy>();
|
||||||
_freeSize = BufferSize;
|
_freeSize = BufferSize;
|
||||||
|
_resourceAlignment = (int)gd.Capabilities.MinResourceAlignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PushData(CommandBufferPool cbp, CommandBufferScoped? cbs, Action endRenderPass, BufferHolder dst, int dstOffset, ReadOnlySpan<byte> data)
|
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.
|
/// Reserve a range on the staging buffer for the current command buffer and upload data to it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cbs">Command buffer to reserve the data on</param>
|
/// <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>
|
/// <param name="alignment">The required alignment for the buffer offset</param>
|
||||||
/// <returns>The reserved range of the staging buffer</returns>
|
/// <returns>The reserved range of the staging buffer</returns>
|
||||||
public unsafe StagingBufferReserved? TryReserveData(CommandBufferScoped cbs, int size, int alignment)
|
public unsafe StagingBufferReserved? TryReserveData(CommandBufferScoped cbs, int size, int alignment)
|
||||||
|
@ -223,6 +228,18 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
return ReserveDataImpl(cbs, size, alignment);
|
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)
|
private bool WaitFreeCompleted(CommandBufferPool cbp)
|
||||||
{
|
{
|
||||||
if (_pendingCopies.TryPeek(out var pc))
|
if (_pendingCopies.TryPeek(out var pc))
|
||||||
|
@ -263,7 +280,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
if (disposing)
|
if (disposing)
|
||||||
{
|
{
|
||||||
_buffer.Dispose();
|
_gd.BufferManager.Delete(Handle);
|
||||||
|
|
||||||
while (_pendingCopies.TryDequeue(out var pc))
|
while (_pendingCopies.TryDequeue(out var pc))
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue