Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
Ask Question
If I setup a custom ascending integer drawID vertex buffer stream for per instance data with:
glVertexAttribDivisor(drawIDVertexStreamIdx, 1)
Using glMultiDrawElementsIndirect() given:
struct DrawElementsIndirectCommand
uint count;
uint instanceCount;
uint firstIndex;
uint baseVertex;
uint baseInstance;
When setting the instanceCount to more than one, I am confused looking at old notes and online about what exactly happens regards the drawID passed to the shader?
If say there are two DrawElementsIndirectCommand records invoked from one glMultiDrawElementsIndirect(), with the first record having an instanceCount of 3, and the second an instanceCount of say 1, what do the instances actually see in the shader? (Assuming the drawID vertex stream contains 0,1,2,3 etc)
Are they supposed to see 0,1,2 for the first DrawElementsIndirectCommand record instances, and 3 for the second DrawElementsIndirectCommand record instance?
All the examples I can find online seem to specifically set instanceCount to one and rely on multiple DrawElementsIndirectCommand records which makes me now doubt this understanding is correct?
const int CustomDrawIDIdx = 1;
const int VertexCount = 4;
DrawElementsIndirectCommand drawCallRecords[2] =
{ VertexCount, 3, 0, 0, 0 },
{ VertexCount, 1, 0, 0, 0 },
// Attempt to set up custom drawID from a vertex attribute, where the vertex stream for it is a sequence of integers 0, 1, 2 etc
glVertexAttribIPointer(CustomDrawIDIdx, 1, GL_UNSIGNED_INT, 0, NULL);
glVertexAttribDivisor(CustomDrawIDIdx, 1);
glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, &drawCallRecords, 2, 0);
In the vertex shader:
layout (location = 1) in uint customDrawID;
void main()
bool match = (customDrawID== gl_InstanceID);
So this should cause 4 actual draw calls, as actual draw calls caused by glMultiDrawElementsIndirect() are determined by the number DrawElementsIndirectCommand records and their contained instance counts.
For each draw call gl_InstanceID should start from zero and count up for each instance, but go back to zero after each DrawElementsIndirectCommand record is processed?
So gl_InstanceID should do (0, 1, 2) for drawCallRecords[0], and then (0) for drawCallRecords[1]? What does the customDrawID do?
I am also curious if ARB_shader_draw_parameters on nVidia (GTX1070+) is still not recommended compared to using a custom drawID from a vertex stream?
*** UPDATE to reflect the answer by the very patient and helpful Nicol Bolas:
So given:
DrawElementsIndirectCommand drawCallRecords[2] =
{ VertexCount, 3, 0, 0, 0 },
{ VertexCount, 1, 0, 0, 3 /*baseInstance will push us along in customDrawID vertex stream*/ },
Then customDrawID will then do (0, 1, 2) and (3) across all instances in the multidrawindirect.
Which means that each drawn instance across the TWO draw calls, and the 3 + 1 total instances drawn (3 instances of one 'object', 1 instance of another 'object'), in one multidrawindirect call could reference completely unique transformation matrices for example. And in essence that emulates the functionality of gl_DrawID as long as you keep bumping the baseInstance like that (exclusive sum style) for each DrawElementsIndirectCommand record.
The baseInstance in each DrawElementsIndirectCommand record will push the offset into the customDrawID vertex stream, giving a customDrawID that is unique to each instance across all objects drawn.
–
–
–
So this should cause 4 actual draw calls, as actual draw calls caused by glMultiDrawElementsIndirect() are determined by the number DrawElementsIndirectCommand records and their contained instance counts.
No. Instances and "draw calls" are not the same thing.
A single draw call is defined as if by a call to glDraw*InstancedBaseVertexBaseInstance
; that's what happens when the system reads a single entry from the array of draw data. That single draw call includes all instances. Instancing is a thing that happens within a draw call.
This is also why per-instance values are not guaranteed to be dynamically uniform expressions.
Individual draws within a multi-draw command are, gl_DrawID
aside, completely separate from one another. They do not interact. The values your shader gets for instanced arrays or gl_InstanceID
would be no different from issuing each draw call separately.
Your "custom drawID" is not a draw ID at all; it is an instanced array value. Therefore, it follows the rules of instancing, and cares nothing for which draw call it is in.
Even if the actual array you use to feed customDrawID
is just a zero-based integer index, instances arrays and gl_InstanceID
don't work the same way.
gl_InstanceID
ignores the base instance. Instance arrays do not. As such, the instance value fetched from any instance array will always be offset first by the base instance.
So if you want the customDrawID
for a specific draw call to start from a particular value, then you set baseInstance
to be the instance index of that particular value. So given a zero-based integer index array, if you want a particular draw call to have its first instance receive the customDrawID
value of "3", you set baseInstance
to 3.
–
–
–
–
–
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.