2010-01-26 13 views
85

Ho difficoltà a distinguere la differenza pratica tra chiamare glFlush() e glFinish().opengl: glFlush() vs. glFinish()

I documenti dicono che glFlush() e glFinish() spingerà tutte le operazioni bufferizzati OpenGL in modo che si può essere certi che saranno tutti eseguiti, con la differenza che glFlush() ritorna immediatamente dove come glFinish() blocca finché tutte le operazioni sono completate.

Avendo letto le definizioni, ho pensato che se dovessi usare glFlush() mi verrebbe probabilmente in mente il problema di inviare più operazioni ad OpenGL di quanto non possa eseguire. Quindi, solo per provare, ho scambiato il mio glFinish() per un glFlush() ed ecco, il mio programma ha funzionato (per quanto ho potuto dire), esattamente lo stesso; frame rate, utilizzo delle risorse, tutto era lo stesso.

Quindi mi chiedo se c'è molta differenza tra le due chiamate, o se il mio codice le fa funzionare in modo diverso. O dove uno dovrebbe essere usato contro l'altro. Ho anche pensato che OpenGL avrebbe qualche chiamata come glIsDone() per verificare se tutti i comandi bufferizzati per un sono completi o meno (quindi non si inviano le operazioni a OpenGL più velocemente di quanto possano essere eseguiti), ma ho potuto trovare nessuna di queste funzioni.

mio codice è il tipico ciclo di gioco:

while (running) { 
    process_stuff(); 
    render_stuff(); 
} 

risposta

76

Ricorda che questi comandi esistono fin dai primi giorni di OpenGL. glFlush garantisce che i comandi OpenGL precedenti devono essere completati in un tempo limitato (OpenGL 2.1 specs, pagina 245). Se si disegna direttamente sul buffer frontale, ciò garantisce che i driver OpenGL inizino a disegnare senza troppo ritardo. Si potrebbe pensare a una scena complessa che appare oggetto dopo oggetto sullo schermo, quando si chiama glFlush dopo ogni oggetto. Tuttavia, quando si utilizza il doppio buffering, glFlush non ha praticamente alcun effetto, poiché le modifiche non saranno visibili finché non si scambiano i buffer.

glFinish non restituisce fino a quando tutti gli effetti dei comandi precedentemente emessi [...] sono completamente realizzati. Ciò significa che l'esecuzione del tuo programma attende qui fino a quando non viene disegnato l'ultimo pixel e OpenGL non ha più nulla da fare. Se si esegue il rendering direttamente sul buffer anteriore, glFinish è la chiamata da effettuare prima di utilizzare le chiamate del sistema operativo per acquisire schermate. È molto meno utile per il doppio buffering, perché non vedi le modifiche che hai costretto a completare.

Quindi, se si utilizza il doppio buffering, probabilmente non sarà necessario né glFlush né glFinish. SwapBuffers indirizza implicitamente le chiamate OpenGL al buffer corretto, there's no need to call glFlush first. E non preoccuparti di stressare il driver OpenGL: glFlush non strozzerà su troppi comandi. Non è garantito che questa chiamata restituisca immediatamente (qualunque cosa significhi), quindi può richiedere del tempo per elaborare i comandi.

+1

Cosa vuoi dire che glFlush "deve completare in FINITE time" e poi dire che glFlush non soffocare perché "può richiedere un po 'di tempo per elaborare i comandi"? (Caps mine) Non sono quelli che si escludono a vicenda? – Praxiteles

+1

Finché finisce, ad un certo punto, soddisfa i criteri temporali FINITE. Alcuni driver no-op questa chiamata interamente. – chrisvarnz

+0

SwapBuffers è specifico per il contesto e deve solo svuotare il contesto del thread chiamante. Se si esegue il rendering di più contesti, ciascuno deve essere svuotato manualmente poiché non è garantito che ciò accada quando si scambiano i buffer attraverso un altro contesto. – Andreas

4

Date un'occhiata here. In breve, si dice:

glFinish() ha lo stesso effetto come glFlush(), con l'aggiunta che glFinish() bloccherà finché non sono stati eseguiti tutti i comandi inviati.

Un'altra article descrive altre differenze:

  • funzioni Swap (utilizzati in applicazioni a doppio buffer) irrigare automaticamente i comandi, quindi non necessità di chiama glFlush
  • glFinish forze OpenGL per eseguire i comandi in sospeso, che è una cattiva idea (es. con VSync)

Per riassumere, questo significa che non hai nemmeno bisogno di queste funzioni quando si utilizza il doppio buffering, tranne se l'implementazione dei buffer di scambio non scarica automaticamente i comandi.

+1

Lo sa già; è nella domanda. – GManNickG

+0

Sì, ma il documento dice che entrambi hanno lo stesso * effetto * con solo poche differenze riguardo al sistema di finestre, per esempio. Ma comunque ho modificato la mia risposta;) – AndiDog

+0

Nice call on the nuance. Chiarifica se è necessario chiamare glFlush() e THEN glFinish() - (una domanda che abbiamo avuto dopo aver letto tutto sopra.) – Praxiteles

3

Non sembra essere un modo per interrogare lo stato del buffer. C'è questo Apple extension che potrebbe servire allo stesso scopo, ma non sembra multipiattaforma (non l'ho provato). A prima vista, sembra che prima del flush avresti premuto il comando fence; è quindi possibile interrogare lo stato di tale barriera mentre si sposta attraverso il buffer.

Mi chiedo se è possibile utilizzare flush prima di eseguire il buffering dei comandi, ma prima di iniziare a eseguire il rendering del frame successivo, chiamare finish. Ciò consentirebbe di iniziare l'elaborazione del fotogramma successivo mentre la GPU funziona, ma se non viene eseguito prima che torni, finish si bloccherà per assicurarsi che tutto sia in uno stato nuovo.

Non l'ho provato, ma lo farò tra poco.

L'ho provato su una vecchia applicazione che ha un utilizzo della CPU pari a CPU &. (Inizialmente utilizzato finish.)

Quando ho cambiato in flush alla fine e finish all'inizio, non ci sono stati problemi immediati. (Tutto sembrava a posto!) La reattività del programma è aumentata, probabilmente perché la CPU non era bloccata in attesa sulla GPU. Sicuramente un metodo migliore.

Per confronto, ho rimosso finished dall'inizio del frame, lasciando flush e ha eseguito lo stesso.

Quindi direi uso flush e finish, perché quando il buffer è vuoto alla chiamata a finish, non v'è alcun calo di prestazioni. E suppongo che se il buffer fosse pieno dovresti voler fare lo finish.

0

La domanda è: vuoi che il tuo codice continui a funzionare mentre i comandi OpenGL sono in esecuzione, o solo per eseguire dopo i tuoi comandi OpenGL sono stati eseguiti.

Questo può importare in alcuni casi, come i ritardi della rete, di avere una certa console solo dopo le immagini sono state disegnate o il simile.

21

Come hanno suggerito le altre risposte, non c'è davvero una buona risposta secondo le specifiche. L'intento generale di glFlush() è che dopo averlo chiamato, la CPU host non avrà alcun lavoro relativo a OpenGL da fare - i comandi saranno stati inviati all'hardware grafico. L'intento generale di glFinish() è che dopo il suo ritorno, non è disponibile il lavoro rimanente ei risultati dovrebbero essere disponibili anche tutte le API non OpenGL appropriate (ad esempio le letture dal framebuffer, schermate, ecc ...). Che sia davvero ciò che accade dipende dal guidatore. La specifica consente una tonnellata di latitudine su ciò che è legale.

7

Se non hai riscontrato alcuna differenza di prestazioni, significa che stai facendo qualcosa di sbagliato. Come altri hanno già detto, non è necessario chiamarli, ma se chiami glFinish, perderai automaticamente il parallelismo che la GPU e la CPU possono ottenere. Lasciami immergere più a fondo:

In pratica, tutto il lavoro inviato al driver viene dosato in batch e inviato all'hardware potenzialmente in un secondo momento (ad esempio, al momento dello SwapBuffer).

Quindi, se si sta chiamando glFinish, si sta essenzialmente costringendo il driver a spingere i comandi sulla GPU (che ha accumulato fino a quel momento e non ha mai chiesto alla GPU di funzionare), e di stoppare la CPU fino al i comandi premuti sono completamente eseguiti. Quindi durante tutto il tempo in cui la GPU funziona, la CPU no (almeno su questo thread). E per tutto il tempo in cui la CPU fa il suo lavoro (principalmente comandi di batching), la GPU non fa nulla. Quindi sì, glFinish dovrebbe danneggiare la tua performance. (Questa è un'approssimazione, poiché i driver potrebbero iniziare a far funzionare la GPU su alcuni comandi se molti di essi erano già in batch. Non è tipico, poiché i buffer dei comandi tendono ad essere abbastanza grandi da contenere molti comandi).

Ora, perché dovresti chiamare glFinish a tutti allora? Le uniche volte in cui l'ho usato erano quando avevo i bug dei driver. Infatti, se uno dei comandi che invii all'hardware crasha la GPU, allora la tua opzione più semplice per identificare quale comando è il colpevole è chiamare glFinish dopo ogni Draw. In questo modo, puoi restringere ciò che determina esattamente l'arresto

Come nota a margine, le API come Direct3D non supportano affatto un concetto Finish.

+5

In "Ora, perché chiameresti glFinish a tutti". Se stai caricando risorse (ad esempio texture) su un thread e utilizzandole per renderle su un altro, con la condivisione tramite wglShareList o simili, devi chiamare glFinish prima di segnalare al thread di rendering che è libero di eseguire il rendering di ciò che è stato caricato in modo asincrono. –

+0

Come ho detto di seguito, sembra una soluzione al problema del driver. Non riesco a trovare alcuna menzione specifica di questo requisito. Su Windows il driver deve prendere un blocco, su Mac devi fare CGLLockContext. Ma usare glFinish sembra molto sbagliato. Per sapere quando una texture è valida devi comunque eseguire il tuo lock o evento. – starmole

+1

opencl opengl interop docs consiglia glFinish per la sincronizzazione "Prima di chiamare clEnqueueAcquireGLObjects, l'applicazione deve garantire che tutte le operazioni GL in sospeso che accedono agli oggetti specificati in mem_objects siano state completate, operazione che può essere eseguita in modo flessibile eseguendo e in attesa del completamento di un comando glFinish su tutti i contesti GL con riferimenti in sospeso a questi oggetti " –

5

glFlush risale davvero a un modello di server client. Mandate tutti i gl-comandi attraverso una pipe a un gl-server. Quella pipa potrebbe tamponare. Proprio come qualsiasi file o rete i/o potrebbe bufferizzare. glFlush dice solo "invia il buffer adesso, anche se non è ancora pieno!". Su un sistema locale questo non è quasi mai necessario perché è improbabile che un'API OpenGL locale si blocchi automaticamente e comandi direttamente i comandi. Anche tutti i comandi che causano il rendering effettivo eseguiranno un flush implicito.

glFinish invece è stato realizzato per la misurazione delle prestazioni. Tipo di PING al server GL. Arrotonda un comando e attende fino a quando il server risponde "I am idle".

Oggigiorno i conducenti locali moderni hanno idee abbastanza creative su ciò che significa essere inattivi. È "tutti i pixel sono disegnati" o "la mia coda di comando ha spazio"? Anche perché molti vecchi programmi spargevano glFlush e glFinish in tutto il loro codice senza motivo, poiché la codifica voodoo di molti driver moderni li ignorava semplicemente come "ottimizzazione". Non posso biasimarli per quello, davvero.

Quindi, in sintesi: Tratta sia glFinish che glFlush come no op in pratica a meno che non si stia codificando per un server remoto SGI OpenGL remoto.

+3

Sbagliato. Come nel commento che ho lasciato nella risposta sopra: Se stai caricando risorse (ad esempio: texture) su un thread e usandole per renderle su un altro, con la condivisione tramite wglShareList o simili, devi chiamare glFinish prima di segnalare al thread di rendering che è libero di mostrare ciò che è stato caricato in modo asincrono. E non è un no-op come hai detto tu. –

+0

Davvero? Riesci a sostenere la necessità di chiamare glFinish prima di utilizzare un oggetto condiviso con un collegamento di specifiche? Posso assolutamente vedere un driver buggato che ha bisogno di questo. E questo tipo di torna a quello che ho detto. Le persone usano glFinish per aggirare i driver infestati. A causa di ciò i driver che funzionano correttamente lo ignorano per le prestazioni. Il caso di utilizzo delle specifiche originali di profilazione (e rendering con buffer singolo) non funziona più. – starmole

+2

Esperienza personale di dover gestire trame corrotte, oltre a questo: http://higherorderfun.com/blog/2011/05/26/multi-thread-opengl-texture-loading/ Se ci pensi, ha senso tuttavia, poiché non è molto diverso dall'avere mutex o altre sincronizzazioni.api tra i thread: prima che un contesto possa utilizzare una risorsa condivisa, l'altro deve completare il caricamento di tale risorsa, quindi è necessario assicurarsi che il buffer sia stato svuotato. Penso più al caso d'angolo delle specifiche piuttosto che al bug, ma non ho prove per questa affermazione :) –

8

ero sempre confuso su quei due comandi troppo, ma questa immagine inventato tutto chiaro per me: Flush vs Finish A quanto pare alcuni driver GPU non inviare i comandi emessi per l'hardware a meno che non è stato accumulato un certo numero di comandi . In questo esempio il numero è .
L'immagine mostra vari comandi OpenGL (A, B, C, D, E ...) che sono stati emessi. Come possiamo vedere in alto, i comandi non vengono ancora emessi, perché la coda non è ancora piena.

Nel mezzo vediamo come glFlush() influenza i comandi in coda. Indica al driver di inviare tutti i comandi in coda all'hardware (anche se la coda non è ancora piena). Questo non blocca il thread chiamante. Segnala semplicemente all'autista che potremmo non inviare alcun comando aggiuntivo.Quindi aspettare che la coda si riempia sarebbe una perdita di tempo.

Nella parte inferiore vediamo un esempio utilizzando glFinish(). Fa quasi la stessa cosa di glFlush(), ma fa in modo che il thread di chiamata attenda che tutti i comandi siano stati elaborati dall'hardware.

Immagine tratta dal libro "Programmazione grafica avanzata con OpenGL".

+0

In realtà so cosa fanno 'glFlush' e' glFinish', e non so dire cosa stia dicendo quell'immagine. Cosa c'è sul lato sinistro e sul lato destro? Inoltre, l'immagine è stata rilasciata nel pubblico dominio o sotto una licenza che ti permette di pubblicarlo su Internet? –

+0

Avrei dovuto elaborare un po '. Informazioni sulla licenza: in realtà non ne sono del tutto sicuro. Mi sono imbattuto nel PDF su google, mentre facevo ricerche. – Tara

Problemi correlati