Search code examples
glsl

Parameter passed in GLSL function not recognized as a constant


I'm doing an exercise in Shader School in which I implement a function that returns the nth power of a matrix. Even when I pass constant parameter n into the following function:

mat2 matrixPower(highp mat2 m, const int n) {
    if(n==0) {
        return mat2(1.0);
    } else {
        mat2 result = m;
        for(int i=1; i < n; ++i) {
            result = result * m;
        }
        return result;
    }
}

I get the following error:

Loop index cannot be compared with non-constant expression

How is this possible?


Solution

  • The keyword const indicates that n is not writable, but it is still a variable and not a constant!
    n varies with the actual parameter to the formal parameter when the function was called.

    Note in Appandix A of The OpenGL ES Shading Language 1.0 are listed possible limitations for OpenGL ES 2.0:

    for loops are supported but with the following restrictions:

    • condition has the form loop_index relational_operator constant_expression
      where relational_operator is one of: > >= < <= == or !=

    In Chapter 5.10 Constant Expressions of The OpenGL ES Shading Language 1.0 is clearly said, that a const function parameter is not a constant expression:

    A constant expression is one of

    • a literal value (e.g., 5 or true)
    • a global or local variable qualified as const excluding function parameters
    • an expression formed by an operator on operands that are constant expressions, including getting an element of a constant vector or a constant matrix, or a field of a constant structure
    • a constructor whose arguments are all constant expressions
    • a built-in function call whose arguments are all constant expressions, with the exception of the texture lookup functions.

    A workaround would be to create a loop which is limited by a constant expression and to break out off the loop with a condition:

    for (int i = 1; i < 10; ++i)
    {
        if ( i >= n )
            break;
        result = result * m;
    }