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?
Answer
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.
No comments:
Post a Comment