Преглед изворни кода

Fix various issues caused by Vertex/Index buffer conversions (#3762)

* Fix various issues caused by #3679

- The arguments for the 0th dummy vertex buffer were incorrect - it was given an offset of 16 rather than a size of 16.
- The wrong size was used when doing `autoBuffer.Get` on a converted vertex buffer.
- The possibility of a vertex buffer being disposed and then rebound can rebindings to find a different buffer where the current range is out of bounds. Avoid binding when out of range to prevent validation errors.
- The above also affects generation of converted buffers, which was a bit more fatal. Conversion functions now attempt to bound input offset/size.

* Fix offset for converted buffer
riperiperi пре 3 година
родитељ
комит
0dbe45ae37

+ 27 - 0
Ryujinx.Graphics.Vulkan/BufferHolder.cs

@@ -386,8 +386,25 @@ namespace Ryujinx.Graphics.Vulkan
             _waitable.WaitForFences(_gd.Api, _device, offset, size);
         }
 
+        private bool BoundToRange(int offset, ref int size)
+        {
+            if (offset >= Size)
+            {
+                return false;
+            }
+
+            size = Math.Min(Size - offset, size);
+
+            return true;
+        }
+
         public Auto<DisposableBuffer> GetBufferI8ToI16(CommandBufferScoped cbs, int offset, int size)
         {
+            if (!BoundToRange(offset, ref size))
+            {
+                return null;
+            }
+
             var key = new I8ToI16CacheKey(_gd);
 
             if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder))
@@ -407,6 +424,11 @@ namespace Ryujinx.Graphics.Vulkan
 
         public Auto<DisposableBuffer> GetAlignedVertexBuffer(CommandBufferScoped cbs, int offset, int size, int stride, int alignment)
         {
+            if (!BoundToRange(offset, ref size))
+            {
+                return null;
+            }
+
             var key = new AlignedVertexBufferCacheKey(_gd, stride, alignment);
 
             if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder))
@@ -428,6 +450,11 @@ namespace Ryujinx.Graphics.Vulkan
 
         public Auto<DisposableBuffer> GetBufferTopologyConversion(CommandBufferScoped cbs, int offset, int size, IndexBufferPattern pattern, int indexSize)
         {
+            if (!BoundToRange(offset, ref size))
+            {
+                return null;
+            }
+
             var key = new TopologyConversionCacheKey(_gd, pattern, indexSize);
 
             if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder))

+ 6 - 1
Ryujinx.Graphics.Vulkan/IndexBufferState.cs

@@ -49,7 +49,12 @@ namespace Ryujinx.Graphics.Vulkan
             }
             else
             {
-                autoBuffer = gd.BufferManager.GetBuffer(cbs.CommandBuffer, _handle, false, out int _);
+                autoBuffer = gd.BufferManager.GetBuffer(cbs.CommandBuffer, _handle, false, out int bufferSize);
+
+                if (_offset >= bufferSize)
+                {
+                    autoBuffer = null;
+                }
 
                 offset = _offset;
                 size = _size;

+ 2 - 2
Ryujinx.Graphics.Vulkan/PipelineBase.cs

@@ -95,7 +95,7 @@ namespace Ryujinx.Graphics.Vulkan
 
             using var emptyVb = gd.BufferManager.Create(gd, EmptyVbSize);
             emptyVb.SetData(0, new byte[EmptyVbSize]);
-            _vertexBuffers[0] = new VertexBufferState(emptyVb.GetBuffer(), 0, EmptyVbSize, 0);
+            _vertexBuffers[0] = new VertexBufferState(emptyVb.GetBuffer(), 0, 0, EmptyVbSize, 0);
             _vertexBuffersDirty = ulong.MaxValue >> (64 - _vertexBuffers.Length);
 
             ClearScissor = new Rectangle<int>(0, 0, 0xffff, 0xffff);
@@ -1243,7 +1243,7 @@ namespace Ryujinx.Graphics.Vulkan
 
                     _vertexBuffers[i].BindVertexBuffer(Gd, Cbs, (uint)i, ref _newState);
 
-                    _vertexBuffersDirty &= ~(1u << i);
+                    _vertexBuffersDirty &= ~(1UL << i);
                 }
             }
 

+ 30 - 19
Ryujinx.Graphics.Vulkan/VertexBufferState.cs

@@ -57,37 +57,48 @@ namespace Ryujinx.Graphics.Vulkan
                 if (gd.NeedsVertexBufferAlignment(AttributeScalarAlignment, out int alignment) && (_stride % alignment) != 0)
                 {
                     autoBuffer = gd.BufferManager.GetAlignedVertexBuffer(cbs, _handle, _offset, _size, _stride, alignment);
-                    int stride = (_stride + (alignment - 1)) & -alignment;
 
-                    var buffer = autoBuffer.Get(cbs, _offset, _size).Value;
-
-                    if (gd.Capabilities.SupportsExtendedDynamicState)
-                    {
-                        gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2(
-                            cbs.CommandBuffer,
-                            binding,
-                            1,
-                            buffer,
-                            0,
-                            (ulong)(_size / _stride) * (ulong)stride,
-                            (ulong)stride);
-                    }
-                    else
+                    if (autoBuffer != null)
                     {
-                        gd.Api.CmdBindVertexBuffers(cbs.CommandBuffer, binding, 1, buffer, 0);
+                        int stride = (_stride + (alignment - 1)) & -alignment;
+                        int newSize = (_size / _stride) * stride;
+
+                        var buffer = autoBuffer.Get(cbs, 0, newSize).Value;
+
+                        if (gd.Capabilities.SupportsExtendedDynamicState)
+                        {
+                            gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2(
+                                cbs.CommandBuffer,
+                                binding,
+                                1,
+                                buffer,
+                                0,
+                                (ulong)newSize,
+                                (ulong)stride);
+                        }
+                        else
+                        {
+                            gd.Api.CmdBindVertexBuffers(cbs.CommandBuffer, binding, 1, buffer, 0);
+                        }
+
+                        _buffer = autoBuffer;
                     }
 
-                    _buffer = autoBuffer;
-                    state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)stride;
+                    state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)_stride;
 
                     return;
                 }
                 else
                 {
-                    autoBuffer = gd.BufferManager.GetBuffer(cbs.CommandBuffer, _handle, false, out int _);
+                    autoBuffer = gd.BufferManager.GetBuffer(cbs.CommandBuffer, _handle, false, out int size);
 
                     // The original stride must be reapplied in case it was rewritten.
                     state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)_stride;
+
+                    if (_offset >= size)
+                    {
+                        autoBuffer = null;
+                    }
                 }
             }