Work around unsized array MoltenVK bug, disable bindless if not supported

This commit is contained in:
Gabriel A 2023-11-18 00:42:48 -03:00
parent 764849b05e
commit deb2c9a981
10 changed files with 87 additions and 27 deletions

View file

@ -8,6 +8,7 @@ namespace Ryujinx.Graphics.GAL
public readonly string VendorName;
public readonly bool HasFrontFacingBug;
public readonly bool HasUnsizedDescriptorArrayBug;
public readonly bool HasVectorIndexingBug;
public readonly bool NeedsFragmentOutputSpecialization;
public readonly bool ReduceShaderPrecision;
@ -24,6 +25,7 @@ namespace Ryujinx.Graphics.GAL
public readonly bool SupportsScaledVertexFormats;
public readonly bool SupportsSnormBufferTextureFormat;
public readonly bool Supports5BitComponentFormat;
public readonly bool SupportsBindlessTextures;
public readonly bool SupportsBlendEquationAdvanced;
public readonly bool SupportsFragmentShaderInterlock;
public readonly bool SupportsFragmentShaderOrderingIntel;
@ -64,6 +66,7 @@ namespace Ryujinx.Graphics.GAL
TargetApi api,
string vendorName,
bool hasFrontFacingBug,
bool hasUnsizedDescriptorArrayBug,
bool hasVectorIndexingBug,
bool needsFragmentOutputSpecialization,
bool reduceShaderPrecision,
@ -79,6 +82,7 @@ namespace Ryujinx.Graphics.GAL
bool supportsScaledVertexFormats,
bool supportsSnormBufferTextureFormat,
bool supports5BitComponentFormat,
bool supportsBindlessTextures,
bool supportsBlendEquationAdvanced,
bool supportsFragmentShaderInterlock,
bool supportsFragmentShaderOrderingIntel,
@ -115,6 +119,7 @@ namespace Ryujinx.Graphics.GAL
Api = api;
VendorName = vendorName;
HasFrontFacingBug = hasFrontFacingBug;
HasUnsizedDescriptorArrayBug = hasUnsizedDescriptorArrayBug;
HasVectorIndexingBug = hasVectorIndexingBug;
NeedsFragmentOutputSpecialization = needsFragmentOutputSpecialization;
ReduceShaderPrecision = reduceShaderPrecision;
@ -130,6 +135,7 @@ namespace Ryujinx.Graphics.GAL
SupportsScaledVertexFormats = supportsScaledVertexFormats;
SupportsSnormBufferTextureFormat = supportsSnormBufferTextureFormat;
Supports5BitComponentFormat = supports5BitComponentFormat;
SupportsBindlessTextures = supportsBindlessTextures;
SupportsBlendEquationAdvanced = supportsBlendEquationAdvanced;
SupportsFragmentShaderInterlock = supportsFragmentShaderInterlock;
SupportsFragmentShaderOrderingIntel = supportsFragmentShaderOrderingIntel;

View file

@ -157,6 +157,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
public bool QueryHostHasFrontFacingBug() => _context.Capabilities.HasFrontFacingBug;
public bool QueryHostHasUnsizedDescriptorArrayBug() => _context.Capabilities.HasUnsizedDescriptorArrayBug;
public bool QueryHostHasVectorIndexingBug() => _context.Capabilities.HasVectorIndexingBug;
public int QueryHostStorageBufferOffsetAlignment() => _context.Capabilities.StorageBufferOffsetAlignment;
@ -165,6 +167,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
public bool QueryHostSupportsBgraFormat() => _context.Capabilities.SupportsBgraFormat;
public bool QueryHostSupportsBindlessTextures() => _context.Capabilities.SupportsBindlessTextures;
public bool QueryHostSupportsFragmentShaderInterlock() => _context.Capabilities.SupportsFragmentShaderInterlock;
public bool QueryHostSupportsFragmentShaderOrderingIntel() => _context.Capabilities.SupportsFragmentShaderOrderingIntel;

View file

@ -134,6 +134,7 @@ namespace Ryujinx.Graphics.OpenGL
api: TargetApi.OpenGL,
vendorName: GpuVendor,
hasFrontFacingBug: intelWindows,
hasUnsizedDescriptorArrayBug: false,
hasVectorIndexingBug: amdWindows,
needsFragmentOutputSpecialization: false,
reduceShaderPrecision: false,
@ -148,6 +149,7 @@ namespace Ryujinx.Graphics.OpenGL
supportsR4G4B4A4Format: true,
supportsSnormBufferTextureFormat: false,
supports5BitComponentFormat: true,
supportsBindlessTextures: HwCapabilities.SupportsArbBindlessTexture,
supportsBlendEquationAdvanced: HwCapabilities.SupportsBlendEquationAdvanced,
supportsFragmentShaderInterlock: HwCapabilities.SupportsFragmentShaderInterlock,
supportsFragmentShaderOrderingIntel: HwCapabilities.SupportsFragmentShaderOrdering,

View file

@ -190,7 +190,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
if (sampler.ArraySize == 0)
{
var sampledImageArrayType = context.TypeRuntimeArray(imageTypeForSampler);
var sampledImageArrayType = context.HostCapabilities.HasUnsizedDescriptorArrayBug
? context.TypeArray(imageTypeForSampler, context.Constant(context.TypeU32(), 1))
: context.TypeRuntimeArray(imageTypeForSampler);
sampledImageArrayPointerType = context.TypePointer(StorageClass.UniformConstant, sampledImageArrayType);
}
else if (sampler.ArraySize != 1)
@ -241,7 +243,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
if (image.ArraySize == 0)
{
var imageArrayType = context.TypeRuntimeArray(imageType);
var imageArrayType = context.HostCapabilities.HasUnsizedDescriptorArrayBug
? context.TypeArray(imageType, context.Constant(context.TypeU32(), 1))
: context.TypeRuntimeArray(imageType);
imageArrayPointerType = context.TypePointer(StorageClass.UniformConstant, imageArrayType);
}
else if (image.ArraySize != 1)

View file

@ -195,6 +195,15 @@ namespace Ryujinx.Graphics.Shader
return false;
}
/// <summary>
/// Queries host about the presence of the unsized descriptor array bug.
/// </summary>
/// <returns>True if the bug is present on the host device used, false otherwise</returns>
bool QueryHostHasUnsizedDescriptorArrayBug()
{
return false;
}
/// <summary>
/// Queries host about the presence of the vector indexing bug.
/// </summary>
@ -231,6 +240,15 @@ namespace Ryujinx.Graphics.Shader
return true;
}
/// <summary>
/// Queries host support for accessing bindless textures.
/// </summary>
/// <returns>True if bindless textures are supported, false otherwise</returns>
bool QueryHostSupportsBindlessTextures()
{
return true;
}
/// <summary>
/// Queries host support for fragment shader ordering critical sections on the shader code.
/// </summary>

View file

@ -3,6 +3,7 @@ namespace Ryujinx.Graphics.Shader.Translation
class HostCapabilities
{
public readonly bool ReducedPrecision;
public readonly bool HasUnsizedDescriptorArrayBug;
public readonly bool SupportsFragmentShaderInterlock;
public readonly bool SupportsFragmentShaderOrderingIntel;
public readonly bool SupportsGeometryShaderPassthrough;
@ -13,6 +14,7 @@ namespace Ryujinx.Graphics.Shader.Translation
public HostCapabilities(
bool reducedPrecision,
bool hasUnsizedDescriptorArrayBug,
bool supportsFragmentShaderInterlock,
bool supportsFragmentShaderOrderingIntel,
bool supportsGeometryShaderPassthrough,
@ -22,6 +24,7 @@ namespace Ryujinx.Graphics.Shader.Translation
bool supportsViewportMask)
{
ReducedPrecision = reducedPrecision;
HasUnsizedDescriptorArrayBug = hasUnsizedDescriptorArrayBug;
SupportsFragmentShaderInterlock = supportsFragmentShaderInterlock;
SupportsFragmentShaderOrderingIntel = supportsFragmentShaderOrderingIntel;
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;

View file

@ -195,12 +195,14 @@ namespace Ryujinx.Graphics.Shader.Translation
private void AddBindlessDefinition(int set, int binding, string name, SamplerType samplerType)
{
TextureDefinition definition = new(set, binding, name, samplerType, TextureFormat.Unknown, TextureUsageFlags.None, 0);
Properties.AddOrUpdateTexture(definition, samplerType & ~(SamplerType.Separate | SamplerType.Shadow));
}
private void AddBindlessSeparateDefinition(int set, int binding, string name, SamplerType samplerType)
{
samplerType = (samplerType & ~SamplerType.Shadow) | SamplerType.Separate;
AddBindlessDefinition(set, binding, name, samplerType);
}
@ -212,6 +214,7 @@ namespace Ryujinx.Graphics.Shader.Translation
binding = _gpuAccessor.QueryBindingConstantBuffer(slot);
_cbSlotToBindingMap[slot] = binding;
string slotNumber = slot.ToString(CultureInfo.InvariantCulture);
AddNewConstantBuffer(binding, $"{_stagePrefix}_c{slotNumber}");
}
@ -234,6 +237,7 @@ namespace Ryujinx.Graphics.Shader.Translation
binding = _gpuAccessor.QueryBindingStorageBuffer(slot);
_sbSlotToBindingMap[slot] = binding;
string slotNumber = slot.ToString(CultureInfo.InvariantCulture);
AddNewStorageBuffer(binding, $"{_stagePrefix}_s{slotNumber}");
}

View file

@ -24,7 +24,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
ref context.BindlessTextureFlags,
ref context.BindlessIndexedBuffersMask,
context.BindlessTexturesAllowed,
context.GpuAccessor.QueryTextureBufferIndex());
context.GpuAccessor.QueryTextureBufferIndex(),
context.GpuAccessor.QueryHostSupportsBindlessTextures());
if (prevNode != node)
{
@ -787,7 +788,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
ref BindlessTextureFlags bindlessTextureFlags,
ref uint bindlessIndexedBuffersMask,
bool bindlessTexturesAllowed,
int textureBufferIndex)
int textureBufferIndex,
bool supportsBindlessTextures)
{
if (node.Value is not TextureOperation texOp)
{
@ -796,6 +798,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
// If it's already bindless, then we have nothing to do.
if (texOp.Flags.HasFlag(TextureFlags.Bindless))
{
if (SupportsBindlessAccess(texOp.Type, supportsBindlessTextures))
{
resourceManager.EnsureBindlessBinding(targetApi, texOp.Type, texOp.Inst.IsImage());
@ -809,11 +813,11 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
bindlessTextureFlags |= BindlessTextureFlags.BindlessFull;
return node;
}
else
{
}
// Set any destination operand to zero and remove the texture access.
// This is a case where bindless elimination failed, and we assume
// it's too risky to try using full bindless emulation.
// it's too risky or not possible to try using full bindless emulation.
for (int destIndex = 0; destIndex < texOp.DestsCount; destIndex++)
{
@ -826,7 +830,6 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
return prevNode;
}
}
// If the index is within the host API limits, then we don't need to make it bindless.
int index = resourceManager.FindTextureDescriptorIndex(texOp.Binding);
@ -866,6 +869,17 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
return node;
}
private static bool SupportsBindlessAccess(SamplerType type, bool supportsBindlessTextures)
{
// TODO: Support bindless buffer texture access.
if ((type & SamplerType.Mask) == SamplerType.TextureBuffer)
{
return false;
}
return supportsBindlessTextures;
}
private static bool IsIndexedAccess(
ResourceManager resourceManager,
TextureOperation texOp,

View file

@ -371,6 +371,7 @@ namespace Ryujinx.Graphics.Shader.Translation
var hostCapabilities = new HostCapabilities(
GpuAccessor.QueryHostReducedPrecision(),
GpuAccessor.QueryHostHasUnsizedDescriptorArrayBug(),
GpuAccessor.QueryHostSupportsFragmentShaderInterlock(),
GpuAccessor.QueryHostSupportsFragmentShaderOrderingIntel(),
GpuAccessor.QueryHostSupportsGeometryShaderPassthrough(),

View file

@ -572,10 +572,13 @@ namespace Ryujinx.Graphics.Vulkan
var limits = _physicalDevice.PhysicalDeviceProperties.Limits;
bool supportsDescriptorIndexing = _physicalDevice.IsDeviceExtensionPresent("VK_EXT_descriptor_indexing");
return new Capabilities(
api: TargetApi.Vulkan,
GpuVendor,
hasFrontFacingBug: IsIntelWindows,
hasUnsizedDescriptorArrayBug: IsMoltenVk,
hasVectorIndexingBug: Vendor == Vendor.Qualcomm,
needsFragmentOutputSpecialization: IsMoltenVk,
reduceShaderPrecision: IsMoltenVk,
@ -590,6 +593,7 @@ namespace Ryujinx.Graphics.Vulkan
supportsR4G4B4A4Format: supportsR4G4B4A4Format,
supportsSnormBufferTextureFormat: true,
supports5BitComponentFormat: supports5BitComponentFormat,
supportsBindlessTextures: supportsDescriptorIndexing,
supportsBlendEquationAdvanced: Capabilities.SupportsBlendEquationAdvanced,
supportsFragmentShaderInterlock: Capabilities.SupportsFragmentShaderInterlock,
supportsFragmentShaderOrderingIntel: false,