Search code examples
openglgpuglslamd-gpu

GLSL Error: '##' : not supported for these tokens


I have an AMD Radeon Graphics (Ryzen 7000) GPU and I am creating a program using OpenGL. I wrote the shaders in GLSL version 330 with the extension GL_ARB_shading_language_420pack enabled. However, when using the ## operator inside a macro function, I receive the following error:

'##' : not supported for these tokens

The problem still persists even if I use a higher GLSL version, such as 420. (I am using 330 for compatibility.)

The code in question:

#define calc_channel( n )                                                                                                                    \
{                                                                                                                                            \
    vec3 enable_light_rgb = vec3( chan_ctrl##n##_color_light_enable, chan_ctrl##n##_color_light_enable, chan_ctrl##n##_color_light_enable ); \
    vec3 light_color_rgb = clamp( diffuse_light.rgb + amb_color##n.rgb * cAmbColor[##n].rgb, 0.0, 1.0 );                                     \
    float light_color_a  = clamp( diffuse_light.a   + amb_color##n.a,                        0.0, 1.0 );                                     \
    color##n##a##n.rgb = chan_ctrl##n##_color.rgb * max( enable_light_rgb, light_color_rgb );                                                \
    color##n##a##n.a   = chan_ctrl##n##_alpha.a   * max( 1.0 - chan_ctrl##0##_alpha_light_enable, light_color_a );                           \
}

Used like this:

calc_channel( 0 );

I use the macro multiple times and not once, hence why it exists. I posted the first occurrence it errors on.
Let me know if any more information is necessary in the comments.

P.S. The code works on other GPUs I have (Nvidia and Intel).

EDIT

You may have noticed the following copy-paste mistake in the macro function above:

chan_ctrl##0##_alpha_light_enable

This is simply a copy-paste mistake, not an error. It is not the source of the problem as the error still occurs even after replacing it with chan_ctrl0_alpha_light_enable.

Interestingly, I tried to remove that entire portion of the shader code to see if the rest would compile, and the compiler still chocked on a different macro function that uses ##, but in a different manner.
The macro function:

#define calc_tex_coord( n )                                        \
{                                                                  \
    expand_tex_func( n );                                          \
    tex_coord##n##.x = dot( expand_tex_mtx( n )[ 0 ], tex_coord ); \
    tex_coord##n##.y = dot( expand_tex_mtx( n )[ 1 ], tex_coord ); \
    float tw         = dot( expand_tex_mtx( n )[ 2 ], tex_coord ); \
}

Used like this:

calc_tex_coord( 0 );

The interesting part is the error I get:

ERROR: 0:355: 'tex_coord0nx' : undeclared identifier
ERROR: 0:355: 'tex_coord0ny' : undeclared identifier
ERROR: 0:355: '' : missing #endif
ERROR: 0:355: '' : compilation terminated
ERROR: 4 compilation errors.  No code generated.

This time, it did not complain about the ## operator. However, it incorrectly expanded the tokens tex_coord##n##.x and tex_coord##n##.y to tex_coord0nx and tex_coord0ny, instead of tex_coord0.x and tex_coord0.y.

EDIT 2

I got a friend with a different Radeon (AMD Radeon RX 5500 XT) and he was able to get more detailed error messages.

For the first macro function, he got:

Pasting "[" and "0" does not give a valid preprocessing token.

(Note that ##0## does not error.)

For the second macro function, it actually pasted the 0 (n) correctly, but still choked on it:

Pasting "tex_coord0" and "." does not give a valid preprocessing token.

Solution

  • Apparently, the AMD preprocessor has an issue with the two following parts:

    • cAmbColor[##n].rgb
    • tex_coord##n##.x

    In the former, it does not like that ## is used after [. In the latter, it does not like that ## is used before ..
    The common property between both is that AMD the preprocessor does not like pasting a macro argument and a symbol that is not valid for identifiers. I do not know much about the GLSL / C standards to tell whether it is correct or wrong to reject this. However, the matter of fact is that the original code works fine on the preprocessors of Nvidia, Intel, and a third proprietary shader compiler. It is solely the AMD preprocessor that complains.