OpenGL 和多线程

OpenGL and Multithreading

我在使用 OpenGL 和多线程时遇到了一些问题。问题是我不明白为什么我有这个问题。 我正在使用 MACOS(因此,如果您尝试我的代码,包含的内容会有所不同)。 这里是我设法 运行 没有任何问题的简单程序。

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
}

所以这是我的基本代码,非常有用。 但是,当我尝试创建一个线程以使其成为 运行 时,我无法再获得 KeyboardInput 以及其他一些错误的方面(例如无法点击 X 退出 window) .

这是我的代码: 除了这部分,我的 OpenGL 函数都是一样的:

/* 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

下面是我创建线程的方式:

//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);

你知道这里出了什么问题吗?因为我已经看了好几天了,但似乎找不到答案。

编辑:我不会共享 OpenGL 上下文或任何必须成为其他线程上 OGL 渲染的一部分的内容。我的其他线程只是与其他设备的服务器通信。

EDIT2:我刚才在这里看到,在主线程上没有 OGL 渲染应该不是问题 OpenGL Rendering in a secondary thread

所以@user1118321 是正确的。

尝试在后台线程上进行渲染绝对没有问题。 但是,如果这样做的话,GLUT 将无法访问 OS window 的信息(即键盘按下,退出 window ...)。不过,如果渲染线程的目的只是为了渲染,把它放在后台线程上一点问题都没有。

希望对其他人也有帮助。