3

After some searching, it is said that the separated VAOs which shares the exact same shader attribute layouts, merging these into one VAO and put all these datas into one VBO so that I can draw this objects with only one draw call.

This perfectly makes sense, but how about uniform variables? Say that I want to draw tree and ball. these have different count of vertices, have different transform but share exactly the same shader program.

Until now, My program was like

// generate VAOs, called only once

glGenVertexArray(1, &treeVaoId);
// generate VBO and bind tree vertices
// enabled vertex attribute and set it for shader program

glGenVertexArray(1, &ballVaoId);
// repeat for ball


// draw, called each frame

// give the tree's transform to shader as uniform
glDrawArrays(...) // first draw call

// repeat for ball
glDrawArrays(...) // second draw call

And with these vertices to one VAO and VBO, like:

glGenVertexArray(1, &treeBallId);
// generate enough size of VBO and bind tree vertices and ball vertices after it.
// enabled vertex attribute and set it for shader program

// to draw, I have to separately give transform to it's uniform to each tree and ball, but how?
glDrawArrays(...)

Sorry for poor example, but the point is, Is there a way for giving different uniform variable while drawing one VAO? Or, is my approach totally wrong?

MyBug18
  • 2,135
  • 2
  • 11
  • 25
  • You could store the all uniforms in a UBO. Then you need an index into that buffer, either an additional attribute, or you could also look into indirect draw commands. Whether that gives you a better performance than issuing two separate draw calls: Depends on your specific situation. – BDL Jun 19 '21 at 08:42

1 Answers1

4

The purpose of batching is to improve performance by minimizing state changes between draw calls (batching reduces them to 0, since there is nothing between draw calls). However, there are degrees of performance improvement, and not all state changes are equal.

On the scale of the costs of state changes, changing program uniforms is the least expensive state change. That's not to say that it's meaningless, but you should consider how much effort you really want to spend compared to the results you get out of it. Especially if you're not pushing hardware as fast as possible.

VAO changes (non-buffer-only changes, that is) are among the more expensive state changes, so you gained a lot by eliminating them.

As the name suggests, uniform variables cannot be changed from one shader instance to another within a draw call. Even a multi-draw call. But that doesn't mean that there's nothing that can be done.

Multi-draw functionality allows you to issue multiple draw calls in a single function call. These individual draws can get their vertex data from different parts of the vertex and index buffers. What you need is a way to communicate to your vertex shader which draw call it is taking part in, so that it can index an array of some sort to extract that draw call's per-object data.

Semi-recent hardware has access to gl_DrawID, which is the index into a multi-draw command of the particular draw call being executed. The ARB_shader_draw_parameters extension is fairly widely implemented. You can use that index to fetch per-object data from a UBO or SSBO.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982