Quale problema risolve il buffering doppio o triplo nei giochi moderni?


31

Voglio verificare se la mia comprensione delle cause dell'uso del buffering doppio (o triplo) è corretta:

Un monitor con 60Hz di aggiornamento è il monitor-display 60 volte al secondo. Se il monitor aggiorna il monitor, aggiorna pixel per pixel e riga per riga. Il monitor richiede i valori di colore per i pixel dalla memoria video.

Se eseguo ora un gioco, questo gioco manipola costantemente questa memoria video.

Se questo gioco non utilizza una strategia di buffer (doppio buffering ecc.), Può verificarsi il seguente problema:

Il monitor ora sta aggiornando il suo monitor-display. In quel momento il monitor aveva già aggiornato il display del primo mezzo monitor. Allo stesso tempo, il gioco aveva manipolato la memoria video con nuovi dati. Ora il monitor accede alla seconda metà del monitor e visualizza questi nuovi dati manipolati dalla memoria video. I problemi possono essere lacrimazione o sfarfallio.

La mia comprensione dei casi di utilizzo della strategia buffer è corretta? Ci sono altri motivi?

Risposte:


62

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.


7
Questa è una risposta incredibilmente dettagliata e spiega perché molte cose vengono fatte così (come lo spazio delle coordinate dello schermo, ecc.). Ha anche risposto alla mia domanda "perché non quadruplicare i buffer? Quintupla?" Non mi rendevo conto che lo scambio di buffer avveniva in background, il che significa che due back buffer sono il massimo necessario. Upvoted.
lunchmeat317,

In realtà esiste un quad buffering. Si tratta di un doppio buffering per la vista stereoscopica. swiftless.com/tutorials/opengl/smooth_rotation.html
Narek

@Narek No. Citando dal tuo link: "Non puoi davvero abilitare il quad buffering reale negli ambienti di grafica del computer in quanto non ha senso". Suggerire che fare doppio buffering su due diverse viste contemporaneamente sarebbe "quad buffering" è solo un divertente gioco di parole; non qualcosa di reale.
Trevor Powell,

@TrevorPowell Aggiungendo una parte che hai dimenticato di includere: "Bene, in genere il buffering quadruplo si riferisce al doppio buffering in un ambiente stereoscopico. Ad esempio: hai due display, in genere per scopi 3D e ogni occhio ha un doppio buffer". Ora il contesto potrebbe essere più chiaro.
Narek,

@TrevorPowell Il tuo punto è del tutto chiaro però. Non ha senso avere più di 3 buffer per un buffer di rendering.
Narek,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.