У меня возникла странная проблема с образцом OpenGL на vbox с включенным 3D-ускорением
Это приложение работает правильно в vbox, когда 3D ускорение отключено, и я проверил это на отдельном Linux-ПК. Когда то же самое выполняется при включенном трехмерном ускорении, его невозможно получить указатели функций GL, дающие ошибки - функция no-op
Приложение просто, основной поток создает 2 потока.
Вот код для примера приложения.
#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
Помогите мне понять, в чем проблема.
Что бы вы ни делали, STOP!
Многопоточность + X11 + OpenGL - очень сложная вещь, чтобы получить право. И это почти невозможно сделать правильно, если вы используете Xlib. Xlib никогда не был действительно безопасным потоком.
В любом случае, в первую очередь, вашей программе не хватает вызова XInitThreads
чтобы сделать его по крайней мере безопасным для использования в многопоточных программах. Тем не менее, все же небезопасно распространять Xlib-вызовы на несколько потоков. Это действительно важно: что бы вы ни делали, держите все вызовы Xlib только в одном потоке.
Сам OpenGL не такой сложный. Но поскольку OpenGL нужен контекст, созданный с помощью glX, который, в свою очередь, основывается на Xlib. Обычным подходом является создание контекста OpenGL в потоке Xlib, но позже его включение в поток рендеринга. Однако имейте в виду, что если у вас есть косвенный контекст рендеринга, все вызовы OpenGL проходят через X11, и это может означать через Xlib, и ситуация снова будет неустойчивой.
Из-за всего этого беспорядка самое простое решение: сохранить всю графику и оконную привязку, связанные с одним потоком. Там ничего не получится, если вы поместите операции OpenGL в поток отдельно от остальных операций GUI (технически OpenGL также выполняет операции с графическим интерфейсом). Если вы хотите использовать многопоточность, тогда используйте, если для вещи, смысл которой будет выполняться одновременно, например, аудио, физическое моделирование и т.д.