Wednesday, March 2, 2011

Drawing Sprites: Minimizing draw calls

One reason OpenGL is so fast is that it allows applications to provide large chunks of work to be done in parallel. When drawing sprites with WebGL, it's important to make an effort to take advantage of this by minimizing the number of draw calls. This is true with OpenGL, but even more so with WebGL because each draw call requires extra validation.

Unfortunately, minimizing draw calls isn't always easy. It's often impractical or impossible to draw all your geometry at once because the geometry must share the same texture(s). FishIE used a single sprite from the beginning, which made it easy to draw everything at once. If possible, move as many sprites into the same texture as possible and sort or group sprites using the same texture into a single draw call. It may also be possible to use multi-texturing, but depending on the GPU architecture, this can cause all textures to be read for each sprite which will have dramatic impact on performance because of limitations on texture bandwidth.

The performance difference between drawing sprites individually versus all at once can be pretty big. I made another version of the FishIE demo that draws each sprite individually. This version draws 2000 fish at 10fps on my test system, while the original WebGL FishIE can do 4000 fish at 60fps on the same system. Since the same texture is used for all sprites I did not have to rebind the texture for each sprite; doing so would likely decrease performance further.

Designing an application around these limitation can be tricky, but often the application is in a better position to make compromises or take short cuts than a more general Canvas 2D implementation would be.

1 comment:

Ricky said...

Hi! I cannot agree anymore on the draw call batching problem of the HTML5 canvas. Apart from it, I think the drawing any image on the canvas can be slow because of the composition rule requirement.
I suggest to introduce something like canvas.beginLayer() and canvas.endLayer() where all image drawing order in the layer are assumed to be ignored and so they can batched together.

I am implementing a browser specifically for game usage, which I will introduce the above idea in it. You can download a demo of it from
this is the window version (I also have an iOS build), I hope you have VS2008SP1 run-time. Hope you enjoy