Sign in to follow this  
Nailgun

GLSL: use of shared struct in multiple shaders

Recommended Posts

Nailgun    122
Hi, I am trying to use same struct in two vertex shaders: test1.glsl
struct Transform {
  mat4 p;
  mat4 mvp;
  mat4 mv;
  mat3 n;
};

in vec3 n;
in vec3 v;
uniform Transform transform;

vec4 applyTransform(const vec3 v, const Transform t);

void main()
{
  gl_Position = applyTransform(v, transform);
}

test2.glsl
struct Transform {
  mat4 p;
  mat4 mvp;
  mat4 mv;
  mat3 n;
};

vec4 applyTransform(const vec3 v, const Transform t)
{
  return t.mvp * vec4(v, 1.0);
}

But link fails with message: Fragment shader(s) linked, vertex shader(s) failed to link. ERROR: 1:1: error(#132) Syntax error: 'Transform' parse error ERROR: error(#273) 1 compilation errors. It's strange to see syntax errors at link time. May be this is driver bug? My GPU is radeon.

Share this post


Link to post
Share on other sites
Danny02    279
i never linked to vertex shader together, but are u sure u can do this??
using a function which is defined somewhere else with out a prototype(here in another vs)?


what u try to do is something like "include" but I'm very sure that this isn't possible just put the function and struct definition in your main vertex shader.

When u want to reuse this code in multiple vertex shaders you have to programm your parser to handle such things

Share this post


Link to post
Share on other sites
Nailgun    122
Hmm. glAttachShader man page says "It is permissible to attach multiple shader objects of the same type because each may contain a portion of the complete shader." Moreover shader system acts like C sources, objects and executables. Why I can't define function in one object and use it in another?

However I missed solution to put all sources to one shader object. Thanks for reply.

Share this post


Link to post
Share on other sites
diablos_blade    257
Define the struct in only one source file. When you attach multiple sources it just concatenates them into one before compiling. Which gives you essentially the same behaviour as a #include.

On a side note. Implementing your own #pragma include directive isn't all that hard, std::string handles most of the leg work for you.

Share this post


Link to post
Share on other sites
cgrant    1825
I don't think the const keyword is valid in GLSL although the shader compiler will let you get away with it. As for the struct, I think there may be a naming collision with the variable n. The struct keyword seems to be more of a convenience thing more than anything(provides logical grouping, I could be wrong) but its probably just the same as doing.

mat4 p;
mat4 mvp;
mat4 mv;
mat3 n;

If changing in vec3 n to another variable name makes the shader compile, then it would have proved my point. Everything else looks fine as far as I can see. I've notice that GLSL have issues with non native type uniforms, so if its not a mat,sampler, vec type then it doesn't work.

Share this post


Link to post
Share on other sites
Nailgun    122
applyTransform is just an example. I want to create something like glsl library with common functions that will be used by specific shaders.

Quote:
Original post by diablos_blade
Define the struct in only one source file. When you attach multiple sources it just concatenates them into one before compiling. Which gives you essentially the same behaviour as a #include.


I got it. But this is different approach. In my case I have applyTransform function defined in one shader object that can be included in multiple program objects. This gives a hint to driver that this shader code is shared and it keeps only one copy of a code in memory. It's like .dll or .so.

In you case applyTransform function code will be copied to multiple shader objects which are used in different program objects. Driver doesn't know that applyTransform is same function. This will add undesirable overhead.

For example, this code works as expected:

test1.glsl

in vec3 v;
vec3 shiftPos(vec3 v);
void main()
{
gl_Position = shiftPos(v);
}




test2.glsl

vec3 shiftPos(vec3 v)
{
return v + vec3(0.0, 0.0, 1.0);
}




Imagine that shiftPos is library function, frequently used in almost all shaders. It will be loaded in only one shader object and driver can optimize code memory usage. This shader object will be linked in multiple programs.

My problem is that I can't find a way to pass user-defined structure to library function. To be more precise, I can't make structure to be known to both shaders. When it is included to shader strings for both shader objects, program fails to link.



Quote:
Original post by cgrant
If changing in vec3 n to another variable name makes the shader compile, then it would have proved my point.

I tried this. No change..

Quote:
Original post by cgrant
I've notice that GLSL have issues with non native type uniforms, so if its not a mat,sampler, vec type then it doesn't work.

Even not having the Transform struct as uniform, I can't pass it to function in other shader object.

[Edited by - Nailgun on April 26, 2010 1:28:03 PM]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this