La VBL

Ou comment afficher à la même vitesse chez tout le monde

Historique

La VBL (VBlank), aussi connue sous l'appellation de "frame". Mais qu'est-ce donc ?

A une époque pas si lointaine, en lieu et place du classique PC, on parlait de micro-informatique. Les micro-ordinateurs possédaient un moniteur cathodique et ces moniteurs avaient une fréquence de balayage bien établie : 50 Hz en PAL, 60 Hz en NTSC.

"Super... Et ça veut dire quoi ?" me direz-vous ? Et bien ça veut dire que sur ces moniteurs, l'image était rafraîchie 50 (ou 60) fois par seconde. Donc, c'est à dire qu'en se synchronisant sur cette fréquence de rafraîchissement, on affichait 50 (ou 60) images par seconde sur toutes les machines.

Alors oui, un C64, c'est un C64, il tourne à la même vitesse chez tout le monde (Je ne parle pas de ceux qui ont été customisés et qu'on peut toujours voir en 2010 dans les demo parties). Mais dans les gammes comme Atari et Amiga, il y avait déjà des différences de configuration qui jouaient sur les performances : Atari STF, STE, Falcon 030, 040, Amiga 500 (7 Mhz), 1200 (12 Mhz), mémoire 'FAST' en plus de la 'CHIP', Amiga 4000... Donc voilà, en se synchronisant sur la fréquence de rafraîchissement, c'est 50 (ou 60, mais je vais arrêter de le répeter maintenant) images par secondes, chez tout le monde.

Techniquement, comment ça se passait : les lignes étaient balayés de gauche à droite par un faisceau d'électrons, de haut en bas. Arrivé en bas de l'écran après la dernière ligne, le faisceau était ramené en haut de l'écran pour l'affichage de l'image suivante. Cet intervalle de temps s'appelait le "vertical blank". C'est à ce moment là qu'on avait une fenêtre de temps pour toucher à la mémoire vidéo (accès direct à la VRAM, switch de pointeurs...) sans risquer d'effet de "déchirure".

A noter que la première ligne balayée n'était pas la ligne 0 pour le programmeur car le faisceau balayait tout l'écran (souvenez vous du "border" !), ce qui laissait un peu de temps supplémentaire (le temps de descendre jusqu'à la ligne 0) et ce qui donnera à certains par la suite l'idée de faire de l'overscan.

Nowadays

Evidement, à l'heure actuelle, avec nos OS fenêtrés, il n'est plus question d'accéder directement au hardware comme à la grande époque. C'était encore possible jusqu'aux premiers pentiums sous DOS, mais dès que vous avez un Windows ou assimilé en tâche de fond, ça se complique.

J'utilise le code suivant pour synchroniser mes programmes. J'ai du le trouver sur un site quelquepart sur la toile, mais je n'arrive pas à retrouver la source. Si jamais j'auteur se reconnait, merci de me faire signe, je mettrai un lien vers son site.

frame.c afficher/masquer
#define FPS_Default 1000 / 70
u32 gnTimer1;

// Init timers.
void FrameInit(void)
{
    gnTimer1 = SDL_GetTicks();
}

// Attente de la frame.
void FrameWait(void)
{
    u32 nTimer2;

    // S'assurer que l'on ne va pas trop vite...
    while (1)
    {
        nTimer2 = SDL_GetTicks() - gnTimer1;
        if (nTimer2 >= FPS_Default) break;
        SDL_Delay(3);
    }
    gnTimer1 = SDL_GetTicks();
}

Chez moi, le code qui va derrière ressemble en gros à ça :

Boucle principale afficher/masquer
FrameInit();
while (condition)
{
    // Gestion des évenements.
    EventHandler();

    //... Gestion du jeu ...

    // Pseudo attente de VBL.
    FrameWait();
    // On passe le double buffer à l'écran.
    SDL_Flip(gVar.pScreen);
}

Un petit exemple d'utilisation avec un petit rotozoom ici.

Comme je l'expliquais dans le LISEZMOI.TXT de mon Arkanoid, c'est une gestion basique qui sous-entend qu'on ne va pas perdre de frame, càd que le programme ne ramera pas. Si jamais ça arrivait, il faudrait le prendre en compte. La fonction "FrameWait()" pourrait par exemple renvoyer le nombre de frames passées depuis le dernier appel. On peut aussi placer un timer sous interruption, qui incrémente une variable à chaque passage. Le programme principal attend alors que cette variable ne soit pas à 0...

Mais bon, étant donné le type de programme qui m'intéresse (principalement 2D), le cas d'un programme qui rame ne s'est encore jamais présenté, y compris sur mon vieux coucou. Donc pour l'instant, cette gestion basique a toujours fait l'affaire.

Home