Question

I'm trying to load textures for an SDL2 program in a separate thread for a loading screen. My code looks something like this

int batchLoad(void *ptr) {
loop through resources
    SDL_LockMutex(renderMutex);

        SDL_Texture *texture = NULL;

    SDL_Surface *surface = IMG_Load(("../resources/" + fileName).c_str());
    if (surface) {
    texture = SDL_CreateTextureFromSurface(renderer, surface);
    SDL_FreeSurface(surface);
    }
    SDL_UnlockMutex(renderMutex);

        // store texture

return 0;
}

void LoadingScreen::loadResources() {
// do some stuff

renderMutex = SDL_CreateMutex();

ScreenMap screenMap;
    // init with data
    SDL_Thread* load = SDL_CreateThread(batchLoad, "batchLoad", &screenMap);

while loading {
    // do work

    SDL_LockMutex(renderMutex);

    SDL_RenderClear(renderer);
    SDL_RenderCopy(renderer, white, NULL, NULL);

    // draw stuff

    SDL_RenderPresent(renderer);
    SDL_UnlockMutex(renderMutex);
}

SDL_WaitThread(load, NULL);
SDL_DestroyMutex(renderMutex);
SDL_DestroyMutex(satMutex);

On Windows this works perfectly fine, but on OSX I get an error at the CreateTextureFromSurface call. It segfaults with a null pointer error. Here's the osx problem report.

Thread 10 Crashed:: batchLoad
0   libGL.dylib                     0x00007fff885ead32 glGenTextures + 18

Thread 10 crashed with X86 Thread State (64-bit):
rax: 0x0000000000000000  rbx: 0x00007ff913c37ad0  rcx: 0x0000000000000001  rdx: 0x00007ff913c37b50
rdi: 0x0000000000000001  rsi: 0x00007ff913c37b50  rbp: 0x00000001157ae4d0  rsp: 0x00000001157ae4d0
r8: 0x0000000000000004   r9: 0x00007ff913c00000  r10: 0x0000000023f4e094  r11: 0x000000000abea012
r12: 0x00007ff913d1e3b0  r13: 0x00007ff913d1e3b0  r14: 0x000000000000001a  r15: 0x0000000000000022
rip: 0x00007fff885ead32  rfl: 0x0000000000010246  cr2: 0x0000000000000000

and lldb

* thread #9: tid = 0xee08, 0x00007fff885ead32 libGL.dylib`glGenTextures + 18, name = 'batchLoad', stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
frame #0: 0x00007fff885ead32 libGL.dylib`glGenTextures + 18
libGL.dylib`glGenTextures + 18:
-> 0x7fff885ead32:  movq   (%rax), %rdi
   0x7fff885ead35:  movq   0x318(%rax), %rax
   0x7fff885ead3c:  movl   %ecx, %esi
   0x7fff885ead3e:  popq   %rbp

when I comment out all the thread stuff and just call batch load normally, there are no errors so I figured there has to be some concurrency issue. But I'm using a mutex for all of the renderer calls so I'm not sure what the issue could be. And then I also don't know why it would work fine on Windows but not on OSX

Was it helpful?

Solution

The renderer API isn't designed to be called from more than one thread (regardless of any locking being done) due to OpenGL's rules related to multi-threading. This warning is mentioned on the CategoryRender page and there's a link to a bug report where you can read more details about why it is this way and how you can work around it.

The simplest fix would be to load the surface on some background thread then hand it off to your renderer thread to be loaded into a texture.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top