Programmation graphique

kongakura.fr

Vulkan Tutoriel C++


1-Qu'est ce que vulkan ?

Ces dernières années, le rapide développement des GPUs (Graphic processing unit) ou cartes graphiques en français, a permis l'essor de nombreuses technologies informatiques allant du simple jeu vidéo avec lequel un enfant s'amuse aux intelligences artificielles ultra-développées, capables de remplacer l'homme dans certains domaines, telle que ChatGPT.

Cette nécessité croissante de puissance de calcul, afin d'améliorer les graphismes des jeux vidéos ou encore de construire des modèles de deep learning encores plus grands, a mené les acteurs du secteur de l'industrie électronique à se pencher sur le développement d'APIs de programmation GPU qui permettent à tout un chacun de tirer pleinement parti de leurs puissances de calcul.

La construction d'une API globale et commune telle que Vulkan, constitue en soi un énorme défi puisqu'une telle API doit fonctionner sur un nombre important de machines différentes (smartphone, PC, console de jeux vidéo, Ordinateur à carte unique, etc.) qui elles-mêmes sont fabriquées avec des composants électroniques différents (NVIDIA RTX, Broadcom Videocore 6, ARM Mali-G610, etc.).

Afin de répondre à ce défi, les différents acteurs industriels impliqués dans le développement des composants électronique et informatique ont dû former en l'an 2000 un consortium du nom de "Khronos group". Ce consortium regroupe plus de 170 organisations dont de grands noms de l'industrie tels que AMD, ARM, Imagination Technologies, NVIDIA, etc.

Le "Khronos group" s'est fixé pour but de construire, des normes, des standards qui seront suivis par l'ensemble des constructeurs de GPU de sorte à permettre la conception de logiciel (jeux vidéos, CAO, etc ...) multiplateforme.

Le "Khronos group" est notamment à l'origine de la très célèbre API de programmation graphique OpenGL, la prédécesseuse de Vulkan, utilisée dans de très nombreux logiciels de modélisation 3D tels que SketchUp, Blender ou encore dans le jeu vidéo Doom. Le "Khronos group" a également développé la librairie de calcul OpenCL et les dérivés d'OpenGL tels que WebGL et OpenGL ES.

OpenGL se faisant vieillissante, puisque datant de 1992 bien que régulièrement mise à jour, elle ne tirait plus pleinement parti des performances des GPU modernes.

En effet, en termes de "frame per rate (FPS)" où d'images par seconde en français, dans de nombreux benchmarks, pour un même jeu vidéo, openGL obtenait un nombre de FPS 20 à 30 % inférieur à celui de DirectX, l'API de programmation graphique de Microsoft.

Aussi, dans le but de combler son retard, le "Khronos group" a mis sur pied un projet d'une nouvelle API sous le nom de "OpenGL Next".

Cette API devait notamment de permettre un contrôle plus fin des GPUs.

Plus tard, ce projet fut officiellement renommé Vulkan et c'est en 2016 que la première version de Vulkan vit le jour.

Vulkan est donc la réponse directe du "Khronos group" à ce besoin d'avoir une API graphique de rendu 3D et de calcul GPU moderne, puissante et multi-plateforme.

Ce pari de reconstruire une nouvelle API en repartant de zéro est relativement réussi, puisque de nombreux benchmarks attestent de la supériorité de Vulkan face à OpenGL. Le site geeks3d a par ailleurs réalisé un benchmark comparant Vulkan et Opengl sur le raspberri pi 4 https://www.geeks3d.com/hacklab/20220818/tested-raspberry-pi-4-and-vulkan-it-works/ et a constaté un gain en termes de performance de 30 %.

Installation des outils nécessaires à la programmation avec Vulkan

Afin de commencer à développer des applications utilisant Vulkan, il te faudra installer différents outils.

Le package vulkan-tools contient des outils qui t'assisteront au cours du développement en te permettant de vérifier que ton application utilise correctement l'API Vulkan

En lançant la ligne de commande suivante : sudo apt install vulkan-tools, tu peux installer Vulkan.

Puis en tapant la commande "vulkaninfo", il t'est possible de confirmer la bonne installation de Vulkan.

...
Capture d'écran du résultat de la commande "vulkaninfo".

Tu peux également confirmer la bonne installation de Vulkan en tapant "vkcube" ou "vkcubepp" dans ton terminal.

...
Capture d'écran du résultat de la commande "vkcube".

Une fois les outils Vulkan installés, il te faudra installer le package "libvulkan-dev" via la commande :

sudo apt install libvulkan-dev

Ce package contient l'ensemble des fichiers nécessaires au développement d'application utilisant Vulkan.

La prochaine étape consiste à installer le package "vulkan-validationlayers-dev", il contient les couches de validation officielle de Khronos, pour Windows, Linux, Android et MacOS.

Mais qu'est-ce que les couches de validation ?

Comme je te l'ai expliqué précédemment, Vulkan est une API qui a été développée dans un souci de performances. Par conséquent, elle se veut orientée "bas niveau", c'est-à-dire proche de la machine. De plus, elle n'intègre autant que le minimum de test d'erreur afin d'éviter quelques surcharges que ce soit au calcul GPU.

Par conséquent, c'est le développeur de l'application, qui a le plein contrôle et la pleine responsabilité du fonctionnement correct de son application.

C'est pour cette raison que de simples erreurs de programmation peuvent provoquer des crashs ou des comportements inattendus de l'application. Et cela, sans que le développeur ait une quelconque idée de l'origine du dysfonctionnement de l'application.

Forte heureusement, Khronos ne nous a pas laissés dans le désarroi. Il ajoute à Vulkan au travers du package "vulkan-validationlayers-dev" un ensemble de fonctionnalités de vérification et de signalement des erreurs. Elles s'intègrent à Vulkan comme des surcouches le temps du développement de l'application et sont retirées lorsque l'application passe en production d'où le nom de "couches de validation". Afin d'être plus explicite, un exemple de message d'erreur renvoyé par les couches de validations est exposé ci-dessous:

...
Capture d'écran du résultat de messages d'erreurs renvoyés par les couches de validation.

Dans cet exemple, Vulkan m'indique clairement que j'ai supprimé l'appareil logique avant d'avoir supprimé plusieurs objets qui y sont liés. Il faut donc que je modifie mon code afin de supprimer l'ensemble des objets liés à l'appareil logique avant de supprimer l'appareil logique. Sans entrer dans les détails, car cette notion sera abordée ultérieurement, l'appareil logique est un objet Vulkan qui va représenter de manière logique, c'est à dire virtuelle la carte graphique utilisée.

L'installation des couches de validation se fait en tapant la commande suivante :

sudo apt install vulkan-validationlayers-dev

Enfin la package spirv-tools permet à Vulkan traiter le bytecode des shaders.

sudo apt install spirv-tools

Qu'est-ce que sont les shaders ? Et qu'est-ce qu'est SPIRV ?

Les shaders sont de courts programmes écrits en langage C qui seront exécutés de manière individuelle par chacun des cœurs de la carte graphique.

SPIR-V est un langage binaire, qui permet de générer à partir du code C des shaders un bytecode qui par la suite sera compilé et exécuté par le GPU.

Les fichiers dont l'extension est ".spv", c'est-à-dire issue du langage SPIR-V sont un moyen que Khronos à trouver afin de standardiser l'interprétation des shaders par le GPU, car par le passé, le code C était directement traduit en instructions assembleur GPU, et cela à mener à des interprétations différentes d'un GPU à un autre. Par conséquent, des comportements imprévus survenaient quand par exemple une application était utilisée sur une plateforme qui différait de celle sur laquelle elle avait été développée.

Afin de justement convertir le langage C des shaders en langage SPIRV. Il te faudra installer un compilateur de shader parmi ceux proposer par la communauté.

Moi à titre personnel j'utilise celui de Google, tout simplement, car c'est avec celui-là que j'ai appris Vulkan, tu peux le télécharger via le lien suivant : https://github.com/google/shaderc/blob/main/downloads.md .

Installer GLFW : une bibliothèque qui permet de gérer l'affichage du rendu 3D mais également les différents évènements pouvant survenir (souris, clavier).

Il n'est pas possible de faire d'interface graphique en utilisant uniquement Vulkan. Aussi faut-il recourir à d'autres bibliothèques qui se chargeront de l'affichage du rendu graphique 3D calculé par Vulkan mais aussi de la gestion des évènements clavier et souris. Pour remplir ces différentes fonctions, j'utilise la bibliothèque glfw, elle s'installe en utilisant la ligne de commande suivante :

sudo apt install libglfw3-dev

Installer GLM: Une bibliothèque contenant les structures et fonctions mathématiques d'algèbre linéaire nécessaire à la gestion de la 3D.

Enfin, la dernière bibliothèque que l'on installera est GLM (OpenGL Mathematics). Elle contient des structures et des fonctions mathématiques telles que mat4, vec2, etc., conçu pour s'accorder avec les conventions de noms et de fonctions utilisés par les shaders. En effet, elle emploie des types de variables tels que mat4 ou encore vec2 qui sont des types couramment employés dans les shaders. De plus, elle permet de manipuler aisément des transformations mathématiques telles que la projection, le raytracing, sans nécessiter une compréhension avancée de ces notions.

sudo apt install libglm-dev

Maintenant que l'ensemble des bibliothèques dont nous avions besoin afin d'utiliser Vulkan, nous allons pouvoir passer aux choses sérieuses dès la section suivante dans laquelle nous verrons comment créer une fenêtre avec GLFW.

Créer une fenêtre avec GLFW

Je vais d'abord commencer par introduire les includes dont nous aurons besoin :

#define GLFW_INCLUDE_VULKAN #include

en écrivant la ligne GLFW_INCLUDE_VULKAN avant la ligne #include on charge l'ensemble des structures et des fonctions de Vulkan.

Afin d'initialiser la bibliothèque GLFW, il faut faire appel à la fonction glfwInit();

glfwInit();

Puis, il faut indiquer à glfw, l'API que l'on va utiliser une API qu'elle ne connait pas(Vulkan). Cela se fait en indiquant le flag GLFW_NO_API, comme API cliente à l'aide de la fonction glfwWindowHint.

glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);

On appelle la fonction glfwCreateWindow afin de créer la fenêtre :

glfw_window = glfwCreateWindow(800, 600, "Ma fenêtre Vulkan", nullptr, nullptr);

on lui indique la hauteur, le longueur et le nom qu'on souhaite donner à la fenêtre.

Puis afin d'éviter sa fermeture, on la met en attente d'un évènement, via une boucle while qui va vérifier à l'aide de la fonction glfwWindowShouldClose si l'utilisateur à

et glfwPollEvents(); qui va permettre de récupérer les évènements :

    while (!glfwWindowShouldClose(objects->glfw_window))
    {
        glfwPollEvents();
    }

Quand l'utilisateur provoque la fermeture de la fenêtre en cliquant sur la croix en haut à droite. On détruit la fenêtre en se servant de glfwDestroyWindow et on ferme GLFW via glfwTerminate.

glfwDestroyWindow(objects->glfw_window);
glfwTerminate();

Voici le code complet, permettant de créer une fenêtre GLFW :

#define GLFW_INCLUDE_VULKAN
#include 

int main()
{

     //Pointeur vers la fenêtre qui sera utilisée par l'application
    GLFWwindow *glfw_window;
    // Initialisation de la bibliothèque glfw()
    glfwInit();
    //Configuration de GLFW de sorte qu'elle puisse accueillir l'API Vulkan
    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    // Création de la fenêtre qui accueillera la zone de dessin de Vulkan
    glfw_window = glfwCreateWindow(800, 600, "Ma fenêtre Vulkan", nullptr, nullptr);

    while (!glfwWindowShouldClose(glfw_window))
    {
        glfwPollEvents();
    }

    // Destruction de la fenêtre qui avait été créée au début du programme pour accueillir Vulkan
    glfwDestroyWindow(glfw_window);
    // Fermeture de la librairie GLFW.
    glfwTerminate();

}

Pour compiler, il te suffit de taper dans la console la ligne de commande suivante :

g++ -o stargazer main.cpp -I . -lglfw -lvulkan -ldl -lpthread -lX11 -lXxf86vm -lXrandr -lXi

Si tu as bien suivi les étapes jusqu'ici, voici le résultat que tu devrais obtenir :

...
Capture d'écran du résultat de la fenêtre GLFW.