6
\$\begingroup\$

In OpenGL 2.0 I can easily make 10,000 draw calls per frame (with state changes in between each call). However, if i try to do this in either OpenGL ES 2.0 or DirectX9 with shaders, my peformance is 1Hz. Is there an inherent different between fixed function and programmable pipeline rendering that requires programmable pipeline to require much fewer draw calls per frame, or is it more likely that I'm just doing something stupid in my code? I thought that most fixed function pipelines were implemented in shaders nowadays anyway, so if it is the case that I have to batch, then how does the fixed function implementation get away with not batching if its really using shaders?

Any "official" resources you could point me to would be great.

\$\endgroup\$
0

2 Answers 2

7
\$\begingroup\$

The fixed function pipeline doesn't involve many changes to shaders (there may even be only a single "fixed function" shader in the driver's fixed-function emulation path; up to the driver how it handles legacy APIs) which are one of the more expensive things to change.

The driver also could be doing a bazillion different things to optimize or not depending on the specific function calls you're using (and even the order you're calling them in). The driver may be internally batching draw calls, for instance, which it doesn't do when shaders are being changed. It may even give you the same performance if you make a minor tweak to how you're doing things.

There are many other variables here, too, of course. You don't list your shaders. Perhaps you have some kind of very bad performance piece of code you've added to a shader that the default ones don't have. Maybe you're using vertex buffers inefficiently. Maybe you're doing one of dozen of things.

You should consider using a tool like Intel GPA or NVPerfHud to track this down.

\$\endgroup\$
1
\$\begingroup\$

I would add to this that using client memory to store your vertices is potentially more detrimental to performance than the number of draw calls. The reason for this is that if GL does not have full control over the vertex memory it has to either make a copy of your vertex array every time you draw or synchronize the pipeline (e.g. glDrawArrays (...) will not return until GL finishes using the data). When you use VBOs, GL manages the memory and it knows when the data changes so glDrawArrays (...) can safely be implemented asynchronously / without making an immediate data copy. Hundreds of draw calls using VBO-managed memory can be quicker than a handful of client memory draw calls as a result.

For this reason, immediate mode (which creates new vertex data each time it draws) can actually be more efficient in certain circumstances than using vertex arrays. Granted, using client memory to store vertex arrays has been deprecated for many years as has immediate mode, but since you brought up the fixed-function pipeline it was worth mentioning.


On the DirectX end of things, prior to Windows Vista issuing a draw call would invoke an expensive kernel-mode context switch. This was never an issue in OpenGL, because it always had a user-mode component to its driver, but D3D only gained a user-mode front-end with the introduction of WDDM. D3D10 also shifts the responsibility of resource validation from usage to load-time, so draw calls are even less expensive when you move from D3D9 to D3D10.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .