ソースを参照

Add support for bindless textures from storage buffer on Vulkan (#6721)

* Halve primitive ID when converting quads to triangles

* Shader cache version bump

* Add support for bindless textures from storage buffer on Vulkan
gdkchan 1 年間 前
コミット
3a3b51893e

+ 3 - 0
src/Ryujinx.Graphics.GAL/Capabilities.cs

@@ -36,6 +36,7 @@ namespace Ryujinx.Graphics.GAL
         public readonly bool SupportsMismatchingViewFormat;
         public readonly bool SupportsMismatchingViewFormat;
         public readonly bool SupportsCubemapView;
         public readonly bool SupportsCubemapView;
         public readonly bool SupportsNonConstantTextureOffset;
         public readonly bool SupportsNonConstantTextureOffset;
+        public readonly bool SupportsQuads;
         public readonly bool SupportsSeparateSampler;
         public readonly bool SupportsSeparateSampler;
         public readonly bool SupportsShaderBallot;
         public readonly bool SupportsShaderBallot;
         public readonly bool SupportsShaderBarrierDivergence;
         public readonly bool SupportsShaderBarrierDivergence;
@@ -93,6 +94,7 @@ namespace Ryujinx.Graphics.GAL
             bool supportsMismatchingViewFormat,
             bool supportsMismatchingViewFormat,
             bool supportsCubemapView,
             bool supportsCubemapView,
             bool supportsNonConstantTextureOffset,
             bool supportsNonConstantTextureOffset,
+            bool supportsQuads,
             bool supportsSeparateSampler,
             bool supportsSeparateSampler,
             bool supportsShaderBallot,
             bool supportsShaderBallot,
             bool supportsShaderBarrierDivergence,
             bool supportsShaderBarrierDivergence,
@@ -146,6 +148,7 @@ namespace Ryujinx.Graphics.GAL
             SupportsMismatchingViewFormat = supportsMismatchingViewFormat;
             SupportsMismatchingViewFormat = supportsMismatchingViewFormat;
             SupportsCubemapView = supportsCubemapView;
             SupportsCubemapView = supportsCubemapView;
             SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset;
             SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset;
+            SupportsQuads = supportsQuads;
             SupportsSeparateSampler = supportsSeparateSampler;
             SupportsSeparateSampler = supportsSeparateSampler;
             SupportsShaderBallot = supportsShaderBallot;
             SupportsShaderBallot = supportsShaderBallot;
             SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence;
             SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence;

+ 12 - 2
src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheGpuAccessor.cs

@@ -18,6 +18,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
         private readonly ShaderSpecializationState _newSpecState;
         private readonly ShaderSpecializationState _newSpecState;
         private readonly int _stageIndex;
         private readonly int _stageIndex;
         private readonly bool _isVulkan;
         private readonly bool _isVulkan;
+        private readonly bool _hasGeometryShader;
+        private readonly bool _supportsQuads;
 
 
         /// <summary>
         /// <summary>
         /// Creates a new instance of the cached GPU state accessor for shader translation.
         /// Creates a new instance of the cached GPU state accessor for shader translation.
@@ -29,6 +31,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
         /// <param name="newSpecState">Shader specialization state of the recompiled shader</param>
         /// <param name="newSpecState">Shader specialization state of the recompiled shader</param>
         /// <param name="counts">Resource counts shared across all shader stages</param>
         /// <param name="counts">Resource counts shared across all shader stages</param>
         /// <param name="stageIndex">Shader stage index</param>
         /// <param name="stageIndex">Shader stage index</param>
+        /// <param name="hasGeometryShader">Indicates if a geometry shader is present</param>
         public DiskCacheGpuAccessor(
         public DiskCacheGpuAccessor(
             GpuContext context,
             GpuContext context,
             ReadOnlyMemory<byte> data,
             ReadOnlyMemory<byte> data,
@@ -36,7 +39,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
             ShaderSpecializationState oldSpecState,
             ShaderSpecializationState oldSpecState,
             ShaderSpecializationState newSpecState,
             ShaderSpecializationState newSpecState,
             ResourceCounts counts,
             ResourceCounts counts,
-            int stageIndex) : base(context, counts, stageIndex)
+            int stageIndex,
+            bool hasGeometryShader) : base(context, counts, stageIndex)
         {
         {
             _data = data;
             _data = data;
             _cb1Data = cb1Data;
             _cb1Data = cb1Data;
@@ -44,6 +48,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
             _newSpecState = newSpecState;
             _newSpecState = newSpecState;
             _stageIndex = stageIndex;
             _stageIndex = stageIndex;
             _isVulkan = context.Capabilities.Api == TargetApi.Vulkan;
             _isVulkan = context.Capabilities.Api == TargetApi.Vulkan;
+            _hasGeometryShader = hasGeometryShader;
+            _supportsQuads = context.Capabilities.SupportsQuads;
 
 
             if (stageIndex == (int)ShaderStage.Geometry - 1)
             if (stageIndex == (int)ShaderStage.Geometry - 1)
             {
             {
@@ -100,7 +106,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
         /// <inheritdoc/>
         /// <inheritdoc/>
         public GpuGraphicsState QueryGraphicsState()
         public GpuGraphicsState QueryGraphicsState()
         {
         {
-            return _oldSpecState.GraphicsState.CreateShaderGraphicsState(!_isVulkan, _isVulkan || _oldSpecState.GraphicsState.YNegateEnabled);
+            return _oldSpecState.GraphicsState.CreateShaderGraphicsState(
+                !_isVulkan,
+                _supportsQuads,
+                _hasGeometryShader,
+                _isVulkan || _oldSpecState.GraphicsState.YNegateEnabled);
         }
         }
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>

+ 1 - 1
src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs

@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
         private const ushort FileFormatVersionMajor = 1;
         private const ushort FileFormatVersionMajor = 1;
         private const ushort FileFormatVersionMinor = 2;
         private const ushort FileFormatVersionMinor = 2;
         private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
         private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
-        private const uint CodeGenVersion = 6577;
+        private const uint CodeGenVersion = 5936;
 
 
         private const string SharedTocFileName = "shared.toc";
         private const string SharedTocFileName = "shared.toc";
         private const string SharedDataFileName = "shared.data";
         private const string SharedDataFileName = "shared.data";

+ 5 - 3
src/Ryujinx.Graphics.Gpu/Shader/DiskCache/ParallelDiskCacheLoader.cs

@@ -601,6 +601,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
 
 
             TargetApi api = _context.Capabilities.Api;
             TargetApi api = _context.Capabilities.Api;
 
 
+            bool hasCachedGs = guestShaders[4].HasValue;
+
             for (int stageIndex = Constants.ShaderStages - 1; stageIndex >= 0; stageIndex--)
             for (int stageIndex = Constants.ShaderStages - 1; stageIndex >= 0; stageIndex--)
             {
             {
                 if (guestShaders[stageIndex + 1].HasValue)
                 if (guestShaders[stageIndex + 1].HasValue)
@@ -610,7 +612,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
                     byte[] guestCode = shader.Code;
                     byte[] guestCode = shader.Code;
                     byte[] cb1Data = shader.Cb1Data;
                     byte[] cb1Data = shader.Cb1Data;
 
 
-                    DiskCacheGpuAccessor gpuAccessor = new(_context, guestCode, cb1Data, specState, newSpecState, counts, stageIndex);
+                    DiskCacheGpuAccessor gpuAccessor = new(_context, guestCode, cb1Data, specState, newSpecState, counts, stageIndex, hasCachedGs);
                     TranslatorContext currentStage = DecodeGraphicsShader(gpuAccessor, api, DefaultFlags, 0);
                     TranslatorContext currentStage = DecodeGraphicsShader(gpuAccessor, api, DefaultFlags, 0);
 
 
                     if (nextStage != null)
                     if (nextStage != null)
@@ -623,7 +625,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
                         byte[] guestCodeA = guestShaders[0].Value.Code;
                         byte[] guestCodeA = guestShaders[0].Value.Code;
                         byte[] cb1DataA = guestShaders[0].Value.Cb1Data;
                         byte[] cb1DataA = guestShaders[0].Value.Cb1Data;
 
 
-                        DiskCacheGpuAccessor gpuAccessorA = new(_context, guestCodeA, cb1DataA, specState, newSpecState, counts, 0);
+                        DiskCacheGpuAccessor gpuAccessorA = new(_context, guestCodeA, cb1DataA, specState, newSpecState, counts, 0, hasCachedGs);
                         translatorContexts[0] = DecodeGraphicsShader(gpuAccessorA, api, DefaultFlags | TranslationFlags.VertexA, 0);
                         translatorContexts[0] = DecodeGraphicsShader(gpuAccessorA, api, DefaultFlags | TranslationFlags.VertexA, 0);
                     }
                     }
 
 
@@ -711,7 +713,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
             GuestCodeAndCbData shader = guestShaders[0].Value;
             GuestCodeAndCbData shader = guestShaders[0].Value;
             ResourceCounts counts = new();
             ResourceCounts counts = new();
             ShaderSpecializationState newSpecState = new(ref specState.ComputeState);
             ShaderSpecializationState newSpecState = new(ref specState.ComputeState);
-            DiskCacheGpuAccessor gpuAccessor = new(_context, shader.Code, shader.Cb1Data, specState, newSpecState, counts, 0);
+            DiskCacheGpuAccessor gpuAccessor = new(_context, shader.Code, shader.Cb1Data, specState, newSpecState, counts, 0, false);
             gpuAccessor.InitializeReservedCounts(tfEnabled: false, vertexAsCompute: false);
             gpuAccessor.InitializeReservedCounts(tfEnabled: false, vertexAsCompute: false);
 
 
             TranslatorContext translatorContext = DecodeComputeShader(gpuAccessor, _context.Capabilities.Api, 0);
             TranslatorContext translatorContext = DecodeComputeShader(gpuAccessor, _context.Capabilities.Api, 0);

+ 17 - 3
src/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs

@@ -17,6 +17,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
         private readonly int _stageIndex;
         private readonly int _stageIndex;
         private readonly bool _compute;
         private readonly bool _compute;
         private readonly bool _isVulkan;
         private readonly bool _isVulkan;
+        private readonly bool _hasGeometryShader;
+        private readonly bool _supportsQuads;
 
 
         /// <summary>
         /// <summary>
         /// Creates a new instance of the GPU state accessor for graphics shader translation.
         /// Creates a new instance of the GPU state accessor for graphics shader translation.
@@ -25,12 +27,20 @@ namespace Ryujinx.Graphics.Gpu.Shader
         /// <param name="channel">GPU channel</param>
         /// <param name="channel">GPU channel</param>
         /// <param name="state">Current GPU state</param>
         /// <param name="state">Current GPU state</param>
         /// <param name="stageIndex">Graphics shader stage index (0 = Vertex, 4 = Fragment)</param>
         /// <param name="stageIndex">Graphics shader stage index (0 = Vertex, 4 = Fragment)</param>
-        public GpuAccessor(GpuContext context, GpuChannel channel, GpuAccessorState state, int stageIndex) : base(context, state.ResourceCounts, stageIndex)
+        /// <param name="hasGeometryShader">Indicates if a geometry shader is present</param>
+        public GpuAccessor(
+            GpuContext context,
+            GpuChannel channel,
+            GpuAccessorState state,
+            int stageIndex,
+            bool hasGeometryShader) : base(context, state.ResourceCounts, stageIndex)
         {
         {
-            _isVulkan = context.Capabilities.Api == TargetApi.Vulkan;
             _channel = channel;
             _channel = channel;
             _state = state;
             _state = state;
             _stageIndex = stageIndex;
             _stageIndex = stageIndex;
+            _isVulkan = context.Capabilities.Api == TargetApi.Vulkan;
+            _hasGeometryShader = hasGeometryShader;
+            _supportsQuads = context.Capabilities.SupportsQuads;
 
 
             if (stageIndex == (int)ShaderStage.Geometry - 1)
             if (stageIndex == (int)ShaderStage.Geometry - 1)
             {
             {
@@ -105,7 +115,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
         /// <inheritdoc/>
         /// <inheritdoc/>
         public GpuGraphicsState QueryGraphicsState()
         public GpuGraphicsState QueryGraphicsState()
         {
         {
-            return _state.GraphicsState.CreateShaderGraphicsState(!_isVulkan, _isVulkan || _state.GraphicsState.YNegateEnabled);
+            return _state.GraphicsState.CreateShaderGraphicsState(
+                !_isVulkan,
+                _supportsQuads,
+                _hasGeometryShader,
+                _isVulkan || _state.GraphicsState.YNegateEnabled);
         }
         }
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>

+ 9 - 2
src/Ryujinx.Graphics.Gpu/Shader/GpuChannelGraphicsState.cs

@@ -106,8 +106,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
         /// Creates a new graphics state from this state that can be used for shader generation.
         /// Creates a new graphics state from this state that can be used for shader generation.
         /// </summary>
         /// </summary>
         /// <param name="hostSupportsAlphaTest">Indicates if the host API supports alpha test operations</param>
         /// <param name="hostSupportsAlphaTest">Indicates if the host API supports alpha test operations</param>
+        /// <param name="hostSupportsQuads">Indicates if the host API supports quad primitives</param>
+        /// <param name="hasGeometryShader">Indicates if a geometry shader is used</param>
+        /// <param name="originUpperLeft">If true, indicates that the fragment origin is the upper left corner of the viewport, otherwise it is the lower left corner</param>
         /// <returns>GPU graphics state that can be used for shader translation</returns>
         /// <returns>GPU graphics state that can be used for shader translation</returns>
-        public readonly GpuGraphicsState CreateShaderGraphicsState(bool hostSupportsAlphaTest, bool originUpperLeft)
+        public readonly GpuGraphicsState CreateShaderGraphicsState(bool hostSupportsAlphaTest, bool hostSupportsQuads, bool hasGeometryShader, bool originUpperLeft)
         {
         {
             AlphaTestOp alphaTestOp;
             AlphaTestOp alphaTestOp;
 
 
@@ -130,6 +133,9 @@ namespace Ryujinx.Graphics.Gpu.Shader
                 };
                 };
             }
             }
 
 
+            bool isQuad = Topology == PrimitiveTopology.Quads || Topology == PrimitiveTopology.QuadStrip;
+            bool halvePrimitiveId = !hostSupportsQuads && !hasGeometryShader && isQuad;
+
             return new GpuGraphicsState(
             return new GpuGraphicsState(
                 EarlyZForce,
                 EarlyZForce,
                 ConvertToInputTopology(Topology, TessellationMode),
                 ConvertToInputTopology(Topology, TessellationMode),
@@ -149,7 +155,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
                 in FragmentOutputTypes,
                 in FragmentOutputTypes,
                 DualSourceBlendEnable,
                 DualSourceBlendEnable,
                 YNegateEnabled,
                 YNegateEnabled,
-                originUpperLeft);
+                originUpperLeft,
+                halvePrimitiveId);
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 1 - 1
src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs

@@ -339,7 +339,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
 
 
                 if (gpuVa != 0)
                 if (gpuVa != 0)
                 {
                 {
-                    GpuAccessor gpuAccessor = new(_context, channel, gpuAccessorState, stageIndex);
+                    GpuAccessor gpuAccessor = new(_context, channel, gpuAccessorState, stageIndex, addresses.Geometry != 0);
                     TranslatorContext currentStage = DecodeGraphicsShader(gpuAccessor, api, DefaultFlags, gpuVa);
                     TranslatorContext currentStage = DecodeGraphicsShader(gpuAccessor, api, DefaultFlags, gpuVa);
 
 
                     if (nextStage != null)
                     if (nextStage != null)

+ 2 - 1
src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs

@@ -161,6 +161,7 @@ namespace Ryujinx.Graphics.OpenGL
                 supportsBgraFormat: false,
                 supportsBgraFormat: false,
                 supportsR4G4Format: false,
                 supportsR4G4Format: false,
                 supportsR4G4B4A4Format: true,
                 supportsR4G4B4A4Format: true,
+                supportsScaledVertexFormats: true,
                 supportsSnormBufferTextureFormat: false,
                 supportsSnormBufferTextureFormat: false,
                 supports5BitComponentFormat: true,
                 supports5BitComponentFormat: true,
                 supportsSparseBuffer: false,
                 supportsSparseBuffer: false,
@@ -175,7 +176,7 @@ namespace Ryujinx.Graphics.OpenGL
                 supportsMismatchingViewFormat: HwCapabilities.SupportsMismatchingViewFormat,
                 supportsMismatchingViewFormat: HwCapabilities.SupportsMismatchingViewFormat,
                 supportsCubemapView: true,
                 supportsCubemapView: true,
                 supportsNonConstantTextureOffset: HwCapabilities.SupportsNonConstantTextureOffset,
                 supportsNonConstantTextureOffset: HwCapabilities.SupportsNonConstantTextureOffset,
-                supportsScaledVertexFormats: true,
+                supportsQuads: HwCapabilities.SupportsQuads,
                 supportsSeparateSampler: false,
                 supportsSeparateSampler: false,
                 supportsShaderBallot: HwCapabilities.SupportsShaderBallot,
                 supportsShaderBallot: HwCapabilities.SupportsShaderBallot,
                 supportsShaderBarrierDivergence: !(intelWindows || intelUnix),
                 supportsShaderBarrierDivergence: !(intelWindows || intelUnix),

+ 9 - 1
src/Ryujinx.Graphics.Shader/GpuGraphicsState.cs

@@ -102,6 +102,11 @@ namespace Ryujinx.Graphics.Shader
         /// </summary>
         /// </summary>
         public readonly bool OriginUpperLeft;
         public readonly bool OriginUpperLeft;
 
 
+        /// <summary>
+        /// Indicates that the primitive ID values on the shader should be halved due to quad to triangles conversion.
+        /// </summary>
+        public readonly bool HalvePrimitiveId;
+
         /// <summary>
         /// <summary>
         /// Creates a new GPU graphics state.
         /// Creates a new GPU graphics state.
         /// </summary>
         /// </summary>
@@ -124,6 +129,7 @@ namespace Ryujinx.Graphics.Shader
         /// <param name="dualSourceBlendEnable">Indicates whether dual source blend is enabled</param>
         /// <param name="dualSourceBlendEnable">Indicates whether dual source blend is enabled</param>
         /// <param name="yNegateEnabled">Indicates if negation of the viewport Y axis is enabled</param>
         /// <param name="yNegateEnabled">Indicates if negation of the viewport Y axis is enabled</param>
         /// <param name="originUpperLeft">If true, indicates that the fragment origin is the upper left corner of the viewport, otherwise it is the lower left corner</param>
         /// <param name="originUpperLeft">If true, indicates that the fragment origin is the upper left corner of the viewport, otherwise it is the lower left corner</param>
+        /// <param name="halvePrimitiveId">Indicates that the primitive ID values on the shader should be halved due to quad to triangles conversion</param>
         public GpuGraphicsState(
         public GpuGraphicsState(
             bool earlyZForce,
             bool earlyZForce,
             InputTopology topology,
             InputTopology topology,
@@ -143,7 +149,8 @@ namespace Ryujinx.Graphics.Shader
             in Array8<AttributeType> fragmentOutputTypes,
             in Array8<AttributeType> fragmentOutputTypes,
             bool dualSourceBlendEnable,
             bool dualSourceBlendEnable,
             bool yNegateEnabled,
             bool yNegateEnabled,
-            bool originUpperLeft)
+            bool originUpperLeft,
+            bool halvePrimitiveId)
         {
         {
             EarlyZForce = earlyZForce;
             EarlyZForce = earlyZForce;
             Topology = topology;
             Topology = topology;
@@ -164,6 +171,7 @@ namespace Ryujinx.Graphics.Shader
             DualSourceBlendEnable = dualSourceBlendEnable;
             DualSourceBlendEnable = dualSourceBlendEnable;
             YNegateEnabled = yNegateEnabled;
             YNegateEnabled = yNegateEnabled;
             OriginUpperLeft = originUpperLeft;
             OriginUpperLeft = originUpperLeft;
+            HalvePrimitiveId = halvePrimitiveId;
         }
         }
     }
     }
 }
 }

+ 1 - 0
src/Ryujinx.Graphics.Shader/IGpuAccessor.cs

@@ -135,6 +135,7 @@ namespace Ryujinx.Graphics.Shader
                 default,
                 default,
                 false,
                 false,
                 false,
                 false,
+                false,
                 false);
                 false);
         }
         }
 
 

+ 10 - 0
src/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs

@@ -84,6 +84,10 @@ namespace Ryujinx.Graphics.Shader.Instructions
                                 value = context.IConvertU32ToFP32(value);
                                 value = context.IConvertU32ToFP32(value);
                             }
                             }
                         }
                         }
+                        else if (offset == AttributeConsts.PrimitiveId && context.TranslatorContext.Definitions.HalvePrimitiveId)
+                        {
+                            value = context.ShiftRightS32(value, Const(1));
+                        }
 
 
                         context.Copy(Register(rd), value);
                         context.Copy(Register(rd), value);
                     }
                     }
@@ -187,6 +191,12 @@ namespace Ryujinx.Graphics.Shader.Instructions
                         }
                         }
                     }
                     }
                 }
                 }
+                else if (op.Imm10 == AttributeConsts.PrimitiveId && context.TranslatorContext.Definitions.HalvePrimitiveId)
+                {
+                    // If quads are used, but the host does not support them, they need to be converted to triangles.
+                    // Since each quad becomes 2 triangles, we need to compensate here and divide primitive ID by 2.
+                    res = context.ShiftRightS32(res, Const(1));
+                }
                 else if (op.Imm10 == AttributeConsts.FrontFacing && context.TranslatorContext.GpuAccessor.QueryHostHasFrontFacingBug())
                 else if (op.Imm10 == AttributeConsts.FrontFacing && context.TranslatorContext.GpuAccessor.QueryHostHasFrontFacingBug())
                 {
                 {
                     // gl_FrontFacing sometimes has incorrect (flipped) values depending how it is accessed on Intel GPUs.
                     // gl_FrontFacing sometimes has incorrect (flipped) values depending how it is accessed on Intel GPUs.

+ 2 - 2
src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs

@@ -66,9 +66,9 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
 
 
             if (nvHandle.AsgOp is not Operation handleOp ||
             if (nvHandle.AsgOp is not Operation handleOp ||
                 handleOp.Inst != Instruction.Load ||
                 handleOp.Inst != Instruction.Load ||
-                handleOp.StorageKind != StorageKind.Input)
+                (handleOp.StorageKind != StorageKind.Input && handleOp.StorageKind != StorageKind.StorageBuffer))
             {
             {
-                // Right now, we only allow bindless access when the handle comes from a shader input.
+                // Right now, we only allow bindless access when the handle comes from a shader input or storage buffer.
                 // This is an artificial limitation to prevent it from being used in cases where it
                 // This is an artificial limitation to prevent it from being used in cases where it
                 // would have a large performance impact of loading all textures in the pool.
                 // would have a large performance impact of loading all textures in the pool.
                 // It might be removed in the future, if we can mitigate the performance impact.
                 // It might be removed in the future, if we can mitigate the performance impact.

+ 2 - 0
src/Ryujinx.Graphics.Shader/Translation/ShaderDefinitions.cs

@@ -45,6 +45,8 @@ namespace Ryujinx.Graphics.Shader.Translation
         public bool YNegateEnabled => _graphicsState.YNegateEnabled;
         public bool YNegateEnabled => _graphicsState.YNegateEnabled;
         public bool OriginUpperLeft => _graphicsState.OriginUpperLeft;
         public bool OriginUpperLeft => _graphicsState.OriginUpperLeft;
 
 
+        public bool HalvePrimitiveId => _graphicsState.HalvePrimitiveId;
+
         public ImapPixelType[] ImapTypes { get; }
         public ImapPixelType[] ImapTypes { get; }
         public bool IaIndexing { get; private set; }
         public bool IaIndexing { get; private set; }
         public bool OaIndexing { get; private set; }
         public bool OaIndexing { get; private set; }

+ 2 - 1
src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs

@@ -691,6 +691,7 @@ namespace Ryujinx.Graphics.Vulkan
                 supportsBgraFormat: true,
                 supportsBgraFormat: true,
                 supportsR4G4Format: false,
                 supportsR4G4Format: false,
                 supportsR4G4B4A4Format: supportsR4G4B4A4Format,
                 supportsR4G4B4A4Format: supportsR4G4B4A4Format,
+                supportsScaledVertexFormats: FormatCapabilities.SupportsScaledVertexFormats(),
                 supportsSnormBufferTextureFormat: true,
                 supportsSnormBufferTextureFormat: true,
                 supports5BitComponentFormat: supports5BitComponentFormat,
                 supports5BitComponentFormat: supports5BitComponentFormat,
                 supportsSparseBuffer: features2.Features.SparseBinding && mainQueueProperties.QueueFlags.HasFlag(QueueFlags.SparseBindingBit),
                 supportsSparseBuffer: features2.Features.SparseBinding && mainQueueProperties.QueueFlags.HasFlag(QueueFlags.SparseBindingBit),
@@ -705,7 +706,7 @@ namespace Ryujinx.Graphics.Vulkan
                 supportsMismatchingViewFormat: true,
                 supportsMismatchingViewFormat: true,
                 supportsCubemapView: !IsAmdGcn,
                 supportsCubemapView: !IsAmdGcn,
                 supportsNonConstantTextureOffset: false,
                 supportsNonConstantTextureOffset: false,
-                supportsScaledVertexFormats: FormatCapabilities.SupportsScaledVertexFormats(),
+                supportsQuads: false,
                 supportsSeparateSampler: true,
                 supportsSeparateSampler: true,
                 supportsShaderBallot: false,
                 supportsShaderBallot: false,
                 supportsShaderBarrierDivergence: Vendor != Vendor.Intel,
                 supportsShaderBarrierDivergence: Vendor != Vendor.Intel,