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 6 of 6

Thread: Multi-threaded loading screen

  1. #1
    Junior Member Newbie
    Join Date
    Mar 2009
    Posts
    2

    Multi-threaded loading screen

    Hi,

    I thought it'd be fun to add a loading screen to my OpenGL game (as a lot of computations are done before the program is loaded, and waiting ~30secs with no reaction at all is pretty dull.)

    I've worked out that the simplest way to do it would be to:
    - create a thread, where all initialization data is handled
    - in the main thread, in te display function, check, whether the initialization has finished, and if not, display something (eg. some text.) If it has finished - the game is loaded and the standard screen can be shown.

    However, the problem is that the initialization stuff handled in the newly created thread uses glCreateList, glNewList, drawing onto that list, etc. As I figured out after reviewing some threads in the forum, my newly created thread doesn't have the OpenGL context, also that I shouldn't even attempt to share the same context over several threads.

    Has anyone have the idea how to make this work? Or perhaps, the better way to create graphical loading screen? Thanks in advance!

  2. #2
    Advanced Member Frequent Contributor
    Join Date
    Apr 2003
    Posts
    661

    Re: Multi-threaded loading screen

    Create one context per thread. You may let them share their lists (i.e. wglShareLists).
    Now start loading/creating your resources in one thread (context 1), while you display the loading progress in the other(context 2).

    If they share lists, be careful, not to make concurrent modifications of the same objects (textures, display lists, VBOs etc) at the same time.

  3. #3
    Intern Newbie
    Join Date
    Aug 2008
    Posts
    35

    Re: Multi-threaded loading screen

    Why not let the new thread display the loading window and keep the init stuff in the main thread? The new thread + the loading window get self terminated once init is done.. Possible?

  4. #4
    Senior Member OpenGL Pro Ilian Dinev's Avatar
    Join Date
    Jan 2008
    Location
    Watford, UK
    Posts
    1,270

    Re: Multi-threaded loading screen

    Here's a simplified version:
    Code :
    struct{
    	bool EverythingLoaded;
    	int level_to_load;
     
    	critical_section cs;
    	ObjVector newStuff;
    }LLL;
     
    void thread2(){ // loads things from HDD to RAM
    	startLoadingLevel(LLL.level_to_load);
    	for(;;){
    		if(noMoreDataToLoad())break;
     
    		Object edx = LoadNextThingFromHDD();
    		EnterCriticalSection(&LLL.cs);
    		LLL.newStuff.add(edx);
    		LeaveCriticalSection(&LLL.cs);		
    	}
    	LLL.EverythingLoaded=true;
    }
     
    void LoadLevel(int id){ // uploads things from RAM to GPU
    	LLL.EverythingLoaded=false;
    	LLL.level_to_load = id;
    	LLL.newStuff = new ObjVector();
    	InitializeCriticalSection(&LLL.cs);
     
    	ObjVector newStuff = new ObjVector();
     
    	startThread(thread2);
     
    	for(;;){
    		EnterCriticalSection(&LLL.cs);
    		newStuff = CopyVectorEntries(LLL.newStuff);
    		LLL.newStuff.clear();
    		LeaveCriticalSection(&LLL.cs);
     
    		foreach(newStuff,Object edx){
    			switch(edx->type){
    			case texture:
    				uploadTexture(edx); // upload texture from RAM to GPU
    				break;
    			case vbo:
    				uploadVbo(edx); // upload vbo from RAM to GPU
    				break;			
    		}
    		newStuff.clear();
     
    		if(LLL.EverythingLoaded)break;
     
     
     
    		glClear(depthbit | colorbit);
    		drawLoadingScreen();
     
    		SwapBuffers();		
    	}
     
    }

    HDD->RAM is the real bottleneck. Now, GLSL compilation can require processing of 1 shader/frame. Or more smartly: You can put timing measurement, if 10ms have been spent inside that "for(;{" in LoadLevel(), return remaining object to LLL.newStuff and break out from the loop.

  5. #5
    Junior Member Newbie
    Join Date
    Mar 2009
    Posts
    2

    Re: Multi-threaded loading screen

    I found myself doing it the way skynet suggested, but I still haven't managed to make it work (still get error 1280, which means the display lists are not being shared properly.) Guess I execute the wglShareLists the wrong way, or something else is wrong. Anyway, I do it that way:

    Code :
    // the display function of main thread
    void display()
    {
        if (!loadingDone)
        {
            threadInit();
            // display the loading stuff
        }
        else
        {
            // draw some else stuff
        }
    }
     
    // thread init function
    void JobQueue::start()
    {
        if (!started)
        {
            // remember display and render context for the main thread
            started = true;
            hMainDC = wglGetCurrentDC();
            hMainRC = wglGetCurrentContext();
     
            // (...) - create the thread
        }
    }
     
    // thread function
    DWORD WINAPI ThreadFunction (LPVOID lpParam)
    {
        // create render context based on main window's device context
        HGLRC hRC = wglCreateContext(queue->hMainDC);
        wglMakeCurrent(queue->hMainDC, hRC);
        wglShareLists(queue->hMainRC,hRC);
     
        // (...) - execute all jobs
        loadingDone = true;
     
        return 1;
    }

    The problem might be that I don't understand gow wglShareLists and wglMakeCurrent work, and I use them the inapropriate way.

    Quote Originally Posted by muvee
    Why not let the new thread display the loading window and keep the init stuff in the main thread? The new thread + the loading window get self terminated once init is done.. Possible?
    You mean like creating two separate windows? Yeah, that might work, though I'm not exactly sure that would look nice. Or perhaps both threads drawing onto the same window, and after finishing the loading, making a switch between their display functions? But again, this is roughly what skynet proposed, only without the wglShareLists call. However, I might find myself doing it that way, if what I've tried doesn't work.

  6. #6
    Advanced Member Frequent Contributor
    Join Date
    Apr 2003
    Posts
    661

    Re: Multi-threaded loading screen

    I guess, you problem is that you want to use the _same_ DC in both threads. (Always check return values!!!)I doubt that you can bind two RCs to one DC at the same time. You may need to create a second "dummy" window for your second RC. It can be invisible and never needs to show up. Its just needed to make wglMakeCurrent() happy. (btw, this got a bit relaxed with WGL_ARB_create_context)

    The call to wglShareLists() is ok, but I suggest doing the creation of those DC's and RC's at initialization time in the main thread and handing the handles over the loading thread when its being created. I have no idea, how a wglShareLists call works, if one of the RC's is already doing something at the same time in a different thread...

    Btw, I never claimed, that the loading _must_ be done in that second thread. You can switch roles of both threads, if it suits you better. The main idea is just to have two separate threads doing their work in two separate contexts.

Posting Permissions

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