diff --git a/Ryujinx.Graphics.GAL/Capabilities.cs b/Ryujinx.Graphics.GAL/Capabilities.cs
index 78a995542..6e5329b2a 100644
--- a/Ryujinx.Graphics.GAL/Capabilities.cs
+++ b/Ryujinx.Graphics.GAL/Capabilities.cs
@@ -9,6 +9,7 @@ namespace Ryujinx.Graphics.GAL
public bool SupportsImageLoadFormatted { get; }
public bool SupportsMismatchingViewFormat { get; }
public bool SupportsNonConstantTextureOffset { get; }
+ public bool SupportsShaderBallot { get; }
public bool SupportsTextureShadowLod { get; }
public bool SupportsViewportSwizzle { get; }
public bool SupportsIndirectParameters { get; }
@@ -24,6 +25,7 @@ namespace Ryujinx.Graphics.GAL
bool supportsImageLoadFormatted,
bool supportsMismatchingViewFormat,
bool supportsNonConstantTextureOffset,
+ bool supportsShaderBallot,
bool supportsTextureShadowLod,
bool supportsViewportSwizzle,
bool supportsIndirectParameters,
@@ -37,6 +39,7 @@ namespace Ryujinx.Graphics.GAL
SupportsImageLoadFormatted = supportsImageLoadFormatted;
SupportsMismatchingViewFormat = supportsMismatchingViewFormat;
SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset;
+ SupportsShaderBallot = supportsShaderBallot;
SupportsTextureShadowLod = supportsTextureShadowLod;
SupportsViewportSwizzle = supportsViewportSwizzle;
SupportsIndirectParameters = supportsIndirectParameters;
diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
index cda3ecb32..926a673aa 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
@@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
///
/// Version of the codegen (to be changed when codegen or guest format change).
///
- private const ulong ShaderCodeGenVersion = 2613;
+ private const ulong ShaderCodeGenVersion = 2627;
// Progress reporting helpers
private volatile int _shaderCount;
diff --git a/Ryujinx.Graphics.Gpu/Shader/TextureDescriptorCapableGpuAccessor.cs b/Ryujinx.Graphics.Gpu/Shader/TextureDescriptorCapableGpuAccessor.cs
index 7c4eea02f..dfb67f358 100644
--- a/Ryujinx.Graphics.Gpu/Shader/TextureDescriptorCapableGpuAccessor.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/TextureDescriptorCapableGpuAccessor.cs
@@ -47,6 +47,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// True if the GPU and driver supports non-constant texture offsets, false otherwise
public bool QueryHostSupportsNonConstantTextureOffset() => _context.Capabilities.SupportsNonConstantTextureOffset;
+ ///
+ /// Queries host GPU shader ballot support.
+ ///
+ /// True if the GPU and driver supports shader ballot, false otherwise
+ public bool QueryHostSupportsShaderBallot() => _context.Capabilities.SupportsShaderBallot;
+
///
/// Queries host GPU texture shadow LOD support.
///
diff --git a/Ryujinx.Graphics.OpenGL/HwCapabilities.cs b/Ryujinx.Graphics.OpenGL/HwCapabilities.cs
index dd917b7b2..9a62bb2ec 100644
--- a/Ryujinx.Graphics.OpenGL/HwCapabilities.cs
+++ b/Ryujinx.Graphics.OpenGL/HwCapabilities.cs
@@ -11,6 +11,7 @@ namespace Ryujinx.Graphics.OpenGL
private static readonly Lazy _supportsPolygonOffsetClamp = new Lazy(() => HasExtension("GL_EXT_polygon_offset_clamp"));
private static readonly Lazy _supportsQuads = new Lazy(SupportsQuadsCheck);
private static readonly Lazy _supportsSeamlessCubemapPerTexture = new Lazy(() => HasExtension("GL_ARB_seamless_cubemap_per_texture"));
+ private static readonly Lazy _supportsShaderBallot = new Lazy(() => HasExtension("GL_ARB_shader_ballot"));
private static readonly Lazy _supportsTextureShadowLod = new Lazy(() => HasExtension("GL_EXT_texture_shadow_lod"));
private static readonly Lazy _supportsViewportSwizzle = new Lazy(() => HasExtension("GL_NV_viewport_swizzle"));
private static readonly Lazy _supportsIndirectParameters = new Lazy(() => HasExtension("GL_ARB_indirect_parameters"));
@@ -45,6 +46,7 @@ namespace Ryujinx.Graphics.OpenGL
public static bool SupportsPolygonOffsetClamp => _supportsPolygonOffsetClamp.Value;
public static bool SupportsQuads => _supportsQuads.Value;
public static bool SupportsSeamlessCubemapPerTexture => _supportsSeamlessCubemapPerTexture.Value;
+ public static bool SupportsShaderBallot => _supportsShaderBallot.Value;
public static bool SupportsTextureShadowLod => _supportsTextureShadowLod.Value;
public static bool SupportsViewportSwizzle => _supportsViewportSwizzle.Value;
public static bool SupportsIndirectParameters => _supportsIndirectParameters.Value;
diff --git a/Ryujinx.Graphics.OpenGL/Renderer.cs b/Ryujinx.Graphics.OpenGL/Renderer.cs
index 92f650835..768c7450c 100644
--- a/Ryujinx.Graphics.OpenGL/Renderer.cs
+++ b/Ryujinx.Graphics.OpenGL/Renderer.cs
@@ -107,6 +107,7 @@ namespace Ryujinx.Graphics.OpenGL
HwCapabilities.SupportsImageLoadFormatted,
HwCapabilities.SupportsMismatchingViewFormat,
HwCapabilities.SupportsNonConstantTextureOffset,
+ HwCapabilities.SupportsShaderBallot,
HwCapabilities.SupportsTextureShadowLod,
HwCapabilities.SupportsViewportSwizzle,
HwCapabilities.SupportsIndirectParameters,
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
index 7b26801a5..e29ff486c 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
@@ -13,7 +13,17 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
{
context.AppendLine("#version 450 core");
context.AppendLine("#extension GL_ARB_gpu_shader_int64 : enable");
- context.AppendLine("#extension GL_ARB_shader_ballot : enable");
+
+ if (context.Config.GpuAccessor.QueryHostSupportsShaderBallot())
+ {
+ context.AppendLine("#extension GL_ARB_shader_ballot : enable");
+ }
+ else
+ {
+ context.AppendLine("#extension GL_KHR_shader_subgroup_basic : enable");
+ context.AppendLine("#extension GL_KHR_shader_subgroup_ballot : enable");
+ }
+
context.AppendLine("#extension GL_ARB_shader_group_vote : enable");
context.AppendLine("#extension GL_EXT_shader_image_load_formatted : enable");
context.AppendLine("#extension GL_EXT_texture_shadow_lod : enable");
@@ -531,6 +541,17 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
code = code.Replace("$SHARED_MEM$", DefaultNames.SharedMemoryName);
code = code.Replace("$STORAGE_MEM$", OperandManager.GetShaderStagePrefix(context.Config.Stage) + "_" + DefaultNames.StorageNamePrefix);
+ if (context.Config.GpuAccessor.QueryHostSupportsShaderBallot())
+ {
+ code = code.Replace("$SUBGROUP_INVOCATION$", "gl_SubGroupInvocationARB");
+ code = code.Replace("$SUBGROUP_BROADCAST$", "readInvocationARB");
+ }
+ else
+ {
+ code = code.Replace("$SUBGROUP_INVOCATION$", "gl_SubgroupInvocationID");
+ code = code.Replace("$SUBGROUP_BROADCAST$", "subgroupBroadcast");
+ }
+
context.AppendLine(code);
context.AppendLine();
}
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/Shuffle.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/Shuffle.glsl
index cb7c8d435..7cb4764dd 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/Shuffle.glsl
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/Shuffle.glsl
@@ -2,10 +2,10 @@ float Helper_Shuffle(float x, uint index, uint mask, out bool valid)
{
uint clamp = mask & 0x1fu;
uint segMask = (mask >> 8) & 0x1fu;
- uint minThreadId = gl_SubGroupInvocationARB & segMask;
+ uint minThreadId = $SUBGROUP_INVOCATION$ & segMask;
uint maxThreadId = minThreadId | (clamp & ~segMask);
uint srcThreadId = (index & ~segMask) | minThreadId;
valid = srcThreadId <= maxThreadId;
- float v = readInvocationARB(x, srcThreadId);
+ float v = $SUBGROUP_BROADCAST$(x, srcThreadId);
return valid ? v : x;
}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleDown.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleDown.glsl
index 450125501..71d901d5d 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleDown.glsl
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleDown.glsl
@@ -2,10 +2,10 @@ float Helper_ShuffleDown(float x, uint index, uint mask, out bool valid)
{
uint clamp = mask & 0x1fu;
uint segMask = (mask >> 8) & 0x1fu;
- uint minThreadId = gl_SubGroupInvocationARB & segMask;
+ uint minThreadId = $SUBGROUP_INVOCATION$ & segMask;
uint maxThreadId = minThreadId | (clamp & ~segMask);
- uint srcThreadId = gl_SubGroupInvocationARB + index;
+ uint srcThreadId = $SUBGROUP_INVOCATION$ + index;
valid = srcThreadId <= maxThreadId;
- float v = readInvocationARB(x, srcThreadId);
+ float v = $SUBGROUP_BROADCAST$(x, srcThreadId);
return valid ? v : x;
}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleUp.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleUp.glsl
index 0781678a9..ae264d870 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleUp.glsl
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleUp.glsl
@@ -1,9 +1,9 @@
float Helper_ShuffleUp(float x, uint index, uint mask, out bool valid)
{
uint segMask = (mask >> 8) & 0x1fu;
- uint minThreadId = gl_SubGroupInvocationARB & segMask;
- uint srcThreadId = gl_SubGroupInvocationARB - index;
+ uint minThreadId = $SUBGROUP_INVOCATION$ & segMask;
+ uint srcThreadId = $SUBGROUP_INVOCATION$ - index;
valid = int(srcThreadId) >= int(minThreadId);
- float v = readInvocationARB(x, srcThreadId);
+ float v = $SUBGROUP_BROADCAST$(x, srcThreadId);
return valid ? v : x;
}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleXor.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleXor.glsl
index 59db54441..789089d69 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleXor.glsl
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleXor.glsl
@@ -2,10 +2,10 @@ float Helper_ShuffleXor(float x, uint index, uint mask, out bool valid)
{
uint clamp = mask & 0x1fu;
uint segMask = (mask >> 8) & 0x1fu;
- uint minThreadId = gl_SubGroupInvocationARB & segMask;
+ uint minThreadId = $SUBGROUP_INVOCATION$ & segMask;
uint maxThreadId = minThreadId | (clamp & ~segMask);
- uint srcThreadId = gl_SubGroupInvocationARB ^ index;
+ uint srcThreadId = $SUBGROUP_INVOCATION$ ^ index;
valid = srcThreadId <= maxThreadId;
- float v = readInvocationARB(x, srcThreadId);
+ float v = $SUBGROUP_BROADCAST$(x, srcThreadId);
return valid ? v : x;
}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/SwizzleAdd.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/SwizzleAdd.glsl
index 7df3e57fd..ed00dfec9 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/SwizzleAdd.glsl
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/SwizzleAdd.glsl
@@ -2,6 +2,6 @@ float Helper_SwizzleAdd(float x, float y, int mask)
{
vec4 xLut = vec4(1.0, -1.0, 1.0, 0.0);
vec4 yLut = vec4(1.0, 1.0, -1.0, 1.0);
- int lutIdx = mask >> int(gl_SubGroupInvocationARB & 3u) * 2;
+ int lutIdx = mask >> int($SUBGROUP_INVOCATION$ & 3u) * 2;
return x * xLut[lutIdx] + y * yLut[lutIdx];
}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs
index 24d4cabd4..3fa13eb5c 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs
@@ -2,6 +2,7 @@ using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using Ryujinx.Graphics.Shader.StructuredIr;
using System;
+using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenBallot;
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenCall;
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper;
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenMemory;
@@ -75,14 +76,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
}
}
- if (inst == Instruction.Ballot)
- {
- return $"unpackUint2x32({info.OpName}({args})).x";
- }
- else
- {
- return info.OpName + "(" + args + ")";
- }
+ return info.OpName + '(' + args + ')';
}
else if ((info.Type & InstType.Op) != 0)
{
@@ -128,6 +122,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
{
switch (inst)
{
+ case Instruction.Ballot:
+ return Ballot(context, operation);
+
case Instruction.Call:
return Call(context, operation);
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenBallot.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenBallot.cs
new file mode 100644
index 000000000..51e7bd212
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenBallot.cs
@@ -0,0 +1,26 @@
+using Ryujinx.Graphics.Shader.StructuredIr;
+
+using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper;
+using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo;
+
+namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
+{
+ static class InstGenBallot
+ {
+ public static string Ballot(CodeGenContext context, AstOperation operation)
+ {
+ VariableType dstType = GetSrcVarType(operation.Inst, 0);
+
+ string arg = GetSoureExpr(context, operation.GetSource(0), dstType);
+
+ if (context.Config.GpuAccessor.QueryHostSupportsShaderBallot())
+ {
+ return $"unpackUint2x32(ballotARB({arg})).x";
+ }
+ else
+ {
+ return $"subgroupBallot({arg}).x";
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs
index 6f4f0c4e6..424a1c4f0 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs
@@ -25,7 +25,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
Add(Instruction.AtomicXor, InstType.AtomicBinary, "atomicXor");
Add(Instruction.Absolute, InstType.CallUnary, "abs");
Add(Instruction.Add, InstType.OpBinaryCom, "+", 2);
- Add(Instruction.Ballot, InstType.CallUnary, "ballotARB");
+ Add(Instruction.Ballot, InstType.Special);
Add(Instruction.Barrier, InstType.CallNullary, "barrier");
Add(Instruction.BitCount, InstType.CallUnary, "bitCount");
Add(Instruction.BitfieldExtractS32, InstType.CallTernary, "bitfieldExtract");
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
index deea6c721..d35525f90 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
@@ -52,20 +52,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
{ AttributeConsts.FrontFacing, new BuiltInAttribute("gl_FrontFacing", VariableType.Bool) },
// Special.
- { AttributeConsts.FragmentOutputDepth, new BuiltInAttribute("gl_FragDepth", VariableType.F32) },
- { AttributeConsts.ThreadKill, new BuiltInAttribute("gl_HelperInvocation", VariableType.Bool) },
- { AttributeConsts.ThreadIdX, new BuiltInAttribute("gl_LocalInvocationID.x", VariableType.U32) },
- { AttributeConsts.ThreadIdY, new BuiltInAttribute("gl_LocalInvocationID.y", VariableType.U32) },
- { AttributeConsts.ThreadIdZ, new BuiltInAttribute("gl_LocalInvocationID.z", VariableType.U32) },
- { AttributeConsts.CtaIdX, new BuiltInAttribute("gl_WorkGroupID.x", VariableType.U32) },
- { AttributeConsts.CtaIdY, new BuiltInAttribute("gl_WorkGroupID.y", VariableType.U32) },
- { AttributeConsts.CtaIdZ, new BuiltInAttribute("gl_WorkGroupID.z", VariableType.U32) },
- { AttributeConsts.LaneId, new BuiltInAttribute("gl_SubGroupInvocationARB", VariableType.U32) },
- { AttributeConsts.EqMask, new BuiltInAttribute("unpackUint2x32(gl_SubGroupEqMaskARB).x", VariableType.U32) },
- { AttributeConsts.GeMask, new BuiltInAttribute("unpackUint2x32(gl_SubGroupGeMaskARB).x", VariableType.U32) },
- { AttributeConsts.GtMask, new BuiltInAttribute("unpackUint2x32(gl_SubGroupGtMaskARB).x", VariableType.U32) },
- { AttributeConsts.LeMask, new BuiltInAttribute("unpackUint2x32(gl_SubGroupLeMaskARB).x", VariableType.U32) },
- { AttributeConsts.LtMask, new BuiltInAttribute("unpackUint2x32(gl_SubGroupLtMaskARB).x", VariableType.U32) },
+ { AttributeConsts.FragmentOutputDepth, new BuiltInAttribute("gl_FragDepth", VariableType.F32) },
+ { AttributeConsts.ThreadKill, new BuiltInAttribute("gl_HelperInvocation", VariableType.Bool) },
+ { AttributeConsts.ThreadIdX, new BuiltInAttribute("gl_LocalInvocationID.x", VariableType.U32) },
+ { AttributeConsts.ThreadIdY, new BuiltInAttribute("gl_LocalInvocationID.y", VariableType.U32) },
+ { AttributeConsts.ThreadIdZ, new BuiltInAttribute("gl_LocalInvocationID.z", VariableType.U32) },
+ { AttributeConsts.CtaIdX, new BuiltInAttribute("gl_WorkGroupID.x", VariableType.U32) },
+ { AttributeConsts.CtaIdY, new BuiltInAttribute("gl_WorkGroupID.y", VariableType.U32) },
+ { AttributeConsts.CtaIdZ, new BuiltInAttribute("gl_WorkGroupID.z", VariableType.U32) },
+ { AttributeConsts.LaneId, new BuiltInAttribute(null, VariableType.U32) },
+ { AttributeConsts.EqMask, new BuiltInAttribute(null, VariableType.U32) },
+ { AttributeConsts.GeMask, new BuiltInAttribute(null, VariableType.U32) },
+ { AttributeConsts.GtMask, new BuiltInAttribute(null, VariableType.U32) },
+ { AttributeConsts.LeMask, new BuiltInAttribute(null, VariableType.U32) },
+ { AttributeConsts.LtMask, new BuiltInAttribute(null, VariableType.U32) },
// Support uniforms.
{ AttributeConsts.FragmentOutputIsBgraBase + 0, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[0]", VariableType.Bool) },
@@ -149,6 +149,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
public static string GetAttributeName(int value, ShaderConfig config, bool isOutAttr = false, string indexExpr = "0")
{
+ value &= ~3;
char swzMask = GetSwizzleMask((value >> 2) & 3);
if (value >= AttributeConsts.UserAttributeBase && value < AttributeConsts.UserAttributeEnd)
@@ -201,12 +202,35 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
return $"{DefaultNames.OAttributePrefix}{(value >> 4)}.{swzMask}";
}
- else if (_builtInAttributes.TryGetValue(value & ~3, out BuiltInAttribute builtInAttr))
+ else if (_builtInAttributes.TryGetValue(value, out BuiltInAttribute builtInAttr))
{
+ string subgroupMask = value switch
+ {
+ AttributeConsts.EqMask => "Eq",
+ AttributeConsts.GeMask => "Ge",
+ AttributeConsts.GtMask => "Gt",
+ AttributeConsts.LeMask => "Le",
+ AttributeConsts.LtMask => "Lt",
+ _ => null
+ };
+
+ if (subgroupMask != null)
+ {
+ return config.GpuAccessor.QueryHostSupportsShaderBallot()
+ ? $"unpackUint2x32(gl_SubGroup{subgroupMask}MaskARB).x"
+ : $"gl_Subgroup{subgroupMask}Mask.x";
+ }
+ else if (value == AttributeConsts.LaneId)
+ {
+ return config.GpuAccessor.QueryHostSupportsShaderBallot()
+ ? "gl_SubGroupInvocationARB"
+ : "gl_SubgroupInvocationID";
+ }
+
// TODO: There must be a better way to handle this...
if (config.Stage == ShaderStage.Fragment)
{
- switch (value & ~3)
+ switch (value)
{
case AttributeConsts.PositionX: return $"(gl_FragCoord.x / {DefaultNames.SupportBlockRenderScaleName}[0])";
case AttributeConsts.PositionY: return $"(gl_FragCoord.y / {DefaultNames.SupportBlockRenderScaleName}[0])";
diff --git a/Ryujinx.Graphics.Shader/IGpuAccessor.cs b/Ryujinx.Graphics.Shader/IGpuAccessor.cs
index 9ae399f79..a74782c8a 100644
--- a/Ryujinx.Graphics.Shader/IGpuAccessor.cs
+++ b/Ryujinx.Graphics.Shader/IGpuAccessor.cs
@@ -1,6 +1,4 @@
-using Ryujinx.Graphics.Shader.Decoders;
-
-namespace Ryujinx.Graphics.Shader
+namespace Ryujinx.Graphics.Shader
{
public interface IGpuAccessor
{
@@ -76,6 +74,11 @@ namespace Ryujinx.Graphics.Shader
return true;
}
+ bool QueryHostSupportsShaderBallot()
+ {
+ return true;
+ }
+
bool QueryHostSupportsTextureShadowLod()
{
return true;