Buffers partagés dans wayland
Un petit post à propos des buffers partagés dans wayland, l'implémentation wl_shm.
Quand un client fait une mise à jour de l'affichage, la nouvelle image pourrait être envoyé à travers la socket entre le client et le compositor, mais ce serait extrêmement lent: des appels à read() / write() passant par la case kernel sans parler des coûts de copie mémoire associés.
Dans wayland, il a été choisi de partager ces informations de surfaces en utilisant des mémoires partagées. Le design est le même que l'extension SHM de X11, sauf que dans wayland ce n'est pas une extension mais le seul moyen pour envoyer des surfaces au compositor.
Petite note: une des différences entre mir et wayland, c'est que les buffers sont gérés par le serveur dans un cas et par les clients dans l'autre.
Donc tout roule comme sur des roulettes, le client fait ses mises à jour de l'affichage dans la zone de mémoire partagée, et il prévient le compositor en envoyant des ordres de mises à jours dans la socket qui le relie au compositor.
Problème: si on se contente de ça, on va avoir des accès concurrents sur le buffer partagé: le client et le serveur vivent leur vie chacun de leur coté, et il y a fort à parier que le client va vouloir faire d'autres modifications graphiques pendant que le serveur sera en train de fabriquer l'image globale du desktop. Pour régler ce problème, le client est prié de ne plus utiliser le buffer tant que le serveur ne l'aura pas notifié. Le serveur notifie les clients quand il a utilisé un buffer pour faire la mise à jour de l'affichage, ce qui permet au client de libérer ou de réutiliser ce buffer.
Le client ne va pas rester à se tourner les pouces en attendant que le serveur ai fini ses opération, on a une implémentation assez classique de double-buffering:
- le client alloue 2 buffers;
- il dessine dans le premier;
- il notifie le compositor de la mise à jour de la surface;
- il dessine dans le second;
- un buffer envoyé au compositor;
- un buffer qu'on a préparé et qu'on attend d'envoyer;
- un buffer qui sert pour les modifications courantes
- le buffer 2 est envoyé;
- le buffer 3 devient celui qui est en attente d'envoi;
- et le buffer 1 qui vient d'être libéré devient celui qui sert pour les modifications courantes