7

我正在上传大量纹理(每秒 60 个 VGA 图像),它阻塞了我的 UI 线程。从Qt 5.1 QGLWidget 手册页(强调我的):

在线程中上传纹理。在线程中进行纹理上传对于处理需要显示的大量图像的应用程序可能非常有用,例如照片库应用程序。这在 Qt 中通过现有的 bindTexture() API 得到支持。一个简单的方法是创建两个共享的 QGLWidgets。一个在主 GUI 线程中成为当前的,而另一个在纹理上传线程中成为当前的。上传线程中的小部件从不显示,它仅用于与主线程共享纹理。对于通过 bindTexture() 绑定的每个纹理,通知主线程以便它可以开始使用该纹理。

什么?如何将基于 QWidget 的类(如 QGLWidget)移动到线程中?尝试这样做会导致:

QObject::moveToThread: Widgets cannot be moved to a new thread

我不明白文档建议我实施什么以便将 egbindTexture()的执行移出 UI 线程。

这里也提到了这一点:Qt4/Opengl bindTexture in separate thread

虽然没有发布代码。

4

2 回答 2

9

答案有点晚了,但是创建它们的线程需要将小部件移动到新线程。在您的情况下,例如:

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 线程尝试使 OpenGL 上下文在 UI 线程中处于当前状态。一旦你覆盖了上述内容,你将需要一个事件系统来通知线程一些事件已经发生,主要是 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);

至于代码,我最近使用线程 QGLWidgets 编写了一个小示例程序,主要用于 openGL/openCL 互操作,但它显示在共享单个上下文的绘制线程中使用多个 QGLWidgets。代码在github上,描述在这里http://www.krazer.com/?p=109

于 2014-05-03T15:42:41.153 回答
3

我不得不说我不记得我是如何做到这一点的,无论如何我不认为 QGLWidget 必须移动到另一个线程,事实上这不是文档所说的。它说使它成为最新的:QGLWidget::makeCurrent ()。这将使该 QGLWidget 的 OpenGL 上下文在新线程中处于当前状态。

但是,我会尝试使用QGLContext类。您可以实例化一个 QGLContext,然后调用 QGLContext::create() 与其中一个 QGLWidget 共享。使用 QGLContext 您可以绑定纹理。

于 2013-08-20T22:18:58.430 回答