Vulkan et Qt 5.10

Troisième partie : afficher quelque chose à l'écran

Laszlo Agocs

Traducteur

Théodore Prévot

Dans les dernières parutions (parties 1 et 2), nous avons abordé les bases de la création d'une instance Vulkan. Il est maintenant temps d'avoir quelque chose à l'écran !

Commentez

- Titre : Vulkan et Qt 5.10

- Auteur : Laszlo Agocs

- Traducteur : Théodore Prévot

- Parution : 20 février 2018

- Mise à jour : 3 avril 2018

- Licence : Copyright ® 2017 Laszlo Agocs. Aucune reproduction, même partielle, ne peut être faite de ce site et 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.

Sommaire

- I. QWindows ou QVulkanWindows ?

- II. Utiliser QWindows avec une QVulkanInstance

- III. Fonctions d'emballage du noyau de l'API

- IV. Remerciements

I - QWindows ou QVulkanWindows ?

La version stable de Qt 5.10 est sortie avec les cinq exemples suivants, triés par ordre croissant de complexité :

- hellovulkanwindow ;

- hellovulkantriangle ;

- hellovulkanwidget ;

- hellovulkantexture ;

- hellovulkancubes.

L'exemple helloVulkanCubes fonctionnant sur une NVIDIA Shield TV avec Android 7.0.

Si vous regardez les codes sources de ces exemples, vous verrez qu'ils utilisent tous QVulkanWindow. L'avantage de cette sous-classe de QWindow est qu'elle gère les chaînes d'échange de tampons et les fenêtres spécifiques pour vous. Bien qu'elle ne sera pas toujours appropriée, QVulkanWindow réduit considérablement le temps requis pour commencer à utiliser le rendu Vulkan.

Cependant, comment faire pour avoir le contrôle complet de la chaîne d'échange et de la fenêtre ? C'est totalement possible, mais ce sera moins évident qu'avec la classe QVulkanWindows, qui est très bien documentée.

II - Utiliser QWindows avec une QVulkanInstance

Il n'y a actuellement aucun exemple sur cette méthode qui devient très vite compliquée. Les sources de Qt fournissent malgré tout de bonnes références : excepté le code de QVulkanWindows, il y a aussi un test manuel qui montre la création d'une QWindow avec QVulkan.

On peut alors voir les règles principales pour les sous-classes QWindow avec QVulkan :

1. Il y a un nouveau type de surface : VulkanSurface. Chaque QWindow basée sur QVulkan doit être appelée avec setSurfaceType(VulkanSurface) ;

2. Chaque telle fenêtre doit être associée avec une QVulkanInstance. Pour ce faire, on utilise la fonction setVulkanInstance() que l'on a vue dans l'article précédent ;

3. La gestion des échanges de tampons est entièrement laissée à l'application. Toutefois, une implémentation correcte est censée appeler presentQueued() pour la QVulkanInstance juste après avoir déclenché une opération de présentation (vkQueuePresentKHR) ;

4. La récupération d'une VKSurfaceKHR se fait à travers la fonction surfaceForWindow() ;

5. Si besoin, on peut utiliser supportPresent() pour vérifier si une file d'exécution Vulkan présente dans un appareil physique peut afficher une présentation à l'écran (comme avec les surfaces, cela est très pratique, puisqu'il n'y a plus besoin d'utiliser vkGetPhysicalDeviceWin32PresentationSupportKHR) ;

6. Il est hautement probable que n'importe quelle sous-classe des fenêtres avec Vulkan devra manipuler QPLatformSurfaceEvent et en particulier QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed. Tout simplement parce que la chaîne d'échange doit être libérée avant la surface et que, avec une QWindow, la surface disparaît lorsque la fenêtre native est détruite. Cela peut arriver malencontreusement trop tôt, suivant la structure de l'application. Pour s'assurer de détruire l'espace d'échange au bon moment, il faut donc écouter SurfaceAboutToBeDestroyed ;

7. Comprendre la fonction exposeEvent() est très important. Comme son fonctionnement dépend des plateformes, l'implémentation correcte de exposeEvent() n'est pas facile. Vérifiez simplement son statut avec isExposed() et, si le résultat diffère du précédent, lancez ou arrêtez la boucle de rendu. Bien qu'il n'y ait pas besoin de faire cela sur la plupart des plateformes, il faut, pour certaines, inclure la sortie des ressources graphiques ;

8. Pareillement, toute initialisation des graphiques doit être liée au premier événement expose. Ne lancez rien de tel dans le constructeur d'une sous-classe de QWindow, puisque la QVulkanInstance ne sera peut-être pas reliée à ce moment-là. De plus, il n'y aura pas de fenêtre native sous-jacente à ce moment ;

9. Pour mettre à jour le rendu continuellement, le choix le plus simple est de lancer requestUpdate() à chaque rafraîchissement, puis de récupérer le signal QEvent::UpdateRequest. Notez toutefois que, sur la plupart des plateformes, la valeur est à 5 ms sans système d'arrière-plan de la fenêtre. Les applications sont aussi libres d'implémenter les mises à jour qu'elles désirent.

III - Fonctions d'emballage du noyau de l'API

Qu'en est-il de l'accès à l'API Vulkan ? Sa documentation est bien sûr disponible dans la documentation de QVulkanInstance. Pour la plupart des applications basées sur Qt, le noyau Vulkan 1.0 sera accessible à travers des objets d'emballage retournés par les fonctions functions() et deviceFunction(). En ce qui concerne les extensions, par exemple pour configurer les chaînes d'échange et les gérer manuellement, utilisez getInstanceProAddr().

Cette approche est utilisée par quasiment tous les tests et les exemples. Toutefois, cela n'est pas obligatoire : vous pouvez toujours utiliser un LIBS += -lvulkan ou toute autre bibliothèque spécialisée. Regardez aussi la partie « Using C++ Bindings for Vulkan » dans la documentation de QVulkanInstance.

IV - Remerciements

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

Je tiens à remercier Thibaut Cuvelier et Alexandre Laurent pour leurs conseils et relectures, ainsi que Claude Leloup pour ses corrections.