IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

OpenGL threadé dans Qt 4.8

Date de publication : 07/06/2011. Date de mise à jour : .

Par Jason Barron
 Traducteur : Guillaume Belz
 Qt Labs
 

résumé
N'hésitez pas à commenter cet article !
Commentez Donner une note à l´article (0)

       Version PDF (Miroir)   Version hors-ligne (Miroir)
Viadeo Twitter Facebook Share on Google+        



I. L'article original
II. Introduction
III. Le thread d'échange de tampons
IV. Introduction
V. Introduction
VI. Conclusion


I. L'article original

Le site Qt Labs permet aux développeurs de Qt de présenter les projets, plus ou moins avancés, sur lesquels ils travaillent.

Nokia, Qt, Qt Labs et leurs logos sont des marques déposées de Nokia Corporation en Finlande et/ou dans les autres pays. Les autres marques déposées sont détenues par leurs propriétaires respectifs.

Cet article est la traduction de l'article QML Scene Graph in Master de Jason Barron paru dans Qt Labs.

Cet article est une traduction d'un des tutoriels écrits par Nokia Corporation and/or its subsidiary(-ies) inclus dans la documentation de Qt, en anglais. Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à Nokia.


II. Introduction

Si vous avez déjà utilisé le module OpenGL dans Qt à un moment ou un autre, vous vous étes peut être retrouvé à vouloir exécuter une partie d'OpenGL dans un thread séparé. L'implémentation sous-jacente d'OpenGL est en elle-même (principalement) rérentrant, il n'y avait rien en pratique qui vous en empêche. En fait, pour rappel, dans le Qt Quarterly numéro 6, nous avions même écrit un article décrivant la façon dont vous pourriez faire cela. C'est bien pour les gens qui passent la plupart de leur temps à écrire en OpenGL pure, mais qu'en est-il si vous souhaitez utiliser une partie des classes de Qt dans un thread séparé ? Malheureusement, cela n'a pas été possible puisque ces classes Qt ne sont pas thread-safe. Avec Qt 4.8, cela a changé et nous avons ajouté le support pour quelques-uns des scénarios les plus courants. Pour utiliser cette nouvelle fonctionnalité sur X11, vous devez activer l'option de l'application Qt::AA_X11InitThreads pour garentir que les appels en arrière-plan à GLX sont thread-safe, mais pour Windows et Mac OS X, ça devrait fonctionner directement.


III. Le thread d'échange de tampons

En fonction de votre pilote et du GPU, l'appel à swapBuffers() peut parfois être un appel de fonction coûteuse (en particulier sur les processeurs embarqués). Dans de nombreux cas, c'est la fonction qui indique au GPU qu'il faut prendre toutes vos commandes de rendu et les exécuter pour réaliser le rendu de l'image en cours. Si cette opération est synchrone, alors votre thread principal est bloqué pendant que le GPU fait son travail. C'est malheureux parce que votre thread en cours a des choses beaucoup mieux à faire que d'attendre pour le GPU. Par exemple, il pourrait revenir à la boucle d'événements et de processus d'entrée des utilisateurs du réseau de la circulation, ou l'avance la scène suivante d'une animation. La solution à ce en 4,8 est d'avoir un thread séparé dont le seul but dans la vie est d'attendre pour le GPU en appelant swapBuffers. En pratique, vous rendrait tout comme d'habitude dans votre thread principal, mais au lieu de swapBuffers appelant (), vous appelez doneCurrent () sur le contexte actuel GL. Vous devez alors aviser le fil échange que vous avez fini de rendu et elle remettrait makeCurrent () pour rendre le contexte actif et ensuite appeler swapBuffers (). Le fil swapping devez ensuite appeler doneCurrent () et en informe le thread principal qu'il a terminé. Remarque, il ya un changement de contexte ici et cette surcharge peut en fait être plus lent que si le thread principal venait attendu pour le GPU pour finir il est donc important que vous tester pour voir si vous avez réellement gagner quelque chose.

If this operation is synchronous then your main thread is blocked while the GPU is doing its thing. That's unfortunate because your current thread has much better things to do than wait for the GPU. For example, it could return to the event loop and process some user input, network traffic or advance the next scene of an animation. The solution to this in 4.8 is to have a separate thread whose sole purpose in life is to wait for the GPU by calling swapBuffers. In practice you would render everything as normal in your main thread, but instead of calling swapBuffers(), you would call doneCurrent() on the current GL context. You would then notify the swapping thread that you have finished rendering and it would call makeCurrent() to make the context active and then call swapBuffers(). The swapping thread should then call doneCurrent() and notify the main thread that it has finished. Note, there is a context switch here and this overhead may actually be slower than if the main thread had just waited for the GPU to finish so it's important that you test this to see if you actually gain anything.


IV. Introduction

thread téléchargement Texture Transfert de nombreux (ou grand) textures est généralement une opération coûteuse en raison de la quantité de données étant poussé vers le GPU. Encore une fois, c'est l'un de ces opérations qui peuvent inutilement bloquer votre thread principal. Dans la version 4.8 vous pouvez résoudre ce problème en créant une paire de QGLWidgets partagé. Un des widgets est en cours dans un thread séparé, mais n'est jamais visible à l'écran. Le thread principal informe le fil le téléchargement des images à télécharger et le fil de téléchargement appelle simplement bindTexture () sur chacune de ces images et en avise alors le thread principal où chacun a fini de sorte qu'il peut être établi à l'écran. Texture uploading thread Uploading many (or large) textures is typically an expensive operation because of the amount of data being pushed to the GPU. Again, this is one of those operations that can unnecessarily block your main thread. In 4.8 you can solve this problem by creating a pair of shared QGLWidgets. One of the widgets is made current in a separate thread, but is never made visible on screen. The main thread informs the uploading thread which images to upload and the uploading thread simply calls bindTexture() on each of these images and then notifies the main thread when each one has finished so it can be drawn to screen.


V. Introduction

thread QPainter Dans la version 4.8 il est maintenant possible d'utiliser QPainter dans un thread séparé pour rendre à un QGLWidget, QGLPixelBuffer et QGLFrameBufferObject en supposant que vous utilisez l'OpenGL [ES] 2.0 moteur de peinture. Il est important de noter que QGLWidget ne puissent pas être déplacées à un thread secondaire (après tout c'est un QWidget). Toutefois, étant donné son contexte seront utilisés ailleurs, il est nécessaire de faire appel doneCurrent () sur le QGLWidget pour libérer le contexte du thread principal. Ensuite, vous devez créer une sous-classe QObject distinct qui peut être déplacé vers le fil peintre secondaire. Cette QObject fera contexte, le QGLWidget de courant dans le fil de peintre et peut alors ouvrir un QPainter sur la cible et commencez à peindre. Si vous utilisez QGLWidget que la cible, alors vous devez aussi définir le "Qt:: WA_PaintOutsidePaintEvent" attribut sur l'QGLWidget. En outre, vous aurez besoin de sous-classe et de réimplémenter le resizeEvent () et paintEvent () fonctions de QGLWidget. L'implémentation par défaut de ces vais essayer de faire le contexte QGLWidget actuelles et étant donné que ces fonctions sont appelées depuis le thread principal (où vit le widget) nous ne voulons pas que cela se produise puisque nous sommes l'aide du contexte dans le fil de peintre. Dans votre nouvelle implémentation de ces fonctions, vous devez en informer la sous-classe QObject qui ne le rendu pour qu'il puisse aller et redimensionner la fenêtre ou de repeindre la scène si nécessaire. Le résultat de tout ceci peut être vu ci-dessous dans une nouvelle démo glhypnotizer appelé qui gère plusieurs sous-fenêtres MDI contenant un rendu QGLWidget à partir d'un thread séparé. QPainter thread In 4.8 it is now possible to use QPainter in a separate thread to render to a QGLWidget, QGLPixelBuffer and QGLFrameBufferObject assuming you are using the OpenGL [ES] 2.0 paint engine. It's important to note that QGLWidget does not get moved to a secondary thread (it's a QWidget afterall). However, since its context will be used elsewhere, it is necessary to call doneCurrent() on the QGLWidget to release the context from the main thread. Next you should create a separate QObject subclass that can be moved to the secondary painter thread. This QObject will make the QGLWidget's context current in the painter thread and can then open a QPainter on the target and start painting. If you are using QGLWidget as the target, then you additionally need to set the “?Qt::WA_PaintOutsidePaintEvent” attribute on the QGLWidget. Additionally, you will need to subclass and reimplement the resizeEvent() and paintEvent() functions of QGLWidget. The default implementation of these will try to make the QGLWidget's context current and since these functions are called from the main thread (where the widget lives) we don't want that to happen since we're using the context in the painter thread. In your reimplementation of these functions, you should notify the QObject subclass that does the rendering so it can go and resize the viewport or repaint the scene if needed. The result of all this can be seen below in a new demo called glhypnotizer which runs several MDI subwindows containing a QGLWidget rendering from a separate thread.


VI. Conclusion

Au nom de toute l'équipe Qt, j'aimerais adresser le plus grand remerciement à Nokia pour nous avoir autorisés à traduire cet article !

Un grand merci à ..., à ... et à ... pour leur relecture très attentive et leurs conseils.



               Version PDF (Miroir)   Version hors-ligne (Miroir)

Valid XHTML 1.0 TransitionalValid CSS!

Copyright © 2011 Jason Barron. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.