diff options
| author | riperiperi <rhy3756547@hotmail.com> | 2023-01-13 00:31:21 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-01-13 01:31:21 +0100 |
| commit | 8fa248ceb4cbc9d199bbac1d968df8b168106c2c (patch) | |
| tree | 678ca26d2a909c6a85aba13a1b03df704cabfa2e /Ryujinx.Graphics.Vulkan | |
| parent | 30862b5ffd6848b1296da23bc8bb7e9f96bb7e60 (diff) | |
Vulkan: Add workarounds for MoltenVK (#4202)
* Add MVK basics.
* Use appropriate output attribute types
* 4kb vertex alignment, bunch of fixes
* Add reduced shader precision mode for mvk.
* Disable ASTC on MVK for now
* Only request robustnes2 when it is available.
* It's just the one feature actually
* Add triangle fan conversion
* Allow NullDescriptor on MVK for some reason.
* Force safe blit on MoltenVK
* Use ASTC only when formats are all available.
* Disable multilevel 3d texture views
* Filter duplicate render targets (on backend)
* Add Automatic MoltenVK Configuration
* Do not create color attachment views with formats that are not RT compatible
* Make sure that the host format matches the vertex shader input types for invalid/unknown guest formats
* FIx rebase for Vertex Attrib State
* Fix 4b alignment for vertex
* Use asynchronous queue submits for MVK
* Ensure color clear shader has correct output type
* Update MoltenVK config
* Always use MoltenVK workarounds on MacOS
* Make MVK supersede all vendors
* Fix rebase
* Various fixes on rebase
* Get portability flags from extension
* Fix some minor rebasing issues
* Style change
* Use LibraryImport for MVKConfiguration
* Rename MoltenVK vendor to Apple
Intel and AMD GPUs on moltenvk report with the those vendors - only apple silicon reports with vendor 0x106B.
* Fix features2 rebase conflict
* Rename fragment output type
* Add missing check for fragment output types
Might have caused the crash in MK8
* Only do fragment output specialization on MoltenVK
* Avoid copy when passing capabilities
* Self feedback
* Address feedback
Co-authored-by: gdk <gab.dark.100@gmail.com>
Co-authored-by: nastys <nastys@users.noreply.github.com>
Diffstat (limited to 'Ryujinx.Graphics.Vulkan')
17 files changed, 526 insertions, 37 deletions
diff --git a/Ryujinx.Graphics.Vulkan/FramebufferParams.cs b/Ryujinx.Graphics.Vulkan/FramebufferParams.cs index 1b99a609..751ef5eb 100644 --- a/Ryujinx.Graphics.Vulkan/FramebufferParams.cs +++ b/Ryujinx.Graphics.Vulkan/FramebufferParams.cs @@ -140,6 +140,25 @@ namespace Ryujinx.Graphics.Vulkan return _attachments[index]; } + public ComponentType GetAttachmentComponentType(int index) + { + if (_colors != null && (uint)index < _colors.Length) + { + var format = _colors[index].Info.Format; + + if (format.IsSint()) + { + return ComponentType.SignedInteger; + } + else if (format.IsUint()) + { + return ComponentType.UnsignedInteger; + } + } + + return ComponentType.Float; + } + public bool IsValidColorAttachment(int bindIndex) { return (uint)bindIndex < Constants.MaxRenderTargets && (_validColorAttachments & (1u << bindIndex)) != 0; diff --git a/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs b/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs index 31acfc9b..0a4d365f 100644 --- a/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs +++ b/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs @@ -1,7 +1,20 @@ using Silk.NET.Vulkan; +using System; namespace Ryujinx.Graphics.Vulkan { + [Flags] + enum PortabilitySubsetFlags + { + None = 0, + + VertexBufferAlignment4B = 1, + NoTriangleFans = 1 << 1, + NoPointMode = 1 << 2, + No3DImageView = 1 << 3, + NoLodBias = 1 << 4 + } + readonly struct HardwareCapabilities { public readonly bool SupportsIndexTypeUint8; @@ -23,6 +36,7 @@ namespace Ryujinx.Graphics.Vulkan public readonly uint MaxSubgroupSize; public readonly ShaderStageFlags RequiredSubgroupSizeStages; public readonly SampleCountFlags SupportedSampleCounts; + public readonly PortabilitySubsetFlags PortabilitySubset; public HardwareCapabilities( bool supportsIndexTypeUint8, @@ -43,7 +57,8 @@ namespace Ryujinx.Graphics.Vulkan uint minSubgroupSize, uint maxSubgroupSize, ShaderStageFlags requiredSubgroupSizeStages, - SampleCountFlags supportedSampleCounts) + SampleCountFlags supportedSampleCounts, + PortabilitySubsetFlags portabilitySubset) { SupportsIndexTypeUint8 = supportsIndexTypeUint8; SupportsCustomBorderColor = supportsCustomBorderColor; @@ -64,6 +79,7 @@ namespace Ryujinx.Graphics.Vulkan MaxSubgroupSize = maxSubgroupSize; RequiredSubgroupSizeStages = requiredSubgroupSizeStages; SupportedSampleCounts = supportedSampleCounts; + PortabilitySubset = portabilitySubset; } } } diff --git a/Ryujinx.Graphics.Vulkan/HelperShader.cs b/Ryujinx.Graphics.Vulkan/HelperShader.cs index 14a63615..223bcc71 100644 --- a/Ryujinx.Graphics.Vulkan/HelperShader.cs +++ b/Ryujinx.Graphics.Vulkan/HelperShader.cs @@ -9,6 +9,13 @@ using VkFormat = Silk.NET.Vulkan.Format; namespace Ryujinx.Graphics.Vulkan { + enum ComponentType + { + Float, + SignedInteger, + UnsignedInteger + } + class HelperShader : IDisposable { private const int UniformBufferAlignment = 256; @@ -18,7 +25,9 @@ namespace Ryujinx.Graphics.Vulkan private readonly ISampler _samplerNearest; private readonly IProgram _programColorBlit; private readonly IProgram _programColorBlitClearAlpha; - private readonly IProgram _programColorClear; + private readonly IProgram _programColorClearF; + private readonly IProgram _programColorClearSI; + private readonly IProgram _programColorClearUI; private readonly IProgram _programStrideChange; private readonly IProgram _programConvertIndexBuffer; private readonly IProgram _programConvertIndirectData; @@ -63,10 +72,22 @@ namespace Ryujinx.Graphics.Vulkan Array.Empty<int>(), Array.Empty<int>()); - _programColorClear = gd.CreateProgramWithMinimalLayout(new[] + _programColorClearF = gd.CreateProgramWithMinimalLayout(new[] + { + new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, colorBlitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), + new ShaderSource(ShaderBinaries.ColorClearFFragmentShaderSource, colorClearFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), + }); + + _programColorClearSI = gd.CreateProgramWithMinimalLayout(new[] + { + new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, colorBlitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), + new ShaderSource(ShaderBinaries.ColorClearSIFragmentShaderSource, colorClearFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), + }); + + _programColorClearUI = gd.CreateProgramWithMinimalLayout(new[] { new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, colorBlitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), - new ShaderSource(ShaderBinaries.ColorClearFragmentShaderSource, colorClearFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), + new ShaderSource(ShaderBinaries.ColorClearUIFragmentShaderSource, colorClearFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), }); var strideChangeBindings = new ShaderBindings( @@ -242,6 +263,7 @@ namespace Ryujinx.Graphics.Vulkan int dstWidth, int dstHeight, VkFormat dstFormat, + ComponentType type, Rectangle<int> scissor) { const int ClearColorBufferSize = 16; @@ -273,7 +295,22 @@ namespace Ryujinx.Graphics.Vulkan scissors[0] = scissor; - _pipeline.SetProgram(_programColorClear); + IProgram program; + + if (type == ComponentType.SignedInteger) + { + program = _programColorClearSI; + } + else if (type == ComponentType.UnsignedInteger) + { + program = _programColorClearUI; + } + else + { + program = _programColorClearF; + } + + _pipeline.SetProgram(program); _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, false, dstFormat); _pipeline.SetRenderTargetColorMasks(new uint[] { componentMask }); _pipeline.SetViewports(viewports, false); @@ -948,7 +985,9 @@ namespace Ryujinx.Graphics.Vulkan { _programColorBlitClearAlpha.Dispose(); _programColorBlit.Dispose(); - _programColorClear.Dispose(); + _programColorClearF.Dispose(); + _programColorClearSI.Dispose(); + _programColorClearUI.Dispose(); _programStrideChange.Dispose(); _programConvertIndexBuffer.Dispose(); _programConvertIndirectData.Dispose(); diff --git a/Ryujinx.Graphics.Vulkan/MoltenVK/MVKConfiguration.cs b/Ryujinx.Graphics.Vulkan/MoltenVK/MVKConfiguration.cs new file mode 100644 index 00000000..4fbae86e --- /dev/null +++ b/Ryujinx.Graphics.Vulkan/MoltenVK/MVKConfiguration.cs @@ -0,0 +1,104 @@ +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Graphics.Vulkan.MoltenVK +{ + enum MVKConfigLogLevel : int + { + None = 0, + Error = 1, + Warning = 2, + Info = 3, + Debug = 4 + } + + enum MVKConfigTraceVulkanCalls : int + { + None = 0, + Enter = 1, + EnterExit = 2, + Duration = 3 + } + + enum MVKConfigAutoGPUCaptureScope : int + { + None = 0, + Device = 1, + Frame = 2 + } + + [Flags] + enum MVKConfigAdvertiseExtensions : int + { + All = 0x00000001, + MoltenVK = 0x00000002, + WSI = 0x00000004, + Portability = 0x00000008 + } + + enum MVKVkSemaphoreSupportStyle : int + { + MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE = 0, + MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS_WHERE_SAFE = 1, + MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS = 2, + MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_CALLBACK = 3, + MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_MAX_ENUM = 0x7FFFFFFF + } + + readonly struct Bool32 + { + uint Value { get; } + + public Bool32(uint value) + { + Value = value; + } + + public Bool32(bool value) + { + Value = value ? 1u : 0u; + } + + public static implicit operator bool(Bool32 val) => val.Value == 1; + public static implicit operator Bool32(bool val) => new Bool32(val); + } + + [StructLayout(LayoutKind.Sequential)] + struct MVKConfiguration + { + public Bool32 DebugMode; + public Bool32 ShaderConversionFlipVertexY; + public Bool32 SynchronousQueueSubmits; + public Bool32 PrefillMetalCommandBuffers; + public uint MaxActiveMetalCommandBuffersPerQueue; + public Bool32 SupportLargeQueryPools; + public Bool32 PresentWithCommandBuffer; + public Bool32 SwapchainMagFilterUseNearest; + public ulong MetalCompileTimeout; + public Bool32 PerformanceTracking; + public uint PerformanceLoggingFrameCount; + public Bool32 DisplayWatermark; + public Bool32 SpecializedQueueFamilies; + public Bool32 SwitchSystemGPU; + public Bool32 FullImageViewSwizzle; + public uint DefaultGPUCaptureScopeQueueFamilyIndex; + public uint DefaultGPUCaptureScopeQueueIndex; + public Bool32 FastMathEnabled; + public MVKConfigLogLevel LogLevel; + public MVKConfigTraceVulkanCalls TraceVulkanCalls; + public Bool32 ForceLowPowerGPU; + public Bool32 SemaphoreUseMTLFence; + public MVKVkSemaphoreSupportStyle SemaphoreSupportStyle; + public MVKConfigAutoGPUCaptureScope AutoGPUCaptureScope; + public IntPtr AutoGPUCaptureOutputFilepath; + public Bool32 Texture1DAs2D; + public Bool32 PreallocateDescriptors; + public Bool32 UseCommandPooling; + public Bool32 UseMTLHeap; + public Bool32 LogActivityPerformanceInline; + public uint ApiVersionToAdvertise; + public MVKConfigAdvertiseExtensions AdvertiseExtensions; + public Bool32 ResumeLostDevice; + public Bool32 UseMetalArgumentBuffers; + } +} diff --git a/Ryujinx.Graphics.Vulkan/MoltenVK/MVKInitialization.cs b/Ryujinx.Graphics.Vulkan/MoltenVK/MVKInitialization.cs new file mode 100644 index 00000000..ca2fbfb9 --- /dev/null +++ b/Ryujinx.Graphics.Vulkan/MoltenVK/MVKInitialization.cs @@ -0,0 +1,31 @@ +using Silk.NET.Vulkan; +using System; +using System.Runtime.Versioning; +using System.Runtime.InteropServices; + +namespace Ryujinx.Graphics.Vulkan.MoltenVK +{ + [SupportedOSPlatform("macos")] + public static partial class MVKInitialization + { + [LibraryImport("libMoltenVK.dylib")] + private static partial Result vkGetMoltenVKConfigurationMVK(IntPtr unusedInstance, out MVKConfiguration config, in IntPtr configSize); + + [LibraryImport("libMoltenVK.dylib")] + private static partial Result vkSetMoltenVKConfigurationMVK(IntPtr unusedInstance, in MVKConfiguration config, in IntPtr configSize); + + public static void Initialize() + { + var configSize = (IntPtr)Marshal.SizeOf<MVKConfiguration>(); + + vkGetMoltenVKConfigurationMVK(IntPtr.Zero, out MVKConfiguration config, configSize); + + config.UseMetalArgumentBuffers = true; + + config.SemaphoreSupportStyle = MVKVkSemaphoreSupportStyle.MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE; + config.SynchronousQueueSubmits = false; + + vkSetMoltenVKConfigurationMVK(IntPtr.Zero, config, configSize); + } + } +}
\ No newline at end of file diff --git a/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/Ryujinx.Graphics.Vulkan/PipelineBase.cs index dfcb32d4..1c0c836b 100644 --- a/Ryujinx.Graphics.Vulkan/PipelineBase.cs +++ b/Ryujinx.Graphics.Vulkan/PipelineBase.cs @@ -2,6 +2,7 @@ using Ryujinx.Graphics.Shader; using Silk.NET.Vulkan; using System; +using System.Linq; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -50,6 +51,11 @@ namespace Ryujinx.Graphics.Vulkan private Auto<DisposableRenderPass> _renderPass; private int _writtenAttachmentCount; + private bool _framebufferUsingColorWriteMask; + + private ITexture[] _preMaskColors; + private ITexture _preMaskDepthStencil; + private readonly DescriptorSetUpdater _descriptorSetUpdater; private IndexBufferState _indexBuffer; @@ -905,24 +911,37 @@ namespace Ryujinx.Graphics.Vulkan } } - SignalStateChange(); - - if (writtenAttachments != _writtenAttachmentCount) + if (_framebufferUsingColorWriteMask) { - SignalAttachmentChange(); - _writtenAttachmentCount = writtenAttachments; + SetRenderTargetsInternal(_preMaskColors, _preMaskDepthStencil, true); + } + else + { + SignalStateChange(); + + if (writtenAttachments != _writtenAttachmentCount) + { + SignalAttachmentChange(); + _writtenAttachmentCount = writtenAttachments; + } } } - public void SetRenderTargets(ITexture[] colors, ITexture depthStencil) + private void SetRenderTargetsInternal(ITexture[] colors, ITexture depthStencil, bool filterWriteMasked) { FramebufferParams?.UpdateModifications(); - CreateFramebuffer(colors, depthStencil); + CreateFramebuffer(colors, depthStencil, filterWriteMasked); CreateRenderPass(); SignalStateChange(); SignalAttachmentChange(); } + public void SetRenderTargets(ITexture[] colors, ITexture depthStencil) + { + _framebufferUsingColorWriteMask = false; + SetRenderTargetsInternal(colors, depthStencil, Gd.IsTBDR); + } + public void SetRenderTargetScale(float scale) { _renderScale[0].X = scale; @@ -1102,7 +1121,7 @@ namespace Ryujinx.Graphics.Vulkan int vbSize = vertexBuffer.Buffer.Size; - if (Gd.Vendor == Vendor.Amd && vertexBuffer.Stride > 0) + if (Gd.Vendor == Vendor.Amd && !Gd.IsMoltenVk && vertexBuffer.Stride > 0) { // AMD has a bug where if offset + stride * count is greater than // the size, then the last attribute will have the wrong value. @@ -1119,7 +1138,8 @@ namespace Ryujinx.Graphics.Vulkan buffer.Dispose(); - if ((vertexBuffer.Stride % FormatExtensions.MaxBufferFormatScalarSize) == 0) + if (!Gd.Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.VertexBufferAlignment4B) && + (vertexBuffer.Stride % FormatExtensions.MaxBufferFormatScalarSize) == 0) { buffer = new VertexBufferState( vb, @@ -1259,8 +1279,62 @@ namespace Ryujinx.Graphics.Vulkan _currentPipelineHandle = 0; } - private void CreateFramebuffer(ITexture[] colors, ITexture depthStencil) + private void CreateFramebuffer(ITexture[] colors, ITexture depthStencil, bool filterWriteMasked) { + if (filterWriteMasked) + { + // TBDR GPUs don't work properly if the same attachment is bound to multiple targets, + // due to each attachment being a copy of the real attachment, rather than a direct write. + + // Just try to remove duplicate attachments. + // Save a copy of the array to rebind when mask changes. + + void maskOut() + { + if (!_framebufferUsingColorWriteMask) + { + _preMaskColors = colors.ToArray(); + _preMaskDepthStencil = depthStencil; + } + + // If true, then the framebuffer must be recreated when the mask changes. + _framebufferUsingColorWriteMask = true; + } + + // Look for textures that are masked out. + + for (int i = 0; i < colors.Length; i++) + { + if (colors[i] == null) + { + continue; + } + + ref var vkBlend = ref _newState.Internal.ColorBlendAttachmentState[i]; + + for (int j = 0; j < i; j++) + { + // Check each binding for a duplicate binding before it. + + if (colors[i] == colors[j]) + { + // Prefer the binding with no write mask. + ref var vkBlend2 = ref _newState.Internal.ColorBlendAttachmentState[j]; + if (vkBlend.ColorWriteMask == 0) + { + colors[i] = null; + maskOut(); + } + else if (vkBlend2.ColorWriteMask == 0) + { + colors[j] = null; + maskOut(); + } + } + } + } + } + FramebufferParams = new FramebufferParams(Device, colors, depthStencil); UpdatePipelineAttachmentFormats(); } diff --git a/Ryujinx.Graphics.Vulkan/PipelineFull.cs b/Ryujinx.Graphics.Vulkan/PipelineFull.cs index 2256c542..e4bf4fff 100644 --- a/Ryujinx.Graphics.Vulkan/PipelineFull.cs +++ b/Ryujinx.Graphics.Vulkan/PipelineFull.cs @@ -79,6 +79,7 @@ namespace Ryujinx.Graphics.Vulkan (int)FramebufferParams.Width, (int)FramebufferParams.Height, FramebufferParams.AttachmentFormats[index], + FramebufferParams.GetAttachmentComponentType(index), ClearScissor); } else diff --git a/Ryujinx.Graphics.Vulkan/Shaders/ColorClearFragmentShaderSource.frag b/Ryujinx.Graphics.Vulkan/Shaders/ColorClearFFragmentShaderSource.frag index ddd4369c..ddd4369c 100644 --- a/Ryujinx.Graphics.Vulkan/Shaders/ColorClearFragmentShaderSource.frag +++ b/Ryujinx.Graphics.Vulkan/Shaders/ColorClearFFragmentShaderSource.frag diff --git a/Ryujinx.Graphics.Vulkan/Shaders/ColorClearSIFragmentShaderSource.frag b/Ryujinx.Graphics.Vulkan/Shaders/ColorClearSIFragmentShaderSource.frag new file mode 100644 index 00000000..4254f4f8 --- /dev/null +++ b/Ryujinx.Graphics.Vulkan/Shaders/ColorClearSIFragmentShaderSource.frag @@ -0,0 +1,9 @@ +#version 450 core + +layout (location = 0) in vec4 clear_colour; +layout (location = 0) out ivec4 colour; + +void main() +{ + colour = floatBitsToInt(clear_colour); +}
\ No newline at end of file diff --git a/Ryujinx.Graphics.Vulkan/Shaders/ColorClearUIFragmentShaderSource.frag b/Ryujinx.Graphics.Vulkan/Shaders/ColorClearUIFragmentShaderSource.frag new file mode 100644 index 00000000..08a6b864 --- /dev/null +++ b/Ryujinx.Graphics.Vulkan/Shaders/ColorClearUIFragmentShaderSource.frag @@ -0,0 +1,9 @@ +#version 450 core + +layout (location = 0) in vec4 clear_colour; +layout (location = 0) out uvec4 colour; + +void main() +{ + colour = floatBitsToUint(clear_colour); +}
\ No newline at end of file diff --git a/Ryujinx.Graphics.Vulkan/Shaders/ShaderBinaries.cs b/Ryujinx.Graphics.Vulkan/Shaders/ShaderBinaries.cs index 992f1e69..667e5a8b 100644 --- a/Ryujinx.Graphics.Vulkan/Shaders/ShaderBinaries.cs +++ b/Ryujinx.Graphics.Vulkan/Shaders/ShaderBinaries.cs @@ -431,7 +431,7 @@ namespace Ryujinx.Graphics.Vulkan.Shaders 0x3C, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, }; - public static readonly byte[] ColorClearFragmentShaderSource = new byte[] + public static readonly byte[] ColorClearFFragmentShaderSource = new byte[] { 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00, @@ -459,6 +459,68 @@ namespace Ryujinx.Graphics.Vulkan.Shaders 0x0C, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, }; + public static readonly byte[] ColorClearSIFragmentShaderSource = new byte[] + { + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, + 0xC2, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x63, 0x6F, 0x6C, 0x6F, + 0x75, 0x72, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x65, 0x61, + 0x72, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x75, 0x72, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, + 0x0D, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x3B, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x03, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, + }; + + public static readonly byte[] ColorClearUIFragmentShaderSource = new byte[] + { + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, + 0xC2, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x63, 0x6F, 0x6C, 0x6F, + 0x75, 0x72, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x65, 0x61, + 0x72, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x75, 0x72, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, + 0x0D, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x3B, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x03, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, + }; + public static readonly byte[] ColorClearVertexShaderSource = new byte[] { 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x36, 0x00, 0x00, 0x00, diff --git a/Ryujinx.Graphics.Vulkan/TextureStorage.cs b/Ryujinx.Graphics.Vulkan/TextureStorage.cs index f4feecbc..28fabb4f 100644 --- a/Ryujinx.Graphics.Vulkan/TextureStorage.cs +++ b/Ryujinx.Graphics.Vulkan/TextureStorage.cs @@ -106,7 +106,7 @@ namespace Ryujinx.Graphics.Vulkan flags |= ImageCreateFlags.CreateCubeCompatibleBit; } - if (type == ImageType.Type3D) + if (type == ImageType.Type3D && !gd.Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.No3DImageView)) { flags |= ImageCreateFlags.Create2DArrayCompatibleBit; } diff --git a/Ryujinx.Graphics.Vulkan/TextureView.cs b/Ryujinx.Graphics.Vulkan/TextureView.cs index c58c9fc5..a9e1ed36 100644 --- a/Ryujinx.Graphics.Vulkan/TextureView.cs +++ b/Ryujinx.Graphics.Vulkan/TextureView.cs @@ -94,8 +94,14 @@ namespace Ryujinx.Graphics.Vulkan var subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, layers); var subresourceRangeDepth = new ImageSubresourceRange(aspectFlagsDepth, (uint)firstLevel, levels, (uint)firstLayer, layers); - unsafe Auto<DisposableImageView> CreateImageView(ComponentMapping cm, ImageSubresourceRange sr, ImageViewType viewType) + unsafe Auto<DisposableImageView> CreateImageView(ComponentMapping cm, ImageSubresourceRange sr, ImageViewType viewType, ImageUsageFlags usageFlags = 0) { + var usage = new ImageViewUsageCreateInfo() + { + SType = StructureType.ImageViewUsageCreateInfo, + Usage = usageFlags + }; + var imageCreateInfo = new ImageViewCreateInfo() { SType = StructureType.ImageViewCreateInfo, @@ -103,7 +109,8 @@ namespace Ryujinx.Graphics.Vulkan ViewType = viewType, Format = format, Components = cm, - SubresourceRange = sr + SubresourceRange = sr, + PNext = usageFlags == 0 ? null : &usage }; gd.Api.CreateImageView(device, imageCreateInfo, null, out var imageView).ThrowOnError(); @@ -124,9 +131,21 @@ namespace Ryujinx.Graphics.Vulkan // Framebuffer attachments also require 3D textures to be bound as 2D array. if (info.Target == Target.Texture3D) { - subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, (uint)info.Depth); + if (gd.Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.No3DImageView)) + { + if (levels == 1 && (info.Format.IsRtColorCompatible() || info.Format.IsDepthOrStencil())) + { + subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, 1); - _imageView2dArray = CreateImageView(identityComponentMapping, subresourceRange, ImageViewType.Type2DArray); + _imageView2dArray = CreateImageView(identityComponentMapping, subresourceRange, ImageViewType.Type2D, ImageUsageFlags.ColorAttachmentBit); + } + } + else + { + subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, (uint)info.Depth); + + _imageView2dArray = CreateImageView(identityComponentMapping, subresourceRange, ImageViewType.Type2DArray); + } } Valid = true; @@ -353,7 +372,7 @@ namespace Ryujinx.Graphics.Vulkan } if (VulkanConfiguration.UseSlowSafeBlitOnAmd && - _gd.Vendor == Vendor.Amd && + (_gd.Vendor == Vendor.Amd || _gd.IsMoltenVk) && src.Info.Target == Target.Texture2D && dst.Info.Target == Target.Texture2D && !dst.Info.Format.IsDepthOrStencil()) diff --git a/Ryujinx.Graphics.Vulkan/Vendor.cs b/Ryujinx.Graphics.Vulkan/Vendor.cs index 7a6e0e60..087d6e9d 100644 --- a/Ryujinx.Graphics.Vulkan/Vendor.cs +++ b/Ryujinx.Graphics.Vulkan/Vendor.cs @@ -5,9 +5,12 @@ namespace Ryujinx.Graphics.Vulkan enum Vendor { Amd, + ImgTec, Intel, Nvidia, + ARM, Qualcomm, + Apple, Unknown } @@ -21,7 +24,10 @@ namespace Ryujinx.Graphics.Vulkan return id switch { 0x1002 => Vendor.Amd, + 0x1010 => Vendor.ImgTec, + 0x106B => Vendor.Apple, 0x10DE => Vendor.Nvidia, + 0x13B5 => Vendor.ARM, 0x8086 => Vendor.Intel, 0x5143 => Vendor.Qualcomm, _ => Vendor.Unknown @@ -34,6 +40,7 @@ namespace Ryujinx.Graphics.Vulkan { 0x1002 => "AMD", 0x1010 => "ImgTec", + 0x106B => "Apple", 0x10DE => "NVIDIA", 0x13B5 => "ARM", 0x1AE0 => "Google", diff --git a/Ryujinx.Graphics.Vulkan/VertexBufferState.cs b/Ryujinx.Graphics.Vulkan/VertexBufferState.cs index 661bb774..7a022010 100644 --- a/Ryujinx.Graphics.Vulkan/VertexBufferState.cs +++ b/Ryujinx.Graphics.Vulkan/VertexBufferState.cs @@ -82,9 +82,9 @@ namespace Ryujinx.Graphics.Vulkan } _buffer = autoBuffer; - } - state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)_stride; + state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)stride; + } return; } diff --git a/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs b/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs index 68462825..fe9462aa 100644 --- a/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs +++ b/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs @@ -389,6 +389,18 @@ namespace Ryujinx.Graphics.Vulkan features2.PNext = &featuresCustomBorderColorSupported; } + PhysicalDeviceRobustness2FeaturesEXT supportedFeaturesRobustness2 = new PhysicalDeviceRobustness2FeaturesEXT() + { + SType = StructureType.PhysicalDeviceRobustness2FeaturesExt + }; + + if (supportedExtensions.Contains("VK_EXT_robustness2")) + { + supportedFeaturesRobustness2.PNext = features2.PNext; + + features2.PNext = &supportedFeaturesRobustness2; + } + api.GetPhysicalDeviceFeatures2(physicalDevice, &features2); var supportedFeatures = features2.Features; @@ -428,14 +440,17 @@ namespace Ryujinx.Graphics.Vulkan pExtendedFeatures = &featuresTransformFeedback; - var featuresRobustness2 = new PhysicalDeviceRobustness2FeaturesEXT() + if (supportedExtensions.Contains("VK_EXT_robustness2")) { - SType = StructureType.PhysicalDeviceRobustness2FeaturesExt, - PNext = pExtendedFeatures, - NullDescriptor = true - }; + var featuresRobustness2 = new PhysicalDeviceRobustness2FeaturesEXT() + { + SType = StructureType.PhysicalDeviceRobustness2FeaturesExt, + PNext = pExtendedFeatures, + NullDescriptor = supportedFeaturesRobustness2.NullDescriptor + }; - pExtendedFeatures = &featuresRobustness2; + pExtendedFeatures = &featuresRobustness2; + } var featuresExtendedDynamicState = new PhysicalDeviceExtendedDynamicStateFeaturesEXT() { diff --git a/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs b/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs index 5c77cb00..f1922efe 100644 --- a/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs +++ b/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs @@ -3,6 +3,7 @@ using Ryujinx.Common.Logging; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Shader; using Ryujinx.Graphics.Shader.Translation; +using Ryujinx.Graphics.Vulkan.MoltenVK; using Ryujinx.Graphics.Vulkan.Queries; using Silk.NET.Vulkan; using Silk.NET.Vulkan.Extensions.EXT; @@ -77,6 +78,8 @@ namespace Ryujinx.Graphics.Vulkan internal bool IsAmdWindows { get; private set; } internal bool IsIntelWindows { get; private set; } internal bool IsAmdGcn { get; private set; } + internal bool IsMoltenVk { get; private set; } + internal bool IsTBDR { get; private set; } public string GpuVendor { get; private set; } public string GpuRenderer { get; private set; } public string GpuVersion { get; private set; } @@ -93,6 +96,14 @@ namespace Ryujinx.Graphics.Vulkan Shaders = new HashSet<ShaderCollection>(); Textures = new HashSet<ITexture>(); Samplers = new HashSet<SamplerHolder>(); + + if (OperatingSystem.IsMacOS()) + { + MVKInitialization.Initialize(); + + // Any device running on MacOS is using MoltenVK, even Intel and AMD vendors. + IsMoltenVk = true; + } } private unsafe void LoadFeatures(string[] supportedExtensions, uint maxQueueCount, uint queueFamilyIndex) @@ -161,7 +172,10 @@ namespace Ryujinx.Graphics.Vulkan properties2.PNext = &propertiesTransformFeedback; } - Api.GetPhysicalDeviceProperties2(_physicalDevice, &properties2); + PhysicalDevicePortabilitySubsetPropertiesKHR propertiesPortabilitySubset = new PhysicalDevicePortabilitySubsetPropertiesKHR() + { + SType = StructureType.PhysicalDevicePortabilitySubsetPropertiesKhr + }; PhysicalDeviceFeatures2 features2 = new PhysicalDeviceFeatures2() { @@ -183,6 +197,11 @@ namespace Ryujinx.Graphics.Vulkan SType = StructureType.PhysicalDeviceCustomBorderColorFeaturesExt }; + PhysicalDevicePortabilitySubsetFeaturesKHR featuresPortabilitySubset = new PhysicalDevicePortabilitySubsetFeaturesKHR() + { + SType = StructureType.PhysicalDevicePortabilitySubsetFeaturesKhr + }; + if (supportedExtensions.Contains("VK_EXT_robustness2")) { features2.PNext = &featuresRobustness2; @@ -200,8 +219,31 @@ namespace Ryujinx.Graphics.Vulkan features2.PNext = &featuresCustomBorderColor; } + bool usePortability = supportedExtensions.Contains("VK_KHR_portability_subset"); + + if (usePortability) + { + propertiesPortabilitySubset.PNext = properties2.PNext; + properties2.PNext = &propertiesPortabilitySubset; + + featuresPortabilitySubset.PNext = features2.PNext; + features2.PNext = &featuresPortabilitySubset; + } + + Api.GetPhysicalDeviceProperties2(_physicalDevice, &properties2); Api.GetPhysicalDeviceFeatures2(_physicalDevice, &features2); + var portabilityFlags = PortabilitySubsetFlags.None; + + if (usePortability) + { + portabilityFlags |= propertiesPortabilitySubset.MinVertexInputBindingStrideAlignment > 1 ? PortabilitySubsetFlags.VertexBufferAlignment4B : 0; + portabilityFlags |= featuresPortabilitySubset.TriangleFans ? 0 : PortabilitySubsetFlags.NoTriangleFans; + portabilityFlags |= featuresPortabilitySubset.PointPolygons ? 0 : PortabilitySubsetFlags.NoPointMode; + portabilityFlags |= featuresPortabilitySubset.ImageView2DOn3DImage ? 0 : PortabilitySubsetFlags.No3DImageView; + portabilityFlags |= featuresPortabilitySubset.SamplerMipLodBias ? 0 : PortabilitySubsetFlags.NoLodBias; + } + bool customBorderColorSupported = supportedExtensions.Contains("VK_EXT_custom_border_color") && featuresCustomBorderColor.CustomBorderColors && featuresCustomBorderColor.CustomBorderColorWithoutFormat; @@ -224,7 +266,7 @@ namespace Ryujinx.Graphics.Vulkan supportedExtensions.Contains(ExtConditionalRendering.ExtensionName), supportedExtensions.Contains(ExtExtendedDynamicState.ExtensionName), features2.Features.MultiViewport, - featuresRobustness2.NullDescriptor, + featuresRobustness2.NullDescriptor || IsMoltenVk, supportedExtensions.Contains(KhrPushDescriptor.ExtensionName), supportsTransformFeedback, propertiesTransformFeedback.TransformFeedbackQueries, @@ -232,7 +274,8 @@ namespace Ryujinx.Graphics.Vulkan propertiesSubgroupSizeControl.MinSubgroupSize, propertiesSubgroupSizeControl.MaxSubgroupSize, propertiesSubgroupSizeControl.RequiredSubgroupSizeStages, - supportedSampleCounts); + supportedSampleCounts, + portabilityFlags); MemoryAllocator = new MemoryAllocator(Api, _device, properties.Limits.MaxMemoryAllocationCount); @@ -413,6 +456,36 @@ namespace Ryujinx.Graphics.Vulkan bool supportsR4G4B4A4Format = FormatCapabilities.OptimalFormatsSupport(compressedFormatFeatureFlags, GAL.Format.R4G4B4A4Unorm); + bool supportsAstcFormats = FormatCapabilities.OptimalFormatsSupport(compressedFormatFeatureFlags, + GAL.Format.Astc4x4Unorm, + GAL.Format.Astc5x4Unorm, + GAL.Format.Astc5x5Unorm, + GAL.Format.Astc6x5Unorm, + GAL.Format.Astc6x6Unorm, + GAL.Format.Astc8x5Unorm, + GAL.Format.Astc8x6Unorm, + GAL.Format.Astc8x8Unorm, + GAL.Format.Astc10x5Unorm, + GAL.Format.Astc10x6Unorm, + GAL.Format.Astc10x8Unorm, + GAL.Format.Astc10x10Unorm, + GAL.Format.Astc12x10Unorm, + GAL.Format.Astc12x12Unorm, + GAL.Format.Astc4x4Srgb, + GAL.Format.Astc5x4Srgb, + GAL.Format.Astc5x5Srgb, + GAL.Format.Astc6x5Srgb, + GAL.Format.Astc6x6Srgb, + GAL.Format.Astc8x5Srgb, + GAL.Format.Astc8x6Srgb, + GAL.Format.Astc8x8Srgb, + GAL.Format.Astc10x5Srgb, + GAL.Format.Astc10x6Srgb, + GAL.Format.Astc10x8Srgb, + GAL.Format.Astc10x10Srgb, + GAL.Format.Astc12x10Srgb, + GAL.Format.Astc12x12Srgb); + PhysicalDeviceVulkan12Features featuresVk12 = new PhysicalDeviceVulkan12Features() { SType = StructureType.PhysicalDeviceVulkan12Features @@ -434,7 +507,9 @@ namespace Ryujinx.Graphics.Vulkan GpuVendor, hasFrontFacingBug: IsIntelWindows, hasVectorIndexingBug: Vendor == Vendor.Qualcomm, - supportsAstcCompression: features2.Features.TextureCompressionAstcLdr, + needsFragmentOutputSpecialization: IsMoltenVk, + reduceShaderPrecision: IsMoltenVk, + supportsAstcCompression: features2.Features.TextureCompressionAstcLdr && supportsAstcFormats, supportsBc123Compression: supportsBc123CompressionFormat, supportsBc45Compression: supportsBc45CompressionFormat, supportsBc67Compression: supportsBc67CompressionFormat, @@ -515,12 +590,13 @@ namespace Ryujinx.Graphics.Vulkan IsAmdWindows = Vendor == Vendor.Amd && RuntimeInformation.IsOSPlatform(OSPlatform.Windows); IsIntelWindows = Vendor == Vendor.Intel && RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + IsTBDR = IsMoltenVk || Vendor == Vendor.Qualcomm || Vendor == Vendor.ARM || Vendor == Vendor.ImgTec; GpuVendor = vendorName; GpuRenderer = Marshal.PtrToStringAnsi((IntPtr)properties.DeviceName); GpuVersion = $"Vulkan v{ParseStandardVulkanVersion(properties.ApiVersion)}, Driver v{ParseDriverVersion(ref properties)}"; - IsAmdGcn = Vendor == Vendor.Amd && VendorUtils.AmdGcnRegex().IsMatch(GpuRenderer); + IsAmdGcn = !IsMoltenVk && Vendor == Vendor.Amd && VendorUtils.AmdGcnRegex().IsMatch(GpuRenderer); Logger.Notice.Print(LogClass.Gpu, $"{GpuVendor} {GpuRenderer} ({GpuVersion})"); } @@ -531,6 +607,7 @@ namespace Ryujinx.Graphics.Vulkan { GAL.PrimitiveTopology.Quads => GAL.PrimitiveTopology.Triangles, GAL.PrimitiveTopology.QuadStrip => GAL.PrimitiveTopology.TriangleStrip, + GAL.PrimitiveTopology.TriangleFan => Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.NoTriangleFans) ? GAL.PrimitiveTopology.Triangles : topology, _ => topology }; } @@ -540,6 +617,7 @@ namespace Ryujinx.Graphics.Vulkan return topology switch { GAL.PrimitiveTopology.Quads => true, + GAL.PrimitiveTopology.TriangleFan => Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.NoTriangleFans), _ => false }; } @@ -553,7 +631,13 @@ namespace Ryujinx.Graphics.Vulkan public bool NeedsVertexBufferAlignment(int attrScalarAlignment, out int alignment) { - if (Vendor != Vendor.Nvidia) + if (Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.VertexBufferAlignment4B)) + { + alignment = 4; + + return true; + } + else if (Vendor != Vendor.Nvidia) { // Vulkan requires that vertex attributes are globally aligned by their component size, // so buffer strides that don't divide by the largest scalar element are invalid. |
