diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2020-11-08 08:10:00 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-11-08 12:10:00 +0100 |
| commit | 8d168574eb04ae1e7026ac2b058e3b184f068fae (patch) | |
| tree | 6e0f79447276619af980055419874f5e99595b58 /Ryujinx.Graphics.Gpu/Memory | |
| parent | 5561a3b95e9c980e3354366570e7896a213b95ae (diff) | |
Use explicit buffer and texture bindings on shaders (#1666)
* Use explicit buffer and texture bindings on shaders
* More XML docs and other nits
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Memory')
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs | 22 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Memory/BufferManager.cs | 272 |
2 files changed, 174 insertions, 120 deletions
diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs b/Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs index 42500342..060171fb 100644 --- a/Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs +++ b/Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs @@ -5,7 +5,25 @@ namespace Ryujinx.Graphics.Gpu.Memory /// </summary> struct BufferBounds { - public ulong Address; - public ulong Size; + /// <summary> + /// Region virtual address. + /// </summary> + public ulong Address { get; } + + /// <summary> + /// Region size in bytes. + /// </summary> + public ulong Size { get; } + + /// <summary> + /// Creates a new buffer region. + /// </summary> + /// <param name="address">Region address</param> + /// <param name="size">Region size</param> + public BufferBounds(ulong address, ulong size) + { + Address = address; + Size = size; + } } }
\ No newline at end of file diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs index eec545b9..568133ca 100644 --- a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs +++ b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs @@ -4,6 +4,8 @@ using Ryujinx.Graphics.Gpu.State; using Ryujinx.Graphics.Shader; using Ryujinx.Memory.Range; using System; +using System.Collections.ObjectModel; +using System.Linq; namespace Ryujinx.Graphics.Gpu.Memory { @@ -12,6 +14,8 @@ namespace Ryujinx.Graphics.Gpu.Memory /// </summary> class BufferManager { + private const int StackToHeapThreshold = 16; + private const int OverlapsBufferInitialCapacity = 10; private const int OverlapsBufferMaxCapacity = 10000; @@ -28,21 +32,61 @@ namespace Ryujinx.Graphics.Gpu.Memory private VertexBuffer[] _vertexBuffers; private BufferBounds[] _transformFeedbackBuffers; + /// <summary> + /// Holds shader stage buffer state and binding information. + /// </summary> private class BuffersPerStage { - public uint EnableMask { get; set; } + /// <summary> + /// Shader buffer binding information. + /// </summary> + public BufferDescriptor[] Bindings { get; } + /// <summary> + /// Buffer regions. + /// </summary> public BufferBounds[] Buffers { get; } + /// <summary> + /// Total amount of buffers used on the shader. + /// </summary> + public int Count { get; private set; } + + /// <summary> + /// Creates a new instance of the shader stage buffer information. + /// </summary> + /// <param name="count">Maximum amount of buffers that the shader stage can use</param> public BuffersPerStage(int count) { + Bindings = new BufferDescriptor[count]; Buffers = new BufferBounds[count]; } - public void Bind(int index, ulong address, ulong size) + /// <summary> + /// Sets the region of a buffer at a given slot. + /// </summary> + /// <param name="index">Buffer slot</param> + /// <param name="address">Region virtual address</param> + /// <param name="size">Region size in bytes</param> + public void SetBounds(int index, ulong address, ulong size) { - Buffers[index].Address = address; - Buffers[index].Size = size; + Buffers[index] = new BufferBounds(address, size); + } + + /// <summary> + /// Sets shader buffer binding information. + /// </summary> + /// <param name="descriptors">Buffer binding information</param> + public void SetBindings(ReadOnlyCollection<BufferDescriptor> descriptors) + { + if (descriptors == null) + { + Count = 0; + return; + } + + descriptors.CopyTo(Bindings, 0); + Count = descriptors.Count; } } @@ -51,6 +95,11 @@ namespace Ryujinx.Graphics.Gpu.Memory private BuffersPerStage[] _gpStorageBuffers; private BuffersPerStage[] _gpUniformBuffers; + private int _cpStorageBufferBindings; + private int _cpUniformBufferBindings; + private int _gpStorageBufferBindings; + private int _gpUniformBufferBindings; + private bool _gpStorageBuffersDirty; private bool _gpUniformBuffersDirty; @@ -159,9 +208,7 @@ namespace Ryujinx.Graphics.Gpu.Memory { ulong address = TranslateAndCreateBuffer(gpuVa, size); - _transformFeedbackBuffers[index].Address = address; - _transformFeedbackBuffers[index].Size = size; - + _transformFeedbackBuffers[index] = new BufferBounds(address, size); _transformFeedbackBuffersDirty = true; } @@ -180,7 +227,7 @@ namespace Ryujinx.Graphics.Gpu.Memory ulong address = TranslateAndCreateBuffer(gpuVa, size); - _cpStorageBuffers.Bind(index, address, size); + _cpStorageBuffers.SetBounds(index, address, size); } /// <summary> @@ -205,7 +252,7 @@ namespace Ryujinx.Graphics.Gpu.Memory _gpStorageBuffersDirty = true; } - _gpStorageBuffers[stage].Bind(index, address, size); + _gpStorageBuffers[stage].SetBounds(index, address, size); } /// <summary> @@ -219,7 +266,7 @@ namespace Ryujinx.Graphics.Gpu.Memory { ulong address = TranslateAndCreateBuffer(gpuVa, size); - _cpUniformBuffers.Bind(index, address, size); + _cpUniformBuffers.SetBounds(index, address, size); } /// <summary> @@ -234,42 +281,69 @@ namespace Ryujinx.Graphics.Gpu.Memory { ulong address = TranslateAndCreateBuffer(gpuVa, size); - _gpUniformBuffers[stage].Bind(index, address, size); - + _gpUniformBuffers[stage].SetBounds(index, address, size); _gpUniformBuffersDirty = true; } /// <summary> - /// Sets the enabled storage buffers mask on the compute pipeline. - /// Each bit set on the mask indicates that the respective buffer index is enabled. + /// Sets the binding points for the storage buffers bound on the compute pipeline. /// </summary> - /// <param name="mask">Buffer enable mask</param> - public void SetComputeStorageBufferEnableMask(uint mask) + /// <param name="descriptors">Buffer descriptors with the binding point values</param> + public void SetComputeStorageBufferBindings(ReadOnlyCollection<BufferDescriptor> descriptors) { - _cpStorageBuffers.EnableMask = mask; + _cpStorageBuffers.SetBindings(descriptors); + _cpStorageBufferBindings = descriptors.Count != 0 ? descriptors.Max(x => x.Binding) + 1 : 0; } /// <summary> - /// Sets the enabled storage buffers mask on the graphics pipeline. - /// Each bit set on the mask indicates that the respective buffer index is enabled. + /// Sets the binding points for the storage buffers bound on the graphics pipeline. /// </summary> /// <param name="stage">Index of the shader stage</param> - /// <param name="mask">Buffer enable mask</param> - public void SetGraphicsStorageBufferEnableMask(int stage, uint mask) + /// <param name="descriptors">Buffer descriptors with the binding point values</param> + public void SetGraphicsStorageBufferBindings(int stage, ReadOnlyCollection<BufferDescriptor> descriptors) { - _gpStorageBuffers[stage].EnableMask = mask; - + _gpStorageBuffers[stage].SetBindings(descriptors); _gpStorageBuffersDirty = true; } /// <summary> - /// Sets the enabled uniform buffers mask on the compute pipeline. + /// 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> + /// Sets the enabled uniform buffers mask on the graphics pipeline. /// Each bit set on the mask indicates that the respective buffer index is enabled. /// </summary> - /// <param name="mask">Buffer enable mask</param> - public void SetComputeUniformBufferEnableMask(uint mask) + /// <param name="stage">Index of the shader stage</param> + /// <param name="descriptors">Buffer descriptors with the binding point values</param> + public void SetGraphicsUniformBufferBindings(int stage, ReadOnlyCollection<BufferDescriptor> descriptors) { - _cpUniformBuffers.EnableMask = mask; + _gpUniformBuffers[stage].SetBindings(descriptors); + _gpUniformBuffersDirty = true; + } + + /// <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> @@ -292,19 +366,6 @@ namespace Ryujinx.Graphics.Gpu.Memory } /// <summary> - /// Sets the enabled uniform buffers mask on the graphics pipeline. - /// Each bit set on the mask indicates that the respective buffer index is enabled. - /// </summary> - /// <param name="stage">Index of the shader stage</param> - /// <param name="mask">Buffer enable mask</param> - public void SetGraphicsUniformBufferEnableMask(int stage, uint mask) - { - _gpUniformBuffers[stage].EnableMask = mask; - - _gpUniformBuffersDirty = true; - } - - /// <summary> /// Gets a bit mask indicating which graphics uniform buffers are currently bound. /// </summary> /// <param name="stage">Index of the shader stage</param> @@ -476,48 +537,42 @@ namespace Ryujinx.Graphics.Gpu.Memory /// </summary> public void CommitComputeBindings() { - uint enableMask = _cpStorageBuffers.EnableMask; + int sCount = _cpStorageBufferBindings; - for (int index = 0; (enableMask >> index) != 0; index++) + Span<BufferRange> sRanges = sCount < StackToHeapThreshold ? stackalloc BufferRange[sCount] : new BufferRange[sCount]; + + for (int index = 0; index < _cpStorageBuffers.Count; index++) { - if ((enableMask & (1u << index)) == 0) - { - continue; - } + ref var bindingInfo = ref _cpStorageBuffers.Bindings[index]; - BufferBounds bounds = _cpStorageBuffers.Buffers[index]; + BufferBounds bounds = _cpStorageBuffers.Buffers[bindingInfo.Slot]; - if (bounds.Address == 0) + if (bounds.Address != 0) { - continue; + sRanges[bindingInfo.Binding] = GetBufferRange(bounds.Address, bounds.Size); } + } - BufferRange buffer = GetBufferRange(bounds.Address, bounds.Size); + _context.Renderer.Pipeline.SetStorageBuffers(sRanges); - _context.Renderer.Pipeline.SetStorageBuffer(index, ShaderStage.Compute, buffer); - } + int uCount = _cpUniformBufferBindings; - enableMask = _cpUniformBuffers.EnableMask; + Span<BufferRange> uRanges = uCount < StackToHeapThreshold ? stackalloc BufferRange[uCount] : new BufferRange[uCount]; - for (int index = 0; (enableMask >> index) != 0; index++) + for (int index = 0; index < _cpUniformBuffers.Count; index++) { - if ((enableMask & (1u << index)) == 0) - { - continue; - } + ref var bindingInfo = ref _cpUniformBuffers.Bindings[index]; - BufferBounds bounds = _cpUniformBuffers.Buffers[index]; + BufferBounds bounds = _cpUniformBuffers.Buffers[bindingInfo.Slot]; - if (bounds.Address == 0) + if (bounds.Address != 0) { - continue; + uRanges[bindingInfo.Binding] = GetBufferRange(bounds.Address, bounds.Size); } - - BufferRange buffer = GetBufferRange(bounds.Address, bounds.Size); - - _context.Renderer.Pipeline.SetUniformBuffer(index, ShaderStage.Compute, buffer); } + _context.Renderer.Pipeline.SetUniformBuffers(uRanges); + // Force rebind after doing compute work. _rebind = true; } @@ -651,7 +706,35 @@ namespace Ryujinx.Graphics.Gpu.Memory /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffers</param> private void BindBuffers(BuffersPerStage[] bindings, bool isStorage) { - BindOrUpdateBuffers(bindings, bind: true, isStorage); + int count = isStorage ? _gpStorageBufferBindings : _gpUniformBufferBindings; + + Span<BufferRange> ranges = count < StackToHeapThreshold ? stackalloc BufferRange[count] : new BufferRange[count]; + + for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++) + { + ref var buffers = ref bindings[(int)stage - 1]; + + 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) + { + ranges[bindingInfo.Binding] = GetBufferRange(bounds.Address, bounds.Size); + } + } + } + + if (isStorage) + { + _context.Renderer.Pipeline.SetStorageBuffers(ranges); + } + else + { + _context.Renderer.Pipeline.SetUniformBuffers(ranges); + } } /// <summary> @@ -660,74 +743,27 @@ namespace Ryujinx.Graphics.Gpu.Memory /// <param name="bindings">Bindings to update</param> private void UpdateBuffers(BuffersPerStage[] bindings) { - BindOrUpdateBuffers(bindings, bind: false); - } - - /// <summary> - /// This binds buffers into the host API, or updates data for already bound buffers. - /// </summary> - /// <param name="bindings">Bindings to bind or update</param> - /// <param name="bind">True to bind, false to update</param> - /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param> - private void BindOrUpdateBuffers(BuffersPerStage[] bindings, bool bind, bool isStorage = false) - { for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++) { - uint enableMask = bindings[(int)stage - 1].EnableMask; + ref var buffers = ref bindings[(int)stage - 1]; - if (enableMask == 0) + for (int index = 0; index < buffers.Count; index++) { - continue; - } + ref var binding = ref buffers.Bindings[index]; - for (int index = 0; (enableMask >> index) != 0; index++) - { - if ((enableMask & (1u << index)) == 0) - { - continue; - } - - BufferBounds bounds = bindings[(int)stage - 1].Buffers[index]; + BufferBounds bounds = buffers.Buffers[binding.Slot]; if (bounds.Address == 0) { continue; } - if (bind) - { - BindBuffer(index, stage, bounds, isStorage); - } - else - { - SynchronizeBufferRange(bounds.Address, bounds.Size); - } + SynchronizeBufferRange(bounds.Address, bounds.Size); } } } /// <summary> - /// Binds a buffer on the host API. - /// </summary> - /// <param name="index">Index to bind the buffer into</param> - /// <param name="stage">Shader stage to bind the buffer into</param> - /// <param name="bounds">Buffer address and size</param> - /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param> - private void BindBuffer(int index, ShaderStage stage, BufferBounds bounds, bool isStorage) - { - BufferRange buffer = GetBufferRange(bounds.Address, bounds.Size); - - if (isStorage) - { - _context.Renderer.Pipeline.SetStorageBuffer(index, stage, buffer); - } - else - { - _context.Renderer.Pipeline.SetUniformBuffer(index, stage, buffer); - } - } - - /// <summary> /// Sets the buffer storage of a buffer texture. /// </summary> /// <param name="texture">Buffer texture</param> |
