Fondamentalmente, un obiettivo principale nel rendering è che ogni fotogramma visualizzato sul monitor presenti una singola immagine coerente. Esistono diverse strategie che sono o sono state utilizzate per raggiungere questo obiettivo.
Di seguito menziono "vsync". Vsync è il momento in cui il monitor inizia a disegnare una nuova immagine dello schermo; è il punto in cui "vblank" inizia su uno schermo CRT tradizionale, in cui la linea di scansione smette momentaneamente di disegnare e torna alla parte superiore del monitor. Questo momento è molto importante per molti degli approcci per inquadrare la coerenza.
"Strappare" è ciò che lo chiamiamo quando viene eseguito il rendering di uno schermo da due diverse immagini, all'interno di un singolo fotogramma. Se, ad esempio, ho disegnato due immagini dello schermo che devono essere visualizzate una dopo l'altra, ma il monitor ha invece visualizzato la metà superiore del fotogramma uno e la metà inferiore del fotogramma due, è "strappante". Ciò accade a causa della modifica dei dati da cui il monitor sta leggendo mentre il monitor sta disegnando, anziché durante vblank. (Nei programmi moderni, ciò accade in genere perché l'utente ha disabilitato l'attesa di vsync nelle impostazioni del driver)
Zero-Buffer
Sull'hardware più vecchio, spesso non c'era memoria sufficiente per contenere un'immagine a schermo intero, quindi invece di disegnare un'immagine dello schermo, era necessario specificare i colori per ciascuna linea di scansione singolarmente, mentre il monitor stava disegnando quella linea. Sull'Atari 2600, ad esempio, c'erano solo 76 cicli di istruzioni della macchina per specificare quale colore andava in ciascun pixel della linea di scansione, prima che il televisore iniziasse a disegnare effettivamente quella linea di scansione. E poi hai avuto 76 cicli di istruzioni per fornire i contenuti per la prossima scanline e così via.
Singolo-buffer
Quando si disegna in un contesto di "buffer singolo", si disegna direttamente nella VRAM che viene letta dal monitor. In questo approccio, "corri sulla scanline". L'idea generale è che quando la linea di scansione inizia a disegnare i contenuti del fotogramma precedente nella parte superiore dello schermo, si disegna in VRAM dietro di esso. Quindi, mentre la linea di scansione disegna l'immagine sullo schermo per l'ultimo fotogramma, stai disegnando il fotogramma successivo dietro la linea di scansione.
In generale, stai cercando di terminare di disegnare l'immagine del fotogramma successivo prima che la linea di scansione ti "giri" tornando indietro e sorpassando i pixel che stai disegnando, e anche per non andare mai avanti rispetto alla linea di scansione, altrimenti il tuo nuovo frame potrebbe disegnare in quello che avrebbe dovuto essere il frame precedente.
Per questo motivo, il rendering a buffer singolo in genere ha funzionato da solo disegnando linee di scansione, dall'alto verso il basso e da sinistra a destra. Se avessi disegnato in un altro ordine, era probabile che la linea di scansione tornasse e individuasse frammenti dell'immagine "successiva" che non avevi ancora disegnato per disegnare.
Si noti che nei moderni sistemi operativi, in genere non si ha mai l'opportunità di disegnare a buffer singolo, anche se questo era abbastanza comune trenta anni fa. (Accidenti mi sento vecchio in questo momento - questo è quello che stavo facendo quando ho iniziato per la prima volta nello sviluppo del gioco)
Doppio-Buffer
Questo è molto, molto più semplice di una delle strategie precedenti.
In un sistema a doppio buffer, disponiamo di memoria sufficiente per memorizzare due diverse immagini dello schermo, e quindi designiamo una di esse come "buffer anteriore" e l'altra, "buffer posteriore". Il "buffer anteriore" è ciò che viene attualmente visualizzato e il "buffer posteriore" è dove stiamo attualmente disegnando.
Dopo aver finito di disegnare un'immagine dello schermo nel buffer posteriore, aspettiamo fino a vsync, quindi scambiamo i due buffer. In questo modo, il buffer posteriore diventa il buffer anteriore e viceversa e l'intero scambio è avvenuto mentre il monitor non stava disegnando nulla.
Triple-Buffer
Un problema spesso sollevato con gli approcci a doppio buffer è che dopo aver finito di disegnare sul back buffer, dobbiamo semplicemente rimanere in attesa di vsync prima di poter scambiare i buffer e continuare a lavorare; avremmo potuto fare calcoli durante quel periodo! Inoltre, per tutto il tempo che stiamo aspettando di scambiare tra i buffer, l'immagine in quel back buffer diventa sempre più vecchia, aumentando così la latenza percepita dall'utente.
Nei sistemi a triplo buffer, creiamo noi stessi tre buffer: un buffer frontale e due buffer posteriori. L'idea è questa:
Il monitor sta visualizzando il buffer anteriore e stiamo disegnando nel buffer posteriore n. 1. Se finiamo di disegnare nel buffer posteriore n. 1 prima che il monitor finisca di disegnare il buffer anteriore, quindi invece di attendere vsync, iniziamo immediatamente a disegnare il fotogramma successivo nel buffer posteriore n. 2. Se finiamo e vsync non è ancora arrivato, ricominciamo a disegnare nel back buffer n. 1 e così via. L'idea è che quando alla fine si verificherà vsync, l'uno o l'altro dei nostri back buffer sarà completo e che uno potrà essere scambiato con il buffer frontale.
Il vantaggio del triplo buffering è che non perdiamo il tempo che abbiamo trascorso aspettando vsync nell'approccio di doppio buffering e l'immagine scambiata sul buffer frontale potrebbe essere "più fresca" di quella che era stata in attesa di vsync per 8ms. Il lato negativo del triplo buffering è che abbiamo bisogno di memoria aggiuntiva per archiviare l'immagine dello schermo extra e che il nostro utilizzo di CPU / GPU sarà maggiore (di nuovo, poiché non rallentiamo per attendere vsync).
In genere, i driver moderni eseguono spesso il triplo buffering in modo trasparente, dietro le quinte. Scrivi il tuo codice per eseguire il doppio buffering e il driver ti restituirà il controllo in anticipo e gestirà internamente lo scambio tra tutti i back buffer che desidera utilizzare, senza che il tuo codice ne sia mai a conoscenza.
I fornitori di GPU attualmente raccomandano di non implementare il triplo buffering da soli: il driver lo farà automaticamente.