29

I'm kind of stuck on the logic behind an SDL2 texture. To me, they are pointless since you cannot draw to them.

In my program, I have several surfaces (or what were surfaces before I switched to SDL2) that I just blitted together to form layers. Now, it seems, I have to create several renderers and textures to create the same effect since SDL_RenderCopy takes a texture pointer.

Not only that, but all renderers have to come from a window, which I understand, but still fouls me up a bit more.

This all seems extremely bulky and slow. Am I missing something? Is there a way to draw directly to a texture? What are the point of textures, and am I safe to have multiple (if not hundreds) of renderers in place of what were surfaces?

anatoly techtonik
  • 17,421
  • 8
  • 111
  • 131
Qix - MONICA WAS MISTREATED
  • 12,202
  • 13
  • 73
  • 131
  • The way the architecture of SDL changed when they introduced 2.0 is forcing me into SFML. I just can't deal with re-structuring my entire program because of their API change; basically, there is no off-screen rendering like SFML supports. – Qix - MONICA WAS MISTREATED Sep 20 '12 at 07:30
  • 2
    SDL2 is in a pre-release state. It's not exactly fair to judge it just yet. In spite of being a WIP, the developer has been kind enough to let us mess with it as it progresses is all. –  Oct 07 '12 at 21:25
  • @Di-0xide The old wiki is still available. http://www.libsdl.org/cgi/docwiki.cgi – Wes Nov 14 '12 at 11:26
  • 6
    Looking back on this 3 years later, I didn't understand what a graphics *texture* really was. For those of you still up-voting, remember textures are not necessarily pieces of images or graphics; they're really any data sent up to the card. – Qix - MONICA WAS MISTREATED Jul 01 '15 at 03:28
  • 1
    Another three year laters and a [response I wrote for a Reddit ELI5](https://medium.com/@qix/eli5-response-how-is-an-internal-3d-representation-of-the-video-game-world-translated-to-what-we-fc1d24f15f2d) makes a bit of sense to link. It's a really bare-bones explanation of how graphics pipelines work and touches on some basic theory. Good diving off point if anyone finding this is completely new to the subject. – Qix - MONICA WAS MISTREATED Sep 21 '18 at 08:31

3 Answers3

39

SDL_Texture objects are stored as close as possible to video card memory and therefore can easily be accelerated by your GPU. Resizing, alpha blending, anti-aliasing and almost any compute-heavy operation can harshly be affected by this performance boost. If your program needs to run a per-pixel logic on your textures, you are encouraged to convert your textures into surfaces temporarily. Achieving a workaround with streaming textures is also possible.

Edit: Since this answer recieves quite the attention, I'd like to elaborate my suggestion.

If you prefer to use Texture -> Surface -> Texture workflow to apply your per-pixel operation, make sure you cache your final texture unless you need to recalculate it on every render cycle. Textures in this solution are created with SDL_TEXTUREACCESS_STATIC flag.

Streaming textures (creation flag is SDL_TEXTUREACCESS_STREAMING) are encouraged for use cases where source of the pixel data is network, a device, a frameserver or some other source that is beyond SDL applications' full reach and when it is apparent that caching frames from source is inefficient or would not work.

It is possible to render on top of textures if they are created with SDL_TEXTUREACCESS_TARGET flag. This limits the source of the draw operation to other textures although this might already be what you required in the first place. "Textures as render targets" is one of the newest and least widely supported feature of SDL2.

Nerd info for curious readers:

Due to the nature of SDL implementation, the first two methods depend on application level read and copy operations, though they are optimized for suggested scenarios and fast enough for realtime applications.

Copying data from application level is almost always slow when compared to post-processing on GPU. If your requirements are more strict than what SDL can provide and your logic does not depend on some outer pixel data source, it would be sensible to allocate raw OpenGL textures painted from you SDL surfaces and apply shaders (GPU logic) to them.

Shaders are written in GLSL, a language which compiles into GPU assembly. Hardware/GPU Acceleration actually refers to code parallelized on GPU cores and using shaders is the prefered way to achieve that for rendering purposes.

Attention! Using raw OpenGL textures and shaders in conjunction with SDL rendering functions and structures might cause some unexpected conflicts or loss of flexibility provided by the library.

TLDR; It is faster to render and operate on textures than surfaces although modifying them can sometimes be cumborsome.

Mansuro
  • 4,194
  • 4
  • 31
  • 72
diegoperini
  • 1,686
  • 19
  • 33
  • 1
    What is this `streaming texture`? – anatoly techtonik Jan 12 '14 at 07:03
  • 1
    "Static textures are designed for sprites and backgrounds and other images that don't change much... ...Streaming textures are designed for things that update frequently, every few seconds, or every frame." quoted from http://slouken.blogspot.com/2011/02/streaming-textures-with-sdl-13.html Technically, they are mutable pixel data that is subject to modification between each render, therefore require extra care to avoid stutters due to heavy access to its buffers.. – diegoperini Jan 14 '14 at 22:32
  • 1
    What's the logic behind `texture > surface > texture`? Why not `surface > texture` every frame? – Hello World Mar 08 '15 at 20:58
  • Right after the very first render loop, many materials would be cached as textures. Applying small modifications to them (like altering some smaller rectangular parts) would benefit from that flow. – diegoperini Apr 01 '15 at 07:50
8

Through creating a SDL2 Texture as a STREAMING type, one can lock and unlock the entire texture or just an area of pixels to perform direct pixel operations. One must create prior a SDL2 Surface, and link with lock-unlock as follows:

SDL_Surface surface = SDL_CreateSurface(..);
SDL_LockTexture(texture, &rect, &surface->pixels, &surface->pitch);
// paint into surface pixels
SDL_UnlockTexture(texture);

The key is, if you draw to texture of larger size, and the drawing is incremental ( e.g. data graph in real time ) be sure to only lock and unlock the actual area to update. Otherwise the operations will be slow, with heavy memory copying.

I have experienced reasonable performance and the usage model is not too difficult to understand.

Dan The man
  • 89
  • 1
  • 1
  • 1
    Creating a surface first is nor required and possibly not desirable. `SDL_LockTexture()` gets you the pixels and pitch of the texture, writing them into the supplied addresses, which don't have to - and possibly shouldn't - be part of any surface. Saying `paint into surface pixels` doesn't make sense: what you actually do here is to overwrite the surface's `*pixels` and `pitch` members with those from the texture, then update the pixels of the texture, not surface, via that pointer. This might work in some cases, and presumably did in yours, but it doesn't seem either necessary nor a good idea – underscore_d Jul 23 '16 at 19:16
6

In SDL2 it is possible to render off-screen / render directly to a texture. The function to use is:

int SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture);

This only works if the renderer enables SDL_RENDERER_TARGETTEXTURE.