From 0f6ec446ea3be41b1c22aa5c3870bd7a6c595d1f Mon Sep 17 00:00:00 2001 From: gdkchan Date: Wed, 11 Aug 2021 16:33:43 -0300 Subject: Replace BGRA and scale uniforms with a uniform block (#2496) * Replace BGRA and scale uniforms with a uniform block * Setting the data again on program change is no longer needed * Optimize and resolve some warnings * Avoid redundant support buffer updates * Some optimizations to BindBuffers (now inlined) * Unify render scale arrays --- Ryujinx.Graphics.Gpu/Memory/BufferManager.cs | 193 +++++++++++++++------------ 1 file changed, 107 insertions(+), 86 deletions(-) (limited to 'Ryujinx.Graphics.Gpu/Memory') 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 /// 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 _bufferTextures; + private readonly BufferRange[] _ranges; /// /// 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(); + + _ranges = new BufferRange[Constants.TotalGpUniformBuffers * Constants.ShaderStages]; } @@ -288,7 +284,6 @@ namespace Ryujinx.Graphics.Gpu.Memory public void SetComputeStorageBufferBindings(ReadOnlyCollection descriptors) { _cpStorageBuffers.SetBindings(descriptors); - _cpStorageBufferBindings = descriptors.Count != 0 ? descriptors.Max(x => x.Binding) + 1 : 0; } /// @@ -302,15 +297,6 @@ namespace Ryujinx.Graphics.Gpu.Memory _gpStorageBuffersDirty = true; } - /// - /// Sets the total number of storage buffer bindings used. - /// - /// Number of storage buffer bindings used - public void SetGraphicsStorageBufferBindingsCount(int count) - { - _gpStorageBufferBindings = count; - } - /// /// Sets the binding points for the uniform buffers bound on the compute pipeline. /// @@ -318,7 +304,6 @@ namespace Ryujinx.Graphics.Gpu.Memory public void SetComputeUniformBufferBindings(ReadOnlyCollection descriptors) { _cpUniformBuffers.SetBindings(descriptors); - _cpUniformBufferBindings = descriptors.Count != 0 ? descriptors.Max(x => x.Binding) + 1 : 0; } /// @@ -333,15 +318,6 @@ namespace Ryujinx.Graphics.Gpu.Memory _gpUniformBuffersDirty = true; } - /// - /// Sets the total number of uniform buffer bindings used. - /// - /// Number of uniform buffer bindings used - public void SetGraphicsUniformBufferBindingsCount(int count) - { - _gpUniformBufferBindings = count; - } - /// /// Gets a bit mask indicating which compute uniform buffers are currently bound. /// @@ -381,7 +357,6 @@ namespace Ryujinx.Graphics.Gpu.Memory return mask; } - /// /// Gets the address of the compute uniform buffer currently bound at the given index. /// @@ -409,46 +384,10 @@ namespace Ryujinx.Graphics.Gpu.Memory /// public void CommitComputeBindings() { - int sCount = _cpStorageBufferBindings; - - Span 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 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 /// 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 /// /// Bind respective buffer bindings on the host API. /// - /// Bindings to bind - /// True to bind as storage buffer, false to bind as uniform buffers - private void BindBuffers(BuffersPerStage[] bindings, bool isStorage) + /// Buffer cache holding the buffers for the specified ranges + /// Buffer memory ranges to bind + /// True to bind as storage buffer, false to bind as uniform buffer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void BindBuffers(BufferCache bufferCache, BuffersPerStage[] bindings, bool isStorage) { - int count = isStorage ? _gpStorageBufferBindings : _gpUniformBufferBindings; + int rangesFirst = 0; + int rangesCount = 0; - Span ranges = count < StackToHeapThreshold ? stackalloc BufferRange[count] : new BufferRange[count]; + Span 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); + } + } + + /// + /// Bind respective buffer bindings on the host API. + /// + /// Buffer cache holding the buffers for the specified ranges + /// Buffer memory ranges to bind + /// True to bind as storage buffer, false to bind as uniform buffer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void BindBuffers(BufferCache bufferCache, BuffersPerStage buffers, bool isStorage) + { + int rangesFirst = 0; + int rangesCount = 0; + + Span 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); + } + } + + /// + /// Bind respective buffer bindings on the host API. + /// + /// Host buffers to bind, with their offsets and sizes + /// First binding point + /// Number of bindings + /// Indicates if the buffers are storage or uniform buffers + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void SetHostBuffers(ReadOnlySpan 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)); } } -- cgit v1.2.3