I. Introduction

À l'occasion de la Game Developers Conference 2015 (GDC), Khronos a présenté la nouvelle bibliothèque de hautes performances pour les GPU : Vulkan.

II. Vidéo


GDC 2015 - Vulkan


III. Résumé

III-A. Historique

Le travail sur Vulkan a commencé en juin 2014 (nom de code : Next Generation OpenGL). Les acteurs de tous les secteurs de l'industrie utilisant une accélération graphique ont rejoint le projet.
Actuellement (mars 2015), les bases de la bibliothèque et sa sémantique sont établies. Les premiers fichiers d'entête sont disponibles en « alpha » pour permettre aux développeurs d'expérimenter avec la bibliothèque. La spécification complète devrait arriver courant 2015.
La spécification de la représentation intermédiaire des shaders (SPIR) est complète, seules quelques modifications/corrections restent à faire.

III-B. Objectifs

Les objectifs de Vulkan sont de fournir un standard ouvert, multiplateforme pour la 3D et le calcul sur GPU et ceux, pour les machines modernes. Pour ce faire, la compatibilité avec OpenGL est rompue. Ainsi, Vulkan fournira :

  • une architecture propre et moderne ;
  • la compatibilité avec les applications multithreads/multicœurs ;
  • un coût CPU du pilote réduit ;
  • une neutralité par rapport à l'architecture (que ce soit pour le rendu direct, ou le rendu en tuiles) ;
  • des performances prévisibles ;
  • une fiabilité et une consistance accrue entre les implémentations.

III-C. Implémentation

Au moment de la présentation, la spécification de Vulkan n'est pas finalisée. Certains éléments de code peuvent changer d'ici la finalisation de la bibliothèque.

III-C-1. Instance

Vulkan est représenté par une instance. Une application peut avoir plusieurs instances de Vulkan. Chacune est indépendante et appartient au pilote l'initiant. Ainsi, il est possible d'agréger les pilotes de différents constructeurs, de découvrir les GPU présents sur la machine et de créer une application en considérant que vous n'avez qu'un seul gros pilote supportant plusieurs GPU.

Créer une instance de Vulkan
Sélectionnez
VK_APPLICATION_INFO appInfo = { ... }; 
VK_ALLOC_CALLBACKS allocCb = { ... }; 
VK_INSTANCE instance; 

vkCreateInstance(&appInfo, &allocCb, &instance);

La création d'une instance demande des informations sur votre application et des callbacks d'allocation. Vulkan alloue de la mémoire en utilisant votre allocateur. Une fois que vous obtenez l'instance, vous pouvez vous renseigner sur les GPU présents sur la machine.
Vous pouvez récupérer des informations sur chaque GPU : le constructeur, ses performances relatives, la taille de la mémoire, les types de queues… Il est aussi possible de savoir si les GPU peuvent partager des ressources entre eux, ou non.

Avoir la liste des GPU
Sélectionnez
uint32_t gpuCount; 
VK_PHYSICAL_GPU gpus[10]; 

vkEnumerateGpus(instance, ARRAYSIZE(gpus), &gpuCount, gpus);
Récupérer des informations sur le GPU
Sélectionnez
VK_SOME_GPU_INFO_STRUCTURE info; 
uint32_t infoSize = sizeof(info); 

vkGetGpuInfo(gpu[0], VK_GPU_INFO_WHATEVER, &infoSize, &info);
Savoir si les GPU sont inter-compatibles
Sélectionnez
VK_GPU_COMPATIBILITY_INFO compatInfo; 

vkGetMultiGpuCompatibility(gpuA, gpuB, &compatInfo);

III-C-2. Périphérique

Ensuite, vous devez créer un périphérique (device) offrant une représentation logique du GPU. Lors de la création, vous pouvez spécifier le nombre de queues nécessaires, les extensions…

Créer un périphérique
Sélectionnez
VK_DEVICE_CREATE_INFO info = { ... }; 
VK_DEVICE device; 

vkCreateDevice(gpu, &info, &device);

III-C-3. Queues

Vous pouvez récupérer les queues à partir du périphérique. Celles-ci exécutent les tampons de commandes. Lors de la création des tampons de commandes, vous devez spécifier quel type de queues ils doivent utiliser.

Récupérer l'identifiant d'une queue
Sélectionnez
VK_DEVICE_CREATE_INFO info = { ... }; 
VK_DEVICE device; 

vkCreateDevice(gpu, &info, &device);

III-C-4. Tampons de commandes

Finalement, vous insérez des commandes dans les tampons de commandes. Vous pouvez créer autant de tampons de commandes que vous avez de threads. Vous pouvez aussi prendre un peu de temps pour optimiser le processus, mais ne le faites pas juste avant le rendu.

Créer un tampon de commandes
Sélectionnez
VK_CMD_BUFFER_CREATE_INFO info; 
VK_CMD_BUFFER cmdBuffer; 

vkCreateCommandBuffer(device, &info, &cmdBuffer);

III-C-5. Shaders

Les shaders sont précompilés dans un langage intermédiaire (SPIR-V). La compilation en instructions natives peut être parallélisée sur le GPU.

Créer un shader
Sélectionnez
VK_SHADER_CREATE_INFO info = { ... }; 
VK_SHADER shader; 

vkCreateShader(device, &info, &shader);

III-C-6. Pipeline

L'état du pipeline de rendu peut être sérialisé et désérialisé. Celui-ci contient les shaders compilés, les états des passes et une liste des états devant être mutables. Ceux-ci sont représentés par des objets indépendants.

Créer un pipeline
Sélectionnez
VK_GRAPHICS_PIPELINE_CREATE_INFO info = { ... }; 
VK_PIPELINE pipeline; 

vkCreateGraphicsPipeline(device, &info, &pipeline);
Sérialiser/Désérialiser un pipeline
Sélectionnez
uint32_t dataSize = DATA_SIZE; 
void* data = malloc(DATA_SIZE); 

vkStorePipeline(pipeline, &dataSize, data); 
... 
vkLoadPipeline(device, dataSize, data, &pipeline)

III-C-7. Ressources

Les objets ressources de Vulkan possèdent un composant CPU et GPU. Du côté du CPU, la ressource est allouée avec une fonction vkCreate*. C'est à l'application d'allouer les ressources mémoire du GPU.

Créer des ressources
Sélectionnez
VK_IMAGE_CREATE_INFO imageInfo = { ... }; 
VK_IMAGE image; 
vkCreateImage(device, &imageInfo, &image); 

VK_BUFFER_CREATE_INFO bufferInfo = { ... }; 
VK_BUFFER buffer; 
vkCreateBuffer(device, &bufferInfo, &buffer)

III-C-8. Passes de rendu

Les passes de rendu (render pass) représentent les phases de l'affichage d'une image. Elles contiennent énormément d'informations sur le rendu (disposition et types liés au tampon d'image, ce qu'il faut faire au début et la fin de la passe de rendu, la région du tampon d'image que la passe affecte). L'affichage est placé dans une passe de rendu.

Créer une passe de rendu
Sélectionnez
VK_RENDER_PASS_CREATE_INFO info = { ... }; 
VK_RENDER_PASS renderPass; 

vkCreateRenderPass(device, &info, &renderPass);

III-C-9. Synchronisation

Du côté de la synchronisation, Vulkan propose les événements. Les tampons de commandes peuvent signaler des événements à la fin de leur exécution. Les opérations d'un tampon de commandes peuvent être démarquées par des barrières. Les barrières peuvent attendre pour un événement ou encore envoyer un signal.

Créer une barrière
Sélectionnez
VK_IMAGE_MEMORY_BARRIER imageBarrier = { ... }; 
VK_PIPELINE_BARRIER barrier = { ..., 1, &imageBarrier }; 

vkCmdPipelineBarrier(cmdBuffer, &barrier);

III-D. SPIR

Sans représentation intermédiaire, les applications devaient embarquer le code source des shaders, le rendant ainsi facilement accessible. De plus, les applications devaient compiler les shaders durant l'initialisation et chaque pilote avait son propre compilateur pouvant interpréter le code différemment (différentes erreurs, différents messages…).

Avec SPIR, l'application embarque un binaire contenant le shader (plus difficile à hacker), la portabilité est accrue, car toutes les implémentations doivent lire le même code, de la même façon. De plus, l'étape de compilation n'est plus comprise dans l'exécution de l'application.

III-D-1. Qu'est-ce que c'est ?

SPIR est une toute nouvelle représentation intermédiaire. Le standard est défini par Khronos. SPIR fait partie de Vulkan, mais aussi d'OpenCL 2.1.

III-D-2. Implémentation

Les fonctions dans un module contiennent un graphe du flux de contrôle (control-flow graph) des blocs basiques. Les résultats intermédiaires sont représentés en utilisant une seule tâche statique (single static-assignment).
Le langage peut être facilement étendu. Il est aussi possible de rajouter des informations de débogage.

III-E. Tests

III-E-1. ARM

Dans une des implémentations préliminaires de Vulkan chez ARM, les ingénieurs ont remarqué une diminution de 79 % du temps passé dans le driver, du côté du CPU.

III-E-2. GFXBench 5.0

GFXBench 5.0 est un test permettant de comparer les performances des nouvelles bibliothèques de rendu (Mantle, Vulkan, Direct3D 12). Dans la démonstration durant la GDC 2015 on voit qu'une fois le rendu passé sur la bibliothèque Vulkan, la consommation du CPU a diminué et le nombre d'images par seconde a augmenté.

III-F. Outils

Valve et LunarG ont présenté un outil : GLAVE, permettant de tracer et de déboguer les appels à la bibliothèque Vulkan. L'outil est capable de montrer le temps passé dans chacun des appels, de rejouer une scène, d'avancer image par image…


Cliquez pour lire la vidéo


IV. Télécharger

Vous pouvez obtenir la présentation en PDF ici.

V. Commenter

Vous pouvez commenter et donner vos avis dans la discussion associée sur le forum.