Domanda

Con quale frequenza devo chiamare le funzioni OpenGL come glEnable () o glEnableClientState () e le corrispondenti controparti glDisable ? Devono essere chiamati una volta all'inizio dell'applicazione o devo tenerli disabilitati e abilitare solo quelle funzionalità di cui ho immediatamente bisogno per disegnare qualcosa? C'è una differenza di prestazioni?

È stato utile?

Soluzione

" Dipende da " ;.

Se l'intera app utilizza solo una combinazione di stati di abilitazione / disabilitazione, allora impostala all'inizio e vai.

La maggior parte delle app del mondo reale devono mescolarsi, quindi sei costretto a chiamare glEnable () per abilitare alcuni stati particolari, effettuare le chiamate di disegno, quindi glDisable ( ) di nuovo quando hai finito di " cancellare lo stage " ;.

L'ordinamento dello stato, il monitoraggio dello stato e molti schemi di ottimizzazione derivano da questo, poiché il cambio di stato a volte è costoso.

Altri suggerimenti

Se scopri che stai controllando spesso il valore delle variabili di stato e successivamente chiamando glEnable / glDisable potresti essere in grado di ripulire un po 'le cose usando lo stack degli attributi (glPushAttrib / glPopAttrib).

Lo stack di attributi consente di isolare aree del codice e tali che le modifiche all'attributo in una sezione non influiscono sullo stato dell'attributo in altre sezioni.

void drawObject1(){
  glPushAttrib(GL_ENABLE_BIT);

  glEnable(GL_DEPTH_TEST);
  glEnable(GL_LIGHTING);    

  /* Isolated Region 1 */

  glPopAttrib();
}        

void drawObject2(){
  glPushAttrib(GL_ENABLE_BIT);

  glEnable(GL_FOG);
  glEnable(GL_GL_POINT_SMOOTH);    

   /* Isolated Region 2 */

  glPopAttrib();
}    

void drawScene(){
  drawObject1();
  drawObject2();
}

Sebbene GL_LIGHTING e GL_DEPTH_TEST sono impostati in drawObject1 il loro stato non viene conservato in drawObject2. In assenza di glPushAttrib questo non sarebbe il caso. Inoltre, tieni presente che non è necessario chiamare glDisable al termine delle chiamate di funzione, glPopAttrib fa il lavoro.

Per quanto riguarda le prestazioni, l'overhead dovuto alle singole chiamate di funzione a glEnable / glDisable è minimo. Se devi gestire molto stato, probabilmente dovrai creare il tuo gestore di stato o effettuare numerose chiamate a glGetInteger ... e quindi agire di conseguenza. Il flusso aggiunto di macchinari e controllo potrebbe rendere il codice meno trasparente, più difficile da eseguire il debug e più difficile da mantenere. Questi problemi possono rendere più difficili altre ottimizzazioni più fruttuose.

Lo stack di attribuzione può aiutare a mantenere livelli di astrazione e creare regioni di isolamento.

glPushAttrib manpage

Prima di tutto, quale versione di OpenGL usi? E quale generazione di hardware grafico ha il tuo gruppo target? Sapere questo renderebbe più semplice dare una risposta più corretta. La mia risposta presuppone OpenGL 2.1.

OpenGL è una macchina a stati, il che significa che ogni volta che uno stato viene modificato, quello stato viene reso "corrente". fino a quando non viene modificato in modo esplicito dal programmatore con una nuova chiamata API OpenGL. Esistono eccezioni a questa regola, come le chiamate dell'array dello stato client che rendono indefinito il colore del vertice corrente. Ma quelle sono le eccezioni che definiscono la regola.

" una volta all'inizio dell'applicazione " non ha molto senso, perché ci sono volte in cui è necessario distruggere il contesto OpenGL mentre l'applicazione è ancora in esecuzione. Suppongo che intendi subito dopo ogni creazione della finestra. Funziona per lo stato che non è necessario modificare in seguito. Esempio: se tutte le chiamate di disegno utilizzano gli stessi dati dell'array di vertici, non è necessario disabilitarli successivamente con glDisableClientState.

Esistono molti stati di abilitazione / disabilitazione associati alla vecchia pipeline a funzione fissa. La facile redenzione per questo è: Usa gli shader! Se prendi di mira una generazione di carte al massimo di cinque anni, probabilmente imita comunque la pipeline a funzione fissa con shader. Usando gli shader hai il controllo più o meno totale di ciò che accade durante le fasi di trasformazione e rasterizzazione e puoi creare i tuoi "stati" personali con le uniformi, che sono molto economiche da cambiare / aggiornare.

Sapere che OpenGL è una macchina a stati come ho detto sopra dovrebbe chiarire che si dovrebbe sforzarsi di mantenere le modifiche allo stato al minimo, il più a lungo possibile. Tuttavia, molto probabilmente ci sono altre cose che incidono sulle prestazioni molto più che abilitare / disabilitare le chiamate di stato. Se vuoi conoscerli, leggi.


La spesa di stato non associata alle vecchie chiamate di stato a funzione fissa e che non è semplice abilitare / disabilitare lo stato può differire ampiamente nei costi. In particolare, il collegamento di shader e nomi di legame ("nomi" di trame, programmi, oggetti buffer) sono generalmente piuttosto costosi. Questo è il motivo per cui molti giochi e applicazioni utilizzati per ordinare l'ordine di disegno delle loro maglie in base alla trama. In questo modo, non hanno dovuto legare due volte la stessa trama. Al giorno d'oggi, lo stesso vale per i programmi shader. Se non è necessario, non si desidera associare due volte lo stesso programma shader. Inoltre, non tutte le funzionalità di una particolare versione di OpenGL sono accelerate dall'hardware su tutte le schede, anche se i fornitori di tali schede dichiarano di essere conformi a OpenGL. Essere conformi significa che seguono le specifiche, non che eseguono necessariamente tutte le imprese in modo efficiente. Alcune funzioni come glHistogram e glMinMax di GL__ ARB __imaging dovrebbero essere ricordate a questo proposito.


Conclusione: a meno che non ci sia una ragione ovvia per non farlo, usa gli shader! Ti salva da molte chiamate di stato non necessarie poiché puoi usare invece le uniformi. Gli shader OpenGL sono in circolazione da circa sei anni. Inoltre, l'overhead di abilitare / disabilitare i cambiamenti di stato può essere un problema, ma di solito c'è molto altro da guadagnare dall'ottimizzazione di altri cambiamenti di stato più costosi, come glUseProgram, glCompileShader, glLinkprogram, glBindBuffer e glBindTexture.

P.S: OpenGL 3.0 ha rimosso le chiamate di abilitazione / disabilitazione dello stato client. Sono abilitati implicitamente poiché gli array di disegno sono l'unico modo per disegnare in questa versione. La modalità immediata è stata rimossa. Sono state rimosse anche le chiamate gl..Pointer, dal momento che si ha davvero bisogno di glVertexAttribPointer.

Una regola empirica che mi è stata insegnata diceva che è quasi sempre più economico abilitare / disabilitare a piacimento piuttosto che controllare lo stato corrente e modificarlo solo se necessario.

Detto questo, la risposta di Marc è qualcosa che dovrebbe sicuramente funzionare.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top