diff options
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Memory/BufferManager.cs')
-rw-r--r-- | Ryujinx.Graphics.Gpu/Memory/BufferManager.cs | 193 |
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)); } } |