Multithread pthread with OpenGL

This is a discussion on Multithread pthread with OpenGL within the C++ Programming forums, part of the General Programming Boards category; I'm having a problem with multithreading with pthreads, here's my code its kinda long so I'm going to put the ...

  1. #1
    Registered User
    Join Date
    Jul 2008
    Posts
    58

    Multithread pthread with OpenGL

    I'm having a problem with multithreading with pthreads, here's my code its kinda long so I'm going to put the important stuff in red:

    Code:
    /**************************
     * Includes
     *
     **************************/
    
    #include <windows.h>
    #include <gl/gl.h>
    #include <pthread.h>
    #include <stdio.h>
    
    
    /**************************
     * Function Declarations
     *
     **************************/
    
    LRESULT CALLBACK WndProc (HWND hWnd, UINT message,
    WPARAM wParam, LPARAM lParam);
    void EnableOpenGL (HWND hWnd, HDC *hDC, HGLRC *hRC);
    void DisableOpenGL (HWND hWnd, HDC hDC, HGLRC hRC);
    
    void *drawGL(void *threadID);
    pthread_t thread;
    
    int rc;
    
    WNDCLASS wc;
        HWND hWnd;
        HDC hDC;
        HGLRC hRC;        
        MSG msg;
        BOOL bQuit = FALSE;
        float theta = 0.0f;
    
    /**************************
     * WinMain
     *
     **************************/
    
    int WINAPI WinMain (HINSTANCE hInstance,
                        HINSTANCE hPrevInstance,
                        LPSTR lpCmdLine,
                        int iCmdShow)
    {
        /* register window class */
        wc.style = CS_OWNDC;
        wc.lpfnWndProc = WndProc;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hInstance = hInstance;
        wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
        wc.hCursor = LoadCursor (NULL, IDC_ARROW);
        wc.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
        wc.lpszMenuName = NULL;
        wc.lpszClassName = "GLSample";
        RegisterClass (&wc);
    
        /* create main window */
        hWnd = CreateWindow (
          "GLSample", "OpenGL Sample", 
          WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE,
          0, 0, 256, 256,
          NULL, NULL, hInstance, NULL);
    
        /* enable OpenGL for the window */
        EnableOpenGL (hWnd, &hDC, &hRC);
    
        /* program main loop */
        while (!bQuit)
        {
            /* check for messages */
            if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
            {
                /* handle or dispatch messages */
                if (msg.message == WM_QUIT)
                {
                    bQuit = TRUE;
                }
                else
                {
                    TranslateMessage (&msg);
                    DispatchMessage (&msg);
                }
            }
            else
            {
    			rc = pthread_create(&thread, NULL, drawGL, (void *)0);
    			if (rc)
    			{
    				printf("ERROR; return code from pthread_create() is %d\n", rc);
    				exit(-1);
    			}
                            pthread_join(thread, NULL);
    //			drawGL(0);
    			Sleep (1);
            }
        }
    
        /* shutdown OpenGL */
        DisableOpenGL (hWnd, hDC, hRC);
    
        /* destroy the window explicitly */
        DestroyWindow (hWnd);
    
        return msg.wParam;
    }
    
    void *drawGL(void *threadID)
    {
    	/* OpenGL animation code goes here */
    
    	glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
    	glClear (GL_COLOR_BUFFER_BIT);
    
    	glPushMatrix ();
    	glRotatef (theta, 0.0f, 0.0f, 1.0f);
    	glBegin (GL_TRIANGLES);
    	glColor3f (1.0f, 0.0f, 0.0f);   glVertex2f (0.0f, 1.0f);
    	glColor3f (0.0f, 1.0f, 0.0f);   glVertex2f (0.87f, -0.5f);
    	glColor3f (0.0f, 0.0f, 1.0f);   glVertex2f (-0.87f, -0.5f);
    	glEnd ();
    	glPopMatrix ();
    
    	SwapBuffers (hDC);
    
    	theta += 1.0f;
    }
    
    
    /********************
     * Window Procedure
     *
     ********************/
    
    LRESULT CALLBACK WndProc (HWND hWnd, UINT message,
                              WPARAM wParam, LPARAM lParam)
    {
    
        switch (message)
        {
        case WM_CREATE:
            return 0;
        case WM_CLOSE:
            PostQuitMessage (0);
            return 0;
    
        case WM_DESTROY:
            return 0;
    
        case WM_KEYDOWN:
            switch (wParam)
            {
            case VK_ESCAPE:
                PostQuitMessage(0);
                return 0;
            }
            return 0;
    
        default:
            return DefWindowProc (hWnd, message, wParam, lParam);
        }
    }
    
    
    /*******************
     * Enable OpenGL
     *
     *******************/
    
    void EnableOpenGL (HWND hWnd, HDC *hDC, HGLRC *hRC)
    {
        PIXELFORMATDESCRIPTOR pfd;
        int iFormat;
    
        /* get the device context (DC) */
        *hDC = GetDC (hWnd);
    
        /* set the pixel format for the DC */
        ZeroMemory (&pfd, sizeof (pfd));
        pfd.nSize = sizeof (pfd);
        pfd.nVersion = 1;
        pfd.dwFlags = PFD_DRAW_TO_WINDOW | 
          PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
        pfd.iPixelType = PFD_TYPE_RGBA;
        pfd.cColorBits = 24;
        pfd.cDepthBits = 16;
        pfd.iLayerType = PFD_MAIN_PLANE;
        iFormat = ChoosePixelFormat (*hDC, &pfd);
        SetPixelFormat (*hDC, iFormat, &pfd);
    
        /* create and enable the render context (RC) */
        *hRC = wglCreateContext( *hDC );
        wglMakeCurrent( *hDC, *hRC );
    
    }
    
    
    /******************
     * Disable OpenGL
     *
     ******************/
    
    void DisableOpenGL (HWND hWnd, HDC hDC, HGLRC hRC)
    {
        wglMakeCurrent (NULL, NULL);
        wglDeleteContext (hRC);
        ReleaseDC (hWnd, hDC);
    }
    when this compiles the drawGL function never works, it just sits there with a black screen, never drawing the triangle.

    I'm very new to multithreading and really want to use pthreads, however no matter what I do I cant seem to make it work : (

    Any help or insight with my problem would be greatly appreciated

  2. #2
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,687
    > pthread_join(thread, NULL);
    1. This causes the caller to wait (see a man page)

    2. //drawGL(0);
    When you had this, it was inside a while() loop, so things like
    theta += 1.0f;
    would be hit many times, and presumably you'd get a new and different scene as a result.

    I think you need
    a) a while loop and a sleep in your thread
    b) remove the pthread_join from inside your winmain message loop.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

  3. #3
    Registered User
    Join Date
    Jul 2008
    Posts
    58
    The reason I had the pthread_join was because I wanted the drawing to finish, then continue on... or else it would run through again and create another thread?

    Also what exactly do you mean by putting a while loop inside my thread? I dont see how that would be useful.... I mean this whole thread stuff is new to me so I dont get it really well... and Im sorry in more than one way for that.

    However I do appreciate your responce and its sparked another frenzy of coding on my part. If you or someone else could share why when I do what you said/except the while loop that is, I still have a freezing program?

    However arbitrarily unintelligent that last sentence was what I mean is how come the thread doesnt work the way I imagine it would? Maybe I'll understand threads better that way

    Even after putting a while loop in the thread, it still crashes

    Code:
    void *drawGL(void *threadID)
    {
    while(bQuit!=TRUE)
    {
    	/* OpenGL animation code goes here */
    	glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
    	glClear (GL_COLOR_BUFFER_BIT);
    
    	glPushMatrix ();
    	glRotatef (theta, 0.0f, 0.0f, 1.0f);
    	glBegin (GL_TRIANGLES);
    	glColor3f (1.0f, 0.0f, 0.0f);   glVertex2f (0.0f, 1.0f);
    	glColor3f (0.0f, 1.0f, 0.0f);   glVertex2f (0.87f, -0.5f);
    	glColor3f (0.0f, 0.0f, 1.0f);   glVertex2f (-0.87f, -0.5f);
    	glEnd ();
    	glPopMatrix ();
    
    	SwapBuffers (hDC);
    
    	theta += 1.0f;
    	Sleep(1);
    }
    }
    for my new thread, and:

    Code:
    else
            {
    			pthread_create(&thread, NULL, drawGL, (void *)0);
    			Sleep (1);
            }
    within my new main thread loop
    Last edited by parad0x13; 07-24-2008 at 12:52 AM.

  4. #4
    Registered User
    Join Date
    Apr 2008
    Posts
    890
    Quote Originally Posted by parad0x13 View Post
    I'm very new to multithreading and really want to use pthreads
    Um, why? Sounds like a solution in search of a problem. OpenGL is a state machine and is not thread safe. If you don't know what you're doing, you'll likely end up making your graphics program slower with threads because of all of the synchronization required.

  5. #5
    Registered User
    Join Date
    Jul 2008
    Posts
    58
    Then what would you recommend that I do to make it so that I can use opengl functions, and also simultaneously scan for user input, and if input is received stop the opengl loops?

  6. #6
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,048
    Code:
    loop:
        process events (user input, etc)
        if the screen ought to be repainted:
            repaint screen
        delay, to keep the CPU usage down (if you want to)
    Do one thing, and then the other.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  7. #7
    Registered User
    Join Date
    Apr 2008
    Posts
    890
    Like dwks suggests, I'd do it sequentially, not in separate threads. Not worth the hassle. Check out the demos on http://nehe.gamedev.net.

  8. #8
    Registered User
    Join Date
    Jul 2008
    Posts
    58
    I had it sequentially, but I had a problem because there was no way of telling if there was user input while the calculation loops were happening.

    My fractal generator isn't very fast right now, I'm working on that, but it takes like 2 seconds to render a fractal, and what i want to happen is during those 2 seconds I want to be able to quit the process by pressing a key.

    If I did it sequentially the program would search for keyboard presses, then do the math and whilst the math was going on I wouldn't be able to stop it because its not searching for keyboard hits...

    I see other fractal generators and they can draw the fractal but after input at anytime they can stop the rendering and move on to the "new" coordinate rendering.

    How would I be able to scan for KB hits and ALSO render? I thought the answer was multithreading, however this may not be the case

  9. #9
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,048
    Well, you might want to use multithreading in that case.

    You just have to be careful what you do in different threads; in the SDL, for example, all of the graphics-related functions are not thread-safe, so you can't call them from more than one thread.

    But I would try to create a function that checks if any keyboard input has been received. In the SDL, for example (sorry, I know the SDL well), you could go:
    Code:
    while(!SDL_PollEvent(&event)) {
        /* . . . continue calculations . . . */
    }
    
    if(!done) {
        /* . . . handle the event, perhaps it's a keypress . . . */
    }
    Sort of like kbhit(), if you're familiar with Borland's compilers.

    [edit] Or perhaps better:
    Code:
    for(;;) {
        if(SDL_PollEvent(&event)) {
            // got an event
            if(event.type == SDL_KEYDOWN) {
                // interrupt the calculations
                break;
            }
        }    
    
        if(done_calculations()) break;
    }
    [/edit]

    I'm sure someone will be able to provide OpenGL-ish code, or perhaps you can find it yourself on NeHe.
    Last edited by dwks; 07-24-2008 at 03:12 PM.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Linking OpenGL in Dev-C++
    By linkofazeroth in forum Game Programming
    Replies: 4
    Last Post: 09-13-2005, 10:17 AM
  2. OpenGL Window
    By Morgul in forum Game Programming
    Replies: 1
    Last Post: 05-15-2005, 12:34 PM
  3. OpenGL .dll vs video card dll
    By Silvercord in forum Game Programming
    Replies: 14
    Last Post: 02-12-2003, 06:57 PM
  4. OpenGL and Windows
    By sean345 in forum Game Programming
    Replies: 5
    Last Post: 06-24-2002, 10:14 PM
  5. opengl code not working
    By Unregistered in forum Windows Programming
    Replies: 4
    Last Post: 02-14-2002, 09:01 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21