我正在进行大量的纹理上传(每秒60个VGA图像)并且它阻止了我的UI线程。来自the Qt 5.1 QGLWidget manual page(强调我的):
在线程中上传纹理。 在线程中进行纹理上传对于处理需要显示的大量图像的应用程序非常有用,例如照片库应用程序。 Qt通过现有的bindTexture()API支持此功能。一种简单的方法是创建两个共享QGLWidgets。一个在主GUI线程中变为当前,而另一个在纹理上载线程中变为当前。 上传线程中的小部件永远不会显示,它仅用于与主线程共享纹理。对于通过bindTexture()绑定的每个纹理,通知主线程,以便它可以开始使用纹理。
什么?如何将基于QWidget的类(如QGLWidget)移动到线程?试图这样做会导致:
QObject::moveToThread: Widgets cannot be moved to a new thread
我不明白文档建议我实施什么以便移动,例如bindTexture()
执行UI线程。
这里也提到了这一点:Qt4/Opengl bindTexture in separated thread
虽然没有张贴代码。
答案 0 :(得分:8)
答案稍晚,但是小部件需要通过创建它们的线程移动到新线程。在你的情况下像:
QGLWidget *glWidget=new QGLWidget();
QThread *newThread=new QThread();
glWidget->doneCurrent();
glWidget->context()->moveToThread(newThread);
这里我只将openGL上下文移动到新线程,这要求捕获并忽略QGLWidget中的一些覆盖。您需要从QGLWidget创建一个新的派生类并覆盖以下内容。
virtual void glInit();
virtual void glDraw();
virtual void initializeGL();
virtual void resizeGL(int width, int height);
virtual void paintGL();
这会阻止标准UI线程尝试在UI线程中使OpenGL上下文变为当前。一旦你覆盖了上面的内容,你将需要一个事件系统来通知线程发生了一些事件,主要是resizeGl和paintGL,否则小部件将不会与周围的其他人做出正确的反应。
最后一部分是创建QGLWidget。构造中的一个参数是const QGLWidget * shareWidget:
QGLWidget ( QWidget * parent = 0, const QGLWidget * shareWidget = 0, Qt::WindowFlags f = 0 )
QGLWidget ( QGLContext * context, QWidget * parent = 0, const QGLWidget * shareWidget = 0, Qt::WindowFlags f = 0 )
QGLWidget ( const QGLFormat & format, QWidget * parent = 0, const QGLWidget * shareWidget = 0, Qt::WindowFlags f = 0 )
然后,您将创建ui QGLWidget和线程GLWidget(从QGLWidget派生,并带有上面提到的所有覆盖),确保在创建线程GLWidget时,您将QGLWidget作为sharedWidget提供。这将使2 opengl上下文共享,并允许您加载纹理,两者都可以看到。代码看起来像这样:
QGLWidget *glWidget=new QGLWidget();
GLWidget *threadedWidget=new GLWidget(0/*parent*/, glWidget);
QThread *newThread=new QThread();
threadedWidget->moveToThread(newThread);
至于代码我最近使用主要用于openGL / openCL互操作的线程QGLWidgets编写了一个小示例程序,但它显示了在共享单个上下文的绘制线程中使用多个QGLWidgets。代码位于github,说明位于http://www.krazer.com/?p=109
答案 1 :(得分:3)
我不得不说我不记得我是怎么做到这一点的,无论如何我不认为QGLWidget必须被移动到另一个线程,事实上这不是文档所说的。它说它是最新的:QGLWidget::makeCurrent()。这将使该QGLWidget的OpenGL上下文在新线程中保持最新状态。
但是,我会尝试使用QGLContext课程。您可以实例化QGLContext,然后调用QGLContext :: create()与其中一个QGLWidget共享。使用QGLContext,您可以绑定纹理。