diff options
author | gdkchan <gab.dark.100@gmail.com> | 2023-12-04 16:30:19 -0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-04 20:30:19 +0100 |
commit | 1df6c07f78c4c3b8c7fc679d7466f79a10c2d496 (patch) | |
tree | b80d247e199503274054259cb2707f44cc072993 /src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs | |
parent | 0531c16326c8215bff1c0a98f3ed217f01065446 (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.cs | 136 |
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> |