AMD锐龙7000核显GLSL宏##运算符编译错误求助
我使用AMD Radeon Graphics(锐龙7000系列)核显开发OpenGL程序,采用GLSL 330版本并启用GL_ARB_shading_language_420pack扩展,但在宏函数里使用##运算符时出现编译错误:
'##' : not supported for these tokens
即便切换到GLSL 420等更高版本,问题依然存在(选用330是为了兼容性)。相同代码在Nvidia、Intel显卡上可正常运行。
最初报错的宏代码
#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 ); \ }
调用方式:
calc_channel( 0 );
修正部分代码后仍报错的情况
把宏中错误的chan_ctrl##0##_alpha_light_enable改为chan_ctrl0_alpha_light_enable后,报错依旧。移除该段代码后,另一个使用##的宏也出现编译问题:
#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 ); \ }
调用方式:
calc_tex_coord( 0 );
报错信息:
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.
预处理器错误地将tex_coord##n##.x和tex_coord##n##.y扩展为tex_coord0nx和tex_coord0ny,而非预期的tex_coord0.x和tex_coord0.y。
补充的详细错误信息(来自AMD Radeon RX 5500 XT)
第一个宏的错误:
Pasting "[" and "0" does not give a valid preprocessing token.
(注:##0##无报错)
第二个宏的错误:
Pasting "tex_coord0" and "." does not give a valid preprocessing token.
问题原因与解决办法
问题根源是AMD的GLSL预处理器对##运算符的实现更严格——GLSL预处理器基于C标准,要求##必须连接合法的预处理记号,而.、[这类标点不属于可拼接的记号元素。
针对第一个宏的修正
cAmbColor[##n]中的##是多余的,直接写成cAmbColor[n]即可,宏参数n会被直接替换为数字,无需拼接:vec3 light_color_rgb = clamp( diffuse_light.rgb + amb_color##n.rgb * cAmbColor[n].rgb, 0.0, 1.0 );- 像
chan_ctrl##n##_color_light_enable、color##n##a##n这类标识符之间的##拼接是合法的,可以保留。
针对第二个宏的修正
tex_coord##n##.x的错误是用##连接了拼接后的标识符和.,这违反了预处理器规则。正确写法是去掉.前的##,直接写成tex_coord##n.x:
#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 ); \ }
通用注意事项
AMD预处理器对##的语法检查比Nvidia/Intel严格,需遵守:
- 仅在标识符片段之间使用
##拼接(比如把chan_ctrl、n、_color_light_enable拼成一个变量名) - 标识符与标点符号(
.、[、]等)之间不能用##,直接书写即可,宏替换后会自动形成合法语法。
内容的提问来源于stack exchange,提问作者AboodXD

