AMD shader linkage issue

Problem: the GLSL program consisting of the following 2 objects doesn’t link with no reason reported under GL 3.* context:


#version 130
precision lowp float;

struct Spatial	{
	vec4 pos,rot;
};


#version 130
precision lowp float;

struct Spatial	{
	vec4 pos,rot;
};
uniform Spatial bone;

void main()	{
	gl_Position = bone.rot;
}

Environment: Catalyst 9.12, Radeon HD-2400, WinXP SP3

Note 1: both are vertex shaders as I don’t need fragment/geometry processing here, using Transform Feedback.

Note 2: AMD customer support is currently not available

Note 3-historical: it definitely worked on Catalyst 9.10. Then my shaders (not exactly these) started to crash on linking on 9.11. I gave up that time waiting for the 9.12. And now it just fails with no reason…

Two structs with same name?
I think that will cause a naming collision. Because vertex shaders share the same namespace.

  1. Where can I read about the shared namespace?
  2. How can I use the same structure definition across multiple GLSL objects?

Implement your own #include-type mechanism. It doesn’t have to be literally #include. It can be something where you always build a shader by concatenating the same N shader files. E.g.: defines.glsl, state.glsl, shared.glsl, guts.glsl.

You could stick your types in that shared section, so they’re effectively only included once.

Cool, but could you provide an easier workaround?
I’m not trying to do anything wrong according to the spec (and it worked before 9.11 after all).

Are you saying the spec says that duplicate type name definitions are valid, if the definitions are identical?:

struct Spatial { vec4 pos,rot; };
struct Spatial { vec4 pos,rot; };
struct Spatial { vec4 pos,rot; };
struct Spatial { vec4 pos,rot; };
struct Spatial { vec4 pos,rot; };

Spatial my_spatial;

I wasn’t aware of that. At any rate, compiles here with no warnings on NVidia (Cg 2.2.6). Doesn’t help you on ATI though.
In any case, a crash isn’t acceptable. I’d file a bug.

I’m not declaring it twice in a single object. I’m declaring it in each shader object that uses the definition (like in C). I’m not aware of any other way of sharing struct definitions across multiple shader objects.

As I wrote before, AMD developer relations is on holidays until 4th January. I guess all I need is to wait for another driver version (10.1?).

Oh, sorry. Like count0 I misunderstood. Given that, I have no idea why these shouldn’t link. Though I confess to have never driven the fixed-function pipe with GLSL, only Cg.

Maybe it has something to do with the lack of a frag shader. Might try linking it with a pass-through fragment shader and see if that suppresses the driver bug.

Thanks, but it’s the first thing I tried - doesn’t help…

AFAIK, the spec lacks [some] definition about the linking behavior of multiple shader objects, so it is implementation defined.

Probably the implementation has be changed in new Catalyst driver…

I hope next GLSL spec could be specific about linking behavior, and how to share information between multiple shader objects.

It does look a linking bug. The shaders should work and don’t violate the spec as far as I can tell. I’ve forwarded your issue to our compiler team and they’re going to try to reproduce it.

I’ll let you know when we’ve found a solution.

Cheers,

Graham

Thank you, Graham!
I’ve almost lost the hope.
It’s good to have ATI presence on this forum now: the support gets better and I hope to hear less complains about it (and experience less problems myself, of course) in a near future.

While it’s still obvious to me that it’s a bug, I’ve got an official answer from AMD that the driver team doesn’t recognize a bug here. They are just going to report a proper error message instead of fixing the bug itself, pointing me to the spec and NV implementation. Well, both (AMD & NV) are wrong then…

Moreover, I tried to argue about that and didn’t receive any answer. If you think I’m wrong and it’s not really a bug, then tell me why, please. Or better - tell me how to access uniform structs from different shaders in the current AMD/NV implementation.

Catalyst 10.1 changed nothing in this case.
Graham, It would be nice to hear your opinion especially.

Update.
Catalyst 10.2 - no changes with the issue.

As those uniform struct names make a collision, I tried to name them differently in different objects (Spatial,Spatial2,Spatial3). The compiler should be happy as well as the linker, which examines (in theory) just contents of the structure, but not the names. Unfortunately, this workaround doesn’t work:

Fragment shader(s) linked, vertex shader(s) failed to link.
Vertex Shader not supported by HW

Now I know that my 2400 HD radeon suddenly dropped vertex shader support… :slight_smile:

If you have any idea about other possible workarounds - please, tell me.

The compiler should be happy as well as the linker, which examines (in theory) just contents of the structure, but not the names.

Why would it? They’re different types; that’s what having different names mean. C/C++ compilers don’t let you pass a Struct1 to a function taking a Struct2 even if Struct1 and Struct2 just so happen to be identical definitions.

If you have any idea about other possible workarounds - please, tell me.

Stop using shader objects like that. Put everything in one string and compile it into one shader object, and use one shader object per shader stage.

I know the spec says you’re supposed to be able to and everything, but obviously ATI has a few loose ends to tie up with this regard. And since virtually nobody does it this way, it equally obviously isn’t something they test for.

Well, it’s not C/C++ even though the syntax is similar.
When you call glGetUniformLocation, you are not specifying a type. Instead, you are providing a path to a basetype through your structures (like bone[1].pos, where bone is an array of structures).
This makes me feel that GLSL linker doesn’t care about the type name and cares only about the type content (well, it does care about uniform names anyway, so let’s apply this sentence to the shared functions arguments at least).

Stop using shader objects like that. Put everything in one string and compile it into one shader object, and use one shader object per shader stage.

I can’t do it without a major restructurization of the shader system. Just joining the shader sources will invoke name collisions.
I’m using shader objects for the polymorphism implementation: each little shader implements a particular piece of work, then for each ‘virtual bind point’ (function) a proper shader is attached. This provides me with a great shading granularity.
As for my case, what you suggest is to write my own shader preprocessor/compiler between the existing functionality and driver calls. Possible, but it’s a huge amount of work that will not be needed eventually (I hope).

When you call glGetUniformLocation, you are not specifying a type. Instead, you are providing a path to a basetype through your structures (like bone[1].pos, where bone is an array of structures).

True, but:


uniform StructA varName;
uniform StructB varName;

is simply not legitimate code, whether in one file or in several. When the linker goes to put all of the uniforms together, and finds a uniform defined with different types but the same names, it’s going to fail. The GLSL spec requires it; you cannot have the same uniform defined in two different shader objects with different types.

Try compiling this in C/C++:


//header1.h
struct StructA {...};
StructA varName;

//header2.h
struct StructB {...};
StructB varName;

This will fail in C++. If the same source file uses both headers, it will be a compiler error. If two source files include one and the other, it will be a linker error. But it is an error either way.

glGetUniformLocation is irrelevant to this requirement; this is a basic linking issue.

I can’t do it without a major restructurization of the shader system. Just joining the shader sources will invoke name collisions.

It’s up to you. You can rely on functionality that ATI clearly isn’t interested in making work (even if they fix it in 10.3, will they test it extensively in every driver version? Or will a new revision come out that regresses). Or you can do it in a way that you know will actually work.

How much “restructurization” is functioning code worth to you?

Well, I understand clearly that the uniform namespace is per program and we can’t use different type names for the same uniform value.
However, your comparison with C/C++ does not make sense here. The linkers behave differently. For example, in GLSL the following objects link together with no problems:


struct Spatial2	{
	vec4 pos,rot;
};
vec4 myfunc(Spatial2 sp)	{
	return sp.pos;
}


uniform struct Spatial	{
	vec4 pos,rot;
}bone;
vec4 myfunc(Spatial);

void main()	{
	gl_Position = myfunc(bone);
}

It’s not correct in C/C++, but OK for GLSL. As I said before, it doesn’t care much about user type names.

That example was tested with Catalyst 10.2. So maybe I can go around with a little blood drop:
I can use external functions in separate shader objects (yeeehaa!)
I can use basic type uniform across different shader objects.
But I can not use my uniform structures across different objects.

So the workaround may be the following: pass uniform structures as arguments for those external functions - not a big deal actually :slight_smile:

Anyway, thanks for your cooperation, Alfonse!
Dmitry

It’s not correct in C/C++, but OK for GLSL.

No, it’s not. Apparently, the driver in question handles it, but the language says that it shouldn’t. This is simply another place where ATI isn’t following the spec.

I am actually not sure that the shader above should really link, although the type have the same layout, they are different types and the link should report that you have an undefined myFunc(Spatial)

on the original thread, I believe that:

  • in the same shader object, you can’t redeclare the struct
  • in separate objects, you can redeclare the struct. the two don’t have to match unless you have extern declaration

Pierre B.