5
\$\begingroup\$

From what I understand, SpriteBatch's purpose is to batch as many draw operations to send to the GPU. Each batch can handle one texture at a time, and changing SpriteBatch context/texture is expensive, so when you need to draw many different textures in one frame you use a texture atlas, putting sprites that are most likely to be drawn by the same component in the same page.

So my questions are:

  • Assuming there are numerous components using the same texture page, how am I supposed to group them together and issue their drawing method?
  • What is an efficient way to deal with a component that uses sprites from two different texture pages? Should I handle two different drawing methods for each texture page? or perhaps take the context texture page as parameter and draw only what's relevant for it?
  • What about dynamically generated textures?
  • What if you don't know which texture pages a component needs? (For example, a custom visual equipment where you can't possible put all the equips in the same texture page since there might be thousands of em, and it's determined only at runtime)

I've seen many articles on how SpriteBatches work technically but nothing meaningfull on how to actually make the best use out of them. Would a good solution be to somehow queue my draw operations sorted by texture? If so, what would be a good generic way to implement it?

\$\endgroup\$
2
  • \$\begingroup\$ If you have a single sprite that uses pieces from different texture pages, you could make a dynamic texture that contains all of those textures and use that for your sprite batch. Haven't tried this personally but it sounds like that would be the way to go. \$\endgroup\$ Commented Jun 12, 2013 at 18:03
  • \$\begingroup\$ Creating a texture is also expensive, and the sprites to render may change each frame so that won't help much. I'm asking how would be a good way to minimize number of batches per frame. \$\endgroup\$ Commented Jun 12, 2013 at 21:57

1 Answer 1

1
\$\begingroup\$

Im assuming you are using spritebatch from xna/monogame, unless you are using a differnt API that does a similar function.

Spritebatch can handle multipe textures and draw calls within Begin() and End() functions, with little performance hinderance depending on how many draw calls you are performing per frame. The only time Spritebatch becomes expensive is if you are calling Begin() multiple times per frame in order to change Modes and Renderstates. Typically you want to try and keep it to one Begin() call per frame unless trying to create a specific effect without hlsl.

As for multiple components using the same texture, simply have an assest manager that holds a dictionary/map with a with all the assets you need loaded in, then pass a string to your component that will get the reference to the texture and store that reference to be called during the draw function. Alternatively, pass in the asset manager to your component and do a get function using the string key during your draw function.

The latter part of my last paragraph can help with your multiple textures issue as you can create more than a draw call during your component Render() function for each texture you need to access.

As for your last question, again the same thing. You can store the string keys and the location on texture in an xml/text file and access your asset manager at runtime and pass in the string and texture coordinates during your draw call.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ You are incorrect in your assertion that using multiple textures has no significant performance implications: every single texture change requires a new batch, equivalent to calling End()/Begin(). It's just done internally by XNA, rather than requiring you to do it explicitly. \$\endgroup\$ Commented Jun 12, 2013 at 19:38
  • \$\begingroup\$ @JLC - It doesn't matter what platform I am using, the principle of SpriteBatch is the same. As for changing textures, ColeCampbell is right - Binding a new texture is expensive. Anyways my question was not how to use an asset manager or a texture atlas, but how do I minimize texture binding switching and many useless batches. \$\endgroup\$ Commented Jun 12, 2013 at 20:16
  • \$\begingroup\$ Would a good solution be to accumulate draw operations sorted by texture and then systematically draw them one at a time? I can have the depth buffer take care of the ordering. \$\endgroup\$ Commented Jun 12, 2013 at 20:19
  • \$\begingroup\$ You guys are both right, binding is expensive. Especially if you are rebinding the same texture several times. What I meant was reallocating the same texture multiple times if some components can simply hold a reference to a texture. I just misinterpreted the question, sorry. Yariv, that does seem like a good, simple solution. Iterating through each texture and sort the draw calls (or sprites associated) to be drawn with that texture id makes sense. \$\endgroup\$
    – JLC
    Commented Jun 13, 2013 at 0:15
  • \$\begingroup\$ I've run some simulations about sorting by texture and I ran into more problems regarding blending modes, projection matrices changing, etc. Each time these happen I'll be forced to end the batch anyways, and I don't know if it's wise to accumulate these operations in a sub queue because the drawing order for a component might be important especially if blending modes are used. E.G draw an opaque rectangle, draw a circle with additive blend mode and then draw another rectangle with normal blend mode that overlaps it will create different effects for different drawing orders. I'm stumped. \$\endgroup\$ Commented Jun 13, 2013 at 9:05

You must log in to answer this question.

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