Oh my, OpenMP and OpenGL probably don't mix very well. The way OpenMP creates multiple threads is not pinned down in terms that would be accessible to OpenGL implementations. Most likely it's using regular POSIX threads or Windows native threads. But it could also be anything else, that creates additional tasks inside the same address space.
I think it'd be far more robust and easier to tackle to create a pool of N threads, each with its own sharing OpenGL context and then use work stealing to schedule the tasks; keep the OpenGL current on the threads between worklets.
Conveniently enough with modern OpenGL one doesn't even need a window or similar drawable to make a context current. glXMakeContextCurrent and wglMakeContextCurrent will accept Nil parameters for the drawables/HDCs. So you can do OpenGL operations on framebuffer objects and all the other stuff, with the only caveat being, that there's no main default framebuffer.
Feel free to use those code snippets for creating the helper contexts.
#include "wglu_context.h"
#include <windows.h>
#include <GL/gl.h>
#include <GL/wglext.h>
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <assert.h>
static char const *wgl_create_context_attribs_name = "wglCreateContextAttribsARB";
static
int wglu_get_proc_address(char const *name, PROC *pproc)
{
int rc= 0;
*pproc = wglGetProcAddress(name);
fprintf(stderr, "%s: %p
", name, (void*)*pproc );
if( !(*pproc) ){
rc= GetLastError();
fprintf(stderr,
"error wglGetProcAddress('%s'): 0x%x
",
name, rc);
}
if( rc ){ fprintf(stderr, "%s: %d
", __func__, rc); }
return rc;
}
/* -----------------------------------------------------------------------
* Create a OpenGL context of desired version and share it */
int wglu_create_context_with_sharing(
int major, int minor, int profile,
HDC surface,
HGLRC share_context,
HGLRC *out_context )
{
int rc= 0;
int attribs[8] = {0};
size_t i_attrib = 0;
HGLRC context = 0;
HDC const save_surface = wglGetCurrentDC();
HGLRC const save_context = wglGetCurrentContext();
if( save_surface != surface
|| save_context != share_context
){
wglMakeCurrent(surface, share_context);
}
PFNWGLCREATECONTEXTATTRIBSARBPROC wgl_create_context_attribs;
if( (rc= wglu_get_proc_address(
wgl_create_context_attribs_name,
(PROC*)&wgl_create_context_attribs))
){
goto fail;
}
if( major ){
attribs[i_attrib++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
attribs[i_attrib++] = major;
}
if( minor ){
attribs[i_attrib++] = WGL_CONTEXT_MINOR_VERSION_ARB;
attribs[i_attrib++] = minor;
}
if( profile ){
attribs[i_attrib++] = WGL_CONTEXT_PROFILE_MASK_ARB;
attribs[i_attrib++] = profile;
}
attribs[i_attrib] = attribs[i_attrib+1] = 0;
context = wgl_create_context_attribs(surface, *share_context, attribs);
if( !context ){
rc= GetLastError();
fprintf(stderr,
"error %s(surface=0x%x, share_context=0x%x, attribs=0x%p): %x
",
wgl_create_context_attribs_name,
(uintptr_t)surface, (uintptr_t)share_context,
attribs,
rc );
goto fail;
}
if( !(wglMakeCurrent(surface, context)) ){
rc= GetLastError();
fprintf(stderr,
"error %s(surface=0x%x, contest=0x%x): 0x%x
",
"wglMakeCurrent",
(uintptr_t)surface, (uintptr_t)context,
rc );
goto fail;
}
assert( context == wglGetCurrentContext() );
fprintf(stderr,
"GL_VENDOR = %s
"
"GL_RENDERER = %s
"
"GL_VERSION = %s
",
glGetString(GL_VENDOR),
glGetString(GL_RENDERER),
glGetString(GL_VERSION) );
if( !(wglMakeCurrent(NULL, NULL)) ){
rc= GetLastError();
fprintf(stderr,
"error %s(0, 0): 0x%x
",
"wglMakeCurrent",
(uintptr_t)surface, (uintptr_t)context,
rc );
goto fail;
}
if( !(wglShareLists(context, share_context)) ){
rc= GetLastError();
fprintf(stderr,
"error %s(context=0x%x, share_context=0x%x): 0x%x
",
"wglShareLists",
(uintptr_t)context, (uintptr_t)share_context,
rc );
goto fail;
}
wglMakeCurrent(save_surface, save_context);
if( !rc ){
if( out_context ){ *out_context = context; }
} else {
if( context ){ wglDeleteContext(context); }
}
if( rc ){ fprintf(stderr, "%s: %d
", __func__, rc); }
return rc;
}
#include <GL/glxext.h>
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <assert.h>
#include <errno.h>
#include <dlfcn.h>
static char const *glX_create_context_attribs_name = "glXCreateContextAttribsARB";
typedef void (*PROC)();
static
int glxu_get_proc_address(char const *name, PROC *pproc)
{
int rc= 0;
static PROC (*glX_get_proc_address)(char const*) = NULL;
if( !glX_get_proc_address ){
*(void**)(&glX_get_proc_address) = dlsym(RTLD_DEFAULT, "glXGetProcAddress");
}
if( !glX_get_proc_address ){
rc = -EFAULT;
} else {
*pproc = glX_get_proc_address(name);
fprintf(stderr, "%s: %p
", name, (void*)*pproc );
if( !(*pproc) ){
rc= -ENOENT;
fprintf(stderr, "error glXGetProcAddress('%s'): so such function
", name);
}
}
if( rc ){ fprintf(stderr, "%s: %d
", __func__, rc); }
return rc;
}
static
int glxu_get_fbconfig_for_xid(
Display *display,
GLXFBConfigID const id,
GLXFBConfig *out_fbconfig )
{
static GLXFBConfig* (*glX_get_fb_configs)(Display*,int,int*) = NULL;
static int (*glX_get_fb_config_attrib)(Display*,GLXFBConfig,int,int*) = NULL;
if( !glX_get_fb_configs ){
*(void**)(&glX_get_fb_configs) = dlsym(RTLD_DEFAULT, "glXGetFBConfigs");
}
if( !glX_get_fb_config_attrib ){
*(void**)(&glX_get_fb_config_attrib) = dlsym(RTLD_DEFAULT, "glXGetFBConfigAttrib");
}
int rc = 0;
int n_configs = 0;
/* we always assume to operate on screen 0, since hardly any X connection
* encountered these days actually operates on multiple screens. */
if( !glX_get_fb_configs || !glX_get_fb_config_attrib ){
rc = -EFAULT;
} else {
GLXFBConfig *const fbconfig = glX_get_fb_configs(display, 0, &n_configs);
for(int i=0; !rc && i < n_configs; ++i){
unsigned int qry_id;
rc= glX_get_fb_config_attrib(display, fbconfig[i], GLX_FBCONFIG_ID, &qry_id);
if( !rc && id == qry_id ){
*out_fbconfig = fbconfig[i];
break;
}
}
}
return rc;
}
Display *glxu_get_current_display(void)
{
static Display* (*glX_get_current_display)(void) = NULL;
if( !glX_get_current_display ){
*(void**)(&glX_get_current_display) = dlsym(RTLD_DEFAULT, "glXGetCurrentDisplay");
}
if( !glX_get_current_display ){
return NULL;
}
return glX_get_current_display();
}
GLXDrawable glxu_get_current_drawable(void)
{
static GLXDrawable (*glX_get_current_drawable)(void) = NULL;
if( !glX_get_current_drawable ){
*(void**)(&glX_get_current_drawable) = dlsym(RTLD_DEFAULT, "glXGetCurrentDrawable");
}
if( !glX_get_current_drawable ){
return 0;
}
return glX_get_current_drawable();
}
/* -----------------------------------------------------------------------
* Create a OpenGL context of desired version and share it */
int glxu_create_context_with_sharing(
int major, int minor, int profile,
Display *display,
GLXDrawable surface,
GLXContext share_context,
GLXContext *out_context )
{
int rc= 0;
int attribs[8] = {0};
size_t i_attrib = 0;
GLXContext context = 0;
unsigned int fbconfigxid = 0;
GLXFBConfig fbconfig = 0;
static GLXContext (*glX_get_current_context)(void) = NULL;
static void (*glX_query_drawable)(Display*,GLXDrawable,int,unsigned*) = NULL;
static Bool (*glX_make_current)(Display*,Drawable,GLXContext) = NULL;
static void (*glX_destroy_context)(Display*,GLXContext) = NULL;
if( !glX_get_current_context ){
*(void**)(&glX_get_current_context) = dlsym(RTLD_DEFAULT, "glXGetCurrentContext");
}
if( !glX_query_drawable ){
*(void**)(&glX_query_drawable) = dlsym(RTLD_DEFAULT, "glXQueryDrawable");
}
if( !glX_make_current ){
*(void**)(&glX_make_current) = dlsym(RTLD_DEFAULT, "glXMakeCurrent");
}
if( !glX_destroy_context ){
*(void**)(&glX_destroy_context) = dlsym(RTLD_DEFAULT, "glXDestroyContext");
}
if( !glX_get_current_context || !glX_query_drawable
|| !glX_make_current || !glX_destroy_context
){
return -EFAULT;
}
Display *const save_display = glxu_get_current_display();
GLXDrawable const save_surface = glxu_get_current_drawable();
GLXContext const save_context = glX_get_current_context();
if( !display ){ display = save_display; }
if( !surface ){ surface = save_surface; }
if( !share_context ){ share_context = save_context; }
if( save_display != display
|| save_surface != surface
|| save_context != share_context
){
fprintf(stderr, ".....
");
if( !(glX_make_current(display, surface, share_context)) ){
rc = -1;
goto fail;
}
}
PFNGLXCREATECONTEXTATTRIBSARBPROC glX_create_context_attribs;
if( (rc= glxu_get_proc_address(
glX_create_context_attribs_name,
(PROC*)&glX_create_context_attribs))
){
rc = -2;
goto fail;
}
glX_query_drawable(display, surface, GLX_FBCONFIG_ID, &fbconfigxid);
glxu_get_fbconfig_for_xid(display, fbconfigxid, &fbconfig);
if( major ){
attribs[i_attrib++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
attribs[i_attrib++] = major;
}
if( minor ){
attribs[i_attrib++] = GLX_CONTEXT_MINOR_VERSION_ARB;
attribs[i_attrib++] = minor;
}
if( profile ){
attribs[i_attrib++] = GLX_CONTEXT_PROFILE_MASK_ARB;
attribs[i_attrib++] = profile;
}
attribs[i_attrib] = attribs[i_attrib+1] = 0;
context = glX_create_context_attribs(display, fbconfig, share_context, True, attribs);
if( !context ){
rc= -3;
fprintf(stderr,
"error %s(surface=0x%p, share_context=0x%p, attribs=0x%p): %x
",
glX_create_context_attribs_name,
(void*)surface, (void*)share_context,
attribs,
rc );
goto fail;
}
if( !(glX_make_current(display, surface,