PDA

View Full Version : glPrimitiveRestartIndex()



debonair
06-27-2012, 01:06 AM
Hi ,
I am trying to use glPrimitiveRestartIndex() to draw GL_LINES. Here is code :

const GLfloat data[] =
{
-0.9f, -0.6f,
-0.9f, -0.9f,
-0.6f, -0.9f,
-0.6f, -0.6f,

-0.3f,-0.6f,
-0.3f,-0.9f,
0.0f,-0.9f,
0.0f,-0.6f
};

GLuint indices [] = {0, 1, 2, 3 ,666, 4 , 5 ,6 , 7 };

glPrimitiveRestartIndex(666);
glDrawElements(GL_LINES, 9 , GL_UNSIGNED_INT ,(GLvoid *)0);

Now, with this code it draws only 3 parallel lines instead of 4.
But when i increase the count in glDraw to 10, it draws 4 lines correctly. Is it what expected?
When i replace GL_LINES with GL_TRIANGLE_FAN with count=9, it correctly draws 2 quads.

Please let me know where i am going wrong.

Thanks in advance,

mhagain
06-27-2012, 02:04 AM
It doesn't make sense to use primitive restart with lines because each line is a discrete primitive. If you were using GL_LINE_STRIP primitive restart would work well and enable you to begin a new strip on a restart index.

debonair
06-27-2012, 02:23 AM
It doesn't make sense to use primitive restart with lines because each line is a discrete primitive. If you were using GL_LINE_STRIP primitive restart would work well and enable you to begin a new strip on a restart index.

Thanks for reply.. !!
I know this is silly thing.:) but can you tell me whats wrong with it..?
I think it should draw 4 lines with count 9 . Is my driver buggy?

mhagain
06-27-2012, 04:50 AM
Your driver isn't buggy, your code is.

When drawing with GL_LINES, each two verts specifies a line. That is all. Two verts, one line, next two verts, another line. There is no restarting needed. So 0, 1 is a line. 2, 3 is a line. 666 is a restart index but there is no current primitive to restart - the last line has already been completed. 4, 5 should be a line and 6, 7 should be a line, but because you've put that index 666 in there you've screwed up - you're right into undefined behaviour country.

So only use primitive restart with primitives that it makes sense to restart. That's why I mentioned line strip earlier - in a line strip each additional single vert continues the strip from the previous vert. If you want to stop this and begin a new strip, that's when you'd use primitive restart.

Alfonse Reinheart
06-27-2012, 04:34 PM
In addition to what mhagain said, you forgot to enable primitive restarting: `glEnable(GL_PRIMITIVE_RESTART);` Obviously you should disable it when done.

mhagain
06-27-2012, 04:53 PM
In addition to what mhagain said, you forgot to enable primitive restarting: `glEnable(GL_PRIMITIVE_RESTART);` Obviously you should disable it when done.

:) Ahhhh, good catch.

That would make 0, 1 the first line, 2, 3 the next, 666, 4 the third, 5, 6 the fourth and 7 the start of a fifth which is incomplete. Because there is no index 666 in your array (and because hardware T&L is forgiving of this kind of thing) you don't get the third line and hence you only see lines 1, 2 and 4.

I should also note that the original NV primitive restart specifies that it's actually legal to use with all primitive types (even points), which I presume was an accomodation to allow primitive restart to be left constantly enabled and a restart index constantly specified. Not sure if that made it into core, although it's interesting that the D3D equivalent also behaves this way (with the exceptions being that you can't disable it and you're stuck with 0xffff or 0xffffffff as restart indexes).

debonair
06-28-2012, 01:01 AM
:) Ahhhh, good catch.

That would make 0, 1 the first line, 2, 3 the next, 666, 4 the third, 5, 6 the fourth and 7 the start of a fifth which is incomplete. Because there is no index 666 in your array (and because hardware T&L is forgiving of this kind of thing) you don't get the third line and hence you only see lines 1, 2 and 4.

I should also note that the original NV primitive restart specifies that it's actually legal to use with all primitive types (even points), which I presume was an accomodation to allow primitive restart to be left constantly enabled and a restart index constantly specified. Not sure if that made it into core, although it's interesting that the D3D equivalent also behaves this way (with the exceptions being that you can't disable it and you're stuck with 0xffff or 0xffffffff as restart indexes).


I enabled and disabled GL_PRIMITIVE_RESTART after use.

its not particular to any index, i tried with 0xffff 0xffffff 0xffffffff but the result is same in all cases.
Also, i am able to see 1, 2 ,3 lines and not 4th one. after replacing count to 10 it draws 4th but fails while drawing other primitives.
Looks completely alien :(

Ludde
06-28-2012, 02:03 AM
You are sending in "(GLvoid *)0" into glDrawElements, do you use buffer objects?
If not then you should pass in "indices" instead.

mhagain
06-28-2012, 02:05 AM
Please try to understand.

Primitive restart will have no effect when drawing with GL_LINES because each line is it's own primitive.

The first vertex in a line begins the line.
The second vertex in a line ends it.
The next vertex will begin a new line.

Lines restart themselves automatically for you. There is nothing to restart and no need to restart manually. You cannot restart after the first vertex in a line because the line is incomplete. You will draw nothing. You cannot restart after the second vertex in a line because the line is now complete - there is nothing to be restarted.

This has been the way of it since OpenGL 1.0 and what you are trying to do makes no sense.

debonair
06-28-2012, 02:26 AM
Worked perfectly with Nvidia card , previously trying on AMD which looks buggy.

mhagain
06-28-2012, 02:45 AM
More likely the case that NV are considerably more lenient in terms of which kinds of any old rubbish they accept.

If it worked, it worked by accident, not by design. Please - you have a fixation on using primitive restart in a context where it makes no sense. That's the problem, not your driver, and whether it works on one but not another is not relevant.

mbentrup
06-28-2012, 09:30 AM
Even if it makes not much sense to use primitive restart with GL_POINTS or GL_LINES, if the driver doesn't follow the OpenGL spec it is a bug IMHO.

mhagain
06-28-2012, 12:07 PM
Got news for you - no driver fully follows the spec. NV allow things they shouldn't, AMD don't allow things they should and Intel are off on a magical mystery tour of their very own.

Are AMD not following the spec here? I'd suggest that you grab a copy of the spec and read it. The original NV_primitive_restart specifies behaviour with lines/points/etc. The core OpenGL spec does not. So unless the OP is using NV_primitive_restart (and he's not because even the #defined GLenums are different) then nothing is guaranteed - the driver is allowed do whatever the driver writers want.

For reference, here is the complete specification from core for primitive restart:
When one of the Draw* commands transfers a set of generic attribute array elements to the GL, if the index within the vertex arrays corresponding to that set is equal to the primitive restart index, then the GL does not process those elements as a vertex. Instead, it is as if the drawing command ended with the immediately preceding transfer, and another drawing command is immediately started with the same parameters, but only transferring the immediately following element through the end of the originally specified elements.

That is all that drivers are obliged to follow. "It works on NV therefore it must be an AMD bug" is not an explanation - it's undefined behaviour, it's not in the spec, and so what if it works with current NV drivers - they're perfectly allowed to change that behaviour in any hypothetical future driver and they would still be conformant (and speaking of which - in the absence of conformance tests can the spec even be considered anything other than a glorified wishlist?)

Alfonse Reinheart
06-28-2012, 01:41 PM
it's not in the spec

How did you manage to quote the spec and yet not read it? The spec says that the restart settings given by the OP are the exact equivalent to:



glDrawElements(GL_LINES, 4 , GL_UNSIGNED_INT ,(GLvoid *)0);
glDrawElements(GL_LINES, 4 , GL_UNSIGNED_INT ,(GLvoid *)(5 * sizeof(GLuint));


That's how the spec translates it: the same parameters except starting from the next index and continuing to the end.

The spec's language with regard to primitive restarting makes no exceptions for primitive types, geometry shaders, or anything at all. If the above two commands are defined behavior, then according to the spec, it should work. Therefore, if it doesn't, (and everything else is correct), it is a driver bug.


The original NV_primitive_restart specifies behaviour with lines/points/etc.

Really? Where? Search the entire specification (http://www.opengl.org/registry/specs/NV/primitive_restart.txt), and you will find not a single reference to POINTS, LINES, or TRIANGLES. Oh, you'll find discussion in the non-normative parts. IE: the Issues and Overview section. But as previously stated, those are non-normative. They don't actually describe how OpenGL should work under the extension; they're just plain-text information. A summary. It has no impact on what the true behavior will be.

The language for NV_primitive_restart is functionally identical to the core language. The principle difference is how they're specified. As old-school GL functionality, NV_primitive_restart is defined around the immediate mode function glPrimitiveRestartNV. This is how it defines the behavior of the function:


this command is equivalent to a call to End, followed by a call to Begin where the mode argument is the same mode as that used by the previous Begin.

It makes no mention of specific primitives or the behavior thereof. It doesn't need to, because the logic for glEnd and glBegin already covers it. And the array section simply says that reading the restart index functions as if glPrimitiveRestartNV were called (since array rendering is defined in terms of glArrayElement).