Многопоточный пример OpenGL в виртуальной коробке Ubuntu

0

У меня возникла странная проблема с образцом OpenGL на vbox с включенным 3D-ускорением

  • Гость: Ubuntu 12.04
  • Хост: Windows 7, nvidia Graphics
  • vbox версии 4.3.6 с установленными гостевыми дополнениями

Это приложение работает правильно в vbox, когда 3D ускорение отключено, и я проверил это на отдельном Linux-ПК. Когда то же самое выполняется при включенном трехмерном ускорении, его невозможно получить указатели функций GL, дающие ошибки - функция no-op


Приложение просто, основной поток создает 2 потока.

  • Основная тема - Создать тему 1, Создать тему 2
  • Тема 1 - Создайте X-Window для рендеринга
  • Тема 2 - Создайте поток рендеринга (нарисуйте OpenGL quad на X-Window).

Вот код для примера приложения.

#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[]) { */

и для компиляции кода -

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

Помогите мне понять, в чем проблема.

  • 0
    Вы ведете тяжелую битву, плывете против течения. Я согласен с datenwolfs ответ. Тот факт, что вы делаете это в условиях виртуализации, немного ... интересен.
  • 0
    Привет, Вы нашли решение? У меня та же проблема (хост Intel / Win7 64, гостевой Scinetific Linux 64, установлен vbox GA). У меня есть приложение QT, которое выполняет вызовы opengl в выделенном высокоприоритетном потоке. OGL-вызовы в главном потоке работают, вызовы в hp-потоке nop (ничего не делать, без ошибок) ...
Теги:
multithreading
opengl
virtualbox

1 ответ

1
Лучший ответ

Что бы вы ни делали, STOP!

Многопоточность + X11 + OpenGL - очень сложная вещь, чтобы получить право. И это почти невозможно сделать правильно, если вы используете Xlib. Xlib никогда не был действительно безопасным потоком.

В любом случае, в первую очередь, вашей программе не хватает вызова XInitThreads чтобы сделать его по крайней мере безопасным для использования в многопоточных программах. Тем не менее, все же небезопасно распространять Xlib-вызовы на несколько потоков. Это действительно важно: что бы вы ни делали, держите все вызовы Xlib только в одном потоке.

Сам OpenGL не такой сложный. Но поскольку OpenGL нужен контекст, созданный с помощью glX, который, в свою очередь, основывается на Xlib. Обычным подходом является создание контекста OpenGL в потоке Xlib, но позже его включение в поток рендеринга. Однако имейте в виду, что если у вас есть косвенный контекст рендеринга, все вызовы OpenGL проходят через X11, и это может означать через Xlib, и ситуация снова будет неустойчивой.

Из-за всего этого беспорядка самое простое решение: сохранить всю графику и оконную привязку, связанные с одним потоком. Там ничего не получится, если вы поместите операции OpenGL в поток отдельно от остальных операций GUI (технически OpenGL также выполняет операции с графическим интерфейсом). Если вы хотите использовать многопоточность, тогда используйте, если для вещи, смысл которой будет выполняться одновременно, например, аудио, физическое моделирование и т.д.

  • 0
    Добавление к потоку datenwolf, в общем, «многопоточный рендеринг» на практике обычно включает создание списков отображения в разных потоках и отправку этих списков отображения в основной поток для фактического отображения.
  • 0
    @datenwolf Я позвонил XInitThreads в основной теме.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню