aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2023-12-04 16:30:19 -0300
committerGitHub <noreply@github.com>2023-12-04 20:30:19 +0100
commit1df6c07f78c4c3b8c7fc679d7466f79a10c2d496 (patch)
treeb80d247e199503274054259cb2707f44cc072993 /src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
parent0531c16326c8215bff1c0a98f3ed217f01065446 (diff)
Implement support for multi-range buffers using Vulkan sparse mappings (#5427)1.1.1098
* Pass MultiRange to BufferManager * Implement support for multi-range buffers using Vulkan sparse mappings * Use multi-range for remaining buffers, delete old methods * Assume that more buffers are contiguous * Dispose multi-range buffers after they are removed from the list * Properly init BufferBounds for constant and storage buffers * Do not try reading zero bytes data from an unmapped address on the shader cache + PR feedback * Fix misaligned sparse buffer offsets * Null check can be simplified * PR feedback
Diffstat (limited to 'src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs')
-rw-r--r--src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs136
1 files changed, 76 insertions, 60 deletions
diff --git a/src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs b/src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
index 01f59477..c65602b5 100644
--- a/src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
+++ b/src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
@@ -3,6 +3,7 @@ using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Graphics.Gpu.Shader;
using Ryujinx.Graphics.Shader;
+using Ryujinx.Memory.Range;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
@@ -62,18 +63,19 @@ namespace Ryujinx.Graphics.Gpu.Memory
Bindings = new BufferDescriptor[count];
Buffers = new BufferBounds[count];
Unaligned = new bool[count];
+
+ Buffers.AsSpan().Fill(new BufferBounds(new MultiRange(MemoryManager.PteUnmapped, 0UL)));
}
/// <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>
+ /// <param name="range">Physical memory regions where the buffer is mapped</param>
/// <param name="flags">Buffer usage flags</param>
- public void SetBounds(int index, ulong address, ulong size, BufferUsageFlags flags = BufferUsageFlags.None)
+ public void SetBounds(int index, MultiRange range, BufferUsageFlags flags = BufferUsageFlags.None)
{
- Buffers[index] = new BufferBounds(address, size, flags);
+ Buffers[index] = new BufferBounds(range, flags);
}
/// <summary>
@@ -120,6 +122,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
_context = context;
_channel = channel;
+ _indexBuffer.Range = new MultiRange(MemoryManager.PteUnmapped, 0UL);
_vertexBuffers = new VertexBuffer[Constants.TotalVertexBuffers];
_transformFeedbackBuffers = new BufferBounds[Constants.TotalTransformFeedbackBuffers];
@@ -150,10 +153,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="type">Type of each index buffer element</param>
public void SetIndexBuffer(ulong gpuVa, ulong size, IndexType type)
{
- ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
+ MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
- _indexBuffer.Address = address;
- _indexBuffer.Size = size;
+ _indexBuffer.Range = range;
_indexBuffer.Type = type;
_indexBufferDirty = true;
@@ -181,16 +183,15 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="divisor">Vertex divisor of the buffer, for instanced draws</param>
public void SetVertexBuffer(int index, ulong gpuVa, ulong size, int stride, int divisor)
{
- ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
+ MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
- _vertexBuffers[index].Address = address;
- _vertexBuffers[index].Size = size;
+ _vertexBuffers[index].Range = range;
_vertexBuffers[index].Stride = stride;
_vertexBuffers[index].Divisor = divisor;
_vertexBuffersDirty = true;
- if (address != 0)
+ if (!range.IsUnmapped)
{
_vertexBuffersEnableMask |= 1u << index;
}
@@ -209,9 +210,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="size">Size in bytes of the transform feedback buffer</param>
public void SetTransformFeedbackBuffer(int index, ulong gpuVa, ulong size)
{
- ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
+ MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateMultiBuffers(_channel.MemoryManager, gpuVa, size);
- _transformFeedbackBuffers[index] = new BufferBounds(address, size);
+ _transformFeedbackBuffers[index] = new BufferBounds(range);
_transformFeedbackBuffersDirty = true;
}
@@ -256,9 +257,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
gpuVa = BitUtils.AlignDown<ulong>(gpuVa, (ulong)_context.Capabilities.StorageBufferOffsetAlignment);
- ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
+ MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateMultiBuffers(_channel.MemoryManager, gpuVa, size);
- _cpStorageBuffers.SetBounds(index, address, size, flags);
+ _cpStorageBuffers.SetBounds(index, range, flags);
}
/// <summary>
@@ -280,15 +281,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
gpuVa = BitUtils.AlignDown<ulong>(gpuVa, (ulong)_context.Capabilities.StorageBufferOffsetAlignment);
- ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
+ MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateMultiBuffers(_channel.MemoryManager, gpuVa, size);
- if (buffers.Buffers[index].Address != address ||
- buffers.Buffers[index].Size != size)
+ if (!buffers.Buffers[index].Range.Equals(range))
{
_gpStorageBuffersDirty = true;
}
- buffers.SetBounds(index, address, size, flags);
+ buffers.SetBounds(index, range, flags);
}
/// <summary>
@@ -300,9 +300,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="size">Size in bytes of the storage buffer</param>
public void SetComputeUniformBuffer(int index, ulong gpuVa, ulong size)
{
- ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
+ MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
- _cpUniformBuffers.SetBounds(index, address, size);
+ _cpUniformBuffers.SetBounds(index, range);
}
/// <summary>
@@ -315,9 +315,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="size">Size in bytes of the storage buffer</param>
public void SetGraphicsUniformBuffer(int stage, int index, ulong gpuVa, ulong size)
{
- ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
+ MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
- _gpUniformBuffers[stage].SetBounds(index, address, size);
+ _gpUniformBuffers[stage].SetBounds(index, range);
_gpUniformBuffersDirty = true;
}
@@ -379,7 +379,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
for (int i = 0; i < _cpUniformBuffers.Buffers.Length; i++)
{
- if (_cpUniformBuffers.Buffers[i].Address != 0)
+ if (!_cpUniformBuffers.Buffers[i].IsUnmapped)
{
mask |= 1u << i;
}
@@ -399,7 +399,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
for (int i = 0; i < _gpUniformBuffers[stage].Buffers.Length; i++)
{
- if (_gpUniformBuffers[stage].Buffers[i].Address != 0)
+ if (!_gpUniformBuffers[stage].Buffers[i].IsUnmapped)
{
mask |= 1u << i;
}
@@ -415,7 +415,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <returns>The uniform buffer address, or an undefined value if the buffer is not currently bound</returns>
public ulong GetComputeUniformBufferAddress(int index)
{
- return _cpUniformBuffers.Buffers[index].Address;
+ return _cpUniformBuffers.Buffers[index].Range.GetSubRange(0).Address;
}
/// <summary>
@@ -426,7 +426,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <returns>The uniform buffer address, or an undefined value if the buffer is not currently bound</returns>
public ulong GetGraphicsUniformBufferAddress(int stage, int index)
{
- return _gpUniformBuffers[stage].Buffers[index].Address;
+ return _gpUniformBuffers[stage].Buffers[index].Range.GetSubRange(0).Address;
}
/// <summary>
@@ -477,7 +477,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
foreach (var binding in _bufferTextures)
{
var isStore = binding.BindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore);
- var range = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(binding.Address, binding.Size, isStore);
+ var range = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(binding.Range, isStore);
binding.Texture.SetStorage(range);
// The texture must be rebound to use the new storage if it was updated.
@@ -511,16 +511,16 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
_indexBufferDirty = false;
- if (_indexBuffer.Address != 0)
+ if (!_indexBuffer.Range.IsUnmapped)
{
- BufferRange buffer = bufferCache.GetBufferRange(_indexBuffer.Address, _indexBuffer.Size);
+ BufferRange buffer = bufferCache.GetBufferRange(_indexBuffer.Range);
_context.Renderer.Pipeline.SetIndexBuffer(buffer, _indexBuffer.Type);
}
}
- else if (_indexBuffer.Address != 0)
+ else if (!_indexBuffer.Range.IsUnmapped)
{
- bufferCache.SynchronizeBufferRange(_indexBuffer.Address, _indexBuffer.Size);
+ bufferCache.SynchronizeBufferRange(_indexBuffer.Range);
}
}
else if (_rebind)
@@ -540,12 +540,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
VertexBuffer vb = _vertexBuffers[index];
- if (vb.Address == 0)
+ if (vb.Range.IsUnmapped)
{
continue;
}
- BufferRange buffer = bufferCache.GetBufferRange(vb.Address, vb.Size);
+ BufferRange buffer = bufferCache.GetBufferRange(vb.Range);
vertexBuffers[index] = new VertexBufferDescriptor(buffer, vb.Stride, vb.Divisor);
}
@@ -558,12 +558,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
VertexBuffer vb = _vertexBuffers[index];
- if (vb.Address == 0)
+ if (vb.Range.IsUnmapped)
{
continue;
}
- bufferCache.SynchronizeBufferRange(vb.Address, vb.Size);
+ bufferCache.SynchronizeBufferRange(vb.Range);
}
}
@@ -579,13 +579,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
BufferBounds tfb = _transformFeedbackBuffers[index];
- if (tfb.Address == 0)
+ if (tfb.IsUnmapped)
{
tfbs[index] = BufferRange.Empty;
continue;
}
- tfbs[index] = bufferCache.GetBufferRange(tfb.Address, tfb.Size, write: true);
+ tfbs[index] = bufferCache.GetBufferRange(tfb.Range, write: true);
}
_context.Renderer.Pipeline.SetTransformFeedbackBuffers(tfbs);
@@ -600,21 +600,39 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
BufferBounds tfb = _transformFeedbackBuffers[index];
- if (tfb.Address == 0)
+ if (tfb.IsUnmapped)
{
buffers[index] = new BufferAssignment(index, BufferRange.Empty);
}
else
{
- ulong endAddress = tfb.Address + tfb.Size;
- ulong address = BitUtils.AlignDown(tfb.Address, (ulong)alignment);
- ulong size = endAddress - address;
+ MultiRange range = tfb.Range;
+ ulong address0 = range.GetSubRange(0).Address;
+ ulong address = BitUtils.AlignDown(address0, (ulong)alignment);
+
+ if (range.Count == 1)
+ {
+ range = new MultiRange(address, range.GetSubRange(0).Size + (address0 - address));
+ }
+ else
+ {
+ MemoryRange[] subRanges = new MemoryRange[range.Count];
+
+ subRanges[0] = new MemoryRange(address, range.GetSubRange(0).Size + (address0 - address));
+
+ for (int i = 1; i < range.Count; i++)
+ {
+ subRanges[i] = range.GetSubRange(i);
+ }
+
+ range = new MultiRange(subRanges);
+ }
- int tfeOffset = ((int)tfb.Address & (alignment - 1)) / 4;
+ int tfeOffset = ((int)address0 & (alignment - 1)) / 4;
_context.SupportBufferUpdater.SetTfeOffset(index, tfeOffset);
- buffers[index] = new BufferAssignment(index, bufferCache.GetBufferRange(address, size, write: true));
+ buffers[index] = new BufferAssignment(index, bufferCache.GetBufferRange(range, write: true));
}
}
@@ -627,12 +645,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
BufferBounds tfb = _transformFeedbackBuffers[index];
- if (tfb.Address == 0)
+ if (tfb.IsUnmapped)
{
continue;
}
- bufferCache.SynchronizeBufferRange(tfb.Address, tfb.Size);
+ bufferCache.SynchronizeBufferRange(tfb.Range);
}
}
@@ -688,12 +706,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
BufferBounds bounds = buffers.Buffers[bindingInfo.Slot];
- if (bounds.Address != 0)
+ if (!bounds.IsUnmapped)
{
var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write);
var range = isStorage
- ? bufferCache.GetBufferRangeAligned(bounds.Address, bounds.Size, isWrite)
- : bufferCache.GetBufferRange(bounds.Address, bounds.Size);
+ ? bufferCache.GetBufferRangeAligned(bounds.Range, isWrite)
+ : bufferCache.GetBufferRange(bounds.Range);
ranges[rangesCount++] = new BufferAssignment(bindingInfo.Binding, range);
}
@@ -725,12 +743,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
BufferBounds bounds = buffers.Buffers[bindingInfo.Slot];
- if (bounds.Address != 0)
+ if (!bounds.IsUnmapped)
{
var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write);
var range = isStorage
- ? bufferCache.GetBufferRangeAligned(bounds.Address, bounds.Size, isWrite)
- : bufferCache.GetBufferRange(bounds.Address, bounds.Size);
+ ? bufferCache.GetBufferRangeAligned(bounds.Range, isWrite)
+ : bufferCache.GetBufferRange(bounds.Range);
ranges[rangesCount++] = new BufferAssignment(bindingInfo.Binding, range);
}
@@ -778,12 +796,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
BufferBounds bounds = buffers.Buffers[binding.Slot];
- if (bounds.Address == 0)
+ if (bounds.IsUnmapped)
{
continue;
}
- _channel.MemoryManager.Physical.BufferCache.SynchronizeBufferRange(bounds.Address, bounds.Size);
+ _channel.MemoryManager.Physical.BufferCache.SynchronizeBufferRange(bounds.Range);
}
}
}
@@ -793,23 +811,21 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary>
/// <param name="stage">Shader stage accessing the texture</param>
/// <param name="texture">Buffer texture</param>
- /// <param name="address">Address of the buffer in memory</param>
- /// <param name="size">Size of the buffer in bytes</param>
+ /// <param name="range">Physical ranges of memory where the buffer texture data is located</param>
/// <param name="bindingInfo">Binding info for the buffer texture</param>
/// <param name="format">Format of the buffer texture</param>
/// <param name="isImage">Whether the binding is for an image or a sampler</param>
public void SetBufferTextureStorage(
ShaderStage stage,
ITexture texture,
- ulong address,
- ulong size,
+ MultiRange range,
TextureBindingInfo bindingInfo,
Format format,
bool isImage)
{
- _channel.MemoryManager.Physical.BufferCache.CreateBuffer(address, size);
+ _channel.MemoryManager.Physical.BufferCache.CreateBuffer(range);
- _bufferTextures.Add(new BufferTextureBinding(stage, texture, address, size, bindingInfo, format, isImage));
+ _bufferTextures.Add(new BufferTextureBinding(stage, texture, range, bindingInfo, format, isImage));
}
/// <summary>