aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Memory
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2020-11-08 08:10:00 -0300
committerGitHub <noreply@github.com>2020-11-08 12:10:00 +0100
commit8d168574eb04ae1e7026ac2b058e3b184f068fae (patch)
tree6e0f79447276619af980055419874f5e99595b58 /Ryujinx.Graphics.Gpu/Memory
parent5561a3b95e9c980e3354366570e7896a213b95ae (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.cs22
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/BufferManager.cs272
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>