7 votes

QGLWidget dans un autre fil ? À quoi la documentation fait-elle référence ?

Je fais beaucoup de téléchargements de textures (60 images VGA par seconde) et cela bloque mon thread d'interface utilisateur. À partir de la page de manuel Qt 5.1 QGLWidget (c'est moi qui souligne) :

Téléchargement de textures dans un fil de discussion. Le téléchargement de textures dans un thread peut être très utile pour les applications gérant de grandes quantités d'images à afficher, comme par exemple une application de galerie photo. Ceci est supporté dans Qt par l'API bindTexture() existante. Une façon simple de procéder est de créer deux QGLWidgets de partage. L'un est mis à jour dans le thread principal de l'interface graphique, tandis que l'autre est mis à jour dans le thread de téléchargement de la texture. Le widget dans le fil de téléchargement n'est jamais affiché, il n'est utilisé que pour le partage des textures avec le thread principal. Pour chaque texture liée via bindTexture(), le thread principal est notifié afin qu'il puisse commencer à utiliser la texture.

Comment une classe basée sur QWidget, telle que QGLWidget, peut-elle être déplacée vers un thread ? Si vous tentez de le faire, le résultat est le suivant :

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

Je ne comprends pas ce que la documentation me suggère d'implémenter pour déplacer, par exemple, les éléments suivants bindTexture() de l'exécution de l'opération en dehors du fil d'exécution de l'interface utilisateur.

Ceci est également mentionné ici : Qt4/Opengl bindTexture dans un fil séparé

Aucun code n'y est affiché.

9voto

Krazer Points 155

Réponse un peu tardive, mais les widgets doivent être déplacés vers un nouveau fil de discussion par le fil qui les a créés. Dans votre cas, quelque chose comme :

QGLWidget *glWidget=new QGLWidget();
QThread *newThread=new QThread();

glWidget->doneCurrent();
glWidget->context()->moveToThread(newThread);

Ici, je déplace uniquement le contexte openGL vers le nouveau thread, ce qui nécessite que certaines surcharges de QGLWidget soient prises en compte et ignorées. Vous devrez créer une nouvelle classe dérivée de QGLWidget et surcharger les éléments suivants.

virtual void glInit();
virtual void glDraw();

virtual void initializeGL();
virtual void resizeGL(int width, int height);
virtual void paintGL();

Cela empêche le thread standard de l'interface utilisateur d'essayer de rendre le contexte OpenGL courant dans le thread de l'interface utilisateur. Une fois que vous avez surchargé ce qui précède, vous aurez besoin d'un système d'événements pour notifier au thread que certains des événements se sont produits, principalement resizeGl et paintGL, sinon le widget ne réagira pas correctement avec les autres autour de lui.

La dernière partie se situe au niveau de la création du QGLWidget. Un des paramètres de la construction est 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 )

Vous devez ensuite créer le QGLWidget de l'interface utilisateur et le GLWidget threadé (dérivé du QGLWidget avec toutes les surcharges mentionnées ci-dessus) en vous assurant, lors de la création du GLWidget threadé, de fournir le QGLWidget en tant que sharedWidget. Cela rendra les deux contextes opengl partagés et vous permettra de charger une texture dans l'un d'eux que les deux pourront voir. Le code devrait ressembler à quelque chose comme ceci :

QGLWidget *glWidget=new QGLWidget();
GLWidget *threadedWidget=new GLWidget(0/*parent*/, glWidget);
QThread *newThread=new QThread();

threadedWidget->moveToThread(newThread);

En ce qui concerne le code, j'ai récemment écrit un petit programme d'exemple utilisant des QGLWidgets threadés principalement pour l'interopérabilité openGL/openCL, mais il montre l'utilisation de plusieurs QGLWidgets dans des threads de dessin partageant un seul contexte. Le code est sur github et une description est ici http://www.krazer.com/?p=109

3voto

Luca Carlon Points 6861

Je dois dire que je ne me souviens pas exactement de la manière dont j'ai procédé, de toute façon je ne pense pas que le QGLWidget doive être déplacé vers un autre fil, et en fait ce n'est pas ce que dit la documentation. Elle dit de le rendre courant : QGLWidget::makeCurrent (). Cela rendra le contexte OpenGL de ce QGLWidget courant dans le nouveau thread.

Cependant, j'essaierais avec un QGLContext classe. Vous pouvez instancier un QGLContext et ensuite appeler QGLContext::create() pour partager avec celui du QGLWidget. Avec le QGLContext vous pouvez lier les textures.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X