This is a hypothetical question, as I haven't yet come across the problem of making too many draw calls, but for my game I am aware that this could become a potential problem.

The style of my game is similar to an old school top down RPG, except the characters and environment are high resolution and not tile based. With moving characters and objects, different textures and geometries are flitting between layers constantly. It's all in 2D.

Currently I'm finding it very hard to batch anything. As I understand, batching requires that multiple geometries appear at the same depth with the same texture. Unfortunately, this doesn't leave me many opportunities to batch. Also consider the high resolution of the textures does not allow me put everything in a single spritesheet, and the z-order of a scene is constantly changing (characters and objects move around)

I'm now trying to add some kind of deferred lighting system and with my many draw calls this appears somewhat incompatible.

I should probably mention I'm fairly new to the concept of GPU rendering. I come from Flash.

This isn't a question really, but I'd appreciate some advice.

  • \$\begingroup\$ How big is your texture that you can't put it on one spritesheet? \$\endgroup\$ – Greffin28 Apr 30 '16 at 15:14
  • \$\begingroup\$ It's a high resolution RPG as I said, and to build a convincing looking world there are a large variety of objects, each one a sprite. I'm not even close to finishing the environment and it already amounts to 3 tightly packed 2048x2048 spritesheets. \$\endgroup\$ – hedgehog90 Apr 30 '16 at 15:24
  • \$\begingroup\$ Also consider a lot of objects will need their own normal and/or specular maps at some stage. \$\endgroup\$ – hedgehog90 Apr 30 '16 at 15:31

Primitives get rendered in the order they're found in the vertex buffer or index buffer if you're using one.

You can use the index buffer to sort your primitives to render multiple mesh at different z-orders without having to move the vertices around in a single draw call provided they all use the same render settings (shaders, textures, blending, etc).

So you don't need them to be at the same depth.

The issue then is you have to figure out how much data you can move around the index buffer to sort your batches before breaking the batches down to multiple draw calls becomes faster. There is no set rule for this you have to experiment as it depends on the hardware, engine and game requirements.

  • \$\begingroup\$ Right, but surely an issue arises when I have multiple textures on screen which are used at several different depths. \$\endgroup\$ – hedgehog90 Apr 30 '16 at 14:51
  • \$\begingroup\$ @hedgehog90 not necessarily. If those textures are at different depths and in different parts of the screen, you have some flexibility in how you sort them to help batch-up calls with the same texture or atlas. You can use topological sorting to ensure all overlapping sprites are sorted in the correct order, without necessarily doing a draw call per depth layer. (Although it can still end up there in the worst-case scenario where many textures from different atlas textures overlap the same pixels) \$\endgroup\$ – DMGregory Apr 30 '16 at 15:05
  • \$\begingroup\$ The game engine I'm using already has a system for sorting geometries and their textures for the least draw calls, like you suggested. It's this worst-case scenario I'm concerned about however, as I can already see it happening in fairly simple scenes. \$\endgroup\$ – hedgehog90 Apr 30 '16 at 15:14

This is one of many ways out there (This is what i think and probably not the best). This way is probably a little expensive to do. But here we go.

Try to split the rendering step into 3 parts (Your spritesheet count) and for each part try to call the draw call as few as possible (batching) using the same texture/spritesheet. If you have a trouble on the sorting (probably yes, because we render it based on spritesheet), you might want to search about depth peeling. You can see it here (It's for opengl though. This might not be the best but that is what i can with the least opengl) about depth peeling. Depth peeling will take away the render order problem. Might want to see the alpha testing too if you don't have a semi-transparent texture.

Though both depth peeling and alpha testing are pretty expensive on my experience.

By the way, i don't recall batching need objects with the same depth

Update: You didn't say what you are using so i assume you use opengl for this one. I'm going to assume (again) you have a tile id for each tile you send to your shader and the texture is 2048x2048 with 16x16 tiles (which is 128x128 in resolution per tile). Use glActiveTexture() and bind your textures for example 2 of your spritesheet and send them to the shader as a uniform sampler2D. We know each spritesheet has tile id from 0 to 255. So, in your shader check if the id >= 256 if yes, then minus it with 256 which will go back to 0 which mean we use the other texture with that new id too. But, this approach will obviously create a branching on the shader which is not good for performance either.


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.