diff options
Diffstat (limited to 'src/Ryujinx.Graphics.Vulkan')
| -rw-r--r-- | src/Ryujinx.Graphics.Vulkan/BufferAllocationType.cs | 1 | ||||
| -rw-r--r-- | src/Ryujinx.Graphics.Vulkan/BufferHolder.cs | 40 | ||||
| -rw-r--r-- | src/Ryujinx.Graphics.Vulkan/BufferManager.cs | 119 | ||||
| -rw-r--r-- | src/Ryujinx.Graphics.Vulkan/Constants.cs | 2 | ||||
| -rw-r--r-- | src/Ryujinx.Graphics.Vulkan/EnumConversion.cs | 10 | ||||
| -rw-r--r-- | src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs | 15 |
6 files changed, 173 insertions, 14 deletions
diff --git a/src/Ryujinx.Graphics.Vulkan/BufferAllocationType.cs b/src/Ryujinx.Graphics.Vulkan/BufferAllocationType.cs index 7987017e..345191f1 100644 --- a/src/Ryujinx.Graphics.Vulkan/BufferAllocationType.cs +++ b/src/Ryujinx.Graphics.Vulkan/BufferAllocationType.cs @@ -8,5 +8,6 @@ namespace Ryujinx.Graphics.Vulkan HostMapped, DeviceLocal, DeviceLocalMapped, + Sparse, } } diff --git a/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs b/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs index b1887eaa..b54ff3ab 100644 --- a/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs +++ b/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs @@ -46,7 +46,7 @@ namespace Ryujinx.Graphics.Vulkan private bool _lastAccessIsWrite; - private readonly BufferAllocationType _baseType; + private BufferAllocationType _baseType; private BufferAllocationType _currentType; private bool _swapQueued; @@ -109,6 +109,22 @@ namespace Ryujinx.Graphics.Vulkan _flushLock = new ReaderWriterLockSlim(); } + public BufferHolder(VulkanRenderer gd, Device device, VkBuffer buffer, int size, Auto<MemoryAllocation>[] storageAllocations) + { + _gd = gd; + _device = device; + _waitable = new MultiFenceHolder(size); + _buffer = new Auto<DisposableBuffer>(new DisposableBuffer(gd.Api, device, buffer), _waitable, storageAllocations); + _bufferHandle = buffer.Handle; + Size = size; + + _baseType = BufferAllocationType.Sparse; + _currentType = BufferAllocationType.Sparse; + DesiredType = BufferAllocationType.Sparse; + + _flushLock = new ReaderWriterLockSlim(); + } + public bool TryBackingSwap(ref CommandBufferScoped? cbs) { if (_swapQueued && DesiredType != _currentType) @@ -122,7 +138,7 @@ namespace Ryujinx.Graphics.Vulkan var currentBuffer = _buffer; IntPtr currentMap = _map; - (VkBuffer buffer, MemoryAllocation allocation, BufferAllocationType resultType) = _gd.BufferManager.CreateBacking(_gd, Size, DesiredType, false, _currentType); + (VkBuffer buffer, MemoryAllocation allocation, BufferAllocationType resultType) = _gd.BufferManager.CreateBacking(_gd, Size, DesiredType, false, false, _currentType); if (buffer.Handle != 0) { @@ -253,6 +269,14 @@ namespace Ryujinx.Graphics.Vulkan } } + public void Pin() + { + if (_baseType == BufferAllocationType.Auto) + { + _baseType = _currentType; + } + } + public unsafe Auto<DisposableBufferView> CreateView(VkFormat format, int offset, int size, Action invalidateView) { var bufferViewCreateInfo = new BufferViewCreateInfo @@ -506,6 +530,16 @@ namespace Ryujinx.Graphics.Vulkan } } + public Auto<MemoryAllocation> GetAllocation() + { + return _allocationAuto; + } + + public (DeviceMemory, ulong) GetDeviceMemoryAndOffset() + { + return (_allocation.Memory, _allocation.Offset); + } + public void SignalWrite(int offset, int size) { ConsiderBackingSwap(); @@ -1072,7 +1106,7 @@ namespace Ryujinx.Graphics.Vulkan } else { - _allocationAuto.Dispose(); + _allocationAuto?.Dispose(); } _flushLock.EnterWriteLock(); diff --git a/src/Ryujinx.Graphics.Vulkan/BufferManager.cs b/src/Ryujinx.Graphics.Vulkan/BufferManager.cs index 20e00338..e9ac9884 100644 --- a/src/Ryujinx.Graphics.Vulkan/BufferManager.cs +++ b/src/Ryujinx.Graphics.Vulkan/BufferManager.cs @@ -96,25 +96,131 @@ namespace Ryujinx.Graphics.Vulkan return Unsafe.As<ulong, BufferHandle>(ref handle64); } + public unsafe BufferHandle CreateSparse(VulkanRenderer gd, ReadOnlySpan<BufferRange> storageBuffers) + { + var usage = DefaultBufferUsageFlags; + + if (gd.Capabilities.SupportsIndirectParameters) + { + usage |= BufferUsageFlags.IndirectBufferBit; + } + + ulong size = 0; + + foreach (BufferRange range in storageBuffers) + { + size += (ulong)range.Size; + } + + var bufferCreateInfo = new BufferCreateInfo() + { + SType = StructureType.BufferCreateInfo, + Size = size, + Usage = usage, + SharingMode = SharingMode.Exclusive, + Flags = BufferCreateFlags.SparseBindingBit | BufferCreateFlags.SparseAliasedBit + }; + + gd.Api.CreateBuffer(_device, in bufferCreateInfo, null, out var buffer).ThrowOnError(); + + var memoryBinds = new SparseMemoryBind[storageBuffers.Length]; + var storageAllocations = new Auto<MemoryAllocation>[storageBuffers.Length]; + int storageAllocationsCount = 0; + + ulong dstOffset = 0; + + for (int index = 0; index < storageBuffers.Length; index++) + { + BufferRange range = storageBuffers[index]; + + if (TryGetBuffer(range.Handle, out var existingHolder)) + { + // Since this buffer now also owns the memory from the referenced buffer, + // we pin it to ensure the memory location will not change. + existingHolder.Pin(); + + (var memory, var offset) = existingHolder.GetDeviceMemoryAndOffset(); + + memoryBinds[index] = new SparseMemoryBind() + { + ResourceOffset = dstOffset, + Size = (ulong)range.Size, + Memory = memory, + MemoryOffset = offset + (ulong)range.Offset, + Flags = SparseMemoryBindFlags.None + }; + + storageAllocations[storageAllocationsCount++] = existingHolder.GetAllocation(); + } + else + { + memoryBinds[index] = new SparseMemoryBind() + { + ResourceOffset = dstOffset, + Size = (ulong)range.Size, + Memory = default, + MemoryOffset = 0UL, + Flags = SparseMemoryBindFlags.None + }; + } + + dstOffset += (ulong)range.Size; + } + + if (storageAllocations.Length != storageAllocationsCount) + { + Array.Resize(ref storageAllocations, storageAllocationsCount); + } + + fixed (SparseMemoryBind* pMemoryBinds = memoryBinds) + { + SparseBufferMemoryBindInfo bufferBind = new SparseBufferMemoryBindInfo() + { + Buffer = buffer, + BindCount = (uint)memoryBinds.Length, + PBinds = pMemoryBinds + }; + + BindSparseInfo bindSparseInfo = new BindSparseInfo() + { + SType = StructureType.BindSparseInfo, + BufferBindCount = 1, + PBufferBinds = &bufferBind + }; + + gd.Api.QueueBindSparse(gd.Queue, 1, bindSparseInfo, default).ThrowOnError(); + } + + var holder = new BufferHolder(gd, _device, buffer, (int)size, storageAllocations); + + BufferCount++; + + ulong handle64 = (uint)_buffers.Add(holder); + + return Unsafe.As<ulong, BufferHandle>(ref handle64); + } + public BufferHandle CreateWithHandle( VulkanRenderer gd, int size, + bool sparseCompatible = false, BufferAllocationType baseType = BufferAllocationType.HostMapped, BufferHandle storageHint = default, bool forceMirrors = false) { - return CreateWithHandle(gd, size, out _, baseType, storageHint, forceMirrors); + return CreateWithHandle(gd, size, out _, sparseCompatible, baseType, storageHint, forceMirrors); } public BufferHandle CreateWithHandle( VulkanRenderer gd, int size, out BufferHolder holder, + bool sparseCompatible = false, BufferAllocationType baseType = BufferAllocationType.HostMapped, BufferHandle storageHint = default, bool forceMirrors = false) { - holder = Create(gd, size, baseType: baseType, storageHint: storageHint); + holder = Create(gd, size, forConditionalRendering: false, sparseCompatible, baseType, storageHint); if (holder == null) { return BufferHandle.Null; @@ -163,6 +269,7 @@ namespace Ryujinx.Graphics.Vulkan int size, BufferAllocationType type, bool forConditionalRendering = false, + bool sparseCompatible = false, BufferAllocationType fallbackType = BufferAllocationType.Auto) { var usage = DefaultBufferUsageFlags; @@ -187,6 +294,11 @@ namespace Ryujinx.Graphics.Vulkan gd.Api.CreateBuffer(_device, in bufferCreateInfo, null, out var buffer).ThrowOnError(); gd.Api.GetBufferMemoryRequirements(_device, buffer, out var requirements); + if (sparseCompatible) + { + requirements.Alignment = Math.Max(requirements.Alignment, Constants.SparseBufferAlignment); + } + MemoryAllocation allocation; do @@ -227,6 +339,7 @@ namespace Ryujinx.Graphics.Vulkan VulkanRenderer gd, int size, bool forConditionalRendering = false, + bool sparseCompatible = false, BufferAllocationType baseType = BufferAllocationType.HostMapped, BufferHandle storageHint = default) { @@ -255,7 +368,7 @@ namespace Ryujinx.Graphics.Vulkan } (VkBuffer buffer, MemoryAllocation allocation, BufferAllocationType resultType) = - CreateBacking(gd, size, type, forConditionalRendering); + CreateBacking(gd, size, type, forConditionalRendering, sparseCompatible); if (buffer.Handle != 0) { diff --git a/src/Ryujinx.Graphics.Vulkan/Constants.cs b/src/Ryujinx.Graphics.Vulkan/Constants.cs index 1bf8c580..cd612211 100644 --- a/src/Ryujinx.Graphics.Vulkan/Constants.cs +++ b/src/Ryujinx.Graphics.Vulkan/Constants.cs @@ -16,5 +16,7 @@ namespace Ryujinx.Graphics.Vulkan public const int MaxStorageBufferBindings = MaxStorageBuffersPerStage * MaxShaderStages; public const int MaxTextureBindings = MaxTexturesPerStage * MaxShaderStages; public const int MaxImageBindings = MaxImagesPerStage * MaxShaderStages; + + public const ulong SparseBufferAlignment = 0x10000; } } diff --git a/src/Ryujinx.Graphics.Vulkan/EnumConversion.cs b/src/Ryujinx.Graphics.Vulkan/EnumConversion.cs index b7787601..e1002705 100644 --- a/src/Ryujinx.Graphics.Vulkan/EnumConversion.cs +++ b/src/Ryujinx.Graphics.Vulkan/EnumConversion.cs @@ -424,12 +424,12 @@ namespace Ryujinx.Graphics.Vulkan public static BufferAllocationType Convert(this BufferAccess access) { - return access switch + if (access.HasFlag(BufferAccess.FlushPersistent) || access.HasFlag(BufferAccess.Stream)) { - BufferAccess.FlushPersistent => BufferAllocationType.HostMapped, - BufferAccess.Stream => BufferAllocationType.HostMapped, - _ => BufferAllocationType.Auto, - }; + return BufferAllocationType.HostMapped; + } + + return BufferAllocationType.Auto; } private static T2 LogInvalidAndReturn<T1, T2>(T1 value, string name, T2 defaultValue = default) diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs index 7240bcad..893ecf1a 100644 --- a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs +++ b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs @@ -392,6 +392,8 @@ namespace Ryujinx.Graphics.Vulkan LoadFeatures(maxQueueCount, queueFamilyIndex); + QueueFamilyIndex = queueFamilyIndex; + _window = new Window(this, _surface, _physicalDevice.PhysicalDevice, _device); _initialized = true; @@ -399,12 +401,12 @@ namespace Ryujinx.Graphics.Vulkan public BufferHandle CreateBuffer(int size, BufferAccess access) { - return BufferManager.CreateWithHandle(this, size, access.Convert(), default, access == BufferAccess.Stream); + return BufferManager.CreateWithHandle(this, size, access.HasFlag(BufferAccess.SparseCompatible), access.Convert(), default, access == BufferAccess.Stream); } - public BufferHandle CreateBuffer(int size, BufferHandle storageHint) + public BufferHandle CreateBuffer(int size, BufferAccess access, BufferHandle storageHint) { - return BufferManager.CreateWithHandle(this, size, BufferAllocationType.Auto, storageHint); + return BufferManager.CreateWithHandle(this, size, access.HasFlag(BufferAccess.SparseCompatible), access.Convert(), storageHint); } public BufferHandle CreateBuffer(nint pointer, int size) @@ -412,6 +414,11 @@ namespace Ryujinx.Graphics.Vulkan return BufferManager.CreateHostImported(this, pointer, size); } + public BufferHandle CreateBufferSparse(ReadOnlySpan<BufferRange> storageBuffers) + { + return BufferManager.CreateSparse(this, storageBuffers); + } + public IProgram CreateProgram(ShaderSource[] sources, ShaderInfo info) { bool isCompute = sources.Length == 1 && sources[0].Stage == ShaderStage.Compute; @@ -571,6 +578,7 @@ namespace Ryujinx.Graphics.Vulkan Api.GetPhysicalDeviceFeatures2(_physicalDevice.PhysicalDevice, &features2); var limits = _physicalDevice.PhysicalDeviceProperties.Limits; + var mainQueueProperties = _physicalDevice.QueueFamilyProperties[QueueFamilyIndex]; return new Capabilities( api: TargetApi.Vulkan, @@ -590,6 +598,7 @@ namespace Ryujinx.Graphics.Vulkan supportsR4G4B4A4Format: supportsR4G4B4A4Format, supportsSnormBufferTextureFormat: true, supports5BitComponentFormat: supports5BitComponentFormat, + supportsSparseBuffer: features2.Features.SparseBinding && mainQueueProperties.QueueFlags.HasFlag(QueueFlags.SparseBindingBit), supportsBlendEquationAdvanced: Capabilities.SupportsBlendEquationAdvanced, supportsFragmentShaderInterlock: Capabilities.SupportsFragmentShaderInterlock, supportsFragmentShaderOrderingIntel: false, |
