2011-11-20 7 views
9

Tengo un juego que funciona bastante bien (55-60 fps) en una pantalla de retina. Quiero agregar una superposición de pantalla completa que combine con la escena existente. Sin embargo, incluso cuando se usa una textura pequeña, el impacto en el rendimiento es enorme. ¿Hay alguna optimización que pueda realizar para que esto sea utilizable?Golpe de rendimiento de la mezcla de quad grande

Si uso una textura de 80x120 (la textura se representa sobre la marcha, por lo que no es cuadrada), obtengo 25-30FPS. Si reduzco la textura, el rendimiento aumenta, pero la calidad no es aceptable. En general, sin embargo, la calidad de la superposición no es muy importante (solo es iluminación).

La utilización de Renderer es al 99%.

Incluso si uso una textura cuadrada de un archivo (.png), el rendimiento es malo.

Éste es cómo crear la textura:

[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); 

Y aquí es la prestación ...

/* 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); 

Éstos son algunos puntos de referencia que tomé cuando se trata de reducir el problema. 'Sin mezcla' significa I glDisable (GL_BLEND) antes de dibujar el quad. "Sin conmutación de almacenamiento intermedio" significa que no cambio hacia atrás y hacia adelante desde el almacenamiento intermedio fuera de la pantalla antes de dibujar.

(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 

Cualquier ayuda es apreciada. ¡Gracias!

ACTUALIZACIÓN

En lugar de mezclar todo el mapa de luz después, terminé escribiendo un sombreado para hacer el trabajo sobre la marcha. Cada fragmento de muestras y mezclas de la lightmap (tipo de multitextura). Al principio, la ganancia de rendimiento fue mínima, pero luego usé un muestreador lowp2d para el mapa de luces, y luego obtuve alrededor de 45FPS.

Aquí está el fragment shader:

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

Sospecho que el búfer 'glView' los interruptores son probablemente el culpable aquí. ¿Qué está pasando en esos métodos? ¿Por qué no usar 'glBindRenderBuffer'? – Justicle

+0

Inventaré esos métodos para aclararlos. – whooops

+0

Ok para debuf el problema de perf, intente pre-renderizar la superposición (simplemente déjelo estático por ahora), y luego copie eso en el buffer principal de cada cuadro. Eso al menos le dirá si los interruptores de la memoria intermedia son lentos (es decir, hacer dos llamadas a glBindFrame, glBindRender, glViewport cada fotograma). – Justicle

Respuesta

3

Ok creo que se le han acabado con las limitaciones del hardware. Combinar un quad del tamaño de una pantalla en toda la escena es probablemente un caso particularmente malo para el hardware basado en mosaicos. El PowerVR SGX (en el iPhone) está optimizado para eliminar superficies ocultas, para evitar que se dibuje cuando no se necesita. Tiene poco ancho de banda de memoria porque está optimizado para dispositivos de baja potencia.

El cuadrante mezclado de tamaño de pantalla está leyendo y escribiendo cada fragmento en la pantalla. ¡Ay!

La velocidad de glClear está relacionada, porque le está diciendo a GL que no le importan los contenidos del backbuffer antes de la reproducción, lo que ahorra la carga de los contenidos anteriores en la memoria.

Hay una muy buena visión general del hardware iOS aquí: http://www.imgtec.com/factsheets/SDK/POWERVR%20SGX.OpenGL%20ES%202.0%20Application%20Development%20Recommendations.1.1f.External.pdf

En cuanto a una solución real - Me gustaría tratar directamente la prestación de su superposición en la escena del juego.

Por ejemplo, su render bucle debe ser similar:

[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

Gracias. Sí, llegué a la misma conclusión. Desafortunadamente, no puedo usar tu solución, la superposición que estoy dibujando es realmente más un mapa de luz, por lo que afecta los píxeles del entorno del juego real. Terminé escribiendo un sombreador para hacer el mismo trabajo, con bastante éxito. Voy a publicar los detalles de eso en mi pregunta. ¡Gracias por toda su ayuda al investigar esto! – whooops

+0

Impresionante - Me encantaría ver lo que hiciste. – Justicle

+0

Estoy usando cuádruples del tamaño de una pantalla mezclados en toda la escena de mi juego, y no obtuve una caída en la velocidad de fotogramas (30 fps en 3G, 60 en retinas). La ralentización podría ser en la creación de la textura? ¿lo estás haciendo en cada cuadro? – led42

1

Si renderiza a un objetivo de hacer que en un chip PowerVR, cambia a otro destino de representación y hacer que, a continuación, cambia de nuevo a cualquier rendir anterior objetivo se sufrirá un gran golpe de rendimiento. Este tipo de patrón de acceso está etiquetado como "carga de búfer lógico" por OpenGL ES Analyzer integrado en los últimos instrumentos.

Si cambia su orden de renderizado para que dibuje su objetivo de renderizado de mapa de luz primero, renderice su escena en el framebuffer principal, luego realice su combinación de pantalla completa de la textura de destino de renderizado de mapa de luz, su rendimiento debería ser mucho mayor.

0

Puedo confirmar, en el iPad 1 con iOS 4.2, habilitar/deshabilitar GL_BLEND para un quad de pantalla completa conmutado entre 18 y 31 fps. En ambas ejecuciones, la utilización del renderizador fue del 90-100%.

0

Incluso antes de juguetear con la textura, asegúrese de que su sombreador esté optimizado. Al llenar una pantalla de 960x640 (614400 píxeles), cualquier operación en el sombreador de fragmentos tiene un gran impacto.

Una cosa buena es crear una versión específica de su sombreador de fragmentos para esta situación. Debe ser algo como esto:

varying mediump vec2 vertexTexCoord; 
uniform sampler2D texture; 

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

crear otro programa con este fragmento de sombreado y utilizarlo antes de sacar su gran patio, a continuación, restaurar el programa normal. El iPhone 4 es capaz de renderizar aproximadamente 7 cuadrículas con textura de pantalla completa, 1: 1 por cuadro con mezcla, pero se reduce rápidamente a aproximadamente 1 con un sombreador más sofisticado.

(Además, en su caso, tratar de hacer que su superposición de texturas en primer lugar, a continuación, los elementos normales, entonces la textura sobre el resto. Se debe mejorar el rendimiento por un margen significativo.)

Cuestiones relacionadas