3 points par GN⁺ 2025-08-08 | 1 commentaires | Partager sur WhatsApp
  • Cet article se concentre sur le développement de Tyr, un nouveau pilote GPU en Rust pour le noyau Linux, et sur les principes de fonctionnement d’un pilote GPU
  • Il explique la distinction des rôles et les interactions entre l’UMD (User Mode Driver) et le KMD (Kernel Mode Driver) dans le développement d’un pilote GPU, à travers l’exemple VkCube
  • L’UMD convertit les API de haut niveau en commandes de bas niveau compréhensibles par le GPU, tandis que le KMD assure des rôles clés comme l’allocation mémoire, la planification des tâches et l’initialisation du périphérique
  • L’API fournie par le pilote Tyr est la même que celle de Panthor, avec des fonctions de requête de périphérique, de gestion mémoire, de gestion de groupes, de soumission de travaux et de gestion du tas Tiler
  • Le prochain article abordera l’architecture matérielle Arm CSF, les composants clés (par ex. MCU) et le processus de boot

Introduction : développement d’un pilote GPU noyau moderne avec Rust

  • Cet article est le deuxième volet de la série de développement du pilote Tyr, un pilote moderne GPU pour le noyau Linux prenant en charge les GPU Arm Mali CSF
  • Comme exemple concret, VkCube, un simple programme 3D qui rend un cube tournant en utilisant l’API Vulkan, a été retenu pour expliquer le fonctionnement interne d’un pilote GPU
  • La simplicité de VkCube en fait un bon cas d’usage pour apprendre les principes de base du fonctionnement d’un pilote GPU

Bases d’un pilote GPU : rôles et structure de l’UMD et du KMD

  • Un pilote GPU est constitué d’un User Mode Driver (UMD) et d’un Kernel Mode Driver (KMD)
    • UMD : implémente les API des programmes classiques, comme panvk (le pilote Vulkan de Mesa, entre autres)
    • KMD : Tyr, etc., pilote au niveau du noyau avec des privilèges sur le matériel, fonctionnant comme partie du noyau Linux
  • Le pilote GPU en mode noyau fait le lien entre l’UMD et le GPU réel, et l’UMD interprète les commandes d’API pour les convertir en un ensemble de commandes compréhensibles par le GPU
  • L’UMD prépare les données nécessaires à la construction de la scène (géométrie, textures, shaders, etc.) et demande au KMD d’allouer ces ressources en mémoire GPU avant exécution
  • Le shader est un programme autonome exécuté sur le GPU ; dans VkCube, il gère la mise en place du cube, la coloration et la logique de rotation, entre autres. Son exécution nécessite des données externes (géométrie, couleur, matrice de rotation, etc.)
  • L’UMD transmet les commandes préparées (ex. : VkCommandBuffers) au KMD pour les exécuter, puis reçoit une notification à la fin de l’exécution afin de pouvoir enregistrer les résultats en mémoire

Responsabilités principales du KMD (Kernel Mode Driver)

  • Allocation et mapping de la mémoire GPU (avec isolation par application)
  • Soumission des travaux à la file d’attente matérielle et notification des utilisateurs à la complétion
  • Dans un environnement matériel asynchrone et parallèle, la gestion des dépendances de travail est essentielle ; pour garantir des résultats corrects, le KMD joue un rôle clé dans la planification et la validation des dépendances
  • Cela inclut aussi l’initialisation du périphérique, l’activation des régulateurs d’horloge/tension, l’exécution du code de démarrage et la gestion de la rotation d’accès afin de permettre à plusieurs clients de partager équitablement le matériel

Où se situe la complexité : séparation des tâches entre UMD et KMD

  • La complexité d’un pilote GPU est majoritairement concentrée au niveau de l’UMD
    • UMD : conversion des commandes API de haut niveau en commandes matérielles
    • KMD : fournit les fonctions essentielles comme l’isolation mémoire, le partage et l’accès équitable pour que l’UMD fonctionne correctement

Structure de l’interface API fournie par Tyr

  • L’API du pilote Tyr (identique à Panthor) peut être divisée en 5 grands groupes
    1. Requête d’informations de périphérique : DEV_QUERY (lecture d’informations matérielles GPU via IOCTL, en tirant parti de la zone ROM)
    2. Allocation et isolation mémoire : VM_CREATE, VM_BIND, VM_DESTROY, VM_GET_STATE, BO_CREATE, BO_MMAP_OFFSET, etc.
    3. Gestion des groupes de planification : GROUP_CREATE, GROUP_DESTROY, GROUP_GET_STATE (plus de détails dans un prochain article)
    4. Soumission de travaux : GROUP_SUBMIT (demande d’exécution de buffers de commandes appareil vers le GPU)
    5. Gestion du tas Tiler : TILER_HEAP_CREATE, TILER_HEAP_DESTROY (pour répondre aux besoins mémoire des GPU de rendu tuilé)
  • Ces API sont relativement éloignées du dessin direct, tandis que l’UMD prend en charge l’exécution effective des commandes et que le KMD n’offre que l’interface ci-dessus pour accéder au matériel

Conclusion et perspectives

  • Cet article a couvert la structure globale et le flux interne d’un pilote GPU, ainsi que les API clés fournies par Tyr
  • Sur la base de ces éléments, les prochains articles de la série traiteront de l’architecture matérielle Arm CSF, du microcontroller unit (MCU) et du processus d’initialisation du pilote

1 commentaires

 
GN⁺ 2025-08-08
Commentaires Hacker News
  • C’était un très bon article, mais il était trop court ; il venait juste de devenir intéressant quand il s’est arrêté, donc j’attends la suite avec impatience.
    • Une suite passionnante est annoncée dès la semaine prochaine : on devrait voir des commandes en attente sur le GPU sortir de la file d’attente pour s’exécuter. Le niveau d’abstraction traité ici concerne surtout le transfert de données à la frontière utilisateur/noyau. Comme l’article se concentre principalement sur la gestion des files d’attente et des buffers, il y a peu d’opérations à proprement parler. Le vrai sujet se situe dans l’exécution des commandes ajoutées à la queue ; il y aura aussi le signal de complétion inverse envoyé par le GPU, ce qui m’intrigue également. La plupart de ce traitement asynchrone est géré côté code utilisateur, pas du côté du pilote ; le pilote se contente de transmettre le signal de fin.
  • J’utilise un appareil RK3588 comme machine de bureau avec panfrost, et il arrive que Firefox affiche un écran noir ou des zones transparentes, un phénomène étrange.
    • En réalité, RK3588 utilise le pilote panthor, qui est le sujet de l’article, et non panfrost.
  • Je me demandais si l’option de remplacer les ioctls par uring_cmd avait été envisagée. Comme le projet est réécrit entièrement, l’intégration semblait possible ; je me demande juste pourquoi vous pensez qu’il n’y a quasiment aucun avantage.
    • Le GPU a déjà sa propre file d’attente de commandes asynchrones, donc l’IOCTL sert déjà à écrire dedans à faible coût ; créer une file asynchrone supplémentaire côté CPU pour planifier ces écritures est donc une option à utilité limitée. Si la proposition est plutôt de faire une queue de commandes GPU en uring et de la mapper en userspace, il faudrait modifier assez profondément le firmware pour respecter correctement la spécification de l’API io_uring, et cela peut être impossible selon les caractéristiques matérielles.
    • Le pilote décrit dans l’article suit exactement l’API requise par la bibliothèque Mesa côté userspace.
  • Je l’ai trouvé très intéressant, et je me demandais s’il y aurait une partie 2 ou quelque chose qui prolongerait logiquement le sujet.
    • C’est le premier article publié aujourd’hui, donc j’attends d’autres mises à jour à venir.
  • Je comprends que le titre “Rust GPU driver” soit plus orienté clics, mais au fond ce n’est quand même pas un pilote GPU basé sur Arm Mali CSF ? Je n’apprécie pas personnellement l’attention portée au méta-outil pour le développement ; il semble que le vrai objectif soit de “faire quelque chose en Rust”. L’article précise pourtant “driver noyau GPU basé sur Arm Mali” sans pourtant appeler ça un pilote Arm Mali. Je pense qu’écrire un pilote, c’est simplement faire l’interface entre l’API de l’OS et celle du fabricant, et non construire un framework qui ajoute une couche d’abstraction supplémentaire au-dessus. Je suis un peu direct, veuillez me le pardonner.
    • Rust est un mot-clé important ici parce que ce cas constitue l’un des premiers exemples (si ce n’est pas le premier) d’utilisation d’une infrastructure Rust dans un pilote GPU.
    • Ne me prenez pas mal sur le ton direct, mais votre manière de parler laisse penser que vous ne savez rien de ce que sont les pilotes GPU modernes. J’en ai déjà utilisé il y a 15 ans, mais je sais qu’ils sont devenus bien plus complexes depuis. Rien qu’en regardant le code source du noyau Linux, la part des pilotes GPU en nombre de lignes est la plus importante. La plupart des pilotes prennent en charge plusieurs cartes graphiques, donc je doute que vous sachiez à quel point il est peu rationnel de fabriquer un pilote entièrement indépendant pour chaque carte GPU à chaque fois. Écrire un pilote GPU n’est pas simplement “connecter des lignes” entre deux API ; c’est bien plus différent en réalité. Si vous voulez le contester, montrez le pilote GPU que vous avez écrit — j’aimerais bien voir si vous avez vraiment fini en ne reliant que quelques lignes.
    • Rust est important ici car c’est le premier (ou l’un des premiers) cas d’utilisation de l’infrastructure Rust pour un pilote GPU.