2011-11-20 9 views
9

Ho un gioco che funziona abbastanza bene (55-60 fps) su un display retina. Desidero aggiungere una sovrapposizione a schermo intero che si fonde con la scena esistente. Tuttavia, anche quando si utilizza una piccola trama, il successo delle prestazioni è enorme. Esiste un'ottimizzazione che posso eseguire per renderlo utilizzabile?Il successo delle prestazioni dalla fusione di quadratini grandi

Se utilizzo una trama 80x120 (la texture è renderizzata al volo, motivo per cui non è quadrata), ottengo 25-30 FPS. Se riduco la trama, le prestazioni aumentano, ma la qualità non è accettabile. In generale, tuttavia, la qualità della sovrapposizione non è molto importante (è solo illuminazione).

L'utilizzo del renderer è del 99%.

Anche se utilizzo una trama quadrata da un file (.png), le prestazioni non sono buone.

Questo è come mi creo la trama:

[EAGLContext setCurrentContext:context]; 

    // Create default framebuffer object. 
    glGenFramebuffers(1, &lightFramebuffer); 
    glBindFramebuffer(GL_FRAMEBUFFER, lightFramebuffer); 

    // Create color render buffer and allocate backing store. 
    glGenRenderbuffers(1, &lightRenderbuffer); 
    glBindRenderbuffer(GL_RENDERBUFFER, lightRenderbuffer); 
    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, LIGHT_WIDTH, LIGHT_HEIGHT); 

    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, lightRenderbuffer); 

    glGenTextures(1, &lightImage); 
    glBindTexture(GL_TEXTURE_2D, lightImage); 

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, LIGHT_WIDTH, LIGHT_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); 

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, lightImage, 0); 

E qui è la resa ...

/* Draw scene... */ 

glBlendFunc(GL_ONE, GL_ONE); 


//Switch to offscreen texture buffer 
glBindFramebuffer(GL_FRAMEBUFFER, lightFramebuffer); 
glBindRenderbuffer(GL_RENDERBUFFER, lightRenderbuffer); 
glViewport(0, 0, LIGHT_WIDTH, LIGHT_HEIGHT); 

glClearColor(ambientLight, ambientLight, ambientLight, ambientLight); 
glClear(GL_COLOR_BUFFER_BIT); 

/* Draw lights to texture... */ 

//Switch back to main frame buffer 
glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer); 
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer); 
glViewport(0, 0, framebufferWidth, framebufferHeight); 

glBlendFunc(GL_DST_COLOR, GL_ZERO); 

glBindTexture(GL_TEXTURE_2D, glview.lightImage);  

/* Set up drawing... */ 

glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, 0); 

Ecco alcuni punti di riferimento che ho preso quando si cerca di circoscrivere il problema. 'Nessuna mescolanza' significa che non posso (GL_BLEND) prima di disegnare il quad. 'Nessuna commutazione del buffer' significa che non passerò avanti e indietro dal buffer fuori dallo schermo prima di disegnare.

(Tests using a static 256x256 .png) 
No blend, No buffer switching: 52FPS 
Yes blend, No buffer switching: 29FPS //disabled the glClear, which would artificially speed up the rendering 
No blend, Yes buffer switching: 29FPS 
Yes blend, Yes buffer switching: 27FPS 

Yes buffer switching, No drawing: 46FPS 

Qualsiasi aiuto è apprezzato. Grazie!

UPDATE

Invece di miscelazione tutta lightmap dopo, ho finito per scrivere uno shader per fare il lavoro al volo. Ogni frammento di campioni e miscele dalla mappa di luce (tipo di multitexturing simile). All'inizio, il guadagno di prestazioni era minimo, ma poi ho usato un sampler2d lowp per la mappa di luce, e poi ho avuto circa 45 FPS.

Ecco lo shader frammento:

lowp vec4 texColor = texture2D(tex, texCoordsVarying); 
lowp vec4 lightColor = texture2D(lightMap, worldPosVarying); 
lightColor.rgb *= lightColor.a; 
lightColor.a = 1.0; 

gl_FragColor = texColor * color * lightColor; 
+0

Ho il sospetto che il buffer 'glView' gli interruttori sono probabilmente il colpevole qui. Cosa sta succedendo in questi metodi? Perché non usare 'glBindRenderBuffer'? – Justicle

+0

Aggiungerò questi metodi per chiarimenti. – whooops

+0

Ok per debuffare il problema di perf, provate il pre-rendering dell'overlay (lasciatelo solo statico per ora) e poi copiandolo nel buffer principale ogni frame. Almeno questo ti dirà se i buffer switch sono lenti (cioè facendo due chiamate a glBindFrame, glBindRender, glViewport a ogni frame). – Justicle

risposta

3

Ok Credo che tu abbia eseguito contro i limiti dell'hardware. La fusione di un quadrante di dimensioni schermo su tutta la scena è probabilmente un caso particolarmente grave per l'hardware basato su piastrelle. PowerVR SGX (su iPhone) è ottimizzato per la rimozione della superficie nascosta, per evitare di disegnare oggetti quando non è necessario. Ha una larghezza di banda di memoria ridotta perché è ottimizzato per dispositivi a basso consumo.

Quindi quad blended a schermo intero sta leggendo, quindi scrive ogni frammento sullo schermo. Ahia!

La velocità di avvio di glClear è correlata - perché stai dicendo a GL che non ti interessa il contenuto del backbuffer prima del rendering, il quale salva il caricamento del contenuto precedente in memoria.

C'è una buona panoramica dell'hardware iOS qui: http://www.imgtec.com/factsheets/SDK/POWERVR%20SGX.OpenGL%20ES%202.0%20Application%20Development%20Recommendations.1.1f.External.pdf

Per quanto riguarda una soluzione reale - vorrei provare direttamente rendering del overlay sulla scena di gioco.

Ad esempio, il render ciclo dovrebbe essere simile:

[EAGLContext setCurrentContext:context]; 

// Set up game view port and render the game 
InitGameViewPort(); 
GameRender(); 

// Change camera to 2d/orthographic, turn off depth write and compare 
InitOverlayViewPort() 

// Render overlay into same buffer 
OverlayRender() 
+0

Grazie. Sì, sono arrivato alla stessa conclusione. Sfortunatamente, non posso usare la tua soluzione: la sovrapposizione che sto disegnando è in realtà più una mappa di luce, quindi influenza i reali pixel dell'ambiente di gioco. Ho finito per scrivere uno shader per fare lo stesso lavoro, con un discreto successo. Pubblicherò i dettagli di ciò nella mia domanda. Grazie per tutto il tuo aiuto per indagare su questo! – whooops

+0

Fantastico - Mi piacerebbe vedere cosa hai fatto. – Justicle

+0

Uso il quadruplo schermo su tutta la scena del mio gioco e non ho avuto un calo del frame-rate (30 fps in 3G, 60 in retine). Il rallentamento potrebbe essere nella creazione della trama? lo stai facendo ogni fotogramma? – led42

1

Se si esegue il rendering di un bersaglio rendering su un chip PowerVR, passa a un altro rendering di destinazione e il rendering, quindi si passa indietro a qualsiasi destinazione di rendering precedente subirà un grande successo in termini di prestazioni. Questo tipo di modello di accesso è etichettato come "Logical Buffer Load" dall'analizzatore OpenGL ES incorporato nei più recenti strumenti.

Se si cambia l'ordine di rendering in modo da disegnare per primo il target di rendering lightmap, quindi renderizzare la scena al framebuffer principale, quindi eseguire la fusione a schermo intero della struttura di destinazione del rendering lightmap, le prestazioni dovrebbero essere molto più elevate.

0

Posso confermare, su iPad 1 utilizzando iOS 4.2, abilitare/disabilitare GL_BLEND per un quad a schermo intero commutato tra 18 e 31 fps. In entrambe le esecuzioni, l'utilizzo del renderer era del 90-100%.

0

Anche prima di armeggiare con la trama, assicurarsi che lo shader sia ottimizzato. Quando si riempie uno schermo 960x640 (614400 pixel) qualsiasi operazione nel framment shader ha un impatto enorme.

Una cosa buona per creare una versione specifica del tuo framment shader per questa situazione. Dovrebbe essere qualcosa di simile:

varying mediump vec2 vertexTexCoord; 
uniform sampler2D texture; 

void main() { 
    gl_FragColor = texture2D(texture, vertexTexCoord); 
} 

creare un altro programma con questo frammento di shader e utilizzarlo prima di disegnare il vostro grande quad, quindi ripristinare il programma normale. L'iPhone 4 è in grado di eseguire il rendering di circa 7 quad a trama intera 1: 1 per fotogramma con fusione, ma scende rapidamente a circa 1 con uno shader più sofisticato.

(Inoltre, nel tuo caso, cercare di rendere il vostro primo overlay tessitura, quindi gli elementi normali, quindi la texture sul resto. Si dovrebbero migliorare le prestazioni di un margine significativo.)

Problemi correlati