QtGraphics et performances - Vue d'ensemble

Image non disponible

Au centre de tous les Qt Graphics, on retrouve la classe QPainter. Elle permet de faire le rendu dans une surface, grâce à la classe QPaintDevice. Des exemples de surface de dessin sont : les classes QImage, QPixmap et QWidget. La façon dont cela fonctionne est que pour une implémentation donnée de QPaintDevice, nous récupérons un moteur de rendu personnalisé qui prend en charge le rendu sur cette surface. Tout cela est expliqué dans notre documentation "ainsi peut-être pas trop intéressant". Regardons cela plus en détail.

Cet article est une traduction autorisée de Qt Graphics and Performance - An Overview, par Gunnar.

N'hésitez pas à commenter cet article !
9 commentaires Donner une note à l'article (5)

Article lu   fois.

Les trois auteurs

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

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 Qt Graphics and Performance - An Overview de Gunnar paru dans Qt Labs.

II. Introduction

Pour cette série blog que j'écris, le mieux est que je commence par une vue d'ensemble de ce que sont les painters, les pixmaps, les widgets, les graphicsview et le backingstore.

Au centre de tous les Qt Graphics, on retrouve la classe QPainter. Elle permet de faire le rendu dans une surface, grâce à la classe QPaintDevice. Des exemples de surface de dessin sont : les classes QImage, QPixmap et QWidget. La façon dont cela fonctionne est que pour une implémentation donnée de QPaintDevice, nous récupérons un moteur de rendu personnalisé qui prend en charge le rendu sur cette surface. Tout cela est expliqué dans notre documentation "ainsi peut-être pas trop intéressant". Regardons cela plus en détail.

III. QWidgets et QWindowSurface

Même si QWidget est une classe héritant de QPaintDevice, on ne réalisera jamais le rendu directement dans une surface de QWidget. Au lieu de cela, au moment d'un paintEvent, le rendu est redirigé vers une surface non visible qui est représenté par la classe interne QWindowSurface. Cela a été traditionnellement implémenté en utilisant la fonction QPainter::setRedirected(), mais cela a depuis été remplacé par un mécanisme interne entre QPainter et QWidget qui est légèrement mieux optimale.

Parfois, nous appelons cette surface le backingstore mais en réalité, ce n'est qu'une surface 2D. Si vous avez déjà regardé dans le code source de Qt et avez trouvé la classe QWidgetBackingStore, vous avez du voir que celle ci est responsable de déterminer quelles parties de la surface de la fenêtre doit être mis à jour avant qu'elle soit affichée à l'écran, ce qui fait de QWidgetBackingStore un véritable gestionnaire de mise à jour du rendu. Lorsque le concept de backingstore a été introduit dans Qt 4.1, les deux classes (ndlt : les classes QWindowSurface et QWidgetBackingStore) étaient les mêmes mais l'introduction de plusieurs méthodes pour effectuer le rendu à l'écran nous a fait les diviser en deux.

Dans les premiers temps, le rendu des widgets était éffectué directement à l'écran. Bien que l'option pour dessiner directement à l'écran est toujours disponible, il n'est pas recommandé de l'utiliser. Je crois que le seul système qui prend en charge à distance ("remotely supports"), c'est X11, mais il est plus ou moins testées et donc cause souvent des artefacts dans les styles les plus complexes. Ajouter l'option Qt::WA_PaintOnScree permet au gestionnaire de rendu interne de Qt d'ignorer ce widget au moment de réaliser le rendu dans la QWindowSurface et d'envoier à la place un paintEvent particulier seulement à ce widget. Avant Qt 4.5, il y avait un gain de vitesse significatif quand 10 à 100 widgets étaient mis à jour mais dans Qt 4.5, le gestionnaire de rendu a été optimisé pour mieux gérer cela ; ainsi réaliser le rendu directement à l'écran est généralement pire que de le réaliser en mémoire.

Retour à la surface de la fenêtre. Tous les widgets sont combinés dans la surface de la fenêtre de haut en bas (ndlt : le haut fait référence au top-widget, c'est à dire le widget parent de tous les autres, et le bas aux bottom-widgets, qui sont contenu dans un widget parent) et top-widget est utilisé pour remplir la surface avec son fond ou avec un fond transparent si l'attribut Qt::WA_TranslucentBackground est fixé. Tous les autres widgets sont considérées comme transparents. Un QLabel affiche seulement un peu de texte mais ne touche à rien d'autre. Qu'est-ce que cela signifie pour le gestionnaire de rendu ? C'est que chaque widget qui chevauche l'étiquette, mais en arrière d'elle, doit être dessiné avant. Si pour une application, vous savez que certains widgets sont opaques et qu'ils redessineront chaque pixel pour chaque paintEvent, on pourra définir l'attribut Qt::WA_OpaquePaintEvent, ce qui permet au gestionnaire de rendu d'exclure les régions des widgets en arrière plan qui seront redessinées par le widget.

Comme tous les widgets sont redessinés sur la même surface, nous devons faire en sorte que les widgets ne soient pas redessinés accidentellement en dehors de leurs propres limites et dans d'autres widgets. Comme il n'y a aucune garantie que les widgets seront dessiné à l'intérieur de leurs limites, ce qui pourrait potentiellement conduire à des artefacts de rendu, nous avons créé un découpage interne au QPainter appelé le système de découpe ("system clip"). Pour la plupart des widgets, le système de découpe est un rectangle et en regardant la section sur la performance dans la documentation de QPainter, nous voyons que ce n'est pas si mal. Le découpage en rectangle, avec des pixels alignés, sont rapides. Un widget utilisant un masque, d'autre part, est un désastre en terme de performance. Il est plus lent à mettre en place et le rendu est plus lent. Le système de découpage utilise le même découpage qui est passé au paintEvent, sauf que le découpage dans le paintEvent été déplacé pour correspondre à la partie supérieure gauche du widget plutôt qu'en haut à gauche de la surface. Il ne fait pas attribuer la région du paintEvent comme étant un découpage du rendu. Elle a déjà été définie et nous ne détectons pas que c'est exactement la même région et il suffit de recommencer entièrement à nouveau. Le but de la région et du rectangle dans le paintEvent est alors que les widgets peuvent décider de ne pas redessiner certaines parties. Ceci est particulièrement utile lorsque vous avez beaucoup d'éléments dans un widget permettant de visualiser un scène ou similaire, par exemple dans une application de cartographie.

En plus du système de découpe qui est utilisé avant l'appel au paintEvent, le système de rendu doit également être dans un état propre, ce qui signifie la mise en place des brosses, des stylos, des polices et autres. Le coût n'est pas énorme mais si vous avez de nombreux widgets, il s'accumule. Ainsi, bien que les widgets ne sont pas des fenêtres natives, il y a quand même un coup pour les redessiner. Soyez conscient de cela quand vous concevez votre application. Par exemple, implémenter une galerie de photo à l'aide QLabel avec des pixmaps dans un QScrollArea ne permet pas de les dimenssionner. Vous devez mettre en place le découpage et tous les autres paramètres pour chaque QLabel, même si le QLabel affiche seulement un pixmap. Un widget unique pour la visualisation pourrait redimensionner plus efficacement, puisque le widget peut alors implémenter une petite boucle qui redessine les pixmaps au bon endroit.

Ce système de backingstore et de surface de fenêtre ne sont valable sur Mac OS X que lorsque les systèmes graphiques Raster ou OpenGL sont utilisés. Personnellement, je recommande fortement d'utiliser Raster, il implémente l'ensemble de toutes les fonctionnalités, il est souvent plus rapide, avec le même profil de performances que Qt sur Windows et la correction des bugs de rendu est une priorité plus élevée pour le Raster que pour le moteur CoreGraphics. Nous prévoyons d'utiliser le système Raster par défaut sur Max OS X, il suffit de régler quelques probèmes d'intégration du système de fenêtre.

IV. Les systèmes graphiques

Le concept de système graphique a été introduite dans Qt 4.5. L'idée est de pouvoir choisir au démarrage, au niveau application, le type de rendu que vous souhaitez. Le système graphique est chargé de dessiner sur les pixmaps en arrière plan et la surface de la fenêtre. Nous avons actuellement des systèmes graphiques pour les systèmes Raster, OpenGL 1.x, OpenGL/ES 2.0, OpenVG et X11. Vous pouvez sélectionner le système graphique au démarrage de l'application avec l'option en ligne de commande -graphicssystem raster|opengl|opengl1|x11|native, où "native" correspond au système par défaut. Une autre possibilité consiste à ajouter la même option dans le fichier configure, ce qui fixera cette option pour toutes les applications utilisant Qt. Enfin, il y a la fonction QApplication::setGraphicsSystem() qui permet de sélectionner le système graphique directement dans le code pour une application donnée.

Dans les prochaines blogs, nous irons plus loin dans la description des moteurs de rendu mais pour l'instant, regardons les simplements les points importants.

IV-a. Le système Raster

Le système Raster est l'implémentation de référence de QPainter. Il implémente toutes les fonctionnalités que nous avons définies et fait tout de manière logiciel. Quand le portage vers une nouvelle plateforme est lancé, comme avec le S60, nous commençons généralement par faire tourner le système Raster. Il est actuellement le système par défaut sur Windows, sur l'embarqué, sur S60 et le sera aussi sur Mac OS X.

Que pensez-vous du système Raster sur X11 ? Si vous ignorez une seconde que vous recevez actuellement un processus local pour le cache des polices locales. Les performances sont correctes sur X11 et j'ai vu beaucoup de personnes basculer dessus à l'exécution. Si l'on considère l'affichage à distance, cela semble énorme, mais il continue à n'être pas trop mauvais. La façon dont il fonctionne avec le moteur de rendu X11 actuellement, c'est que chaque gradient et transformation de pixmaps se fait au niveau logiciel puis est transféré sous forme d'image au niveau des commandes de rendu. Pourquoi ne pas tout faire du côté client et ne télécharger que les parties qui doivent être actualisées. Nous pouvons regarder les vidéos HD (pour une définition de la HD, de toute façon) sur YouTube, probablement que nous pouvons nous permettre de télécharger quelques pixels. Ceci est lié à la génération de commentaires sur XRender et aux gradients et aux transformations côté serveur, mais cela a été tenté à plusieurs reprises et les performances ne sont tout simplement pas assez bonnes.

L'intégrtion du système de fenêtre est codé à la main pour chaque plate-forme pour tirer le meilleur parti de celui-ci. Pour Windows, la surface est une QImage qui partage ses données avec une DIBSECTION (structure qui inclue des informations sur une bitmap : dimensions, format de couleur, masques et d'autres informations permettant de gérer le stockage des données), ce qui permet d'obtenir une bonne vitesse lors de la copie des bits. Sur X11, nous utilisons de images MIT à mémoire partagée. Nous avons utilisé les pixmaps à mémoire partagée, ils ont été retiré de Xorg mais nous avons eu ce patch impressionnant de la communauté, ce qui nous a permis d'être à nouveau opérationnel. Sur Mac OS X, nous testons l'utilisation dez "GL texture streaming" pour le transfert de l'image en cache vers l'écran et nous obtenons des chiffres prometteurs, donc j'espère que cela sera ajouté aussi à Qt 4.7.

Du fait que c'est juste un tableau d'octets, la plupart des API natives ont la capacité de réaliser le rendu dans le même tampon que nous utilisons. Cela rend l'intégration avec les thèmes natifs assez simple, ce qui est l'une des raisons pour lesquelles cela est attrayante en tant que système de bureau graphique par défaut, bien que n'ayant pas d'accélération matérielle.

IV-b. Le système OpenGL

Nous avons deux systèmes graphiques OpenGL dans Qt. Un pour OpenGL 1.x, qui est principalement implémenté en utilisant les fonctionnalités de pipeline fixe en combinaison avec quelques programmes de fragments ARB. Il a été écrit pour les versions Desktop de Qt, au début de Qt 4.0 (2004-2005) et a peu évolué depuis. Vous pouvez l'activer en écrivant -graphicssystem opengl1 dans la ligne de commande. Il est actuellement en mode de survie, ce qui signifie que nous corrigeons les problèmes critiques telque les crashes, mais sinon, nous le laissons tel quel. De notre côté, nous ne nous concentrons pas dessus pour améliorer les performances, même s'il donne d'assez bons résultats dans certain cas.

Notre objectif principal est le système graphique OpenGL/ES 2.0, qui est écrit pour fonctionner sur du matériel graphique moderne. Il n'utilise pas des fonctionnalités d'un pipeline fixe, mais seulement les vertex shaders et fragment shaders. Depuis Qt 4.6, c'est le moteur de rendu utilisé par défaut pour QGLWidget. Ce n'est que lorsque l'une des fonctionnalités demandées n'est pas disponibles que nous réutilisons la version 1.x. Quand nous faison référence à notre moteur de rendu OpenGL, c'est bien de la version 2.0 que nous parlons.

Nous voulions utiliser OpenGL comme moteur de rendu par défaut sur tous les systèmes Desktop pendant un moment, mais il y a deux problèmes majeurs avec. Dessiner sans anti-aliasing est une plaie, il est presque impossible de garantir qu'une ligne sera dessinée où vous le souhaitez sur certains pilotes. L'intégration des thèmes natifs est une plaie. Il est rarement possible de passer un contexte OpenGL à une fonction utilisant les thèmes et lui demander de dessiner dedans, donc nous devons utiliser les pixmaps temporaire pour les éléments de style. Sur Mac OS X, il existe une fonction pour obtenir un contexte CGContext à partir d'un contexte OpenGL, mais nous n'avons pas réussi pour le moment à obtenir des résultats appréciables avec. D'un autre côté, une grande partie du contenu de l'interface graphiqu ne dépend pas de ces caractéristiques, ce qui rend OpenGL optimal typiquement pour le rendu de scène, comme la fenêtre d'un QGraphicsView ou une galerie de photos. Donc, autant la configuration par défaut de Qt est tournée vers l'avenir, nous considérons que la meilleure configuration par défaut pour un ordinateur de bureau doit être une combinaison du système Raster pour les widgets utilisant la thématique native et OpenGL pour un ou deux widgets haute. Rien n'est décidé à ce sujet mais nous continuons à étudier les alternatives.

Un autre problème avec l'utilisation d'OpenGL par défaut est le partage des polices. Avec le système Raster, nous pourrions théoriquement partager les symboles pré-rendus entre les processus d'une manière multi-plateforme en utilisant la mémoire partagée, alors qu'avec OpenGL, cela devient un peu plus difficile. Sur le système X11, il existe une extension pour convertir des texture dans des XPixmaps, lesquelles peuvent être partagées entre les processus, mais cela force généralement à convertir les textures dans un format moins optimal, ce qui les rend un peu plus long à dessiner, alors ce n'est pas encore optimale. Sur Windows, Mac OS X, S60 ou QWS, nous aurions besoin de travailler au niveau des pilotes pour le partage des identifiants des textures, ce que nous n'avons pas actuellement.

IV-c. Le système OpenVG

Je laisse actuellement cette section un peu vide. Je n'ai pas participé à son implémentation, à le mettre en place et le faire tourner. Il est basé sur EGL, ce qui la rend tout à fait similaire au système graphique OpenGL. Nous espérons que OpenVG sera utilisée dans un certain nombre systèmes embarqués de milieu de gamme.

La chose intéressante avec OpenVG est qu'il correspond assez bien à l'API de QPainter. Il prend en charge les chemins, stylos, pinceaux, les dégradés et les modes de composition donc, en théorie, les API vectorielle devrait fonctionner de manière optimale.

Rhys Weatherley, qui a écrit le moteur de rendu OpenVG, envisage de faire un post sur le fonctionnement interne du moteur de rendu OpenVG en totalité dans un avenir proche.

V. Les images et les pixmaps

La différence entre ces deux classes est largement abordée dans la documentation mais je voudrais mettre en évidence une petite chose mais pas des moindres.

Notre documentation dit : "QImage est conçu et optimisé pour les entrées et sorties et pour l'accès direct aux pixels et leurs manipulations, tandis que QPixmap est conçu et optimisé pour montrer des images à l'écran."

V-a. Le système Raster

Lorsque vous utilisez le système de rendu Raster, les pixmaps sont implémentées comme des QImage, avec une différence pourrait être importante : lorsque vous convertissez une QImage à une QPixmap, nous ajoutons quelques petites choses.

L'image est convertie en un format de pixel qui est rapide à rendre dans le tampon mémoire, c'est-à-dire ARGB32_Premultiplied, RGB32, RGB16 ou ARGB8565_Premultiplied. Lorsque les images sont chargées depuis le disque en utilisant le plugin PNG ou lorsqu'elles sont généréss par l'application, le format est souvent ARGB32 (non-prémultiplié) puiqu'il s'agit d'un format facile à travailler. J'ai mesuré que copier depuis le format ARGB32_Premultiplied vers RGB32 est 2 à 4 fois plus rapide que de dessiner directement sur RGB32 non-premultiplié, selon les cas d'utilisation.

Deuxièmement, nous vérifions les données de pixels pour les pixels transparents et nous le convertissons dans un format opaque si aucun pixel transparent n'est trouvé. Cela signifie que si un fichier ".png" est chargé au format ARGB32 à partir du disque, mais qu'il ne contient que des pixels opaques, il sera rendu par un RGB32, qui est aussi 2 à 4 fois plus rapide.

V-b. Le système OpenGL

Lorsque vous utilisez le système graphique OpenGL, l'implémentation effective de QPixmap varie un peu d'une configuration à l'autre. La meilleure option s'active lorsque votre version d'OpenGL prend en charge les Frame Buffer Objects (FBO) en combinaison avec l'extension GL_EXT_framebuffer_blit. Dans ce cas, la pixmap est représentée comme une texture OpenGL, et à chaque fois qu'un QPainter est ouvert sur la pixmap, nous récupérons un FBO du pool interne et nous l'utilisons pour dessiner dans la texture.

Sans ces extensions disponibles, ce qui est généralement le cas pour OpenGL/ES 2.0, l'implémentation de QPixmap est une QImage (avec les mêmes optimisations que Raster) qui est référencé par un identifiant de texture. Lorsque vous ouvrez un QPainter sur la pixmap, vous dessiner dans la QImage et quand la pixmap est affichée sur l'écran, l'identifiant de la texture est utilisé. En interne, il y a un processus de synchronisation entre les deux représentations, il y aura donc une étape unique de rechargement de la texture après avoir dessiné dedans.

V-c. En général

Si vous avez l'intention de dessiner deux fois la même QImage, convertissez le toujours en QPixmap.

Il y a quelques cas où QPixmap est potentiellement un mauvais choix. Nous avons les fonctions QPixmap::scaled(), QPixmap::tranformed() et similaires, qui, historiquement, sont là parce que nous voulions que QImage et QPixmap aient la même interface. Nous avons le projet de réimplémenter ces fonctionnalités en se basant sur QPixmap, mais actuellement, aucun moteur de rendu ne fait cela. Aussi, dans le cas d'OpenGL, ou pour X11 sur ce point, appeler QPixmap::tranformed() implique une conversion de QPixmap en QImage, conversion uniquement logiciel, la conversion en arrière vers le format original.

Par défaut, un QPixmap est considéré comme opaque. Lorsque vous faites QPixmap::fill(Qt::transparent), cela est réalisé dans un pixmap avec canal alpha, qui est plus lent à dessiner. Si le pixmap va finir comme opaque, initialisez le avec QPixmap::fill(Qt::white). Vous pouvez même sauter complètement l'étape d'initialisation, si vous savez que tous les pixels seront écrits avec une couleur opaque au moment où la pixmap est dessinée.

Avant de passer à autre chose, je vais juste donner un petit avertissement sur les fonctions setAlphaChannel et setMask et regarder naïvement les fonctions alphaChannel() et mask(). Ces fonctions font partie de l'héritage de Qt 3 que nous n'avons pas tout à fait réussi à se débarasser lors du passage à Qt 4. Dans le passé, le canal alpha d'une pixmap, ou son masque, était stocké séparément des données de la pixmap. En fonction de la plate-forme sur laquelle vous êtes, l'implémentation effective était un peu différente. Par exemple, sur X11, vous aviez une pixmap de 1 bit pour le masque, un canal alpha de 8 bits et un tampon de couleurs considéré de 24 bits. Sous Windows, vous aviez un masque de 1 bit et un tampon de pixels codé en ARGB 32 bits. Dans Qt 4, nous avons fusionné tout cela en une seule API, de sorte que QPixmap peut être considéré comme une structure de données compacte de pixels ARGB. Pour autant, nous n'avons pas supprimer les fonctions implémentées de l'ancienne API. En fait, nous avons même ajouté les accesseurs pour le canal alpha, donc nous avons fait qu'aggraver la situation. L'API est restée dans une certaine mesure pratique, mais ces quatre fonctions impliquaient de toucher à l'ensemble des données et, soit de fusionner la source avec la pixmap, ou soit d'extraire une nouvelle pixmap à partir du contenu de la pixmap actuelle. En conclusion : ne les utilisez pas. Avec les modes de composition, vous pouvez manipuler le canal alpha des pixmap à l'aide de QPainter. Un autre avantage est que cela pourrait également être optimisé par des instructions SSE pour le moteur de rendu Raster, ou par accélération matériel avec OpenGL, donc cela pourrait être potentiellement un peu plus rapide. Il y a aussi QGraphicsOpacityEffect qui vous permet de définir un masque sur des widgets et des éléments graphiques, mais pour le moment, ce n'est pas aussi rapide que nous le souhaiterions.

VI. QGraphicsView

Je vais faire au moins un chapitre distinct sur graphicsview seul, donc je vais commenter rapidement la différence entre l'utilisation de QGraphicsView avec des items et de QWidget. QGraphicsView, avec sa scène peuplées avec des objets, est très semblables sur plusieurs points aux widgets et à leurs mise à jour "their repaint handling". Avec l'ajout des layouts et les QGraphicsWidgets, la différence est encore plus floue. Alors, quelle solution faut-il choisir ? De plus en plus souvent, nous constatons que les gens choisissent de créer leurs interfaces utilisateur dans des QGraphicsView plutôt que de les créer en utilisant des widgets traditionnels.

Par rapport à des widgets, des items dans une vue graphique sont peu couteux. Si l'on considère à nouveau la galerie photo, qui utilise un item différent pour chacun des éléments de la vue, cela peut (je dis bien "peut") être raisonnable. Un widget est redessiné dans son paintEvent. Un QGraphicsItem est redessiné dans sa fonction paint. Une chose intéressante cette fonction, pour les items, est qu'il n'y a pas d'appel à begin puisque QPainter est déjà correctement configuré pour le rendu. Il a moins de garantie concernant l'état du QPainter contrairement à une utilisation par un widget. Il peut y avoir une transformation et des découpages, mais aucune garantie à propos des polices, des styles de dessin ou des brosses. Cela rend la configuration un peu moins couteuse.

Une autre amélioration considérable par rapport aux widgets est que les items ne sont pas découpées par défaut. Ils ont un rectangle enveloppant et il y a un contrat entre celui qui implémente une sous-classe d'item et la scène pour que l'objet ne dessine par à l'extérieur de ce rectangle. Si l'on compare cela au système de découpe que nous devons définir pour les widgets, alors ici encore, il y a moins de travail à faire pour les items. Si un item ne respecte pas ce contrat, il y aura des artefacts de rendu, mais pour graphicsview, cela est considéré comme étant un compromis acceptable.

La plupart des éléments d'interface sont assez simples. Un bouton, par exemple, peut être composé d'une image de fond et un texte court. Du point de vue de QPainter, il y a un appel à drawPixmap et un appel à DrawText. Moins il y a de temps passé entre les appels à QPainter, meilleure est la performance. Moins il y a de changement d'états entre les appels à QPainter, meilleure est la performance. Si vous retourner voir combien de temps se passe entre ces appels pour un bouton, vous rendrez rapidement compte que les widgets traditionnels sont assez lourdes. Si les widgets veulent survivre à l'épreuve du temps, ils auront besoin de se comporter davantage comme les QGraphicsItem.

VII. Conclusion

J'ai déblatéré pendant un certain temps, mais j'espère que vous avez trouvé quelques informations utiles quand même. Vous avez peut être remarqué que je ne mentionne pas l'impression, la génération des PDF ou des SVG, je ne mets pas l'accent sur les moindres détails des moteurs de rendu X11 ou CoreGraphics. C'est parce que, comme indiqué dans la documentation de QPainter sur les performances, nous concentrons nos efforts sur la performance sur seulement quelques moteurs que nous considérons comme essentiel pour Qt.

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

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

Qt Graphics et performances
Ce qui est critique et ce qui ne l'est pas
Vue d'ensemble
Le moteur de rendu Raster
Le moteur de rendu OpenVG
Le moteur de rendu OpenGL
Le coût des commodités
Du texte rapide
Génération de contenu dans des threads
La folie est de mettre en forme le même texte encore et espérer un résultat différent
Velours et QML Scene Graph