Jump to content
  • Advertisement
Sign in to follow this  
Zebratov

OpenGL Drawing in one draw call vertex buffer with different programs

This topic is 1469 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all, 

 

I am trying to figure out how to implement the following concept with modern OpenGL API (4.3)

 

I have a vertex buffer which has a regular vertex array, But I need half of its data to process with ShaderProgram A,

and another half - with ShaderProgram B.

 

Currently what I do is creating two different VAOs with vertex attribute pointers pointing to related parts of the vertex array.

But in this case I must issue 2 draw calls -one per VAO.

Can I do it with a single draw call?

 

P.S: I thought of primitive restart,but AFAIK it doesn't switch shaders on each restart.

 

Thanks!

Share this post


Link to post
Share on other sites
Advertisement
Yeah, either you have to combine your shaders (and then only if you can make a shader that will run on GPU efficiently, e.g. with a minimum a branching or dynamic loops), or just suck it up and use two draw calls.

Remember, multiple draw calls _is not a problem_, so long as they don't scale linearly with the number of objects in your scene! You can easily have hundreds of draw calls even on mobile devices. It's better to have a system that always needs 57 draw calls to render any scene (whether it has 1 object or 10,000) than it is to need "only" 1 draw call per object (meaning you'd only ever be able to have a few hundred objects in a scene at once on low-end devices).

Look into instancing or deferred approaches to help ensure you only use one draw call per material to the extent possible.

Share this post


Link to post
Share on other sites

Thanks for the help.

 

And It is possible, using the new 

  • GL_ARB_multi_draw_indirect
  • "Approaching Zero Driver Overhead"

Share this post


Link to post
Share on other sites

Thanks for the help.
 
And It is possible, using the new 

  • GL_ARB_multi_draw_indirect
  • "Approaching Zero Driver Overhead"
Those still have one shader per each draw call.
You can't use two different programs within one call, ever.

Share this post


Link to post
Share on other sites

 

Thanks for the help.
 
And It is possible, using the new 

  • GL_ARB_multi_draw_indirect
  • "Approaching Zero Driver Overhead"
Those still have one shader per each draw call.
You can't use two different programs within one call, ever.

 

By implementing an übershader .. and using shader subroutines, which are the GLSL equivalent of function pointers. These can be formed into arrays and different implementations of the subroutine can have entirely different behavior.

Share this post


Link to post
Share on other sites
That kind of ubershader is still one program though ;-)

Also, I would recommend only ever using that approach if you're desperate to reduce CPU-side overhead. That technique allows you to drastically reduce the amount of gl* calls that the CPU has to make, but it's also likely to cause a huge amount of overhead on the GPU-side - so you're wasting GPU-time in order to gain CPU-time.
If your game is GPU-bound, then you'd be better off making more draw calls with non-uber shaders ;)

Share this post


Link to post
Share on other sites

Currently what I do is creating two different VAOs with vertex attribute pointers pointing to related parts of the vertex array.

 

Just to address this part, you don't need this kind of set up at all.  You can do it with a single VAO and a single set of attrib pointers, but still with two draw calls, so it takes away some of the overhead.

 

So, say you're using glDrawArrays: look at the documentation for that and you'll see that it has a first parameter.  Let's assume that you have 200 vertices, and you want the first 100 drawn with ShaderProgramA, the second 100 with ShaderProgramB.  Your code is:

 

glBindVertexArray (LetsUseASingleVAOHere);

glUseProgram (ShaderProgramA);

glDrawArrays (GL_TRIANGLES, 0, 100);

glUseProgram (ShaderProgramB);

glDrawArrays (GL_TRIANGLES, 100, 100);

 

Similarly with glDrawElements you can see that it has a pointer parameter, (GLvoid *indices), as well as a count parameter, so again rather than using two sets of attrib pointers, you just use a single set and then adjust the parameters of your draw call to specify which range of the buffers to draw.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!