我使用两个QGLWidgets。一个用于加载纹理,一个用于渲染,但它不起作用。
我使用了以下解释 http://blog.qt.digia.com/blog/2011/06/03/threaded-opengl-in-4-8/
纹理上传线程 由于将数据量推送到GPU,上载许多(或大)纹理通常是昂贵的操作。同样,这是可能不必要地阻止主线程的那些操作之一。在4.8中,您可以通过创建一对共享QGLWidgets来解决此问题。其中一个小部件在一个单独的线程中是最新的,但从未在屏幕上显示。主线程通知上传线程要上传哪些图像,上传线程只是在每个图像上调用bindTexture(),然后在每个图像完成时通知主线程,以便可以将其绘制到屏幕上。
使用Qt 4.8和MinGW它工作正常,但现在我使用Qt 5.1和MSVC。当我想让线程中的小部件变为当前时,我收到错误:
无法使QOpenGLContext在另一个线程中保持最新状态
我理解错误,但我该如何修复它。当我没有设置小部件当前我无法加载纹理(在bindTexture()函数冻结)。我也想知道,为什么它适用于我的旧QT版本。当错误出现时,我可以按“忽略错误”,程序无论如何都会加载纹理。
以下是一些示例代码:
加载纹理:
GLContext::GLContext(QWidget *parent, QGLWidget *myDisplayWidget) :
QGLWidget(parent,myDisplayWidget)
{
}
...
GLContext* myTextureWidget = new GLContext(this,myDisplayWidget);
...
void TextureLoadingThread::run()
{
makeCurrent(); //Here is the bug!
QImage *im = new QImage(filename);
GLuint textid = myTextureWidget->bindTexture(*im, GL_TEXTURE_2D, GL_RGBA);
}
编辑:
当我将myTextureWidget的上下文移动到它运行的线程时,但是当构建GUI时,我从API获取makeCurrent Error(堆栈跟踪在QT5Widgetsd中的QLineEdit :: setPlaceHolderText函数中说明)。当我在主窗口显示几秒后将myTextureWidget移动到线程时,一切正常。但是我怎么知道qt什么时候完成了所有GUI构建的东西?我使用QGLWidget视口将GUI绘制到QGraphicsView。
myTextureWidget->context()->moveToThread(myTextureLoadingThread);
答案 0 :(得分:4)
在开始新的Thread并调用makeCurrent()之前,你必须启动doneCurrent(),例如。
void QGLWidget::startRendering()
{
doneCurrent();
context()->moveToThread(mTextureLoadingThread);
}
然后致电
void TextureLoadingThread::run()
{
makeCurrent(); //Here is the bug!
...
}
这就是我为解决这个错误所做的工作。不幸的是,我没有使用线程进行渲染的完美解决方案。
//编辑
我上传了一个例子:https://dl.dropboxusercontent.com/u/165223/thread_example.zip
答案 1 :(得分:1)
可能为时已晚,但我遇到了同样的问题,并找到了解决方案,所以这就是我所做的,希望它能帮助未来的编码员:
Omgodie走在正确的轨道上。我认为你仍然得到相同的错误,因为主线程也调用paintEvent(),它可能试图使上下文最新。但是,相同的上下文在您的第二个线程中已经是当前的,因此是错误。
因此,当您的第二个线程处于活动状态时,您基本上需要阻止主线程尝试在窗口小部件中呈现。我通过在我的QGLWidget中添加一个布尔属性并在创建第二个线程之前将其设置为true来做到这一点,并在我的线程完成时返回false。然后我将我的小部件的paintEvent()修改为仅在布尔值设置为false时呈现。最后,我从第二个线程手动调用render函数。 这是一些代码:
//GLWidget derives from QGLWidget:
void GLWidget::paintEvent(QPaintEvent *e) {
if ( !_second_thread_active )
render();
}
//Then in your thread:
void Thread::doWork() {
//Do stuff
render();
}
线程完成后,不要忘记将上下文从第二个线程发送回主线程!
doneCurrent();
context()->moveToThread(&qapp->thread());
HTH