Vulkan est différent des API graphiques plus anciennes en ce sens que les pilotes n'effectuent pas certaines optimisations, telles que la réutilisation du pipeline, pour les applications. Au lieu de cela, les applications qui utilisent Vulkan doivent implémenter ces optimisations elles-mêmes. Si elles ne le font pas, elles peuvent offrir de moins bonnes performances que les applications utilisant OpenGL ES.
Lorsque les applications implémentent elles-mêmes ces optimisations, elles peuvent le faire plus efficacement que le pilote, car elles ont accès à des informations plus précises pour un cas d'utilisation donné. Par conséquent, une application savamment optimisée qui utilise Vulkan peut générer de meilleures performances que si elle utilisait OpenGL ES.
Cette page présente plusieurs optimisations que votre application Android peut mettre en œuvre pour être plus performante grâce à Vulkan.
Accélération matérielle
La plupart des appareils sont compatibles avec Vulkan 1.1 via l'accélération matérielle, tandis qu'un petit sous-ensemble d'entre eux le sont via l'émulation logicielle. Les applications peuvent détecter un appareil Vulkan à émulation logicielle à l'aide de vkGetPhysicalDeviceProperties
, en vérifiant le champ deviceType
de la structure renvoyée.
SwiftShader et les autres intégrations basées sur le processeur ont la valeur VK_PHYSICAL_DEVICE_TYPE_CPU
.
Les applications peuvent détecter spécifiquement SwiftShader en recherchant les valeurs correspondantes dans les champs vendorID
et deviceID
de cette même structure.
Les applications pour lesquelles les performances sont un aspect critique doivent éviter d'utiliser des implémentations Vulkan émulées par logiciel et utiliser OpenGL ES à la place.
Appliquer la rotation de l'écran pendant le rendu
Lorsque la direction vers le haut d'une application ne correspond pas à l'orientation de l'écran de l'appareil, le compositeur fait pivoter les images de la chaîne d'échange de l'application pour qu'elles correspondent. Il effectue cette rotation lors de l'affichage des images, ce qui entraîne une consommation d'énergie plus importante (parfois beaucoup plus) que s'il ne les faisait pas pivoter.
En revanche, la rotation des images de la chaîne d'échange pendant leur génération entraîne une consommation d'énergie supplémentaire minime, voire nulle. Le champ VkSurfaceCapabilitiesKHR::currentTransform
indique la rotation que le compositeur applique à la fenêtre. Une fois que l'application a effectué cette rotation lors du rendu, elle utilise le champ VkSwapchainCreateInfoKHR::preTransform
pour signaler que la rotation est terminée.
Limiter le nombre de passes de rendu par image
Sur la plupart des architectures GPU mobiles, les opérations consistant à commencer et à terminer une passe de rendu sont coûteuses. Votre application peut améliorer ses performances en organisant les opérations de rendu de façon à effectuer le moins de passes possible.
Différentes opérations de chargement et de stockage de pièces jointes offrent des niveaux de performance différents. Par exemple, si vous n'avez pas besoin de conserver le contenu d'une pièce jointe, vous pouvez utiliser les opérations VK_ATTACHMENT_LOAD_OP_CLEAR
ou VK_ATTACHMENT_LOAD_OP_DONT_CARE
, qui sont beaucoup plus rapides, plutôt que VK_ATTACHMENT_LOAD_OP_LOAD
. De même, si vous n'avez pas besoin d'écrire en mémoire les valeurs finales d'une pièce jointe pour une utilisation ultérieure, vous pouvez utiliser VK_ATTACHMENT_STORE_OP_DONT_CARE
pour obtenir de bien meilleures performances qu'avec VK_ATTACHMENT_STORE_OP_STORE
.
En outre, pour la plupart des passes de rendu, votre application n'a pas besoin de charger ni de stocker la pièce jointe de profondeur/gabarit. Dans ce cas, vous pouvez éviter d'allouer de la mémoire physique pour la pièce jointe en utilisant l'option VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT
lors de la création de son image. Ce bit offre les mêmes avantages que glFramebufferDiscard
dans OpenGL ES.
Sélectionner les types de mémoire appropriés
Lorsqu'elles allouent la mémoire de l'appareil, les applications doivent sélectionner un type de mémoire. Celui-ci détermine la manière dont une application peut utiliser la mémoire et décrit les propriétés de mise en cache et de cohérence de la mémoire. Les types de mémoire disponibles varient selon les appareils. Chaque type de mémoire présente des caractéristiques de performances différentes.
Une application peut utiliser un algorithme simple afin de sélectionner le meilleur type de mémoire pour une utilisation donnée. Cet algorithme sélectionne dans le tableau VkPhysicalDeviceMemoryProperties::memoryTypes
le premier type de mémoire qui répond à deux critères : il doit être autorisé pour le tampon ou l'image, et il doit avoir les propriétés minimales requises par l'application.
Les systèmes mobiles ne disposent généralement pas de tas de mémoire physique distincts pour le CPU et le GPU. Sur ces systèmes, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
n'est pas aussi important que sur les systèmes disposant de GPU distincts dotés de leur propre mémoire dédiée. L'application ne doit pas supposer que cette propriété est obligatoire.
Regrouper les ensembles de descripteurs par fréquence
Si vous disposez de liaisons de ressources qui changent à des fréquences différentes, utilisez plusieurs ensembles de descripteurs par pipeline au lieu de lier à nouveau toutes les ressources pour chaque dessin. Par exemple, vous pouvez utiliser un ensemble de descripteurs pour les liaisons par scène, un autre pour les liaisons par matière et un troisième pour les liaisons par instance de maillage.
Utilisez des constantes immédiates pour les modifications les plus fréquentes, telles que celles exécutées à chaque appel de dessin.