aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Memory/BufferManager.cs')
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/BufferManager.cs193
1 files changed, 107 insertions, 86 deletions
diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
index eccc2ca3..855a444f 100644
--- a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
@@ -5,7 +5,7 @@ using Ryujinx.Graphics.Shader;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.Linq;
+using System.Runtime.CompilerServices;
namespace Ryujinx.Graphics.Gpu.Memory
{
@@ -14,8 +14,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary>
class BufferManager
{
- private const int StackToHeapThreshold = 16;
-
private readonly GpuContext _context;
private readonly GpuChannel _channel;
@@ -23,6 +21,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
private readonly VertexBuffer[] _vertexBuffers;
private readonly BufferBounds[] _transformFeedbackBuffers;
private readonly List<BufferTextureBinding> _bufferTextures;
+ private readonly BufferRange[] _ranges;
/// <summary>
/// Holds shader stage buffer state and binding information.
@@ -88,11 +87,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
private readonly BuffersPerStage[] _gpStorageBuffers;
private readonly BuffersPerStage[] _gpUniformBuffers;
- private int _cpStorageBufferBindings;
- private int _cpUniformBufferBindings;
- private int _gpStorageBufferBindings;
- private int _gpUniformBufferBindings;
-
private bool _gpStorageBuffersDirty;
private bool _gpUniformBuffersDirty;
@@ -130,6 +124,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
_bufferTextures = new List<BufferTextureBinding>();
+
+ _ranges = new BufferRange[Constants.TotalGpUniformBuffers * Constants.ShaderStages];
}
@@ -288,7 +284,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
public void SetComputeStorageBufferBindings(ReadOnlyCollection<BufferDescriptor> descriptors)
{
_cpStorageBuffers.SetBindings(descriptors);
- _cpStorageBufferBindings = descriptors.Count != 0 ? descriptors.Max(x => x.Binding) + 1 : 0;
}
/// <summary>
@@ -303,22 +298,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
/// <summary>
- /// Sets the total number of storage buffer bindings used.
- /// </summary>
- /// <param name="count">Number of storage buffer bindings used</param>
- public void SetGraphicsStorageBufferBindingsCount(int count)
- {
- _gpStorageBufferBindings = count;
- }
-
- /// <summary>
/// Sets the binding points for the uniform buffers bound on the compute pipeline.
/// </summary>
/// <param name="descriptors">Buffer descriptors with the binding point values</param>
public void SetComputeUniformBufferBindings(ReadOnlyCollection<BufferDescriptor> descriptors)
{
_cpUniformBuffers.SetBindings(descriptors);
- _cpUniformBufferBindings = descriptors.Count != 0 ? descriptors.Max(x => x.Binding) + 1 : 0;
}
/// <summary>
@@ -334,15 +319,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
/// <summary>
- /// Sets the total number of uniform buffer bindings used.
- /// </summary>
- /// <param name="count">Number of uniform buffer bindings used</param>
- public void SetGraphicsUniformBufferBindingsCount(int count)
- {
- _gpUniformBufferBindings = count;
- }
-
- /// <summary>
/// Gets a bit mask indicating which compute uniform buffers are currently bound.
/// </summary>
/// <returns>Mask where each bit set indicates a bound constant buffer</returns>
@@ -381,7 +357,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
return mask;
}
-
/// <summary>
/// Gets the address of the compute uniform buffer currently bound at the given index.
/// </summary>
@@ -409,46 +384,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary>
public void CommitComputeBindings()
{
- int sCount = _cpStorageBufferBindings;
-
- Span<BufferRange> sRanges = sCount < StackToHeapThreshold ? stackalloc BufferRange[sCount] : new BufferRange[sCount];
-
- for (int index = 0; index < _cpStorageBuffers.Count; index++)
- {
- ref var bindingInfo = ref _cpStorageBuffers.Bindings[index];
-
- BufferBounds bounds = _cpStorageBuffers.Buffers[bindingInfo.Slot];
-
- if (bounds.Address != 0)
- {
- // The storage buffer size is not reliable (it might be lower than the actual size),
- // so we bind the entire buffer to allow otherwise out of range accesses to work.
- sRanges[bindingInfo.Binding] = _channel.MemoryManager.Physical.BufferCache.GetBufferRangeTillEnd(
- bounds.Address,
- bounds.Size,
- bounds.Flags.HasFlag(BufferUsageFlags.Write));
- }
- }
-
- _context.Renderer.Pipeline.SetStorageBuffers(sRanges);
-
- int uCount = _cpUniformBufferBindings;
-
- Span<BufferRange> uRanges = uCount < StackToHeapThreshold ? stackalloc BufferRange[uCount] : new BufferRange[uCount];
-
- for (int index = 0; index < _cpUniformBuffers.Count; index++)
- {
- ref var bindingInfo = ref _cpUniformBuffers.Bindings[index];
-
- BufferBounds bounds = _cpUniformBuffers.Buffers[bindingInfo.Slot];
-
- if (bounds.Address != 0)
- {
- uRanges[bindingInfo.Binding] = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(bounds.Address, bounds.Size);
- }
- }
+ var bufferCache = _channel.MemoryManager.Physical.BufferCache;
- _context.Renderer.Pipeline.SetUniformBuffers(uRanges);
+ BindBuffers(bufferCache, _cpStorageBuffers, isStorage: true);
+ BindBuffers(bufferCache, _cpUniformBuffers, isStorage: false);
CommitBufferTextureBindings();
@@ -491,20 +430,22 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary>
public void CommitGraphicsBindings()
{
+ var bufferCache = _channel.MemoryManager.Physical.BufferCache;
+
if (_indexBufferDirty || _rebind)
{
_indexBufferDirty = false;
if (_indexBuffer.Address != 0)
{
- BufferRange buffer = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(_indexBuffer.Address, _indexBuffer.Size);
+ BufferRange buffer = bufferCache.GetBufferRange(_indexBuffer.Address, _indexBuffer.Size);
_context.Renderer.Pipeline.SetIndexBuffer(buffer, _indexBuffer.Type);
}
}
else if (_indexBuffer.Address != 0)
{
- _channel.MemoryManager.Physical.BufferCache.SynchronizeBufferRange(_indexBuffer.Address, _indexBuffer.Size);
+ bufferCache.SynchronizeBufferRange(_indexBuffer.Address, _indexBuffer.Size);
}
uint vbEnableMask = _vertexBuffersEnableMask;
@@ -524,7 +465,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
continue;
}
- BufferRange buffer = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(vb.Address, vb.Size);
+ BufferRange buffer = bufferCache.GetBufferRange(vb.Address, vb.Size);
vertexBuffers[index] = new VertexBufferDescriptor(buffer, vb.Stride, vb.Divisor);
}
@@ -542,7 +483,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
continue;
}
- _channel.MemoryManager.Physical.BufferCache.SynchronizeBufferRange(vb.Address, vb.Size);
+ bufferCache.SynchronizeBufferRange(vb.Address, vb.Size);
}
}
@@ -562,7 +503,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
continue;
}
- tfbs[index] = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(tfb.Address, tfb.Size);
+ tfbs[index] = bufferCache.GetBufferRange(tfb.Address, tfb.Size);
}
_context.Renderer.Pipeline.SetTransformFeedbackBuffers(tfbs);
@@ -578,7 +519,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
continue;
}
- _channel.MemoryManager.Physical.BufferCache.SynchronizeBufferRange(tfb.Address, tfb.Size);
+ bufferCache.SynchronizeBufferRange(tfb.Address, tfb.Size);
}
}
@@ -586,7 +527,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
_gpStorageBuffersDirty = false;
- BindBuffers(_gpStorageBuffers, isStorage: true);
+ BindBuffers(bufferCache, _gpStorageBuffers, isStorage: true);
}
else
{
@@ -597,7 +538,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
_gpUniformBuffersDirty = false;
- BindBuffers(_gpUniformBuffers, isStorage: false);
+ BindBuffers(bufferCache, _gpUniformBuffers, isStorage: false);
}
else
{
@@ -612,13 +553,16 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <summary>
/// Bind respective buffer bindings on the host API.
/// </summary>
- /// <param name="bindings">Bindings to bind</param>
- /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffers</param>
- private void BindBuffers(BuffersPerStage[] bindings, bool isStorage)
+ /// <param name="bufferCache">Buffer cache holding the buffers for the specified ranges</param>
+ /// <param name="bindings">Buffer memory ranges to bind</param>
+ /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void BindBuffers(BufferCache bufferCache, BuffersPerStage[] bindings, bool isStorage)
{
- int count = isStorage ? _gpStorageBufferBindings : _gpUniformBufferBindings;
+ int rangesFirst = 0;
+ int rangesCount = 0;
- Span<BufferRange> ranges = count < StackToHeapThreshold ? stackalloc BufferRange[count] : new BufferRange[count];
+ Span<BufferRange> ranges = _ranges;
for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++)
{
@@ -633,20 +577,97 @@ namespace Ryujinx.Graphics.Gpu.Memory
if (bounds.Address != 0)
{
var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write);
- ranges[bindingInfo.Binding] = isStorage
- ? _channel.MemoryManager.Physical.BufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite)
- : _channel.MemoryManager.Physical.BufferCache.GetBufferRange(bounds.Address, bounds.Size, isWrite);
+ var range = isStorage
+ ? bufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite)
+ : bufferCache.GetBufferRange(bounds.Address, bounds.Size);
+
+ if (rangesCount == 0)
+ {
+ 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)
+ {
+ SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage);
+ }
+ }
+
+ /// <summary>
+ /// Bind respective buffer bindings on the host API.
+ /// </summary>
+ /// <param name="bufferCache">Buffer cache holding the buffers for the specified ranges</param>
+ /// <param name="buffers">Buffer memory ranges to bind</param>
+ /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void BindBuffers(BufferCache bufferCache, BuffersPerStage buffers, bool isStorage)
+ {
+ int rangesFirst = 0;
+ int rangesCount = 0;
+
+ Span<BufferRange> ranges = _ranges;
+
+ for (int index = 0; index < buffers.Count; index++)
+ {
+ ref var bindingInfo = ref buffers.Bindings[index];
+
+ BufferBounds bounds = buffers.Buffers[bindingInfo.Slot];
+
+ if (bounds.Address != 0)
+ {
+ var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write);
+ var range = isStorage
+ ? bufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite)
+ : bufferCache.GetBufferRange(bounds.Address, bounds.Size);
+
+ if (rangesCount == 0)
+ {
+ 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)
+ {
+ SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage);
+ }
+ }
+
+ /// <summary>
+ /// Bind respective buffer bindings on the host API.
+ /// </summary>
+ /// <param name="ranges">Host buffers to bind, with their offsets and sizes</param>
+ /// <param name="first">First binding point</param>
+ /// <param name="count">Number of bindings</param>
+ /// <param name="isStorage">Indicates if the buffers are storage or uniform buffers</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void SetHostBuffers(ReadOnlySpan<BufferRange> ranges, int first, int count, bool isStorage)
+ {
if (isStorage)
{
- _context.Renderer.Pipeline.SetStorageBuffers(ranges);
+ _context.Renderer.Pipeline.SetStorageBuffers(first, ranges.Slice(0, count));
}
else
{
- _context.Renderer.Pipeline.SetUniformBuffers(ranges);
+ _context.Renderer.Pipeline.SetUniformBuffers(first, ranges.Slice(0, count));
}
}