Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 3 of 3

Thread: Sharing contexts with GLX for multithreaded app

  1. #1
    Junior Member Newbie
    Join Date
    Nov 2012
    Posts
    10

    Sharing contexts with GLX for multithreaded app

    Hello everyone.

    I'm programming a flight simulator app and I have data for the whole world.
    Then, there is a lot of textures and geometry to load so I made a background thread that dynamically load all that data depending on my position on Earth.
    Since I'm using SOIL to load my textures, I need to create a 2nd context for that background thread that will share OpenGL data with the main thread's context.

    I use GLX to manage my window and I didn't find any example of this. I just know which functions to use but I'm facing some problems.

    Here's what I do:

    - init XLib thread support
    - create the foreground context
    - create the background context with the foreground one as shareList
    - make the foreground context current for the rendering thread
    - create the loader thread passing a structure containing the Display, the Window and the background context
    - in the loader thread, make the background context current

    It crashes with a segfault on the last step, when I call glXMakeCurrent with the Display, the Window and the thread context...

    I'm doing something wrong but I don't know what and can't find solutions on forums.
    Do you have any idea ?

    Thank you for your help !

    Here's my full code :

    main
    Code :
    Display *dpy;
    Window win;
    GLXContext foregroundCtx, backgroundCtx;
     
    int32_t main(int32_t argc, char** argv) 
    {       
        //init my own stuff (data paths, ini...)
        initVisualSystem(argc, argv);
     
        //create the window
        initXDisplay();
     
        glewInit();
        //init my openGL stuff and create background thread
        init(dpy, &backgroundCtx, &win, argc, argv);
     
        event_loop(dpy, win);
     
        cleanVisualSystem();
     
        //XClean
        glXDestroyContext(dpy, foregroundCtx);
        glXDestroyContext(dpy, backgroundCtx);
        XDestroyWindow(dpy, win);
        XCloseDisplay(dpy);
     
        return 0;
    }

    initXDisplay
    Code :
    void initXDisplay()
    {
        XInitThreads();
     
        dpy = XOpenDisplay(NULL);
        if (!dpy) 
        {
            cerr << "Error: couldn't open display" << endl;
            exit(1);
        }
     
        uint32_t width = renderer.getView()->getWidth();
        uint32_t height = renderer.getView()->getHeight();
     
        make_window(dpy, "XN3", 0, 0, width, height, &win, &foregroundCtx, &backgroundCtx);
     
        XMapWindow(dpy, win);
        [b]glXMakeCurrent(dpy, win, foregroundCtx);[/b]
     
        if (FULLSCREEN) 
        {
            makeFullscreen(dpy, win);
        }
        hideCursor(dpy, win);
    }
     
     
    static void make_window( Display *dpy, const char *name,
                 int x, int y, int width, int height,
                 Window *winRet, GLXContext *foregroundCtxRet, GLXContext *backgroundCtxRet)
    {
        if(VSYNC)
            putenv( (char *) "__GL_SYNC_TO_VBLANK=1" );
        else
            putenv( (char *) "__GL_SYNC_TO_VBLANK=0" );
     
        int attrib[] = { GLX_RGBA,
                         GLX_RED_SIZE, 1,
                         GLX_GREEN_SIZE, 1,
                         GLX_BLUE_SIZE, 1,
                         GLX_DOUBLEBUFFER,
                         GLX_DEPTH_SIZE, 24,
                         GLX_SAMPLE_BUFFERS  , 1*MULTISAMPLING,      // <-- MSAA
                         GLX_SAMPLES         , 4*MULTISAMPLING,      // <-- MSAA
                         None };
        int scrnum;
        XSetWindowAttributes attr;
        unsigned long mask;
        Window root;
        Window win;
        GLXContext foregroundCtx, backgroundCtx;
        XVisualInfo *visinfo;
     
        scrnum = DefaultScreen( dpy );
        root = RootWindow( dpy, scrnum );
     
        visinfo = glXChooseVisual( dpy, scrnum, attrib );
        if (!visinfo) {
           printf("Error: couldn't get an RGB, Double-buffered visual\n");
           exit(1);
        }
     
        /* window attributes */
        attr.background_pixel = 0;
        attr.border_pixel = 0;
        attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
        attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPress | PointerMotionMask;
        mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
     
        win = XCreateWindow( dpy, root, 0, 0, width, height,
                             0, visinfo->depth, InputOutput,
                             visinfo->visual, mask, &attr );
     
        /* set hints and properties */
        {
           XSizeHints sizehints;
           sizehints.x = x;
           sizehints.y = y;
           sizehints.width  = width;
           sizehints.height = height;
           sizehints.flags = USSize | USPosition;
           XSetNormalHints(dpy, win, &sizehints);
           XSetStandardProperties(dpy, win, name, name,
                                   None, (char **)NULL, 0, &sizehints);
        }
     
        foregroundCtx = glXCreateContext( dpy, visinfo, NULL, True );
        if (!foregroundCtx) {
           printf("Error: glXCreateContext for mainCtx failed\n");
           exit(1);
        }  
        backgroundCtx = glXCreateContext( dpy, visinfo, foregroundCtx, True );
        if (!backgroundCtx) {
           printf("Error: glXCreateContext for threadCtx failed\n");
           exit(1);
        }
     
        XFree(visinfo);
     
        *winRet = win;
        *foregroundCtxRet = foregroundCtx;
        *backgroundCtxRet = backgroundCtx;
    }

    init
    Code :
    void init(Display *dpy, GLXContext* backgroundCtx, Window* win, int32_t argc, char** argv)
    {          
        //init my OpenGL stuff (shaders...)
        ...
     
        SLoaderThread sLoaderThread;
        sLoaderThread.pBV3DManager = renderer.getBV3DManager();
        sLoaderThread.dpy = dpy;
        sLoaderThread.backgroundCtx = backgroundCtx;
        sLoaderThread.win = win;
        pthread_create(&loaderThread, NULL, startLoaderThread, (void*)&sLoaderThread);
    }
     
    struct SLoaderThread
    {
        CBV3DManager* pBV3DManager;    //manages my world geometries and textures
        Display *dpy;
        GLXContext* backgroundCtx;
        Window* win;
    };
     
     
    void* startLoaderThread(void* data)
    {
        SLoaderThread* pSLoaderThread = (SLoaderThread*)data;
     
        glXMakeCurrent(pSLoaderThread->dpy, *pSLoaderThread->win, *pSLoaderThread->backgroundCtx);    //Crashes here with a segfault
        while(1)
        {
            pSLoaderThread->pBV3DManager->updateZones();
        }
        return NULL;
    }
    Last edited by Vylsain; 05-15-2013 at 02:09 AM.

  2. #2
    Junior Member Regular Contributor
    Join Date
    Dec 2009
    Posts
    198
    You pass the address of a stack-allocated structure to pthread_create, this will be destroyed as soon as the main thread leaves init(), so probably before the loader thread has a chance to read the stuff. Pass the data in static or malloc()ed memory.

  3. #3
    Junior Member Newbie
    Join Date
    Nov 2012
    Posts
    10
    Oh ok. That's the first time I use theads and even though that's completely logical and the first thing to check, I missed that !

    Thank you for your help mbentrup !

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •