rendering different window parts from different threads

Hello,

for an application where I use SDL2/SDL_RenderDrawPoint - SDL Wiki to draw each pixel of the window I would like to split the pixels of the window into disjunct parts I would be drawing from threads.

Is this possible with SDL ?

I read an advice against using SDL video functions from threads here: Multi-threaded Programming

I can imagine either drawing into different parts of the window (can I setup different renderer for this? How?) or composing the final pixels from individual different pixels (can I use textures for this? How?).

The application rasters a mathematical sphere, mapped from satellite map images, from a new angle for every supported input.

I thank you very much for your relase of SDL and your caring.

No, you can’t use SDL_Renderer API from concurrent threads, but better way to achieve your task is to use streaming texture with SDL_LockTexture. Then you can manipulate your pixels from concurrent threads, wait for every drawing thread will finish then finally unlock texture and display it from the renderer thread. Sure you also can use the legacy SDL_Surface + blit on window approach, but I won’t recommend this for various reasons.

1 Like

If you will face performance issues again, then look for OpenGL to draw your sphere.

i’m sorry for my insecurity, do i write to a texture by creating a renderer from a window and switching it to the texture? Or how can i write to a texture? If the former, i can create 2 renderer from 1 window (1 for getting set to a texture, 1 for getting the texture copied to)?

EDIT: i can not create 2 renderer from 1 window.

EDIT: SDL_LockTexture puts a pointer to the (texture) memory to write to inside its pixels parameter.

SDL2/SDL_LockTexture - SDL Wiki appears to imply being optimised when wanting to write to the texture. Is this so or can i write to the texture without it equally good? Can I lock multiple disjunct regions of a texture at the same time (for access from concurrent threads)?

You got it a bit wrong. The bytes you receive from locking it’s just dynamic allocated memory, that will be sent back to renderer after you unlock the texture, you can access it any way you want before then.
And you can’t lock texture recursively, so if you plan to update the whole area you just need to lock the whole area.
So, your pipeline will look like this:

  1. main()
  2. Spawn N threads and make them wait for the rendering task. Best way to implement it is to use condition variable mechanisms.
  3. Create your window, renderer, and streaming texture.
  4. Lock the texture, split it to N parts (logically), and sent this data to the renderer threads.
    your rendering task can be something like this:
struct RenderTask {
  SDL_Rect area;
  SDL_Point texture_size;
  unsigned char *pixels;
};
  1. Wake up the threads, and wait them to finish. And make them wait for the data again.
  2. Unlock texture, and display it on the screen.
  3. Update your state, timers, etc. and jump to step 4

Remember that you need to care about pixel format, and more. Also, it’s just a basic example, the other details is up to you.

3 Likes

do i have to lock the texture again after unlocking it (unlocking = it was sent to video memory) if I still have the pointer to the memory which unlock sends to video memory, from the first lock ?

I have let written the whole texture memory after all threads completed but some parts are filled by a placeholder due to waiting for asynchronous received data and once that data arrived I let it get written to the texture making up the final composition which then gets unlocked again.

In my tests I have in some of them noticed something looking like a glitch but the inputs leading to a new drawing happened so fast that by the time they ended the asynchronous data already arrived and I couldn’t tell whether they were just from the placeholders getting replaced.

If the texture is supposed to be locked again after every unlock, does SDL have a way to set the previous content again (which contains the placeholders and parts of the final image) (eg copying back from video memory or instructing it to “lock into the same buffer” again) or should the buffer be copied by the application before unlock to retain it and be copied back after locking again?

After unlocking the pointer is no longer valid (known as a dangling pointer) because it was de-allocated by SDL_UnlockTexture call.
So you need lock-unlock the texture every time you need to write pixels.

Sounds confusing for me, do you really wait for all the threads done their job?

You need to sync your main loop to texture rendering jobs.

“As an optimization, the pixels made available for editing don’t necessarily contain the old texture data. This is a write-only operation, and if you need to keep a copy of the texture data you should do that at the application level.” So you need to keep your old buffer somewhere if you want to keep your pixels. Just operate your buffer instead of SDL provided one, and copy it to bytes you got from SDL after you done.

1 Like

This would be good to add to the documentation SDL2/SDL_UnlockTexture - SDL Wiki

I knew the LockTexture remark :slight_smile: I asked in case i missed the low probability of SDL providing a mean after all.

Re threads and async: threads draw sat map data (sort of “window height / number cores” lines per core) but those sat map are requested via internet so a thread might complete drawing a map it already has but i let it draw a placeholder if the map is not present yet and overdraw the placeholder once the async requested sat map arrives.

Sounds quite complex, so I can’t help here without a code sample. Sounds like you need to implement some task pool or task queue to solve your problem.

oh, i’m almost all done now already, I don’t require further help right now!

I thank you.

1 Like