简体   繁体   English

Ubuntu virtualbox中的OpenGL多线程示例

[英]OpenGL Multithreaded sample in Ubuntu virtualbox

I am facing a weird problem with an OpenGL sample on vbox with 3D acceleration enabled 我在启用3D加速的vbox上遇到OpenGL示例的怪异问题

  • Guest: Ubuntu 12.04 访客:Ubuntu 12.04
  • Host: Windows 7, nvidia Graphics 主机:Windows 7,nvidia Graphics
  • vbox version 4.3.6 with guest additions installed 安装了来宾添加功能的vbox版本4.3.6

This application runs properly on vbox when 3D acceleration is disabled and I have checked this on stand alone Linux PC as well. 禁用3D加速后,此应用程序可在vbox上正常运行 ,我也在独立的Linux PC上也进行了检查。 When the same is run with 3D acceleration enabled, its not able to get the GL function pointers giving errors - function no-op 如果在启用3D加速的情况下运行相同的代码,则它无法获取出现错误的GL函数指针-function no-op


The App is Simple, Main thread creates 2 threads. 该应用程序很简单,主线程创建2个线程。

  • Main Thread - Create Thread 1, Create Thread 2 主线程-创建线程1,创建线程2
  • Thread 1 - Create a X-Window for Rendering 线程1-创建用于渲染的X窗口
  • Thread 2 - Create Render thread (Draw OpenGL quad on the X-Window). 线程2-创建渲染线程(在X窗口上绘制OpenGL Quad)。

Here is the code for the sample app. 这是示例应用程序的代码。

#include<stdio.h>
#include<stdlib.h>
#include<X11/X.h>
#include<X11/Xlib.h>
#include<GL/gl.h>
#include<GL/glx.h>
//#include<GL/glu.h>
#include <dlfcn.h> /*dlopen*/
#include <pthread.h>
#include <unistd.h> /*sleep*/

Display                 *dpy;
Display                 *dpy2;
Window                  root;
GLint                   att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
XVisualInfo             *vi;
XVisualInfo             *vi2;
Colormap                cmap;
XSetWindowAttributes    swa;
Window                  win;
GLXContext              glc;
XWindowAttributes       gwa;
XEvent                  xev;
bool            render;


void DrawAQuad() 
{
    glClearColor(1.0, 1.0, 1.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1., 1., -1., 1., 1., 20.);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    //gluLookAt(0., 0., 10., 0., 0., 0., 0., 1., 0.);
    glTranslatef(0.0, 0.0, -10.0);

    glBegin(GL_QUADS);
     glColor3f(1., 0., 0.); glVertex3f(-.75, -.75, 0.);
     glColor3f(0., 1., 0.); glVertex3f( .75, -.75, 0.);
     glColor3f(0., 0., 1.); glVertex3f( .75,  .75, 0.);
     glColor3f(1., 1., 0.); glVertex3f(-.75,  .75, 0.);
    glEnd();
}

void *CreateMainWindow(void* threadID)
{
    dpy = XOpenDisplay(NULL);
    if(dpy == NULL) 
    {
        printf("\n\tWindow Thread: cannot connect to X server\n\n");
        exit(0);
    }

    root = DefaultRootWindow(dpy);
    printf("\n *** CreateWindow: xopendisplay over *** \n");

    vi = (XVisualInfo*)glXChooseVisual(dpy, 0, att);
    if(vi == NULL) 
    {
        printf("\n\tWindow Thread: no appropriate visual found\n\n");
        exit(0);
    } 
    else 
    {
        printf("\n\tWindow Thread: visual %p selected\n", (void *)vi->visualid);
    }

    cmap = XCreateColormap(dpy, root, vi->visual, AllocNone);
    swa.colormap = cmap;
    swa.event_mask = ExposureMask | KeyPressMask;

    win = XCreateWindow(dpy, root, 0, 0, 600, 600, 0, vi->depth, InputOutput, vi->visual, CWColormap | CWEventMask, &swa);
    XMapWindow(dpy, win);
    XStoreName(dpy, win, "VERY SIMPLE APPLICATION");

    while(1) 
    {
        XNextEvent(dpy, &xev);
        printf("\nXEVENT\n");
        if(xev.type == Expose)
        {
            render = true;
        }
        else if(xev.type == KeyPress)
        {
            XDestroyWindow(dpy, win);
            XCloseDisplay(dpy);
            render = false;
            break;
            //exit(0);
        }
    }
}

void *RenderThread(void* threadID)
{
    vi2 = (XVisualInfo*)glXChooseVisual(dpy2, 0, att);
    printf("\n\tRenderThread : visual %p selected\n", (void *)vi2->visualid);

    glc = (GLXContext)glXCreateContext(dpy2, vi2, NULL, GL_TRUE);
    glXMakeCurrent(dpy2, win, glc);

    glEnable(GL_DEPTH_TEST); 

    while(render) 
    {
        //XGetWindowAttributes(dpy, win, &gwa);
        glViewport(0, 0, 600, 600);
        DrawAQuad(); 
        glXSwapBuffers(dpy2, win);
    } /* this closes while(render) */

    glXMakeCurrent(dpy2, None, NULL);
    glXDestroyContext(dpy2, glc);
    XCloseDisplay(dpy2);
}

int main(int argc, char *argv[]) 
{
    render = true;
    pthread_t thread1;
    pthread_t thread2;
    char *temp1;
    char *temp2;

    //For Async issue
    if(!XInitThreads())
    {
        fprintf(stderr, "XInitThread failed\n");
        return 0;
    }

    //Create Main Window
    int err = pthread_create(&thread1, NULL, CreateMainWindow, (void*)temp1);
    if (err != 0)
        printf("\n ERROR::can't create thread1 :[%d]", err);
    else
        printf("\n Thread1 created successfully\n");

    sleep(1); // Wait for thread 1 to complete

    dpy2 = XOpenDisplay(NULL);
    if(dpy2 == NULL) 
    {
        printf("\n\tMain : cannot connect to X server\n\n");
        exit(0);
    }

    //Create Render Thread
    err = pthread_create(&thread2, NULL, RenderThread, (void*)temp2);
    if (err != 0)
        printf("\n ERROR::can't create thread2 :[%d]", err);
    else
        printf("\n Thread2 created successfully\n");

    pthread_join( thread1, NULL);
    pthread_join( thread2, NULL);

} /* this is the } which closes int main(int argc, char *argv[]) { */

and to compile the code - 并编译代码-

g++ -o quad quad.cpp -lGL -lX11 -lXmu -lXi -lpthread -lm

Help me understand where the issue lies 帮我了解问题所在

Whatever you thick you're doing, STOP! 无论您在做什么,停止!

Multithreading + X11 + OpenGL is a very tricky thing to get right. 多线程+ X11 + OpenGL是一件非常棘手的事情。 And it's nearly impossible to do correct if you're using Xlib. 如果您使用的是Xlib,几乎不可能进行更正。 Xlib never was truly thread safe. Xlib从来没有真正做到线程安全。

Anyway, first and foremost your program lacks a call to XInitThreads to make it at least safe to use in multithreaded programs. 无论如何,最重要的是您的程序缺少对XInitThreads的调用,以使其至少在多线程程序中安全使用。 It's however still unsafe to spread out Xlib calls over multiple threads. 但是,将Xlib调用分散到多个线程仍然不安全。 This is really important: Whatever you do, keep all Xlib calls to one thread only. 这真的很重要:无论您做什么,都将所有Xlib调用仅保留到一个线程中。

OpenGL itself is not as tricky. OpenGL本身并不那么棘手。 But because OpenGL needs a context created with glX, which in turn builds on Xlib. 但是因为OpenGL需要使用glX创建的上下文,而后者又基于Xlib构建。 The usual approach is to create the OpenGL context in the Xlib thread, but later on make it current in the renderer thread. 通常的方法是在Xlib线程中创建OpenGL上下文,但稍后使其在渲染器线程中成为当前上下文。 However be advised that if you got an indirect rendering context all OpenGL calls go through X11 and that may mean through Xlib and things are going to be unstable again. 但是请注意,如果您获得了间接渲染上下文,则所有OpenGL调用都将通过X11,这可能意味着通过Xlib,并且情况将再次变得不稳定。

Because of all that mess the simplest solution is: Keep everything graphics and windowing related to one thread. 由于种种混乱,最简单的解决方案是:使所有图形和窗口与一个线程相关。 There's nothing to be gained if you put OpenGL operations into a thread separate from the rest of the GUI operations (technically OpenGL does GUI operations as well). 如果将OpenGL操作放入与其余GUI操作分开的线程中,则没有任何收获(从技术上讲,OpenGL也执行GUI操作)。 If you want to use multithreading, then use if for thing that make sense to be executed concurrently, like audio, physics simulation and such. 如果要使用多线程,则可以将if用于有意义的事情并发执行,例如音频,物理模拟等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM