Forward Declaration of Scoped Variables (Uniform Buffer Objects)

I attach two vertex-shaders to my Program Object

Vertex Shader1:


uniform BlockName{
  int varName;
} scopeName;

// ...

in Vertex Shader2, i want to use varName. So i forward declarate it.


uniform int scopeName.varName; // Compile Error: unexpected syntax Error at "."

Edit:
Makes sense, because the compiler doesn’t know about scopeName when compiling Shader2.
But how can i use the scoped uniforms in my second Shader? Can i forward declarate or redeclarate the Scope or the Uniform Buffer?

I didn’t find anything about it in the Uniform_Buffer_Object specification.
(I use a GeForxe GTX 560 with Driver 296.10)

If a symbol, in your case scopeName, has already been declared previously in the same scope (in your case user global scope), you’ll get a conflict. Second, you cannot use the instance name of an interface block in a variable declaration. When the compiler sees somthing like

uniform int scopeName.varName;

it sees the uniform qualifier, than a basic type which lets it know you’re going to define a uniform variable of type int, and then expects an identifier which hasn’t been declared previously. This can either be followed by an assignment or the end of the statement which is the semicolon. Therefore your statement where you select a member of an instance is invalid.

Why is varName at global scope.

In the same shader, it’s because you shift varName from the uniform block out the global scope by using an instance name, in your case scopeName. Therefore scopeName.varName isn’t the same variable as varName.

If you declare a block in one shader and declare a variable in another shader which bears the name of a block variable there is no conflict because VS1 doesn’t know about anthing in VS2. If, however, you declare the following



 uniform Block
 {
   mat3 blockMat;

 };

 

 mat3 blockMat;

then you have the same problem as before. blockMat is declared two times at global scope since no instance name(s) is(are) used for Block which implicitly puts variables from the uniform block at global scope.

Is this expected behavior
Since it’s clearly specified this behaviour is pretty much expected. :slight_smile:

How do I handle Name Conflicts (two scopes that contain the same varName)?

Use instance names or use different variable names.

How can i use the scoped uniforms in my second Shader?

You simply declare the block in both shaders to use the data. Depending on the layout you’re using you’ll have to query the offsets of the uniform block in either shader. If you use layout(std140) you are guaranteed to have to same layout across all shaders. Consult the spec on layouts.

Edit: Btw, in GLSL there is no such thing as a forward declartion in the sense of C++'s forward declaration.

Thanks for your answer and excuse me for editing my initial question (i reformulated it before your answer appeared)

Another sorry for not being clear about my intentions:
In my second shader i want to use the value that is stored inside the UniformBufferObject for varName.

If i omit the instance name (“debugScope”) in my first shader and do something like:

VertexShader1:


uniform BlockName{
  int varName;
};

VertexShader2


uniform int varName;

I can use the uniformBuffers Value for varName in my Shader2. That works for me.
Isn’t this a kind of “forward declaration”, because i say “There will be some uniform called varName, you’ll hear later about that”?!
Or is it just some nasty mixing of uniform declarations and UniformBufferObjects-Internal uniforms?
I couldn’t read something about that in the specification.
But with this “uniform variable names at global scope” everything seems to work. (My “is this expected behavoir” question was meant as
Is it specified, that a variable inside a UniformBlock can be refferred to by another shader by declaring it as a >common uniform< with the same name?”)

Now i want to do the same thing for a scoped UniformBlock (one with instance name “debugScope”).

VertexShader1:


uniform BlockName{
  int varName;
} scopeName;

You simply declare the block in both shaders to use the data

If i redeclare the uniform Block like

VertexShader2


uniform BlockName{
  int varName;
} scopeName;

i get an error C1038: declaration of BlockName conflicts with previous declaration at [Declaration Position in VertexShader1]

Any idea what i am doing wrong?

I can use the uniformBuffers Value for varName in my Shader2. That works for me.

It shouldn’t. As far as GLSL is concerned, it’s nonsense.

If i redeclare the uniform Block like

Then your compiler has a bug in it.

Personally, I would suggest avoiding this multi-shader approach altogether. If you have several strings you want to compile into a vertex shader, then do that by supplying all of them to glShaderSource. Don’t try to link multiple vertex shaders into a program.

Yes, the spec says you can. But most people don’t use this functionality, which means that most implementations of this are not well tested. So you’re more likely to avoid bugs if you don’t do it.

BTW, can you please stop inserting random bold-face text into your posts? We can decide for ourselves what the important words are.

Personally, I would suggest avoiding this multi-shader approach altogether.

Agreed. I actually got that wrong and thought he was talking about seperate programs. Now it makes a lot more sense.

BTW, can you please stop inserting random bold-face text into your posts? We can decide for ourselves what the important words are.

Please stop! You’re making me dizzy… :wink:

Edit:

“Is it specified, that a variable inside a UniformBlock can be refferred to by another shader by declaring it as a >common uniform< with the same name?”

One of the main concepts of uniform blocks is sharing of data across multiple stages (i.e. vertex shader, fragment shader …) of a single shader program and across multiple programs. If you do this in a vertex and a fragment shader



layout(std140) uniform BlockName
{   
  int varName; 
};

you can access varName in both shaders and get the same value. However, if you declare the block in two source files which are to be combined to form a single translation unit, the thing you’re doing right now, you’ll get the redeclaration error.

Personally, I would suggest avoiding this multi-shader approach altogether

Thanks for the Tip. I always thought it would be the cleaner approach.
Perhaps it’s the best solution for me to switch over to the glShaderSource-with-multiple-sources approach.

Thanks again for helping (and sorry for the bolding, i personally prefer it when skimming throug other people’s thread, because to me it looks a bit more structured)

Did i get it right, that then there is no possibility for sharing a uniformBlock’s data across two vertexShaders that are compiled seperately and then linked together?
So i have (don’t dare bolding anymore :dejection: :slight_smile: ) to stick to the “multiple srcs to one compiled shader” solution?

Think about what you just wrote. If you link code together that has two symbols declared with the same name what does that get you? Right, a redeclaration and thus an error. My understanding of the whole thing is, that multiple sources are compiled as a single translation unit. Thus if you use the source file containing the block declaration as the first one in the array used in glShaderSource() and simply refer to block variables somewhere in the second, I think it should work. After all, the source code either has to be merged before compilation or linked together to form valid object code for the vertex stage. The latter is unlikely I suppose.

However, why do you want to use multiple shader sources for the vertex shader in the first place?

If you link code together that has two symbols declared with the same name what does that get you? Right, a redeclaration and thus an error.

Um, no. You can have multiple declarations in different translation units just fine. Both C++ and GLSL allow this. The problem is that his GLSL compiler/linker is broken and not doing what it’s supposed to.

There is no workaround for broken GLSL; you just have to rework your code to use it in a way that works in your environment.

For functions, it works (defining the function in one shader, declaring and using it in another shader of the same type, compiling them separately and then attach both to the program).

If i use glShaderSource with multiple strings (from multiple files), the line-numbers of the error messages from the GLSL-Compiler are from the concatenation of all strings. If i compile the strings separately, i get a sepperate error handling and thus the line numbers start at zero for every string. => Just nicer to debug.

Sad to hear, but thanks for your help.

Um, no. You can have multiple declarations in different translation units just fine. Both C++ and GLSL allow this. The problem is that his GLSL compiler/linker is broken and not doing what it’s supposed to.

I am well aware of that. I shouldn’t have used the term link in the first statement. I actually was thinking about what I clearly stated later, the merging of multiple source strings to form a single translation unit which is substantiated by the quote

In that case there would be multiple declarations of the block. It is beyond me why the option of linking seperate objects isn’t tested well enough since this has been around since 110 (judging from the API ref).

If i use glShaderSource with multiple strings (from multiple files), the line-numbers of the error messages from the GLSL-Compiler are from the concatenation of all strings. If i compile the strings separately, i get a sepperate error handling and thus the line numbers start at zero for every string. => Just nicer to debug.

The NVIDIA driver (at the very least) gives line numbers and shader string indices. It looks something like this: (X)YY, where X is the shader string index and YY is the line number. I’m pretty sure the AMD driver does something similar.

Indeed, this is a required part of the GLSL specification:

Even with the latest nVidia drivers (296.10 and 301.32) i always get “0(XY)” where XY is the line of the concatenation, as you explained in Opengl.org - Multi-string-shaders-compiler-diagnostics-wrong.

So if the pro-way is using multiple strings in glShaderSource, then all the pros have to live with this bug?! :frowning: too bad.

Or did i get something wrong?

Edit:
Just found the "
#line" directive. That should be sufficiant as a workaround.
Thanks again for all answers.

Someone should file a bug with NVIDIA then. Personally, I haven’t needed to use multiple strings, so I assumed that it would actually work.

I think the problem goes further. Except for NVIDIA disregarding the GLSL spec in the above mentioned case the format of diagnostic messages varies across vendors. The differences are manageable but implementing 3 or more special cases (in my case Intel, AMD and NVIDIA) is tedious and there is no guarantee the format is forward compatible. Although this is a minor proposition it could be worthwhile standardizing a common reporting format. Any thoughts on that?

Someone should file a bug with NVIDIA then.

Incidentally, how do you generally submit bugs to NVIDIA? Via the dev forums? Via nvnews.net? Is there a bug tracker somewhere?

In the past, I’ve used their bug form/tracking system on http://nvdeveloper.nvidia.com. Works pretty well, particularly if you include a small repro test program.

Although this is a minor proposition it could be worthwhile standardizing a common reporting format. Any thoughts on that?

It wouldn’t help. The standard already says that it should report the string number of the error. Standardizing it more won’t make NVIDIA suddenly comply.

It wouldn’t help. The standard already says that it should report the string number of the error. Standardizing it more won’t make NVIDIA suddenly comply.

On the count of this particular problem this is probably true. However, just because they don’t report the correct source string ID in their messages that doesn’t mean they’re not able to put out messages in a standardized formatted string. I can’t fathom how sophisticated error reporting is inside GLSL compilers but at some point they’re going to need to write a string somewhere. The general format of that string is what I’d like to see consistent across vendors, regardless of the fact that some information might be incorrect inside that string. As far as I can tell the spec doesn’t say anything about that - just about what should go into a diagnostic message.

Something as simple as

source:[i]line:severity/i:message

or

[i]severity/i:source:line:[i]message

[/i](where message may include the symbol or operation in question. Something like ‘initialize’ in VS)

would do. Very easy to parse and understand and useful if you’re writing tools which need to analyze diagnostic messages beyond printing them to stdout.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.