9
\$\begingroup\$

I have been programming a 2D game in C++, using the SDL2 graphics API for rendering. My game concept currently features effects that could result in even tens of thousands of sprites being drawn simultaneously to the screen. I'd like to know what can be done for increasing rendering efficiency if the need arises, preferably using the SDL2 API only. I have previously given a quick look at OpenGL-based 2D rendering, and noticed that SDL2 lacks a command like

int SDL_RenderCopyMulti(SDL_Renderer* renderer,   SDL_Texture* texture,
                        const SDL_Rect* srcrects, SDL_Rect* dstrects,   int count)

Which would permit SDL to benefit from two common techniques used for efficient 2D graphics:

  • Texture batching: Sorting sprites by the texture used, and then simultaneously rendering as many sprites that use the same texture as possible, changing only the source area on the texture and the destination area on the render target between sprites. This allows the encapsulation of the whole operation in a single GPU command, reducing the overhead drastically from multiple distinct calls.

  • Texture atlases: Instead of creating one texture for each frame of each animation of each sprite, combining multiple animations and even multiple sprites into a single large texture. This lessens the impact of changing the current texture when switching between sprites, as the correct texture is often ready to be used from the previous draw call. Furthemore the GPU is optimized for handling large textures, in contrast to the many tiny textures typically used for sprites.

My question: Would SDL2 still get somewhat faster from any rudimentary sprite sorting or from combining multiple images into one texture thanks to automatic video driver optimizations? If I will encounter performance issues related to 2D rendering in the future, will I be forced to switch to OpenGL for lower level control over the GPU?

Edit: Are there any plans to include such functionality in the near future?

\$\endgroup\$
1
  • 1
    \$\begingroup\$ You didn't accepted any answer so far, have you found any information on the subject by yourself? I'm pretty curious on this question too. \$\endgroup\$
    – pabdulin
    Commented Oct 23, 2014 at 6:36

3 Answers 3

10
\$\begingroup\$

SDL2 doesn't need any functionality to be added for either of those items.

Texture batching

You yourself can sort the sprites by texture used. The SDL backends can already do draw call batching if they wish to (nothing requires that the Copy command be executed immediately; the only requirement is that it be executed by the time any side effects are required, such as by the end of a Present or if you try to read from the destination or if render/blend state is changed).

In order to sort draw calls, a renderer needs a lot more additional information such as layering information, draw state (blending, etc.) and so on. SDL2 certainly could offer something similar to XNA's SpriteBatch. You can already do that today on your own, though, so it's hardly necessary for SDL2 to do it in order for you to obtain the best performance.

Texture atlases

Nothing in the world is making you put one frame of animation on distinct textures. The draw commands take a source rect. Use a different source rect (on the same texture) for each frame of your animation. You're already aware of the source rects so it's unclear to me why you would think something needs to change.

SDL2 doesn't itself offer a texture atlas abstraction layer which is perhaps what you meant. It's your job to know that a particular frame of a sprite animation is at a certain location within a texture. An abstraction can be built that lets you operate on a SubTexture that encodes its SDL_Texture and source rect and your SpriteBatch can work from there. My (non-SDL) sprite batching class has methods something like:

class SpriteBatch {
public:
  // when we know the specific texture and source rectangle
  void Draw(TextureHandle tex, Rect source, /*...*/);

  // helper for drawing a whole texture
  void Draw(TextureHandle tex, /*...*/) {
    Draw(tex, Texture_SizeOf(text), /*...*/);
  }

  // helper if we have an atlas and a specific index of a sub-texture therein
  void Draw(TextureAtlasHandle atlas, int index, /*...*/) {
    Draw(TextureAtlas_TextureOf(atlas), TextureAtlas_RectOf(atlas, index), /*...*/);
  }

  // helper if we have an abstract sprite handle without details about a specific atlas
  void Draw(SpriteFrameHandle sprite, /*...*/) {
    Draw(SpriteFrame_SheetOf(sprite), SpriteFrame_IndexOf(sprite), /*...*/);
  }
};

That's obviously "paraphrased" a bit, but you get the gist.

That SpriteBatch can handle your sorting requirements as well as making it trivial to deal with atlases and single-texture animations.

Are there any plans to include such functionality in the near future?

This question is better suited for libsdl.org's SDL Development Forum which is frequented by many/most of the SDL developers.

\$\endgroup\$
1
  • \$\begingroup\$ In "The SDL backends can already do draw call batching if they wish to" by backends to you mean OpenGL or DirectX, or just SDL internals? \$\endgroup\$
    – pabdulin
    Commented Oct 7, 2014 at 1:44
1
\$\begingroup\$

SDL2 can handle these things. As previously stated you need to make a engine to load the image, the sprite rect or poly, and you could even tie into this a animation frame que to this. I pushed well into 1k sprites and collision detection between each of them and the system did not even blink. And AND that was with the basic software rendering SDL2 renderer setup under Windows 10. I since have changed it to accelerated graphics and regulated the frame rate and it isn't even pulling more than 2% of the processing. Memory allocation is very small from what I have seen with SDL2, the only obvious memory hog in this is the size of the sprite(s) sheet(s) which are loaded.

Another thing which helps with this greatly I have found. Make a camera class, have it control a source rect, destination rect, and also insert a SDL_Texture into that and on object construction and deconstruct build the texture into a large view area. This not only works well for keeping track of what you are rendering and culling the non-visible but it also double buffers with the system. On the rendering segment of the game loop; change renderer to the camera, render the layers you need to it, swap back to the window renderer and render the full camera texture to the window, present and it is smooth and organized.

If you are making a 2d game using SDL2 sprites are the heart of the whole engine/game. All other things such as UI, events, physics, update (collision/states) are the fun parts to change after the sprite system is read to load on init or on the fly and able to call a fast sprite rect, modify flip/color blend/alpha and push quick to the double buff texture. If you focus on the sprites you can make a robust game which can be changed easily and have a whole different feel.

\$\endgroup\$
0
\$\begingroup\$

I'm also making a game, 2.5D, and I use texture atlases. Like OP said, creating a single large texture from individual sprites can speed up the process for each frame. The only flaw with this is that there cannot be any moving parts in the larger texture. This method is best used for static backgrounds/foregrounds or anything else that remains the same from level start to end.

I'm using the original SDL, not SDL2, and as far as I know, neither has a built-in implementation of this method. However, if you simply use:

SDL_Surface* static_background = SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask);

(or set it to a NULL pointer and then blit some texture to it) you can create a surface of size width x height to use as your large image. You may want to set the default color to a colorkey and remove it later, unless you intend to make a wholly opaque image with no holes.

\$\endgroup\$
1
  • 5
    \$\begingroup\$ > The only flaw with this is that there cannot be any moving parts in the larger texture. What? Why? That doesn't sound right at all. \$\endgroup\$ Commented Sep 23, 2014 at 1:10

You must log in to answer this question.

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