Using the SpriteBatch the correct way

Hello everyone,

I’m going to start a new project with Monogame with Monogame.Extended extension and I have a question about the good way to retrieve the SpriteBatch.

I’m currently experimenting the Screen class, and looking to the Demo.Screens project of the Monogame.Extended solution, I saw that the instance of the Game’s GameServiceContainer (the service provider) is given at the instantiation of each screens. With the GameServiceContainer, it’s possible to create a new SpriteBatch object, it’s done like this in the MenuScreen class (all screen classes of this example inherit from this MenuScreen class):

var graphicsDeviceService = (IGraphicsDeviceService)_serviceProvider.GetService(typeof(IGraphicsDeviceService));
_spriteBatch = new SpriteBatch(graphicsDeviceService.GraphicsDevice);

Does it have any sense to create a screen without SpriteBatch? Is there a reason why this code is not in the Screen class directly?

But do we really want to have a new SpriteBatch for every screen? Why don’t we use the instance of SpriteBatch that already exists in our Game object? Is this really a problem to make this SpriteBatch public and to give the Game object to each screen?

I would really appreciate to have your opinion on this.

Thank you in advance. :slightly_smiling:

Well no, some screens don’t use SpriteBatch.

For example rendering a 3d scene is possible without drawing any 2d stuff at all. So there are definitely some Screens that don’t use a spritebatch and it would be a bit of a waste to have every screen have its own spritebatch by default.

And even for 2d screens developers might choose to implement their own quad renderer instead of using spritebatch, since spritebatch is essentially just creating 4 vertices, making a quad out of them and then batch a bunch of stuff, depending on the mode. In some cases a custom implementation might be more performant and convenient with custom shaders (although spritebatch is pretty good and makes things a lot easier, and GPU performance should rarely be the bottleneck in 2d anyways.)

Having a specific spritebatch for each Screen is just a “beauty” thing as far as i know. Yes, you can have only a single spritebatch passed around between all screens and it will work the same, but it’s a bit more “ugly” from a code perspective to pass it around.
The class and instance itself is not very heavy, it doesn’t really matter to have a few more in terms of performance.

But if you want to have only one spriteBatch for everything that is fine, really.

EDIT: Some good points made below. Yes it should be a good idea to render the whole scene in one spritebatch.

I made it a static class and never went back… I suggest that anyone using XNA/MonoGame should do the same.

As for passing it around through parameters or creating a new one each time… It’s a nightmare of repetitiveness…

SpriteBatch
spriteBatch
spritebatch
Spritebatch
SPRITEBATCH
SB
sb
sB
Sb
S
P
R
I
T
E
B
A
T
C
H

X_x

Having separate spritbatches in separate objects seems like a waste of memory and also as far as I know it is more efficient to use one instance of spritebatch in the graphics manager class*, call Begin and End at the beginning/end of the Draw method and draw everything you need in one go instead of calling begin/end in each objects. :slightly_smiling: Between the Begin/End, just call your objects’ Draw , pass the contents to the graphics manager (these can be objects holding references of textures, or can be actual texture instances**) and the manager will draw them on the screen.


*You should separate the actual drawing from your game. Your game actually should not know anything about how its content will be rendered. Just pass the object or texture to your graphics manager and let it decide how to display it on the screen. It’s like travelling on a bus: there is only one instance of bus and the passengers are not interested in how its working and also there is no bus for each passenger, one bus will take them to the destination.
**For efficiency, I am also using a texture manager that holds only one instance of each texture I need and my objects contain only references of these textures. When I pass my object to my graphics manager, it grabs the texture reference out of the object, retrieve the texture from the texture manager (by this reference) and draws it on the screen.

Having multiple spritebatch instances is not always a bad thing. If you want to change renderstate things can’t be batched anyway. In those cases IMO it’s nice to have seperate batches. That’s just personal preference though, because I’d rather not make it public static somewhere and this way you don’t have to pass it around everywhere.

A spritebatch instance doesn’t need much space :stuck_out_tongue: You shouldn’t recreate them each frame though.

How is this more efficient?

1000 objects with 1 spritebatch in each of them may have an impact on performance, though I have never tested this. So I agreee with the “create one when it is really necessary” opinion.

On texture manager thing (in pseudo):

class TextureObject
{
   string Name;
   Texture2D Texture;
   int ReferenceCount;
}

static TextureManager
{
   List<TextureObject> TextureCache;
   LoadTextureMethod (string name) { if Exists( increaseRefCount, else Load texture and add to List with Refcount 1 }
}

//In game:

class Something
{
   string TextureName;
   void Draw(texturemanager.GetTextureByName(TextureName));
}
class SomethingElse
{
   texture2D Texture;
   void Draw(Texture);
}

for(int i = 0; i < 1000; i++)
  CreateObject(new Something(sameTextureNameEveryTime);
//After iteration, you will have 1000 different objects with 1000 strings, but only 1 texture in memory.

//Without texture manager
for(int i = 0; i < 1000; i++)
   CreateObject(new SomethingElse(sameTexture2DeveryTime);
//After iteration, you will have 1000 different objects with one texture 1000 times in memory.

Of course, this texturemanager is only good if you use raw pngs, like I do. If the content manager is good enough for your game, then as far as I know my above example will not load the same texture 1000 times into memory, but I do not have much experience with the content manager (I prefer to avoid it whenever I can :smiley: ).

Ah, I thought you used a ContentManager. It caches assets for you, so it wouldn’t make sense in that case to wrap it and cache again yourself.

IMO using the content manager is better, especially if you target multiple platforms.

Well, take a look at the source code of SpriteBatch (along with it’s helpers: SpriteBatcher, and SpriteBatchItem). Each SpriteBatch instance has a unique SpriteBatcher instance which has an array of SpriteBatchItem classes.

Each SpriteBatch instance (along with its helpers) does not use much space when it’s first created but can demand more space as the batch item buffer, vertex array buffer (not a GPU VertexBuffer) and index array buffer grow to meet the demand of many SpriteBatch.Draw calls. Currently, there is an upper limit of 5461 ((int)(short.MaxValue / 6)) for how many SpriteBatchItem classes can be created per SpriteBatcher instance. As the SpriteBatchItem array grows, the vertices and indices array also grow to match where each SpriteBatchItem takes 4 vertices and 6 indices. So the maximum number of VertexPositionColorTexture vertices and short indices is 21844 and 32766 respectively. The minimum number of vertices and indices is 1024 and 1536 respectively. Don’t forget that the array of SpriteBatchItem takes space and each SpriteBatchItem class as well. So all in all, I wouldn’t recommend creating new SpriteBatch instances willy nilly, and definitely not every frame, but it doesn’t hurt to have a couple of instances.

1 Like

I meant just the spritebatch+spritebatcher themselves. If you draw x+y items with a single spritebatch (where between x and y you have an end/begin so the batch gets flushed) or x with one and y with another will hardly make a difference in memory