OpenGL中匿名结构体Uniform的异常行为及原因咨询
在编写OpenGL代码时,发现使用匿名结构体类型的Uniform存在异常行为:根据Khronos Wiki说明,GLSL不支持匿名结构体,但顶点着色器中创建如下匿名结构体Uniform时编译完全正常:
uniform struct // no name here! compiled fine! { mat4 device; mat4 position; mat3 normal; } uni_transforms;
但当将sampler2D放入匿名结构体Uniform时,虽然着色器编译正常,却无法获取sampler2D的Uniform位置(该Uniform已在着色器中使用,不会被当作未使用丢弃):
uniform struct { sampler2D diffuse; sampler2D specular; sampler2D normal; } uni_textures;
为结构体添加类型名称后,就能正常找到Uniform位置。
测试环境:Windows 10,Intel UHD Graphics 620(i5-8265U);补充:AMD Radeon Graphics(Ryzen 5 5600H)环境下匿名结构体可正常运行(未测试sampler2D场景)。
请问:
- 为何标准禁止却能创建匿名结构体?
- 为何含
sampler2D时无法正常获取位置?
解答
为何标准禁止却能创建匿名结构体?
Khronos官方的GLSL规范明确禁止匿名结构体作为Uniform的类型,但GPU厂商的编译器通常会实现语法兼容扩展——为了适配部分非标准代码或历史遗留写法,会放宽语法检查逻辑,允许这类匿名结构体定义通过编译。不同厂商的编译器实现差异较大:比如AMD的编译器对这类非标准写法支持更宽松,Intel的编译器在处理不含特殊类型(如采样器)的匿名结构体时也能兼容,但这种行为属于未定义行为,规范不保证其在不同平台、不同厂商GPU间的一致性。为何含
sampler2D时无法正常获取位置?
GLSL中的采样器类型(如sampler2D)属于特殊的Uniform对象,它们的存储布局、绑定逻辑和普通Uniform变量(矩阵、向量等)完全不同,需要绑定到纹理单元才能工作。当使用匿名结构体包裹采样器时,Intel的编译器在处理Uniform反射(即通过glGetUniformLocation等API获取变量位置)时存在实现缺陷:编译器虽然能通过语法编译,但没有正确将结构体中的采样器变量注册到Uniform反射系统中,导致应用层无法获取到对应的位置。而给结构体添加类型名称后,编译器能正确识别结构体的布局和成员元数据,从而正常导出采样器的Uniform信息,让应用层可以获取到位置。
内容的提问来源于stack exchange,提问作者postcoital-solitaire

