0
\$\begingroup\$

I am researching about "batching" objects for one big VBO and reduce draw call.

These are what I am doing now:

  1. Create interleaved VBO based on texture or render state (like Blending)

    • So, for example, there will be two separate VBO and draw call if I want only some object has blending
  2. For more batching, add unused vertex data.

    • eg) Object "A" doesn't need to have color data, but I added white empty color, so can be batched in interleaved array
  3. For hiding object, set vertex positions to 0.0. So, stay on the array, but cannot see.

    • eg) if it is quad, set to [0.0, 0.0, 0.0, 0.0]

These are my questions:

  1. Should I create one Giant VBO, and use draw call based on offset??

    • If I do that, then is there any limitation on glbufferData?? (or performance drop, if too much data in)
    • Is there any method that vbo can contain different types of interleaved vertex?
    • Is multiple "offset" draw call not affect performance unlike single draw call?
  2. Should I bind multiple texture atlas to each unit, and use uniform?

    • Currently, I am only binding one texture per draw.
  3. Is there correct way for above #3 method?? (Feels like not correct)

  4. I am updating "All" vertices every frame, even though some object doesn't need to be updated. (glBufferData) Should I do multiple update call??

Sorry for my wording, but please point me anything that I am doing something wrong.

Thank you.

\$\endgroup\$
  • \$\begingroup\$ Whats your frame-time with "normal" rendering using separate draw calls? \$\endgroup\$ – Maik Semder Sep 10 '13 at 8:02
  • \$\begingroup\$ I am getting solid 60. but because it is small game. and while implementing, I feels like it doesnt optimized enough \$\endgroup\$ – PowerDDang Sep 10 '13 at 16:15
1
\$\begingroup\$

Should I create one Giant VBO, and use draw call based on offset??

Maybe. Try it that way and any other way that works for you on your target hardware. What works best in this regard can vary quite a bit with target hardware and driver version. "Giant" is a bit of a relative term, too. There's a big difference between 1,000 objects, 50,000 objects, and 1 million objects. Your definition of "giant" may not be all that big to the hardware, or it might be way too big. Depends on the hardware.

If I do that, then is there any limitation on glbufferData?? (or performance drop, if too much data in)

There is a limit, and particularly large updates can be slower than smaller incremental updates, though making a ton of small updates can be slower than making one big update. Whether it's faster to use a single array and update it with glBufferSubData or multiple VBOs can, again, vary by hardware and driver.

Is there any method that vbo can contain different types of interleaved vertex?

Just append all the vertices of whatever types you want in contiguous chunks in the VBO(s). A VBO is really nothing more than a chunk of memory on the GPU. You can only use a single vertex layout per draw call, however. Nothing stops you from filling up a big VBO with a few thousand Position/Color vertices followed by several thousand Position/TexCoord/Normal vertices, assuming you don't intend to draw them all at the same time. VBO offsets are partly for handling this in the event you think you need it.

Is multiple "offset" draw call not affect performance unlike single draw call?

Again, it'll vary. In theory, it's one less bit of state to switch (VBO bindings) between draw calls which is usually a win, but a particular driver/GPU may be really good at such state changes and have a lot of draw call overhead. It may just be a balancing act on your hardware to find the right trade off between state changes and draw calls, assuming you come even remotely close to stressing the hardware in the first place (and if you don't, just do whatever is simplest and concentrate on more important aspects of your game).

Should I bind multiple texture atlas to each unit, and use uniform?

The uniform approach is unlikely to perform well from my understanding of how most modern GPUs works. Just bind a different texture per batch. It's easier. If unsure... profile on target hardware and find out.

Is there correct way for above #3 method?? (Feels like not correct)

Just don't write the object into the VBO. If you're dynamically updating the whole thing every draw call, just append your "live" objects to the buffer in a loop, and draw the corresponding number of vertices in your draw call. No reason to spend time copying vertices for invisible objects around. You don't need a particular sprite/object to maintain the same position in the VBO with each draw call; the GPU does not know or care what was in the VBO in the previous frame.

index = 0
for each object:
  if object is visible:
    vbo[++index] = object.topleft
    vbo[++index] = object.bottomleft
    vbo[++index] = object.bottomright
    vbo[++index] = object.topright

Note that the "if object is visible" part can be more sophisticated than just checking a visibility flag. If you have a large play area and lots of objects, culling out objects which will be entirely off screen is often beneficial here, and it can be one of the easier parts of the engine to parallelize should you need that performance boost.

Just remember to use a dynamic/streaming (GL_DYNAMIC_DRAW) VBO config.

\$\endgroup\$
  • \$\begingroup\$ Thank you for great explanation! It gives me direction where I should go. \$\endgroup\$ – PowerDDang Sep 10 '13 at 16:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.