From 17078ad929f9942d2b03ede00b30867aeab924de Mon Sep 17 00:00:00 2001 From: Mary Date: Wed, 15 Feb 2023 09:41:48 +0100 Subject: [PATCH] vulkan: Respect VK_KHR_portability_subset vertex stride alignment (#4419) * vulkan: Respect VK_KHR_portability_subset vertex stride alignment We were hardcoding alignment to 4, but by specs it can be any values that is a power of 2. This also enable VK_KHR_portability_subset if present as per specs requirements. * address gdkchan's comment * Make NeedsVertexBufferAlignment internal --- Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs | 14 ++++++++------ Ryujinx.Graphics.Vulkan/PipelineBase.cs | 5 +++-- Ryujinx.Graphics.Vulkan/PipelineConverter.cs | 5 +++-- Ryujinx.Graphics.Vulkan/VulkanInitialization.cs | 3 ++- Ryujinx.Graphics.Vulkan/VulkanRenderer.cs | 13 ++++++++----- 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs b/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs index 82fcaea102..1ed2b0ccc6 100644 --- a/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs +++ b/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs @@ -8,11 +8,10 @@ namespace Ryujinx.Graphics.Vulkan { None = 0, - VertexBufferAlignment4B = 1, - NoTriangleFans = 1 << 1, - NoPointMode = 1 << 2, - No3DImageView = 1 << 3, - NoLodBias = 1 << 4 + NoTriangleFans = 1, + NoPointMode = 1 << 1, + No3DImageView = 1 << 2, + NoLodBias = 1 << 3 } readonly struct HardwareCapabilities @@ -40,6 +39,7 @@ namespace Ryujinx.Graphics.Vulkan public readonly ShaderStageFlags RequiredSubgroupSizeStages; public readonly SampleCountFlags SupportedSampleCounts; public readonly PortabilitySubsetFlags PortabilitySubset; + public readonly uint VertexBufferAlignment; public HardwareCapabilities( bool supportsIndexTypeUint8, @@ -64,7 +64,8 @@ namespace Ryujinx.Graphics.Vulkan uint maxSubgroupSize, ShaderStageFlags requiredSubgroupSizeStages, SampleCountFlags supportedSampleCounts, - PortabilitySubsetFlags portabilitySubset) + PortabilitySubsetFlags portabilitySubset, + uint vertexBufferAlignment) { SupportsIndexTypeUint8 = supportsIndexTypeUint8; SupportsCustomBorderColor = supportsCustomBorderColor; @@ -89,6 +90,7 @@ namespace Ryujinx.Graphics.Vulkan RequiredSubgroupSizeStages = requiredSubgroupSizeStages; SupportedSampleCounts = supportedSampleCounts; PortabilitySubset = portabilitySubset; + VertexBufferAlignment = vertexBufferAlignment; } } } diff --git a/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/Ryujinx.Graphics.Vulkan/PipelineBase.cs index 02b1c38961..8ed39ee26e 100644 --- a/Ryujinx.Graphics.Vulkan/PipelineBase.cs +++ b/Ryujinx.Graphics.Vulkan/PipelineBase.cs @@ -1,4 +1,5 @@ -using Ryujinx.Graphics.GAL; +using Ryujinx.Common; +using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Shader; using Silk.NET.Vulkan; using System; @@ -1136,7 +1137,7 @@ namespace Ryujinx.Graphics.Vulkan buffer.Dispose(); - if (!Gd.Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.VertexBufferAlignment4B) && + if (Gd.Capabilities.VertexBufferAlignment < 2 && (vertexBuffer.Stride % FormatExtensions.MaxBufferFormatScalarSize) == 0) { buffer = new VertexBufferState( diff --git a/Ryujinx.Graphics.Vulkan/PipelineConverter.cs b/Ryujinx.Graphics.Vulkan/PipelineConverter.cs index 5c9193fa62..da480d9f5a 100644 --- a/Ryujinx.Graphics.Vulkan/PipelineConverter.cs +++ b/Ryujinx.Graphics.Vulkan/PipelineConverter.cs @@ -1,4 +1,5 @@ -using Ryujinx.Graphics.GAL; +using Ryujinx.Common; +using Ryujinx.Graphics.GAL; using Silk.NET.Vulkan; using System; @@ -253,7 +254,7 @@ namespace Ryujinx.Graphics.Vulkan if (gd.NeedsVertexBufferAlignment(vbScalarSizes[i], out int alignment)) { - alignedStride = (vertexBuffer.Stride + (alignment - 1)) & -alignment; + alignedStride = BitUtils.AlignUp(vertexBuffer.Stride, alignment); } // TODO: Support divisor > 1 diff --git a/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs b/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs index b8b48f6ca0..4401f032db 100644 --- a/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs +++ b/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs @@ -36,7 +36,8 @@ namespace Ryujinx.Graphics.Vulkan "VK_KHR_shader_float16_int8", "VK_EXT_shader_subgroup_ballot", "VK_EXT_subgroup_size_control", - "VK_NV_geometry_shader_passthrough" + "VK_NV_geometry_shader_passthrough", + "VK_KHR_portability_subset", // By spec, we should enable this if present. }; public static string[] RequiredExtensions { get; } = new string[] diff --git a/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs b/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs index 595e033cbb..a7b4b41a72 100644 --- a/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs +++ b/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs @@ -234,10 +234,12 @@ namespace Ryujinx.Graphics.Vulkan Api.GetPhysicalDeviceFeatures2(_physicalDevice, &features2); var portabilityFlags = PortabilitySubsetFlags.None; + uint vertexBufferAlignment = 1; if (usePortability) { - portabilityFlags |= propertiesPortabilitySubset.MinVertexInputBindingStrideAlignment > 1 ? PortabilitySubsetFlags.VertexBufferAlignment4B : 0; + vertexBufferAlignment = propertiesPortabilitySubset.MinVertexInputBindingStrideAlignment; + portabilityFlags |= featuresPortabilitySubset.TriangleFans ? 0 : PortabilitySubsetFlags.NoTriangleFans; portabilityFlags |= featuresPortabilitySubset.PointPolygons ? 0 : PortabilitySubsetFlags.NoPointMode; portabilityFlags |= featuresPortabilitySubset.ImageView2DOn3DImage ? 0 : PortabilitySubsetFlags.No3DImageView; @@ -278,7 +280,8 @@ namespace Ryujinx.Graphics.Vulkan propertiesSubgroupSizeControl.MaxSubgroupSize, propertiesSubgroupSizeControl.RequiredSubgroupSizeStages, supportedSampleCounts, - portabilityFlags); + portabilityFlags, + vertexBufferAlignment); MemoryAllocator = new MemoryAllocator(Api, _physicalDevice, _device, properties.Limits.MaxMemoryAllocationCount); @@ -636,11 +639,11 @@ namespace Ryujinx.Graphics.Vulkan PrintGpuInformation(); } - public bool NeedsVertexBufferAlignment(int attrScalarAlignment, out int alignment) + internal bool NeedsVertexBufferAlignment(int attrScalarAlignment, out int alignment) { - if (Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.VertexBufferAlignment4B)) + if (Capabilities.VertexBufferAlignment > 1) { - alignment = 4; + alignment = (int)Capabilities.VertexBufferAlignment; return true; }