PDA

View Full Version : Odd issue with gl_InstanceID



skypers
11-05-2011, 10:43 AM
Hey there,

I have a problem with hardware geometry instancing. I'm trying to render two instances of an object. So I send the geometry and the indices to a buffer, create VAO and all the stuff, then I render this way :


glDrawElementsInstanced(P_TRIANGLE, 36, UINT, 0, 2);


P_TRIANGLE and UINT are just part of my framework, it's not a point here. You can see I render 2 instances. Well, here the vertex shader :



#version 150

uniform mat4 projection;
uniform mat4 view;
in vec4 co;

layout (std140) uniform B {
mat4 model[2];
} instance;

vec4 transf() {
return projection * view * instance.model[gl_InstanceID] * co; /* actually fails */

#if 0
if (gl_InstanceID == 0)
return projection * view * instance.model[0] * co;
else if (gl_InstanceID == 1)
return projection * view * instance.model[1] * co;
#endif
}

void main() {
gl_Position = transf();
}

If I render it, I got a really weird static render (though the matrices represents rotations and translations that change along the time ...).

If I comment the return in the transf() function and get the #if/#endif out, all is ok.

Is this a compiler error ? Thanks.

thokra
11-05-2011, 12:18 PM
I'm not even sure why the function works at all when using the if/else if statements. The symbol model2 isn't defined anywhere in the shader (typo perhaps?) and even if you used model[0] or model[1] the compiler is supposed to report an error, because the symbol would still not be defined.

Since you're using a named instance of the interface block B, the correct name can only be instance.model[i]. model2[i] implies an array type declared at global scope.

Please revise and correct the shader code.

skypers
11-05-2011, 12:45 PM
Oh yes sorry, I just mixed some versions of the vertex shader... sorry for that.

thokra
11-05-2011, 04:23 PM
I really don't think the using the instance ID is the issue here. If you can use the ID in an if-statement, it makes absolutely no sense that it would produce different results when used directly.

Just out of curiosity, does anything change when you assign the result directly like this:



gl_Position = projection * view * instance.model[gl_InstanceID] * co;

skypers
11-06-2011, 04:52 AM
Nothing changes thokra. I check all things I can check (compilation state, any OpenGL error, buffer correctly sent, correctly bound, binding point, etc ...), all is ok.

Another thing :

gl_Position = transf();
gl_Position += gl_InstanceID * 10;

This actually works too. I have my two instances drawn. The fact gl_InstanceID can not be used as an array index is really odd (it must be !).

I have the brand new Macbook Pro 15" 2.2GHz, on Mac OSX Lion 10.7.2. I'm gonna try to compile my sample on another platform, see if the issue is driver-related.

thokra
11-06-2011, 07:54 AM
The fact gl_InstanceID can not be used as an array index is really odd (it must be !)


Using it as an index for array lookups is one of proposed use cases. So yes, it has to work.

As for your code, I have absolutely no idead why that works. For the first instance it doesn't do anything and the second alters the w-component thus changing the NDCs which is supposed to yield a differently projected vertex. So, absolutely no idea. :)

Then again, I've never used a Mac before and don't know about conformance and reliability of Apple's drivers.

skypers
11-06-2011, 09:38 AM
Ok new clue. I tried to use simple uniforms (a simple uniform instances[2] in the global uniform bloc and use glUniformMatrix4fv). And here, I can index the instances[2] array with gl_InstanceID, so the problem is within the uniform block.

Once the shaders are compiled and the program linked, I get the index of the uniform block named "B" using glGetUniformBlockIndex. Then I get its size and store it in a variable (even if I don't use it). Then I reserve enough space for storing my two matrices in a buffer. Next, I link the binding point 0 to the buffer location. I bind the uniform block then. In the end, before any call to glDrawElementsInstanced, I send the two matrices to the buffer.

Any new idea ?

EDIT: Oh ! I found it ! Really weird the 0 and 1 work and gl_InstanceID doesn't, but here the thing : I only bound the buffer once (just before the render loop). I thought it was just a link done between the buffer location and the binding point one, but apparently, after the first glDrawElementsInstanced, I have to bind again.

aqnuep
11-07-2011, 01:55 AM
Arrays in uniform block can be indexed with gl_InstanceID as well as with any other dynamic index.

Also, binding a uniform buffer to a binding once should have effect on all subsequent draw commands, unless you replace the binding, of course.

So I think this is is gonna be a bug in the Apple drivers, if I understand you correctly.