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
This commit is contained in:
parent
b5b7e23fc4
commit
0f6ec446ea
13 changed files with 269 additions and 226 deletions
|
@ -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>
|
||||
|
@ -302,15 +297,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
_gpStorageBuffersDirty = true;
|
||||
}
|
||||
|
||||
/// <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>
|
||||
|
@ -318,7 +304,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
public void SetComputeUniformBufferBindings(ReadOnlyCollection<BufferDescriptor> descriptors)
|
||||
{
|
||||
_cpUniformBuffers.SetBindings(descriptors);
|
||||
_cpUniformBufferBindings = descriptors.Count != 0 ? descriptors.Max(x => x.Binding) + 1 : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -333,15 +318,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
_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>
|
||||
/// Gets a bit mask indicating which compute uniform buffers are currently bound.
|
||||
/// </summary>
|
||||
|
@ -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;
|
||||
var bufferCache = _channel.MemoryManager.Physical.BufferCache;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
_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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue