[英]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示例的怪异问题
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个线程。
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.