I don't understand how this command structure works. All of it seems to make sense (in the documentation; I haven't actually called the function yet) except for firstIndex. It looks to me as if there is a typo in the documentation, actually.
Here's the text I seem to see in every place where I look for the relevant documentation:
The parameters addressed by indirect are packed into a structure that takes the form (in C):
typedef struct { uint count; uint instanceCount; uint firstIndex; uint baseVertex; uint baseInstance; } DrawElementsIndirectCommand;A single call to glMultiDrawElementsIndirect is equivalent, assuming no errors are generated to:
GLsizei n; for (n = 0; n < drawcount; n++) { const DrawElementsIndirectCommand *cmd; if (stride != 0) { cmd = (const DrawElementsIndirectCommand *)((uintptr)indirect + n * stride); } else { cmd = (const DrawElementsIndirectCommand *)indirect + n; } glDrawElementsInstancedBaseVertexBaseInstance(mode, cmd->count, type, cmd->firstIndex + size-of-type, cmd->instanceCount, cmd->baseVertex, cmd->baseInstance); }
But these pages don't say what "size-of-type" means, or why it is added to firstIndex, rather than being, say, multiplied by it. It appears that glDrawElementsInstancedBaseVertexBaseInstance takes a byte offset there, so it would make sense to me for firstIndex to be the index into the GL_ELEMENT_ARRAY_BUFFER array of vertex indices--so, an index of an index--and for size-of-type to be the size in bytes of a vertex index (4, say), which you'd need there to convert "index into the indices array" into a byte offset into that array.
But... that conversion would be expressed as a multiplication, and they said + not *. :(
Am I right? Is firstIndex the index of an entry in the vertex indices array, and size-of-type the size in bytes of a vertex index, and the + a typo? If not, what am I missing?
This is just a typo in the man page. While the man pages are on the official web site, they are not the official documentation. They fairly often contain errors or omissions.
The official documentation is the spec document. It indeed has a multiplication instead of an addition there. From pages 353/354 of the OpenGL 4.5 spec:
The command
void DrawElementsIndirect( enum mode, enum type, const void *indirect );
is equivalent to
typedef struct {
uint count;
uint instanceCount;
uint firstIndex;
int baseVertex;
uint baseInstance;
} DrawElementsIndirectCommand;
if (no element array buffer is bound) {
generate appropriate error
} else {
DrawElementsIndirectCommand *cmd =
(DrawElementsIndirectCommand *)indirect;
DrawElementsInstancedBaseVertexBaseInstance(mode,
cmd->count, type,
cmd->firstIndex * size-of-type,
cmd->instanceCount, cmd->baseVertex,
cmd->baseInstance);
}
So firstIndex is pretty much what you already guessed. It's an offset into the index buffer (aka element array buffer), very much like the last element of glDrawElements(). The only slight wrinkle is that in this case, the offset is measured in units of indices, while for glDrawElements() it's measured in units of bytes. That's where the multiplication by size-of-type comes in.
For example, say you have an element array buffer containing indices of type GL_UNSIGNED_SHORT. You want your draw command to start using indices from this buffer starting at the 50th index. For glDrawElements(), you would pass in 100 for the last argument, because the offset is in bytes, and each index is two bytes. For the firstIndex value in glDrawElementsIndirect(), you would use 50, because it's measured in indices. The multiplication by size-of-type in the spec, which is 2 in this case, accounts for this difference, saying that the byte offset will be 100 if you set firstIndex to 50, and therefore matches the offset used for glDrawElements().
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With