mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-05-14 17:25:46 +00:00
Add shader non-uniform indexing support (#91)
This PR marks ALL texture indexes as nonuniform to fix an issue with the paths in Tomodachi Life: Living the Dream on AMD cards. It should have a negligible impact on performance (and it should not have an impact at all on NVIDIA cards!) It's caused by what is called 'implicit non-uniform sampler array indexing'. The idea is basically that some GPUs optimize texture lookups from indexed texture arrays, by assuming that you are never going to index different textures within a single workgroup. What this causes is that visual glitch where a subgroup is tasked with rendering a block of the screen, and in the boundaries some cores are indexing the wrong texture. Co-authored-by: AsperTheDog <guillerman0000@gmail.com> Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/91
This commit is contained in:
@@ -42,6 +42,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
public readonly bool SupportsShaderBallot;
|
public readonly bool SupportsShaderBallot;
|
||||||
public readonly bool SupportsShaderBarrierDivergence;
|
public readonly bool SupportsShaderBarrierDivergence;
|
||||||
public readonly bool SupportsShaderFloat64;
|
public readonly bool SupportsShaderFloat64;
|
||||||
|
public readonly bool SupportsShaderNonUniformIndexing;
|
||||||
public readonly bool SupportsTextureGatherOffsets;
|
public readonly bool SupportsTextureGatherOffsets;
|
||||||
public readonly bool SupportsTextureShadowLod;
|
public readonly bool SupportsTextureShadowLod;
|
||||||
public readonly bool SupportsVertexStoreAndAtomics;
|
public readonly bool SupportsVertexStoreAndAtomics;
|
||||||
@@ -110,6 +111,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
bool supportsShaderBallot,
|
bool supportsShaderBallot,
|
||||||
bool supportsShaderBarrierDivergence,
|
bool supportsShaderBarrierDivergence,
|
||||||
bool supportsShaderFloat64,
|
bool supportsShaderFloat64,
|
||||||
|
bool supportsShaderNonUniformIndexing,
|
||||||
bool supportsTextureGatherOffsets,
|
bool supportsTextureGatherOffsets,
|
||||||
bool supportsTextureShadowLod,
|
bool supportsTextureShadowLod,
|
||||||
bool supportsVertexStoreAndAtomics,
|
bool supportsVertexStoreAndAtomics,
|
||||||
@@ -172,6 +174,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
SupportsShaderBallot = supportsShaderBallot;
|
SupportsShaderBallot = supportsShaderBallot;
|
||||||
SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence;
|
SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence;
|
||||||
SupportsShaderFloat64 = supportsShaderFloat64;
|
SupportsShaderFloat64 = supportsShaderFloat64;
|
||||||
|
SupportsShaderNonUniformIndexing = supportsShaderNonUniformIndexing;
|
||||||
SupportsTextureGatherOffsets = supportsTextureGatherOffsets;
|
SupportsTextureGatherOffsets = supportsTextureGatherOffsets;
|
||||||
SupportsTextureShadowLod = supportsTextureShadowLod;
|
SupportsTextureShadowLod = supportsTextureShadowLod;
|
||||||
SupportsVertexStoreAndAtomics = supportsVertexStoreAndAtomics;
|
SupportsVertexStoreAndAtomics = supportsVertexStoreAndAtomics;
|
||||||
|
|||||||
@@ -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 = 7353;
|
private const uint CodeGenVersion = 7354;
|
||||||
|
|
||||||
private const string SharedTocFileName = "shared.toc";
|
private const string SharedTocFileName = "shared.toc";
|
||||||
private const string SharedDataFileName = "shared.data";
|
private const string SharedDataFileName = "shared.data";
|
||||||
|
|||||||
@@ -231,6 +231,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
|
|
||||||
public bool QueryHostSupportsShaderFloat64() => _context.Capabilities.SupportsShaderFloat64;
|
public bool QueryHostSupportsShaderFloat64() => _context.Capabilities.SupportsShaderFloat64;
|
||||||
|
|
||||||
|
public bool QueryHostSupportsShaderNonUniformIndexing() => _context.Capabilities.SupportsShaderNonUniformIndexing;
|
||||||
|
|
||||||
public bool QueryHostSupportsSnormBufferTextureFormat() => _context.Capabilities.SupportsSnormBufferTextureFormat;
|
public bool QueryHostSupportsSnormBufferTextureFormat() => _context.Capabilities.SupportsSnormBufferTextureFormat;
|
||||||
|
|
||||||
public bool QueryHostSupportsTextureGatherOffsets() => _context.Capabilities.SupportsTextureGatherOffsets;
|
public bool QueryHostSupportsTextureGatherOffsets() => _context.Capabilities.SupportsTextureGatherOffsets;
|
||||||
|
|||||||
@@ -184,6 +184,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
supportsShaderBallot: HwCapabilities.SupportsShaderBallot,
|
supportsShaderBallot: HwCapabilities.SupportsShaderBallot,
|
||||||
supportsShaderBarrierDivergence: !(intelWindows || intelUnix),
|
supportsShaderBarrierDivergence: !(intelWindows || intelUnix),
|
||||||
supportsShaderFloat64: true,
|
supportsShaderFloat64: true,
|
||||||
|
supportsShaderNonUniformIndexing: false,
|
||||||
supportsTextureGatherOffsets: true,
|
supportsTextureGatherOffsets: true,
|
||||||
supportsTextureShadowLod: HwCapabilities.SupportsTextureShadowLod,
|
supportsTextureShadowLod: HwCapabilities.SupportsTextureShadowLod,
|
||||||
supportsVertexStoreAndAtomics: true,
|
supportsVertexStoreAndAtomics: true,
|
||||||
|
|||||||
@@ -587,6 +587,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
return OperationResult.Invalid;
|
return OperationResult.Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void MarkNonUniform(CodeGenContext context, SpvInstruction inst)
|
||||||
|
{
|
||||||
|
if (context.HostCapabilities.SupportsShaderNonUniformIndexing)
|
||||||
|
{
|
||||||
|
context.Decorate(inst, Decoration.NonUniform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static OperationResult GenerateImageAtomic(CodeGenContext context, AstOperation operation)
|
private static OperationResult GenerateImageAtomic(CodeGenContext context, AstOperation operation)
|
||||||
{
|
{
|
||||||
AstTextureOperation texOp = (AstTextureOperation)operation;
|
AstTextureOperation texOp = (AstTextureOperation)operation;
|
||||||
@@ -613,6 +621,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
SpvInstruction textureIndex = Src(AggregateType.S32);
|
SpvInstruction textureIndex = Src(AggregateType.S32);
|
||||||
|
|
||||||
image = context.AccessChain(imagePointerType, image, textureIndex);
|
image = context.AccessChain(imagePointerType, image, textureIndex);
|
||||||
|
MarkNonUniform(context, image);
|
||||||
}
|
}
|
||||||
|
|
||||||
int coordsCount = texOp.Type.Dimensions;
|
int coordsCount = texOp.Type.Dimensions;
|
||||||
@@ -683,15 +692,21 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
|
|
||||||
ImageDeclaration declaration = context.Images[texOp.GetTextureSetAndBinding()];
|
ImageDeclaration declaration = context.Images[texOp.GetTextureSetAndBinding()];
|
||||||
SpvInstruction image = declaration.Image;
|
SpvInstruction image = declaration.Image;
|
||||||
|
bool isIndexed = declaration.IsIndexed;
|
||||||
|
|
||||||
if (declaration.IsIndexed)
|
if (isIndexed)
|
||||||
{
|
{
|
||||||
SpvInstruction textureIndex = Src(AggregateType.S32);
|
SpvInstruction textureIndex = Src(AggregateType.S32);
|
||||||
|
|
||||||
image = context.AccessChain(declaration.ImagePointerType, image, textureIndex);
|
image = context.AccessChain(declaration.ImagePointerType, image, textureIndex);
|
||||||
|
MarkNonUniform(context, image);
|
||||||
}
|
}
|
||||||
|
|
||||||
image = context.Load(declaration.ImageType, image);
|
image = context.Load(declaration.ImageType, image);
|
||||||
|
if (isIndexed)
|
||||||
|
{
|
||||||
|
MarkNonUniform(context, image);
|
||||||
|
}
|
||||||
|
|
||||||
int coordsCount = texOp.Type.Dimensions;
|
int coordsCount = texOp.Type.Dimensions;
|
||||||
|
|
||||||
@@ -740,15 +755,21 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
|
|
||||||
ImageDeclaration declaration = context.Images[texOp.GetTextureSetAndBinding()];
|
ImageDeclaration declaration = context.Images[texOp.GetTextureSetAndBinding()];
|
||||||
SpvInstruction image = declaration.Image;
|
SpvInstruction image = declaration.Image;
|
||||||
|
bool isIndexed = declaration.IsIndexed;
|
||||||
|
|
||||||
if (declaration.IsIndexed)
|
if (isIndexed)
|
||||||
{
|
{
|
||||||
SpvInstruction textureIndex = Src(AggregateType.S32);
|
SpvInstruction textureIndex = Src(AggregateType.S32);
|
||||||
|
|
||||||
image = context.AccessChain(declaration.ImagePointerType, image, textureIndex);
|
image = context.AccessChain(declaration.ImagePointerType, image, textureIndex);
|
||||||
|
MarkNonUniform(context, image);
|
||||||
}
|
}
|
||||||
|
|
||||||
image = context.Load(declaration.ImageType, image);
|
image = context.Load(declaration.ImageType, image);
|
||||||
|
if (isIndexed)
|
||||||
|
{
|
||||||
|
MarkNonUniform(context, image);
|
||||||
|
}
|
||||||
|
|
||||||
int coordsCount = texOp.Type.Dimensions;
|
int coordsCount = texOp.Type.Dimensions;
|
||||||
|
|
||||||
@@ -1878,35 +1899,56 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
private static SpvInstruction GenerateSampledImageLoad(CodeGenContext context, AstTextureOperation texOp, SamplerDeclaration declaration, ref int srcIndex)
|
private static SpvInstruction GenerateSampledImageLoad(CodeGenContext context, AstTextureOperation texOp, SamplerDeclaration declaration, ref int srcIndex)
|
||||||
{
|
{
|
||||||
SpvInstruction image = declaration.Image;
|
SpvInstruction image = declaration.Image;
|
||||||
|
bool imageIndexed = declaration.IsIndexed;
|
||||||
|
|
||||||
if (declaration.IsIndexed)
|
if (imageIndexed)
|
||||||
{
|
{
|
||||||
SpvInstruction textureIndex = context.Get(AggregateType.S32, texOp.GetSource(srcIndex++));
|
SpvInstruction textureIndex = context.Get(AggregateType.S32, texOp.GetSource(srcIndex++));
|
||||||
|
|
||||||
image = context.AccessChain(declaration.SampledImagePointerType, image, textureIndex);
|
image = context.AccessChain(declaration.SampledImagePointerType, image, textureIndex);
|
||||||
|
MarkNonUniform(context, image);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (texOp.IsSeparate)
|
if (texOp.IsSeparate)
|
||||||
{
|
{
|
||||||
image = context.Load(declaration.ImageType, image);
|
image = context.Load(declaration.ImageType, image);
|
||||||
|
if (imageIndexed)
|
||||||
|
{
|
||||||
|
MarkNonUniform(context, image);
|
||||||
|
}
|
||||||
|
|
||||||
SamplerDeclaration samplerDeclaration = context.Samplers[texOp.GetSamplerSetAndBinding()];
|
SamplerDeclaration samplerDeclaration = context.Samplers[texOp.GetSamplerSetAndBinding()];
|
||||||
|
|
||||||
SpvInstruction sampler = samplerDeclaration.Image;
|
SpvInstruction sampler = samplerDeclaration.Image;
|
||||||
|
bool samplerIndexed = samplerDeclaration.IsIndexed;
|
||||||
|
|
||||||
if (samplerDeclaration.IsIndexed)
|
if (samplerIndexed)
|
||||||
{
|
{
|
||||||
SpvInstruction samplerIndex = context.Get(AggregateType.S32, texOp.GetSource(srcIndex++));
|
SpvInstruction samplerIndex = context.Get(AggregateType.S32, texOp.GetSource(srcIndex++));
|
||||||
|
|
||||||
sampler = context.AccessChain(samplerDeclaration.SampledImagePointerType, sampler, samplerIndex);
|
sampler = context.AccessChain(samplerDeclaration.SampledImagePointerType, sampler, samplerIndex);
|
||||||
|
MarkNonUniform(context, sampler);
|
||||||
}
|
}
|
||||||
|
|
||||||
sampler = context.Load(samplerDeclaration.ImageType, sampler);
|
sampler = context.Load(samplerDeclaration.ImageType, sampler);
|
||||||
|
if (samplerIndexed)
|
||||||
|
{
|
||||||
|
MarkNonUniform(context, sampler);
|
||||||
|
}
|
||||||
|
|
||||||
image = context.SampledImage(declaration.SampledImageType, image, sampler);
|
image = context.SampledImage(declaration.SampledImageType, image, sampler);
|
||||||
|
if (imageIndexed || samplerIndexed)
|
||||||
|
{
|
||||||
|
MarkNonUniform(context, image);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
image = context.Load(declaration.SampledImageType, image);
|
image = context.Load(declaration.SampledImageType, image);
|
||||||
|
if (imageIndexed)
|
||||||
|
{
|
||||||
|
MarkNonUniform(context, image);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
|
|||||||
@@ -60,6 +60,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
context.AddCapability(Capability.Float64);
|
context.AddCapability(Capability.Float64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parameters.HostCapabilities.SupportsShaderNonUniformIndexing)
|
||||||
|
{
|
||||||
|
context.AddExtension("SPV_EXT_descriptor_indexing");
|
||||||
|
context.AddCapability(Capability.ShaderNonUniform);
|
||||||
|
context.AddCapability(Capability.SampledImageArrayNonUniformIndexing);
|
||||||
|
context.AddCapability(Capability.StorageImageArrayNonUniformIndexing);
|
||||||
|
}
|
||||||
|
|
||||||
if (parameters.Definitions.TransformFeedbackEnabled && parameters.Definitions.LastInVertexPipeline)
|
if (parameters.Definitions.TransformFeedbackEnabled && parameters.Definitions.LastInVertexPipeline)
|
||||||
{
|
{
|
||||||
context.AddCapability(Capability.TransformFeedback);
|
context.AddCapability(Capability.TransformFeedback);
|
||||||
|
|||||||
@@ -336,6 +336,10 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
bool QueryHostSupportsShaderNonUniformIndexing()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queries host GPU support for signed normalized buffer texture formats.
|
/// Queries host GPU support for signed normalized buffer texture formats.
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
public readonly bool SupportsShaderBallot;
|
public readonly bool SupportsShaderBallot;
|
||||||
public readonly bool SupportsShaderBarrierDivergence;
|
public readonly bool SupportsShaderBarrierDivergence;
|
||||||
public readonly bool SupportsShaderFloat64;
|
public readonly bool SupportsShaderFloat64;
|
||||||
|
public readonly bool SupportsShaderNonUniformIndexing;
|
||||||
public readonly bool SupportsTextureShadowLod;
|
public readonly bool SupportsTextureShadowLod;
|
||||||
public readonly bool SupportsViewportMask;
|
public readonly bool SupportsViewportMask;
|
||||||
|
|
||||||
@@ -20,6 +21,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
bool supportsShaderBallot,
|
bool supportsShaderBallot,
|
||||||
bool supportsShaderBarrierDivergence,
|
bool supportsShaderBarrierDivergence,
|
||||||
bool supportsShaderFloat64,
|
bool supportsShaderFloat64,
|
||||||
|
bool supportsShaderNonUniformIndexing,
|
||||||
bool supportsTextureShadowLod,
|
bool supportsTextureShadowLod,
|
||||||
bool supportsViewportMask)
|
bool supportsViewportMask)
|
||||||
{
|
{
|
||||||
@@ -30,6 +32,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
SupportsShaderBallot = supportsShaderBallot;
|
SupportsShaderBallot = supportsShaderBallot;
|
||||||
SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence;
|
SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence;
|
||||||
SupportsShaderFloat64 = supportsShaderFloat64;
|
SupportsShaderFloat64 = supportsShaderFloat64;
|
||||||
|
SupportsShaderNonUniformIndexing = supportsShaderNonUniformIndexing;
|
||||||
SupportsTextureShadowLod = supportsTextureShadowLod;
|
SupportsTextureShadowLod = supportsTextureShadowLod;
|
||||||
SupportsViewportMask = supportsViewportMask;
|
SupportsViewportMask = supportsViewportMask;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -364,6 +364,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
GpuAccessor.QueryHostSupportsShaderBallot(),
|
GpuAccessor.QueryHostSupportsShaderBallot(),
|
||||||
GpuAccessor.QueryHostSupportsShaderBarrierDivergence(),
|
GpuAccessor.QueryHostSupportsShaderBarrierDivergence(),
|
||||||
GpuAccessor.QueryHostSupportsShaderFloat64(),
|
GpuAccessor.QueryHostSupportsShaderFloat64(),
|
||||||
|
GpuAccessor.QueryHostSupportsShaderNonUniformIndexing(),
|
||||||
GpuAccessor.QueryHostSupportsTextureShadowLod(),
|
GpuAccessor.QueryHostSupportsTextureShadowLod(),
|
||||||
GpuAccessor.QueryHostSupportsViewportMask());
|
GpuAccessor.QueryHostSupportsViewportMask());
|
||||||
|
|
||||||
|
|||||||
@@ -494,6 +494,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
UniformBufferStandardLayout = supportedPhysicalDeviceVulkan12Features.UniformBufferStandardLayout,
|
UniformBufferStandardLayout = supportedPhysicalDeviceVulkan12Features.UniformBufferStandardLayout,
|
||||||
UniformAndStorageBuffer8BitAccess = supportedPhysicalDeviceVulkan12Features.UniformAndStorageBuffer8BitAccess,
|
UniformAndStorageBuffer8BitAccess = supportedPhysicalDeviceVulkan12Features.UniformAndStorageBuffer8BitAccess,
|
||||||
StorageBuffer8BitAccess = supportedPhysicalDeviceVulkan12Features.StorageBuffer8BitAccess,
|
StorageBuffer8BitAccess = supportedPhysicalDeviceVulkan12Features.StorageBuffer8BitAccess,
|
||||||
|
ShaderSampledImageArrayNonUniformIndexing = supportedPhysicalDeviceVulkan12Features.ShaderSampledImageArrayNonUniformIndexing,
|
||||||
|
ShaderStorageImageArrayNonUniformIndexing = supportedPhysicalDeviceVulkan12Features.ShaderStorageImageArrayNonUniformIndexing,
|
||||||
};
|
};
|
||||||
|
|
||||||
pExtendedFeatures = &featuresVk12;
|
pExtendedFeatures = &featuresVk12;
|
||||||
|
|||||||
@@ -775,6 +775,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
supportsShaderBallot: false,
|
supportsShaderBallot: false,
|
||||||
supportsShaderBarrierDivergence: Vendor != Vendor.Intel,
|
supportsShaderBarrierDivergence: Vendor != Vendor.Intel,
|
||||||
supportsShaderFloat64: Capabilities.SupportsShaderFloat64,
|
supportsShaderFloat64: Capabilities.SupportsShaderFloat64,
|
||||||
|
supportsShaderNonUniformIndexing:
|
||||||
|
featuresVk12.ShaderSampledImageArrayNonUniformIndexing &&
|
||||||
|
featuresVk12.ShaderStorageImageArrayNonUniformIndexing,
|
||||||
supportsTextureGatherOffsets: features2.Features.ShaderImageGatherExtended && !IsMoltenVk,
|
supportsTextureGatherOffsets: features2.Features.ShaderImageGatherExtended && !IsMoltenVk,
|
||||||
supportsTextureShadowLod: false,
|
supportsTextureShadowLod: false,
|
||||||
supportsVertexStoreAndAtomics: features2.Features.VertexPipelineStoresAndAtomics,
|
supportsVertexStoreAndAtomics: features2.Features.VertexPipelineStoresAndAtomics,
|
||||||
|
|||||||
Reference in New Issue
Block a user