2013-07-12 12 views
7

Sto usando un FBO + RBO, e invece del doppio buffering regolare sul framebuffer predefinito, sto disegnando sull'RBO e poi blit direttamente sul buffer GL_FRONT dell'FBO predefinito (0) in un contesto OpenGL con buffer singolo.doppio buffering con FBO + RBO e glFinish()

Va bene e non ho alcun sfarfallio, ma se la scena diventa un po 'complessa, ho un calo enorme in fps, qualcosa di così strano che sapevo che qualcosa doveva essere sbagliato. E non intendo da 1/60 a 1/30 a causa di una sincronizzazione saltata, voglio dire un improvviso calo del 90% dei fps.

Ho provato un glFlush() dopo il blit - nessuna differenza, poi ho provato un glFinish() dopo la "blit", e ho avuto un boost di 10x fps.

Quindi ho usato il normale buffering di doble sul framebuffer e lo swapbuster() predefiniti, e anche l'fps ha avuto un boost, come quando si usa glFinish().

Non riesco a capire cosa sta succedendo. Perché glFinish() fa tanta differenza quando non dovrebbe? e, è corretto usare un RBO e blittare direttamente sul buffer frontale, invece di usare una chiamata swap in un doppio contesto di buffering? So che mi manca il vsync ma il gestore composito si sincronizzerà comunque (in realtà non vedo alcuno strappo), è come se il monitor mancasse 9 fotogrammi su 10.

E proprio per curiosità, uno swapbuffer nativo() usa glFinish() su Windows o Linux?

+0

* "poi ho provato un glFinish() dopo il blit, e ho avuto un boost 10x fps" * - Piuttosto suona come un problema con il tuo metodo di temporizzazione, qualcosa di simile non è sincronizzato bene con la tua GPU (che ' glFinish' ovviamente raggiunge). Qualche altro codice sarebbe interessante. –

+0

Non vedo come reimplementare Double Buffering sarebbe comunque meglio, considerando tutte le cose in driver come Triple Buffering, Adaptive VSync e così via. –

+0

@BartekBanachewicz Ha senso se è necessario il buffer sia per il rendering su schermo sia per quello fuori schermo, ma in effetti avrai un po 'di lavoro per (ri) ottimizzare la parte sullo schermo. – KillianDS

risposta

1

Credo che sia un problema correlato alla sincronizzazione.

Quando si esegue il rendering direttamente sull'RBO e si esegue il blitting sul buffer anteriore, non vi è semplicemente alcuna sincronizzazione. Pertanto, nelle scene complesse la coda dei comandi GPU si riempirà abbastanza velocemente, quindi la coda dei driver della CPU si riempirà rapidamente, fino a quando una sincronizzazione della CPU sarà forzata dal driver durante un comando OpenGL. A quel punto il thread della CPU verrà interrotto.

Ciò che intendo è che, senza alcuna forma di sincronizzazione, i rendering complessi (i rendering per i quali uno o più comandi OpenGL verranno messi in coda) causeranno sempre l'interruzione del thread della CPU ad un certo punto, poiché come le code si riempiranno, la CPU emetterà sempre più comandi.

Al fine di ottenere un'interazione utente regolare (più costante), è necessaria una sincronizzazione (con uno swapbuffer specifico della piattaforma() o un glFinish()) in modo da impedire alla CPU di peggiorare le cose emettendo sempre più comandi (che a sua volta portare il filo CPU ad una fermata dopo)

riferimento: OpenGL Synchronization

+0

La CPU che emette un numero sempre maggiore di comandi non dovrebbe peggiorare le cose per il rendering effettivo, ma renderà la CPU e la GPU fuori sincrono, la CPU potrebbe pensare di aver già eseguito il rendering di 20 frame mentre la GPU ha terminato solo 1. Ma non penso che la CPU che invia molti comandi in coda dovrebbe influenzare molto il framerate visibile (misurando il framerate però ...). Tuttavia, questo è solo un po 'di intuizione, non posso provarlo adesso :). – KillianDS

1

ci sono questioni separate qui, che sono anche un po 'connessa.

1) Reimplementare il doppio buffering autonomamente, mentre su spec la stessa cosa, non è la stessa cosa per il driver. I driver sono altamente ottimizzati per il caso comune. Ad esempio, molti chip hanno unità distinte 2D e 3D. Lo swap in swapBuffers viene spesso gestito dall'unità 2d. Bloccare un buffer è probabilmente ancora fatto con l'unità 3d.

2) glFlush (e Fine) vengono ignorati da molti driver. Flush è una reliquia del rendering del server client. Finish era destinato alla profilazione. Ma è stato abusato per aggirare i bug dei driver. Così ora i driver spesso lo ignorano per migliorare le prestazioni del codice legacy che utilizzava Finish come soluzione alternativa.

3) Basta non eseguire il buffer singolo. Non vi è alcun vantaggio in termini di prestazioni e si sta lavorando sul "buon" percorso del conducente. I window manager sono ottimizzati per il doppio buffered opengl.

4) Quello che state vedendo sembra molto come se steste semplicemente perdendo risorse. Assegni i buffer senza liberarli? Un modo rapido e sporco per controllare è se eventuali funzioni di glGen * restituiscono ID sempre crescenti.