-1

I'm having some troubles with OpenGL and multithreading. The thing is I cannot understand why I have this issue. I'm using MACOS (the includes are therefore going to be different if you try my code). Here the simple program that I manage to run without any problem.

char title[] = "3D Shapes with animation"; 

GLfloat anglePyramid = 0.0f;  // Rotational angle for pyramid [NEW]
GLfloat angleCube = 0.0f;     // Rotational angle for cube [NEW]
int refreshMills = 15;        // refresh interval in milliseconds [NEW]

bool serverHasInput = false ;

float matrix[16] = {0.7599139,0.0,-0.65002376,0.0,-0.45789394,0.709777,-0.5353035,0.0,0.4613719,0.70442647,0.5393694,0.0,0.0,0.0,0.0,1.0};

float moveX = 0;
float moveY = 0;

pthread_mutex_t mymutex ;
pthread_cond_t mycondition ;



/* Initialize OpenGL Graphics */
void initGL() {
   glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set background color to black and opaque
   glClearDepth(1.0f);                   // Set background depth to farthest
   glEnable(GL_DEPTH_TEST);   // Enable depth testing for z-culling
   glDepthFunc(GL_LEQUAL);    // Set the type of depth-test
   glShadeModel(GL_SMOOTH);   // Enable smooth shading
   glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);  // Nice perspective corrections
}

/* Handler for window-repaint event. Called back when the window first appears and
   whenever the window needs to be re-painted. */
void display() {
   //while(matrixSet == true){
     // sleep(0.01);
   //}
   pthread_mutex_lock(&mymutex);
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear color and     depth buffers
   glMatrixMode(GL_MODELVIEW);     // To operate on model-view matrix

   // Render a color-cube consisting of 6 quads with different colors
   glLoadIdentity();                 // Reset the model-view matrix
   glTranslatef(1.5f, 0.0f, -7.0f);  // Move right and into the screen
   glRotatef(angleCube, 1.0f, 1.0f, 1.0f);  // Rotate about (1,1,1)-axis [NEW]
      glMultMatrixf(matrix);
   pthread_mutex_unlock(&mymutex);
   glBegin(GL_QUADS);                // Begin drawing the color cube with 6 quads
      // Top face (y = 1.0f)
      // Define vertices in counter-clockwise (CCW) order with normal pointing out
  glColor3f(0.0f, 1.0f, 0.0f);     // Green
  glVertex3f( 1.0f, 1.0f, -1.0f);
  glVertex3f(-1.0f, 1.0f, -1.0f);
  glVertex3f(-1.0f, 1.0f,  1.0f);
  glVertex3f( 1.0f, 1.0f,  1.0f);

  // Bottom face (y = -1.0f)
  glColor3f(1.0f, 0.5f, 0.0f);     // Orange
  glVertex3f( 1.0f, -1.0f,  1.0f);
  glVertex3f(-1.0f, -1.0f,  1.0f);
  glVertex3f(-1.0f, -1.0f, -1.0f);
  glVertex3f( 1.0f, -1.0f, -1.0f);

  // Front face  (z = 1.0f)
  glColor3f(1.0f, 0.0f, 0.0f);     // Red
  glVertex3f( 1.0f,  1.0f, 1.0f);
  glVertex3f(-1.0f,  1.0f, 1.0f);
  glVertex3f(-1.0f, -1.0f, 1.0f);
  glVertex3f( 1.0f, -1.0f, 1.0f);

  // Back face (z = -1.0f)
  glColor3f(1.0f, 1.0f, 0.0f);     // Yellow
  glVertex3f( 1.0f, -1.0f, -1.0f);
  glVertex3f(-1.0f, -1.0f, -1.0f);
  glVertex3f(-1.0f,  1.0f, -1.0f);
  glVertex3f( 1.0f,  1.0f, -1.0f);

  // Left face (x = -1.0f)
  glColor3f(0.0f, 0.0f, 1.0f);     // Blue
  glVertex3f(-1.0f,  1.0f,  1.0f);
  glVertex3f(-1.0f,  1.0f, -1.0f);
  glVertex3f(-1.0f, -1.0f, -1.0f);
  glVertex3f(-1.0f, -1.0f,  1.0f);

  // Right face (x = 1.0f)
  glColor3f(1.0f, 0.0f, 1.0f);     // Magenta
  glVertex3f(1.0f,  1.0f, -1.0f);
  glVertex3f(1.0f,  1.0f,  1.0f);
  glVertex3f(1.0f, -1.0f,  1.0f);
  glVertex3f(1.0f, -1.0f, -1.0f);
glEnd();  // End of drawing color-cube
   glutSwapBuffers();  // Swap the front and back frame buffers (double buffering)

   // Update the rotational angle after each refresh [NEW]
   //anglePyramid += 1.2f;
   //angleCube -= 0.15f;
   pthread_cond_signal(&mycondition);
   pthread_mutex_unlock(&mymutex);

}

/* Called back when timer expired [NEW] */
void timer(int value) {
   glutPostRedisplay();      // Post re-paint request to activate display()
   glutTimerFunc(refreshMills, timer, 0); // next timer call milliseconds later
}

/* Handler for window re-size event. Called back when the window first appears and
   whenever the window is re-sized with its new width and height */
void reshape(GLsizei width, GLsizei height) {  // GLsizei for non-negative integer
   // Compute aspect ratio of the new window
   if (height == 0) height = 1;                // To prevent divide by 0
   GLfloat aspect = (GLfloat)width / (GLfloat)height;

   // Set the viewport to cover the new window
   glViewport(0, 0, width, height);

   // Set the aspect ratio of the clipping volume to match the viewport
   glMatrixMode(GL_PROJECTION);  // To operate on the Projection matrix
   glLoadIdentity();             // Reset
   // Enable perspective projection with fovy, aspect, zNear and zFar
   gluPerspective(45.0f, aspect, 0.1f, 100.0f);
}

void keyPressed (unsigned char key, int x, int y) {  
      if (key == 'y'){
         moveY += 0.5;
         cout << "y" << endl ;
      }
}  

/* Main function: GLUT runs as a console application starting at main() */
int main(int argc, char* argv[]) {
   glutInit(&argc, argv);            // Initialize GLUT
   glutInitDisplayMode(GLUT_DOUBLE); // Enable double buffered mode
   glutInitWindowSize(640, 480);   // Set the window's initial width & height
   glutInitWindowPosition(50, 50); // Position the window's initial top-left corner
   glutCreateWindow(title);          // Create window with the given title
   glutDisplayFunc(display);       // Register callback handler for window re-paint event
   glutReshapeFunc(reshape);       // Register callback handler for window re-size event
   initGL();                       // Our own OpenGL initialization
   glutTimerFunc(0, timer, 0);     // First timer call immediately [NEW]
   glutKeyboardFunc(keyPressed); // Tell GLUT to use the method "keyPressed" for key presses  
   glutMainLoop();                 // Enter the infinite event-processing loop
}

So this is my basic code that works like a charm. However, when I'm trying to create a thread to make it run I cannot get theKeyboardInput anymmore as well as some other aspects that are wrong (cannot clic on the X to exit the window for instace).

Here is my code: My OpenGL functions are all the same except for this part:

/* Main function: GLUT runs as a console application starting at main() */
void* launch(void* args) {
   mainArg* arg = (mainArg*) args ;
   glutInit(arg->argc, &arg->argv);            // Initialize GLUT

And here is how I create the threads:

//the thread function
void *connection_handler(void *);

void * connection_thread(void *);

void * input_thread(void *);

void test();


int main(int argc , char *argv[])
{
    //Draw* d = new Draw() ;
    pthread_t server_thread ;
    pthread_t drawing_thread ;
pthread_t input_thread ;
mainArg args ;
args.argc = &argc ;
args.argv = *argv ;


pthread_mutex_init (&mymutex, NULL);
pthread_cond_init (&mycondition, NULL);

cout << "Begin" << endl ;

if( pthread_create( &server_thread , NULL ,  &connection_thread , NULL) != 0)
{
        cout << "could not create Connection thread" << endl ;
        return 1;
}
/*if( pthread_create( &input_thread , NULL ,  &connection_thread , NULL) != 0)
{
        cout << "could not create input thread" << endl ;
        return 1;
}*/
if( pthread_create( &drawing_thread , NULL ,  &launch , &args) != 0)
{
        perror("could not create Drawing thread");
        return 1;
}

//while(1);
pthread_join(server_thread, NULL);
pthread_join(drawing_thread,NULL);

Would you happen to know what's wrong here? Cause I've been looking at it for days now and I can't seem to find an answer.

EDIT: I am not sharing the OpenGL context or anything that has to be a part of the OGL rendering on an other thread. My other thread is only a server communication with other devices.

EDIT2: I saw here a while ago that not having OGL rendering on the main thread should not be an issue OpenGL Rendering in a secondary thread

Community
  • 1
  • 1
LBes
  • 3,366
  • 1
  • 32
  • 66
  • Old OpenGL is single-threaded, as is much of X as well, you have to keep all window handling and actual rendering in a single thread. That includes window event handling. – Some programmer dude May 21 '15 at 13:32
  • OpenGL + Multithreading: don't try to mix them unless you are already *very* familiar with both! OpenGL contexts are *per-thread*, and the UI thread is also usually only one thread. – Dietrich Epp May 21 '15 at 13:33
  • I am actually not sharing the OpenGL on other threads. I just have a server that is actually communicating with something else while the rendering is done. The messages that the server gets help to assign new values to some of my global variables that are used by OpenGL. But I've been careful to use Mutexes and Semaphores to lock everything and avoid conflict in reading/writing. The only thing I'm trying to have is one thread with OpenGL rendering and an other thread with a server communcating with other clients. None of the rendering is share – LBes May 21 '15 at 13:35
  • 1
    Keep OpenGL and the UI both on the main thread. Only create background threads, and don't do UI or OpenGL in the background threads. – Dietrich Epp May 21 '15 at 13:36
  • Do they really have to be on the main thread? Because not having something else running as my main thread is kind of not consistent with the architecture I need to have – LBes May 21 '15 at 13:39
  • AFAIK you can create the window on a separate thread, and keep all the rendering stuff on that thread, and it will work. – Colonel Thirty Two May 21 '15 at 14:12
  • That's basically what I did isn't it? – LBes May 21 '15 at 14:14
  • 2
    Most of the above information is incorrect. For example, Apple's own Final Cut Pro and Motion do OpenGL rendering with OpenGL 2.1 on background threads. If you ever write an FxPlug, you'll be called to render it on a background thread and passed an OpenGL 2.1 texture. You do have to be careful not to use the same OpenGL context on 2 threads, for sure. But it can be done and works fine if you follow the rules. You should not create or use (OS-Native) windows or views on any thread other than the main thread. – user1118321 May 21 '15 at 15:14
  • That said, if GLUT is trying to access its OS window, then you may not want to use GLUT on any other thread than the main thread. (BTW, GLUT is deprecated. You should use something else going forward.) – user1118321 May 21 '15 at 15:15
  • I do know that GLUT is deprecated but the thing is that I don't want to spend ages learning Cocoa ... I know the old way (GLUT) and I'm happy to stick with for the toy example that I'm building. So you reckon that the fact that it's a background thread prevents GLUT from accessing the different inputs done on the OS windows? Keeping in as a main thread really doesn't make sense for what I'm doing though ... – LBes May 21 '15 at 15:25

1 Answers1

1

So @user1118321 was correct.

There are absolutely no problem to try and do the rendering on a background thread. However, GLUT will not be able to access the information of the OS window (i.e keyboard press, exit window ... ) if it is done that way. Still, if the purpose of the rendering thread is just to render, no problem at all to put it on a background thread.

Hope it helps other people too.

LBes
  • 3,366
  • 1
  • 32
  • 66