Yes you can do that.
First you have to enable shared context in SDL_GL attributes. The last context created will be active in the creator thread. So create the glRenderContext last, or after creating use SDL_GL_MakeCurrent to make it current. This will also make sure that the glThreadContext is not active in this thread and can be activated in another one. (Only one can be current in a thread)
To call SDL_GL_MakeCurrent in the thread you just use the pointer to your main windows.
A example below: Note that a real loading thread would not get closed until the program is. Because MakeCurrent is very expensive. Better paused it by a Semaphore and then throw work at it when you need something done.
Code:
SDL_GLContext glRenderContext, glThreadContext;
SDL_Window *mainWindow;
SDL_atomic_t stuffIsReady;
int loadGlInBackground( void *ptr )
{
SDL_GL_MakeCurrent(mainWindow, glThreadContext);
//Do some fancy loading gl stuff in the background...
//It is very important in shared contexts to make sure the driver is done with all Objects before signaling other threads that they can use them!
GLsync fenceId = glFenceSync( GL_SYNC_GPU_COMMANDS_COMPLETE, 0 );
GLenum result;
while(true)
{
glClientWaitSync(fenceId, GL_SYNC_FLUSH_COMMANDS_BIT, GLuint64(5000000000)); //5 Second timeout
if(result != GL_TIMEOUT_EXPIRED) break; //we ignore timeouts and wait until all OpenGL commands are processed!
}
SDL_AtomicIncRef(&stuffIsReady);
//im not 100% sure what happens to a context that still is active when a thread gets closed.
//But you can't call SDL_GL_DeleteContext on it!
//So I just unbind it from this thread and call SDL_GL_DeleteContext in the main thread at closing.
SDL_GL_MakeCurrent(mainWindow, NULL);
return 0;
}
int main(int argc, char* argv[])
{
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
cout << "Unable to initialize SDL: " << SDL_GetError() << endl;
return -1;
}
else
{
cout << “sdl init ok” << endl;
}
mainWindow = SDL_CreateWindow(“SDL2 window”, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
if(mainWindow == NULL){
std::cout << "Could not create window: " << SDL_GetError() << std::endl;
return -1;
}
SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
glThreadContext = SDL_GL_CreateContext(mainWindow);
glRenderContext = SDL_GL_CreateContext(mainWindow);
SDL_Thread *thread = SDL_CreateThread( loadGlInBackground, "testThread", (void *)NULL);
while(true)
{
//Event handling and all the fancy rendering...
if (SDL_AtomicGet(&stuffIsReady) == 1)
{
//now the opengl stuff loaded by the thread can be used
}
}
int threadReturnValue;
SDL_WaitThread(thread, &threadReturnValue);
SDL_GL_DeleteContext(glThreadContext);
SDL_GL_DeleteContext(glRenderContext);
SDL_DestroyWindow(mainWindow);
SDL_Quit();
return 0;
}