2013-03-17 3 views
7

Per esempio, se io uso vertex shader come la seguente:GLSL esegue davvero calcoli superflui con valori uniformi (non per vertice)?

#version 400 core 

uniform mat4 projM; 
uniform mat4 viewM; 
uniform mat4 modelM; 

in vec4 in_Position; 

out vec4 pass_position_model; 

void main(void) { 
    gl_Position = projM * viewM * modelM * in_Position; 
    pass_position_model = modelM * in_Position; 
} 

intende fare projM * viewM * modelM moltiplicazione di matrici per ogni vertice, o abbastanza intelligente per calcolare se una volta e non ricalcolare fino variabili uniformi sono cambiati? Se non è "abbastanza intelligente", c'è un modo per ottimizzarlo se non quello di calcolare tutti i valori dipendenti dalla CPU e inviarli come variabili uniformi alla GPU?
Inoltre sono interessato alle soluzioni che possono essere convertite in OpenGL ES 2.0 in seguito senza problemi.

risposta

10

Quindi non c'è una risposta generale, come ho capito. Ho fatto alcuni test sul mio hardware, però. Ho 2 GPU nel mio inventario, Intel HD Graphics 3000 e NVidia GeForce GT 555M. Ho testato il mio programma (il programma stesso è stato scritto in java/scala) con moltiplicazione della matrice in vertex shader, quindi ho spostato la moltiplicazione nel programma della CPU e ho testato di nuovo.

(sferaN: è una sfera a rotazione continua con 2 * N^2 quad, disegnata con glDrawElements (GL_QUADS, ...) Con 1 consistenza e senza alcuna illuminazione/altri effetti)

matrice moltiplicazione nella vertex:

intel: 
    sphere400: 57.17552887364208 fps 
    sphere40: 128.1394156842645 fps 
nvidia: 
    sphere400: 134.9527665317139 fps 
    sphere40: 242.0135527589545 fps 

moltiplicazione matriciale sulla CPU:

intel: 
    sphere400: 57.37234652897303 fps 
    sphere40: 128.2051282051282 fps 
nvidia: 
    sphere400: 142.28799089356858 fps 
    sphere40: 247.1576866040534 fps 

test dimostrano che multiplicating (uniforme) le matrici in vertex shader sono una pessima idea, almeno su questo hardware. Quindi in generale non si può fare affidamento sull'ottimizzazione del compilatore GLSL corrispondente.

+0

Awsome. Dovrò tenerlo a mente. –

+0

+1 per lo sforzo di profilazione (e utilizzando le 2 schede grafiche che ho). – GraphicsMuncher

+0

+1. Ma come hai valutato i risultati? Sembra che la differenza sia quasi trascurabile. Suggerisco di eseguire entrambe le simulazioni per 60 secondi e considerare solo la migliore lettura FPS (poiché rappresenta le migliori prestazioni che la CPU/GPU può fare). – Calmarius

3

Effettua moltiplicazione di matrice projM * viewM * modelM per ogni vertice o è abbastanza intelligente da calcolare se una volta e non ricalcolare fino a quando non vengono modificate le variabili uniformi?

Chiedi allo sviluppatore l'implementazione di OpenGL in questione. Le specifiche OpenGL non hanno nulla da dire su questo, ma i produttori di compilatori di driver e GLSL potrebbero aver implementato ottimizzazioni per questo.

Se non lo è "abbastanza intelligente", allora c'è un modo per ottimizzarlo altro di calcolare tutti i valori uniformi-dipendente dalla CPU e inviarli come variabili uniformi per GPU?

No. Devi fare il legwork da solo.

+0

Se sono interessato solo alla situazione con un paio di fornitori leader di oggi, ad esempio NVidia, AMD, PoverVR, la domanda potrebbe essere più semplice? –

+0

@SargeBorsch: non è più facile rispondere, perché le ottimizzazioni come questa di solito sono mantenute segrete. Almeno per i driver open source del progetto Mesa puoi vedere cosa fanno. Ma con i driver di sorgente chiusi di NVidia, AMD e Imaginon è impossibile fare una dichiarazione definitiva. – datenwolf

1

Tutte le ottimizzazioni OpenGL e GLSL sono specifiche del fornitore. È piuttosto difficile stabilire quale sia l'output finale del compilatore glsl.

Potete guardare qui per informazioni specifiche del fornitore: http://renderingpipeline.com/graphics-literature/low-level-gpu-documentation/

Per il vostro codice è possibile sempre 'pack' matrici in nuova uniforme: matModelViewProjection, moltiplicarlo nella domanda e inviarla al vertex shader.

0

Questo dipende interamente dal conducente. OpenGL è una specifica, se li paghi per i diritti di fare un'implantosa ti daranno una implzione di esempio da usare, ma il gioco è fatto.

Oltre a ciò è necessario considerare le limitazioni di moltiplicazione della matrice, facendo projM * viewM * modelM * vertex non è lo stesso di vertex * projM * viewM * modelM. Questo perché le matrici vengono moltiplicate da destra a sinistra e l'ordine conta con questo. Quindi lo shader non ha potuto calcolare lo projM * viewM * modelM pre-calcolato da condividere tra i vertici, perché ciò darebbe risultati fasulli.

+0

Sei sicuro? 'projM * viewM * modelM * in_Position' è uguale a' (projM * viewM * modelM) * in_Position' (almeno fornisce fotogrammi indistinguibili nel mio programma, dove tutte e 3 le matrici non sono banali). Ma le matrici sono effettivamente moltiplicate da destra a sinistra. –

+0

Davvero? dispari. Per eseguire un test, usando il tuo computer potresti creare un semplice programma che calcola la matrice 'projM * viewM * modelM' sulla CPU e ** quindi ** lo passa allo shader. Inoltre, dovresti essere in grado di vedere cosa finirà con "glGetShaderSource", per vedere se sta facendo qualcosa di strano con il tuo codice prima della compilazione. –

+0

Recentemente ho letto un articolo su Internet, ha detto che è valido l'ottimizzazione per cambiare 'M1 * M2 * v' in' M1 * (M2 * v) ', quindi può essere fatto anche all'indietro, se la M1 * M2 è precalcolato. Sfortunatamente, non riesco a trovare il link :( –