Compare commits

..

5 Commits

Author SHA1 Message Date
riperiperi
ece36b274d GAL: Send all buffer assignments at once rather than individually (#3881)
* GAL: Send all buffer assignments at once rather than individually

The `(int first, BufferRange[] ranges)` method call has very significant performance implications when the bindings are spread out, which they generally always are in Vulkan. This change makes it so that these methods are only called a maximum of one time per draw.

Significantly improves GPU thread performance in Pokemon Scarlet/Violet.

* Address Feedback

Removed SetUniformBuffers(int first, ReadOnlySpan<BufferRange> buffers)
2022-11-24 07:50:59 +00:00
riperiperi
f3cc2e5703 GPU: Access non-prefetch command buffers directly (#3882)
* GPU: Access non-prefetch command buffers directly

Saves allocating new arrays for them constantly - they can be quite small so it can be very wasteful. About 0.4% of GPU thread in SMO, but was a bit higher in S/V when I checked.

Assumes that non-prefetch command buffers won't be randomly clobbered before they finish executing, though that's probably a safe bet.

* Small change while I'm here

* Address feedback
2022-11-24 01:56:55 +00:00
riperiperi
5a39d3c4a1 GPU: Relax locking on Buffer Cache (#3883)
I did this on ncbuffer2 when we were using it for LDN 3, but I noticed that it can apply to the current buffer manager too, and it's an easy performance win.

The only buffer access that can come from another thread is the overlap search for buffers that have been unmapped. Everything else, including modifications, come from the main GPU thread. That means we only need to lock the range list when it's being modified, as that's the only time where we'll cause a race with the unmapped handler.

This has a significant performance improvements in situations where FIFO is high, like the other two PRs. Joined together they give a nice boost (73.6 master -> 79 -> 83 fps in SMO).
2022-11-24 01:41:16 +00:00
dependabot[bot]
cc51a03af9 nuget: bump Avalonia from 0.10.15 to 0.10.18 (#3817)
Bumps [Avalonia](https://github.com/AvaloniaUI/Avalonia) from 0.10.15 to 0.10.18.
- [Release notes](https://github.com/AvaloniaUI/Avalonia/releases)
- [Commits](https://github.com/AvaloniaUI/Avalonia/compare/0.10.15...0.10.18)

---
updated-dependencies:
- dependency-name: Avalonia
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-24 01:26:53 +00:00
Ac_K
567c64e149 ava: Fix JsonSerializer warnings (#3884)
Since we move to .NET7, JsonSerializer now needs to have explicit options as arguments, which leads to some warnings in Avalonia project. This is fixed by using our `JsonHelper` class.
2022-11-23 17:55:26 +00:00
16 changed files with 132 additions and 110 deletions

View File

@@ -1,5 +1,6 @@
using Ryujinx.Ava.Ui.ViewModels; using Ryujinx.Ava.Ui.ViewModels;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Utilities;
using Ryujinx.Ui.Common.Configuration; using Ryujinx.Ui.Common.Configuration;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
@@ -93,7 +94,7 @@ namespace Ryujinx.Ava.Common.Locale
return; return;
} }
var strings = JsonSerializer.Deserialize<Dictionary<string, string>>(languageJson); var strings = JsonHelper.Deserialize<Dictionary<string, string>>(languageJson);
foreach (var item in strings) foreach (var item in strings)
{ {

View File

@@ -18,7 +18,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.15" /> <PackageReference Include="Avalonia" Version="0.10.18" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.15" /> <PackageReference Include="Avalonia.Desktop" Version="0.10.15" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.15" /> <PackageReference Include="Avalonia.Diagnostics" Version="0.10.15" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.15" /> <PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.15" />

View File

@@ -8,6 +8,7 @@ using Ryujinx.Ava.Ui.Models;
using Ryujinx.Ava.Ui.Windows; using Ryujinx.Ava.Ui.Windows;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Utilities;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
@@ -189,7 +190,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
{ {
amiiboJsonString = File.ReadAllText(_amiiboJsonPath); amiiboJsonString = File.ReadAllText(_amiiboJsonPath);
if (await NeedsUpdate(JsonSerializer.Deserialize<Amiibo.AmiiboJson>(amiiboJsonString).LastUpdated)) if (await NeedsUpdate(JsonHelper.Deserialize<Amiibo.AmiiboJson>(amiiboJsonString).LastUpdated))
{ {
amiiboJsonString = await DownloadAmiiboJson(); amiiboJsonString = await DownloadAmiiboJson();
} }
@@ -206,7 +207,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
} }
} }
_amiiboList = JsonSerializer.Deserialize<Amiibo.AmiiboJson>(amiiboJsonString).Amiibo; _amiiboList = JsonHelper.Deserialize<Amiibo.AmiiboJson>(amiiboJsonString).Amiibo;
_amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList(); _amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
ParseAmiiboData(); ParseAmiiboData();

View File

@@ -0,0 +1,14 @@
namespace Ryujinx.Graphics.GAL
{
public struct BufferAssignment
{
public readonly int Binding;
public readonly BufferRange Range;
public BufferAssignment(int binding, BufferRange range)
{
Binding = binding;
Range = range;
}
}
}

View File

@@ -86,12 +86,12 @@ namespace Ryujinx.Graphics.GAL
void SetStencilTest(StencilTestDescriptor stencilTest); void SetStencilTest(StencilTestDescriptor stencilTest);
void SetStorageBuffers(int first, ReadOnlySpan<BufferRange> buffers); void SetStorageBuffers(ReadOnlySpan<BufferAssignment> buffers);
void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler); void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler);
void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers); void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers);
void SetUniformBuffers(int first, ReadOnlySpan<BufferRange> buffers); void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers);
void SetUserClipDistance(int index, bool enableClip); void SetUserClipDistance(int index, bool enableClip);

View File

@@ -142,6 +142,30 @@ namespace Ryujinx.Graphics.GAL.Multithreading
return ranges; return ranges;
} }
internal Span<BufferAssignment> MapBufferRanges(Span<BufferAssignment> ranges)
{
// Rewrite the buffer ranges to point to the mapped handles.
lock (_bufferMap)
{
for (int i = 0; i < ranges.Length; i++)
{
ref BufferAssignment assignment = ref ranges[i];
BufferRange range = assignment.Range;
BufferHandle result;
if (!_bufferMap.TryGetValue(range.Handle, out result))
{
result = BufferHandle.Null;
}
assignment = new BufferAssignment(ranges[i].Binding, new BufferRange(result, range.Offset, range.Size));
}
}
return ranges;
}
internal Span<VertexBufferDescriptor> MapBufferRanges(Span<VertexBufferDescriptor> ranges) internal Span<VertexBufferDescriptor> MapBufferRanges(Span<VertexBufferDescriptor> ranges)
{ {
// Rewrite the buffer ranges to point to the mapped handles. // Rewrite the buffer ranges to point to the mapped handles.

View File

@@ -6,19 +6,17 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands
struct SetStorageBuffersCommand : IGALCommand struct SetStorageBuffersCommand : IGALCommand
{ {
public CommandType CommandType => CommandType.SetStorageBuffers; public CommandType CommandType => CommandType.SetStorageBuffers;
private int _first; private SpanRef<BufferAssignment> _buffers;
private SpanRef<BufferRange> _buffers;
public void Set(int first, SpanRef<BufferRange> buffers) public void Set(SpanRef<BufferAssignment> buffers)
{ {
_first = first;
_buffers = buffers; _buffers = buffers;
} }
public static void Run(ref SetStorageBuffersCommand command, ThreadedRenderer threaded, IRenderer renderer) public static void Run(ref SetStorageBuffersCommand command, ThreadedRenderer threaded, IRenderer renderer)
{ {
Span<BufferRange> buffers = command._buffers.Get(threaded); Span<BufferAssignment> buffers = command._buffers.Get(threaded);
renderer.Pipeline.SetStorageBuffers(command._first, threaded.Buffers.MapBufferRanges(buffers)); renderer.Pipeline.SetStorageBuffers(threaded.Buffers.MapBufferRanges(buffers));
command._buffers.Dispose(threaded); command._buffers.Dispose(threaded);
} }
} }

View File

@@ -6,19 +6,17 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands
struct SetUniformBuffersCommand : IGALCommand struct SetUniformBuffersCommand : IGALCommand
{ {
public CommandType CommandType => CommandType.SetUniformBuffers; public CommandType CommandType => CommandType.SetUniformBuffers;
private int _first; private SpanRef<BufferAssignment> _buffers;
private SpanRef<BufferRange> _buffers;
public void Set(int first, SpanRef<BufferRange> buffers) public void Set(SpanRef<BufferAssignment> buffers)
{ {
_first = first;
_buffers = buffers; _buffers = buffers;
} }
public static void Run(ref SetUniformBuffersCommand command, ThreadedRenderer threaded, IRenderer renderer) public static void Run(ref SetUniformBuffersCommand command, ThreadedRenderer threaded, IRenderer renderer)
{ {
Span<BufferRange> buffers = command._buffers.Get(threaded); Span<BufferAssignment> buffers = command._buffers.Get(threaded);
renderer.Pipeline.SetUniformBuffers(command._first, threaded.Buffers.MapBufferRanges(buffers)); renderer.Pipeline.SetUniformBuffers(threaded.Buffers.MapBufferRanges(buffers));
command._buffers.Dispose(threaded); command._buffers.Dispose(threaded);
} }
} }

View File

@@ -275,9 +275,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetStorageBuffers(int first, ReadOnlySpan<BufferRange> buffers) public void SetStorageBuffers(ReadOnlySpan<BufferAssignment> buffers)
{ {
_renderer.New<SetStorageBuffersCommand>().Set(first, _renderer.CopySpan(buffers)); _renderer.New<SetStorageBuffersCommand>().Set(_renderer.CopySpan(buffers));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
@@ -293,9 +293,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetUniformBuffers(int first, ReadOnlySpan<BufferRange> buffers) public void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers)
{ {
_renderer.New<SetUniformBuffersCommand>().Set(first, _renderer.CopySpan(buffers)); _renderer.New<SetUniformBuffersCommand>().Set(_renderer.CopySpan(buffers));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }

View File

@@ -51,16 +51,35 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
/// </summary> /// </summary>
public uint EntryCount; public uint EntryCount;
/// <summary>
/// Get the entries for the command buffer from memory.
/// </summary>
/// <param name="memoryManager">The memory manager used to fetch the data</param>
/// <param name="flush">If true, flushes potential GPU written data before reading the command buffer</param>
/// <returns>The fetched data</returns>
private ReadOnlySpan<int> GetWords(MemoryManager memoryManager, bool flush)
{
return MemoryMarshal.Cast<byte, int>(memoryManager.GetSpan(EntryAddress, (int)EntryCount * 4, flush));
}
/// <summary>
/// Prefetch the command buffer.
/// </summary>
/// <param name="memoryManager">The memory manager used to fetch the data</param>
public void Prefetch(MemoryManager memoryManager)
{
Words = GetWords(memoryManager, true).ToArray();
}
/// <summary> /// <summary>
/// Fetch the command buffer. /// Fetch the command buffer.
/// </summary> /// </summary>
/// <param name="memoryManager">The memory manager used to fetch the data</param>
/// <param name="flush">If true, flushes potential GPU written data before reading the command buffer</param> /// <param name="flush">If true, flushes potential GPU written data before reading the command buffer</param>
public void Fetch(MemoryManager memoryManager, bool flush = true) /// <returns>The command buffer words</returns>
public ReadOnlySpan<int> Fetch(MemoryManager memoryManager, bool flush)
{ {
if (Words == null) return Words ?? GetWords(memoryManager, flush);
{
Words = MemoryMarshal.Cast<byte, int>(memoryManager.GetSpan(EntryAddress, (int)EntryCount * 4, flush)).ToArray();
}
} }
} }
@@ -158,7 +177,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
if (beforeBarrier && commandBuffer.Type == CommandBufferType.Prefetch) if (beforeBarrier && commandBuffer.Type == CommandBufferType.Prefetch)
{ {
commandBuffer.Fetch(processor.MemoryManager); commandBuffer.Prefetch(processor.MemoryManager);
} }
if (commandBuffer.Type == CommandBufferType.NoPrefetch) if (commandBuffer.Type == CommandBufferType.NoPrefetch)
@@ -199,7 +218,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
} }
_currentCommandBuffer = entry; _currentCommandBuffer = entry;
_currentCommandBuffer.Fetch(entry.Processor.MemoryManager, flushCommandBuffer); ReadOnlySpan<int> words = entry.Fetch(entry.Processor.MemoryManager, flushCommandBuffer);
// If we are changing the current channel, // If we are changing the current channel,
// we need to force all the host state to be updated. // we need to force all the host state to be updated.
@@ -209,7 +228,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
entry.Processor.ForceAllDirty(); entry.Processor.ForceAllDirty();
} }
entry.Processor.Process(entry.EntryAddress, _currentCommandBuffer.Words); entry.Processor.Process(entry.EntryAddress, words);
} }
_interrupt = false; _interrupt = false;

View File

@@ -22,6 +22,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
private readonly GpuContext _context; private readonly GpuContext _context;
private readonly PhysicalMemory _physicalMemory; private readonly PhysicalMemory _physicalMemory;
/// <remarks>
/// Only modified from the GPU thread. Must lock for add/remove.
/// Must lock for any access from other threads.
/// </remarks>
private readonly RangeList<Buffer> _buffers; private readonly RangeList<Buffer> _buffers;
private Buffer[] _bufferOverlaps; private Buffer[] _bufferOverlaps;
@@ -200,12 +204,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="size">Size in bytes of the buffer</param> /// <param name="size">Size in bytes of the buffer</param>
private void CreateBufferAligned(ulong address, ulong size) private void CreateBufferAligned(ulong address, ulong size)
{ {
int overlapsCount; int overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref _bufferOverlaps);
lock (_buffers)
{
overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref _bufferOverlaps);
}
if (overlapsCount != 0) if (overlapsCount != 0)
{ {
@@ -410,10 +409,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
if (size != 0) if (size != 0)
{ {
lock (_buffers) buffer = _buffers.FindFirstOverlap(address, size);
{
buffer = _buffers.FindFirstOverlap(address, size);
}
buffer.SynchronizeMemory(address, size); buffer.SynchronizeMemory(address, size);
@@ -424,10 +420,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
} }
else else
{ {
lock (_buffers) buffer = _buffers.FindFirstOverlap(address, 1);
{
buffer = _buffers.FindFirstOverlap(address, 1);
}
} }
return buffer; return buffer;
@@ -442,12 +435,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
{ {
if (size != 0) if (size != 0)
{ {
Buffer buffer; Buffer buffer = _buffers.FindFirstOverlap(address, size);
lock (_buffers)
{
buffer = _buffers.FindFirstOverlap(address, size);
}
buffer.SynchronizeMemory(address, size); buffer.SynchronizeMemory(address, size);
} }

View File

@@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
private readonly VertexBuffer[] _vertexBuffers; private readonly VertexBuffer[] _vertexBuffers;
private readonly BufferBounds[] _transformFeedbackBuffers; private readonly BufferBounds[] _transformFeedbackBuffers;
private readonly List<BufferTextureBinding> _bufferTextures; private readonly List<BufferTextureBinding> _bufferTextures;
private readonly BufferRange[] _ranges; private readonly BufferAssignment[] _ranges;
/// <summary> /// <summary>
/// Holds shader stage buffer state and binding information. /// Holds shader stage buffer state and binding information.
@@ -134,7 +134,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
_bufferTextures = new List<BufferTextureBinding>(); _bufferTextures = new List<BufferTextureBinding>();
_ranges = new BufferRange[Constants.TotalGpUniformBuffers * Constants.ShaderStages]; _ranges = new BufferAssignment[Constants.TotalGpUniformBuffers * Constants.ShaderStages];
} }
@@ -618,10 +618,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void BindBuffers(BufferCache bufferCache, BuffersPerStage[] bindings, bool isStorage) private void BindBuffers(BufferCache bufferCache, BuffersPerStage[] bindings, bool isStorage)
{ {
int rangesFirst = 0;
int rangesCount = 0; int rangesCount = 0;
Span<BufferRange> ranges = _ranges; Span<BufferAssignment> ranges = _ranges;
for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++) for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++)
{ {
@@ -640,25 +639,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
? bufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite) ? bufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite)
: bufferCache.GetBufferRange(bounds.Address, bounds.Size); : bufferCache.GetBufferRange(bounds.Address, bounds.Size);
if (rangesCount == 0) ranges[rangesCount++] = new BufferAssignment(bindingInfo.Binding, range);
{
rangesFirst = bindingInfo.Binding;
}
else if (bindingInfo.Binding != rangesFirst + rangesCount)
{
SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage);
rangesFirst = bindingInfo.Binding;
rangesCount = 0;
}
ranges[rangesCount++] = range;
} }
} }
} }
if (rangesCount != 0) if (rangesCount != 0)
{ {
SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage); SetHostBuffers(ranges, rangesCount, isStorage);
} }
} }
@@ -671,10 +659,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void BindBuffers(BufferCache bufferCache, BuffersPerStage buffers, bool isStorage) private void BindBuffers(BufferCache bufferCache, BuffersPerStage buffers, bool isStorage)
{ {
int rangesFirst = 0;
int rangesCount = 0; int rangesCount = 0;
Span<BufferRange> ranges = _ranges; Span<BufferAssignment> ranges = _ranges;
for (int index = 0; index < buffers.Count; index++) for (int index = 0; index < buffers.Count; index++)
{ {
@@ -689,24 +676,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
? bufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite) ? bufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite)
: bufferCache.GetBufferRange(bounds.Address, bounds.Size); : bufferCache.GetBufferRange(bounds.Address, bounds.Size);
if (rangesCount == 0) ranges[rangesCount++] = new BufferAssignment(bindingInfo.Binding, range);
{
rangesFirst = bindingInfo.Binding;
}
else if (bindingInfo.Binding != rangesFirst + rangesCount)
{
SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage);
rangesFirst = bindingInfo.Binding;
rangesCount = 0;
}
ranges[rangesCount++] = range;
} }
} }
if (rangesCount != 0) if (rangesCount != 0)
{ {
SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage); SetHostBuffers(ranges, rangesCount, isStorage);
} }
} }
@@ -718,15 +694,15 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="count">Number of bindings</param> /// <param name="count">Number of bindings</param>
/// <param name="isStorage">Indicates if the buffers are storage or uniform buffers</param> /// <param name="isStorage">Indicates if the buffers are storage or uniform buffers</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void SetHostBuffers(ReadOnlySpan<BufferRange> ranges, int first, int count, bool isStorage) private void SetHostBuffers(ReadOnlySpan<BufferAssignment> ranges, int count, bool isStorage)
{ {
if (isStorage) if (isStorage)
{ {
_context.Renderer.Pipeline.SetStorageBuffers(first, ranges.Slice(0, count)); _context.Renderer.Pipeline.SetStorageBuffers(ranges.Slice(0, count));
} }
else else
{ {
_context.Renderer.Pipeline.SetUniformBuffers(first, ranges.Slice(0, count)); _context.Renderer.Pipeline.SetUniformBuffers(ranges.Slice(0, count));
} }
} }

View File

@@ -1296,9 +1296,9 @@ namespace Ryujinx.Graphics.OpenGL
_stencilFrontMask = stencilTest.FrontMask; _stencilFrontMask = stencilTest.FrontMask;
} }
public void SetStorageBuffers(int first, ReadOnlySpan<BufferRange> buffers) public void SetStorageBuffers(ReadOnlySpan<BufferAssignment> buffers)
{ {
SetBuffers(first, buffers, isStorage: true); SetBuffers(buffers, isStorage: true);
} }
public void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler) public void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler)
@@ -1366,9 +1366,9 @@ namespace Ryujinx.Graphics.OpenGL
} }
} }
public void SetUniformBuffers(int first, ReadOnlySpan<BufferRange> buffers) public void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers)
{ {
SetBuffers(first, buffers, isStorage: false); SetBuffers(buffers, isStorage: false);
} }
public void SetUserClipDistance(int index, bool enableClip) public void SetUserClipDistance(int index, bool enableClip)
@@ -1460,21 +1460,22 @@ namespace Ryujinx.Graphics.OpenGL
GL.MemoryBarrier(MemoryBarrierFlags.TextureFetchBarrierBit); GL.MemoryBarrier(MemoryBarrierFlags.TextureFetchBarrierBit);
} }
private void SetBuffers(int first, ReadOnlySpan<BufferRange> buffers, bool isStorage) private void SetBuffers(ReadOnlySpan<BufferAssignment> buffers, bool isStorage)
{ {
BufferRangeTarget target = isStorage ? BufferRangeTarget.ShaderStorageBuffer : BufferRangeTarget.UniformBuffer; BufferRangeTarget target = isStorage ? BufferRangeTarget.ShaderStorageBuffer : BufferRangeTarget.UniformBuffer;
for (int index = 0; index < buffers.Length; index++) for (int index = 0; index < buffers.Length; index++)
{ {
BufferRange buffer = buffers[index]; BufferAssignment assignment = buffers[index];
BufferRange buffer = assignment.Range;
if (buffer.Handle == BufferHandle.Null) if (buffer.Handle == BufferHandle.Null)
{ {
GL.BindBufferRange(target, first + index, 0, IntPtr.Zero, 0); GL.BindBufferRange(target, assignment.Binding, 0, IntPtr.Zero, 0);
continue; continue;
} }
GL.BindBufferRange(target, first + index, buffer.Handle.ToInt32(), (IntPtr)buffer.Offset, buffer.Size); GL.BindBufferRange(target, assignment.Binding, buffer.Handle.ToInt32(), (IntPtr)buffer.Offset, buffer.Size);
} }
} }

View File

@@ -163,12 +163,13 @@ namespace Ryujinx.Graphics.Vulkan
SignalDirty(DirtyFlags.Image); SignalDirty(DirtyFlags.Image);
} }
public void SetStorageBuffers(CommandBuffer commandBuffer, int first, ReadOnlySpan<BufferRange> buffers) public void SetStorageBuffers(CommandBuffer commandBuffer, ReadOnlySpan<BufferAssignment> buffers)
{ {
for (int i = 0; i < buffers.Length; i++) for (int i = 0; i < buffers.Length; i++)
{ {
var buffer = buffers[i]; var assignment = buffers[i];
int index = first + i; var buffer = assignment.Range;
int index = assignment.Binding;
Auto<DisposableBuffer> vkBuffer = _gd.BufferManager.GetBuffer(commandBuffer, buffer.Handle, false); Auto<DisposableBuffer> vkBuffer = _gd.BufferManager.GetBuffer(commandBuffer, buffer.Handle, false);
ref Auto<DisposableBuffer> currentVkBuffer = ref _storageBufferRefs[index]; ref Auto<DisposableBuffer> currentVkBuffer = ref _storageBufferRefs[index];
@@ -243,12 +244,13 @@ namespace Ryujinx.Graphics.Vulkan
SignalDirty(DirtyFlags.Texture); SignalDirty(DirtyFlags.Texture);
} }
public void SetUniformBuffers(CommandBuffer commandBuffer, int first, ReadOnlySpan<BufferRange> buffers) public void SetUniformBuffers(CommandBuffer commandBuffer, ReadOnlySpan<BufferAssignment> buffers)
{ {
for (int i = 0; i < buffers.Length; i++) for (int i = 0; i < buffers.Length; i++)
{ {
var buffer = buffers[i]; var assignment = buffers[i];
int index = first + i; var buffer = assignment.Range;
int index = assignment.Binding;
Auto<DisposableBuffer> vkBuffer = _gd.BufferManager.GetBuffer(commandBuffer, buffer.Handle, false); Auto<DisposableBuffer> vkBuffer = _gd.BufferManager.GetBuffer(commandBuffer, buffer.Handle, false);
ref Auto<DisposableBuffer> currentVkBuffer = ref _uniformBufferRefs[index]; ref Auto<DisposableBuffer> currentVkBuffer = ref _uniformBufferRefs[index];

View File

@@ -177,7 +177,7 @@ namespace Ryujinx.Graphics.Vulkan
gd.BufferManager.SetData<float>(bufferHandle, 0, region); gd.BufferManager.SetData<float>(bufferHandle, 0, region);
_pipeline.SetUniformBuffers(1, stackalloc[] { new BufferRange(bufferHandle, 0, RegionBufferSize) }); _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, RegionBufferSize)) });
Span<GAL.Viewport> viewports = stackalloc GAL.Viewport[1]; Span<GAL.Viewport> viewports = stackalloc GAL.Viewport[1];
@@ -240,7 +240,7 @@ namespace Ryujinx.Graphics.Vulkan
gd.BufferManager.SetData<float>(bufferHandle, 0, clearColor); gd.BufferManager.SetData<float>(bufferHandle, 0, clearColor);
_pipeline.SetUniformBuffers(1, stackalloc[] { new BufferRange(bufferHandle, 0, ClearColorBufferSize) }); _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, ClearColorBufferSize)) });
Span<GAL.Viewport> viewports = stackalloc GAL.Viewport[1]; Span<GAL.Viewport> viewports = stackalloc GAL.Viewport[1];
@@ -302,7 +302,7 @@ namespace Ryujinx.Graphics.Vulkan
gd.BufferManager.SetData<float>(bufferHandle, 0, region); gd.BufferManager.SetData<float>(bufferHandle, 0, region);
pipeline.SetUniformBuffers(1, stackalloc[] { new BufferRange(bufferHandle, 0, RegionBufferSize) }); pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, RegionBufferSize)) });
Span<GAL.Viewport> viewports = stackalloc GAL.Viewport[1]; Span<GAL.Viewport> viewports = stackalloc GAL.Viewport[1];
@@ -380,7 +380,7 @@ namespace Ryujinx.Graphics.Vulkan
_pipeline.SetCommandBuffer(cbs); _pipeline.SetCommandBuffer(cbs);
_pipeline.SetUniformBuffers(0, stackalloc[] { new BufferRange(bufferHandle, 0, ParamsBufferSize) }); _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) });
Span<Auto<DisposableBuffer>> sbRanges = new Auto<DisposableBuffer>[2]; Span<Auto<DisposableBuffer>> sbRanges = new Auto<DisposableBuffer>[2];
@@ -571,7 +571,7 @@ namespace Ryujinx.Graphics.Vulkan
int conversionType = srcIsMs ? src.Info.BytesPerPixel : -src.Info.BytesPerPixel; int conversionType = srcIsMs ? src.Info.BytesPerPixel : -src.Info.BytesPerPixel;
_pipeline.Specialize(conversionType); _pipeline.Specialize(conversionType);
_pipeline.SetUniformBuffers(0, stackalloc[] { new BufferRange(bufferHandle, 0, ParamsBufferSize) }); _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) });
if (src.Info.Target == Target.Texture2DMultisampleArray || if (src.Info.Target == Target.Texture2DMultisampleArray ||
dst.Info.Target == Target.Texture2DMultisampleArray) dst.Info.Target == Target.Texture2DMultisampleArray)
@@ -776,7 +776,7 @@ namespace Ryujinx.Graphics.Vulkan
srcIndirectBufferOffset, srcIndirectBufferOffset,
indirectDataSize); indirectDataSize);
_pipeline.SetUniformBuffers(0, stackalloc[] { 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(), patternBuffer.GetBuffer() });
_pipeline.SetProgram(_programConvertIndirectData); _pipeline.SetProgram(_programConvertIndirectData);
@@ -804,7 +804,7 @@ namespace Ryujinx.Graphics.Vulkan
0, 0,
convertedCount * outputIndexSize); convertedCount * outputIndexSize);
_pipeline.SetUniformBuffers(0, stackalloc[] { new BufferRange(patternBufferHandle, 0, ParamsBufferSize) }); _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(patternBufferHandle, 0, ParamsBufferSize)) });
_pipeline.SetStorageBuffers(1, new[] { srcIndexBuffer.GetBuffer(), dstIndexBuffer.GetBuffer() }); _pipeline.SetStorageBuffers(1, new[] { srcIndexBuffer.GetBuffer(), dstIndexBuffer.GetBuffer() });
_pipeline.SetProgram(_programConvertIndexBuffer); _pipeline.SetProgram(_programConvertIndexBuffer);

View File

@@ -973,9 +973,9 @@ namespace Ryujinx.Graphics.Vulkan
SignalStateChange(); SignalStateChange();
} }
public void SetStorageBuffers(int first, ReadOnlySpan<BufferRange> buffers) public void SetStorageBuffers(ReadOnlySpan<BufferAssignment> buffers)
{ {
_descriptorSetUpdater.SetStorageBuffers(CommandBuffer, first, buffers); _descriptorSetUpdater.SetStorageBuffers(CommandBuffer, buffers);
} }
public void SetStorageBuffers(int first, ReadOnlySpan<Auto<DisposableBuffer>> buffers) public void SetStorageBuffers(int first, ReadOnlySpan<Auto<DisposableBuffer>> buffers)
@@ -1013,9 +1013,9 @@ namespace Ryujinx.Graphics.Vulkan
} }
} }
public void SetUniformBuffers(int first, ReadOnlySpan<BufferRange> buffers) public void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers)
{ {
_descriptorSetUpdater.SetUniformBuffers(CommandBuffer, first, buffers); _descriptorSetUpdater.SetUniformBuffers(CommandBuffer, buffers);
} }
public void SetUserClipDistance(int index, bool enableClip) public void SetUserClipDistance(int index, bool enableClip)