In GLSL there seems to be linking error of shaders when I try to pass a uniform struct with a sampler2D attribute to a function which is forward declared. The code works if I remove forward declaration and move the function above main. Is this illegal code?
#version 330 core
in vec2 texcoords;
out vec4 color;
struct Material{
sampler2D tex; // Sampler inside a struct
};
uniform Material material;
// Forward Declaration
vec4 add(Material m);
void main() {
color = add(material);
}
// Function Definition
vec4 add(Material m) {
return vec4(texture(m.tex, texcoords));
}
// C++
glUniform1f(glGetUniformLocation(shader, "material.tex"), 0);
glBindTexture(GL_TEXTURE_2D, texture);
EDIT: So after a bit of searching it appears to be a bug in AMD's driver. I personally use ATI Mobility Radeon HD 4670 which is pretty old, but it still runs OpenGL 3.3. On AMD's forums I found a similar post, and so it would be interesting to know how big this is on AMD's graphic cards. Because if you're developing on Intel or NVidia, then how are you to know your shaders won't compile on some AMD's graphic cards? Should we stay safe and not use prototypes on structs with samplers, or even go as far as not putting samplers in struct completely?... It's also worth noting that WebGL doesn't even allow for samplers inside structs.
Error Message:
Vertex shader(s) failed to link, fragment shader(s) failed to link.
unexpected error.
unexpected error.
This actually is not supposed to work because you cannot instantiate a struct that contains an opaque data type (sampler, image, atomic counter). It is acceptable to have a struct with an opaque type as a uniform, but you cannot implement the function add (...)
by passing an instance of Material
.
Variables of opaque types can only be declared in one of two ways. They can be declared at global scope, as a uniform variables. Such variables can be arrays of the opaque type. They can be declared as members of a struct, but if so, then the struct can only be used to declare a uniform variable (or to declare a member of a struct/array that itself a uniform variable). They cannot be part of a buffer-backed interface block or an input/output variable, either directly or indirectly.
// Must be in, because you cannot assign values to an opaque type.
vec4 add (in sampler2D tex) {
return vec4(texture(tex, texcoords));
}
material.tex
uniform:vec4 add (void) {
return vec4(texture(material.tex, texcoords));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With