nonuniformEXT in switch statements

This is a question based on this stackoverflow question I found related to OpenGL

const int numTextures = 2;

uniform sampler2D textures[numTextures];

in vec2 uv;
flat in int tex;
out vec4 colour;

void main(void)
{
    // this caused the compiler error 
        /// "sampler arrays indexed with non-constant expressions"
    // colour = texture( textures[ tex ], uv );

    // hence this (ugh) ...
    switch ( tex ) 
    {
        case 0:
            colour = texture( textures[0], uv );
            break;
        case 1:
            colour = texture( textures[1], uv );
            break;
        default:
            colour = vec4( 0.3f, 0.3f, 0.3f, 1.0f );
            break;
    };
} 

So we know this isn’t legal since the accesses to textures isn’t dynamically uniform
.
In Vulkan we can now do this using nonuniformEXT(). However, would just putting nonuniformEXT() around the integers be correct (i.e texture[nonuniformEXT(0), uv] )? Or must nonuniformEXT() be wrapped around an actually non-uniform variable?
That is, if the array index itself is constant, but the branch that causes the array access to occur is non-uniform, what is the correct way to code that in the shader?
Thanks!

No, that’s legal. It’s perfectly legal to have texture accesses behind non-dynamically-uniform control flow. So long as you provide explicit derivatives if your blending mechanism needs them.

Of course, on old hardware (the code you copied was for OpenGL 3.3; 4.0+ would compile the original code, but it would yield UB if the input were not dynamically uniform), this would almost certainly mean accessing both of the textures and discarding one of the results. But the code itself is valid.

As for nonuniformEXT, it is essentially a property of an expression. An expression is explicitly “nonuniform” if the operands of the expression are explicitly nonuniform or if the result of the expression is explicitly declared to be nonuniform.

You can declare variables that are qualified with nonuniformEXT, so an expression that uses only that variable has this property. Shader stage input variables can be qualified as well. Common math expressions where one operand is nonuniform and the other is not evaluates to being nonuniform.

The result of a function call is nonuniform if its return type is explicitly qualified as such. And so forth.

Constructor syntax for nonuniformEXT is just a convenience feature for when your non-uniform value comes from something that isn’t a variable. A good compiler should make nonuniformEXT(0) into a compilation failure (or at least a warning), since 0 will never actually be non-uniform.

That’s interesting. Assuming derivatives aren’t needed, why isn’t a function with a giant case statement to access sampler2D arrays a more widely used solution to accessing samplers using arbitrary indices? I understand it can be super slow due to all branches evaluating, but just focusing on what’s legal, everything I read about Dynamically Uniform index imply it’s just not something that’s solvable in default GL.

In the OpenGL space, this answers itself: there’s really no point, since you can only have 16 textures per-stage in most hardware.

In Vulkan, the question is irrelevant: even if you ignore the performance implications and derivative issues, you typically use arrays of samplers for when you have a large number of textures, typically 100+. You’re not going to write a switch/case statement for that.

Also, array textures exist, and are serviceable for most cases where you have a legitimate need for dynamic array indices.

Well I disagree that there’s no point. I know I have cases where I want to choose between less than 16 textures dynamically.
Thanks for your answer.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.