Contexte matériel
Le microcontrôleur RP2350, utilisé dans la carte Raspberry Pi Pico 2, dispose de 520 kB de SRAM et d’un périphérique HSTX capable de générer du signal DVI. Le rendu vidéo repose entièrement sur le logiciel : chaque ligne de balayage doit être remplie en moins de six cycles par pixel, sinon la fréquence de rafraîchissement chute. Cette contrainte impose une optimisation extrême du code de rendu, surtout lorsqu’on veut dépasser le modèle classique à cellule fixe et adopter un framebuffer bitmap.
Architecture du rendu JIT
Le moteur vic‑2350 organise les objets graphiques dans une liste d’affichage double‑bufferisée. Chaque objet possède un vtable, un rectangle de délimitation et des données spécifiques. Avant le rendu, la liste est triée par ordonnée y0 afin que l’insertion dans la liste active, qui représente les objets intersectant la ligne de balayage courante, se fasse en O(1). Le texte est traité comme un objet dédié : il stocke la chaîne (un octet par caractère), un pointeur vers la police et les couleurs de premier plan et d’arrière‑plan.
Lors de l’insertion, la méthode start alloue un tampon de travail d’un bit par pixel et un espace pour le code JIT. Le compilateur JIT traduit la chaîne en une séquence d’instructions ARM très spécialisées, chaque instruction écrivant directement le bit correspondant du glyphe dans le tampon. Cette génération se fait une fois par chaîne, ce qui élimine les boucles de décodage à chaque scanline.
Analyse des performances
Le second passage, qui convertit le tampon 1 bpp en RGB565 (16 bits), s’exécute à un débit moyen de 1,75 cycle par pixel, bien en dessous du budget de six cycles. La police est stockée dans un bitmap large où chaque ligne de glyphe s’aligne sur une frontière de 32 bits ; ainsi, la lecture d’une rangée de pixels ne nécessite qu’un seul chargement 32‑bits, évitant les accès non alignés. Les métadonnées de chaque glyphe contiennent les espaces latéraux (proportional spacing) et le kerning, ce qui permet de conserver la flexibilité typographique sans alourdir le rendu.
Le choix du langage symbolasm, un assembleur à haut niveau dédié aux Cortex‑M33, a permis d’atteindre le niveau de granularité requis. Rust, bien que plus sûr, ne pouvait pas garantir le respect du budget de cycles, d’où le recours à l’assembleur. La technique JIT, bien que rare sur des microcontrôleurs, réduit le nombre d’instructions exécutées par pixel de façon proportionnelle à la longueur de la chaîne, car le code généré ne parcourt pas la police à chaque appel.
En termes de consommation de mémoire, le tampon 1 bpp occupe un octet par huit pixels, ce qui reste négligeable comparé aux 520 kB disponibles. La double‑bufferisation de la liste d’affichage impose toutefois une duplication des structures d’objet, mais le texte stocke uniquement la chaîne brute, évitant l’expansion pré‑rendu qui aurait dépassé les limites de SRAM.