Autor Wątek: OpenGL ES 2.0 a optymalizacja  (Przeczytany 1373 razy)

Offline dynax

  • Użytkownik

# Wrzesień 08, 2012, 20:34:41
Witam, pisząc demo na Androida zauważyłem dość duży spadek wydajności po narysowaniu efektu post-process. O ile w normalnym programie FPS waha się od 55 do 80, to po wyrenderowaniu shadera spada do 15 i niżej. Taka prędkość jest nie do zaakceptowania.
Na PC i desktopowej wersji OpenGL rysowanie w dokładnie ten sposób nie wprowadza zbytnich zmian w wydajności. Gra jakby w ogóle nie odczuwa, że rysujemy dodatkowego fullscreen quada z efektem. Problem występuje tylko w OpenGL ES 2.0.

Shadera rysuję w ten sposób:
// get current framebuffer
glBindTexture(GL_TEXTURE_2D, framebuffer);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, screenWidth, screenHeight, 0);
glBindTexture(GL_TEXTURE_2D, 0);

glUseProgram(shader->shaderProgramId);

// bind all textures
int i = 0;
for(auto it = shader->textures.begin(); it != shader->textures.end(); it++)
{
int location = glGetUniformLocation(shader->shaderProgramId, it->first.c_str());
glUniform1i(location, i);

glActiveTexture((GLenum)(GL_TEXTURE0 + i));
glEnable(GL_TEXTURE_2D);

if(it->second != -1) {
glBindTexture(GL_TEXTURE_2D, it->second);
}
else {
glBindTexture(GL_TEXTURE_2D, framebuffer);
}

i++;
}

// draw effect
static GLfloat vertices[8] = {
-1, -1,
1, -1,
-1, 1,
1, 1
};
static GLfloat texCoords[8] = {
0, 0,
1, 0,
0, 1,
1, 1
};

int positionLocation = glGetAttribLocation(shader->shaderProgramId, "a_position");
int texcoordLocation = glGetAttribLocation(shader->shaderProgramId, "a_texCoord");

glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, vertices);
glEnableVertexAttribArray(positionLocation);
glVertexAttribPointer(texcoordLocation, 2, GL_FLOAT, GL_FALSE, 0, texCoords);
glEnableVertexAttribArray(texcoordLocation);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

// unbind shader
for(int j = i; j >= 0; j--) {
glActiveTexture((GLenum)(GL_TEXTURE0 + j));
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
}

glActiveTexture(GL_TEXTURE0);
glUseProgram(0);

Nie profilowałem tego programu i zbytnio nie wiem gdzie może być wąskie gardło. Stawiam albo na to, że funkcja glCopyTexImage2D na komórkach chodzi bardzo wolno, albo na sposób w jaki wypluwam na ekran quada (nie VBO tylko vertex arrays). To drugie dość łatwo jest zamienić acz zastanawiam się nad zamiennikiem dla glCopyTexImage2D. Myślałem, żeby od razu wyrenderować całą scenę do framebuffera i jego lokację wrzucić do samplera ale wtedy powstają 2 nowe problemy.

1. Do renderowania dwuwymiarowej części sceny używam SDL 1.3 i wbudowanego renderera opengles2. Nie wiem czy on przypadkiem nie binduje gdzieś własnego framebuffera i czy takie rozwiązanie w ogóle by działało.
2. Żeby zacząć renderować do FBO, musiałbym go podpiąć już na samym początku klatki. Problem w tym, że w tym momencie działania programu nie wiem ile shaderów będę musiał nałożyć (i czy w ogóle jakieś). Takie rozwiązanie ogranicza mnie tylko do 1 efektu działającego efektu na klatkę. Jeśli zaś żaden shader nie będzie rysowany przez całą klatkę to będę musiał na sam koniec wyświetlić FBO na fullscreen quadzie bez żadnego efektu (żeby cokolwiek było widoczne). To może być zabójcze dla wydajności.

Zaproponujecie jakąś optymalizację?

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline mihu

  • Użytkownik
    • mihu

# Wrzesień 08, 2012, 21:06:18
Nie sądzisz że dość istotne może być co to za post-process i jak wygląda shader? :)

Offline dynax

  • Użytkownik

# Wrzesień 08, 2012, 21:22:47
Nie sądzę. To banalny shader mieszający dwie tekstury.

Vertex shader:
attribute vec2 a_position;
attribute vec2 a_texCoord;
varying vec2 TexCoords;
 
void main() {
    TexCoords = a_texCoord;
    gl_Position = vec4(a_position, 0.0, 1.0);
}

Fragment shader:

uniform sampler2D backbuffer;
uniform sampler2D tex0;

varying lowp vec2 TexCoords;

void main() {
gl_FragColor = mix(texture2D(backbuffer, TexCoords.xy), texture2D(tex0, TexCoords.xy), 0.2);
}

Offline .:NOXY:.

  • Użytkownik
    • Profil

# Wrzesień 09, 2012, 13:09:47
Z postprocesem na mobilnym to jest teraz tak ze raczej malo ktory device daje rady to pociagnac jak by to nie bylo uproszczone. Z moich testow wynika ze na iStuffie jedynie iPad2 , iPhone 4S radza sobie z postprocesem. (Czytaj 2 core trzeba miec) Niewiem jak z Androidem ale probowalm bym testowac na jakims Galaxy S2 , S3 bo to dla mnie jedyne miarodajne telefony w sensie mocy. (No ogolnie brac flagowki moze byc jakis HTC itp)

Jedyny hint jaki ci moge dac to taki zeby kolor samplowac tez jako lowp bo by def bedzie chyba mediump co mocno cie moze spowolnic na pixelshaderze.

A no i moze drugi hint, pobierz all uniform location po zlinkowaniu shadera i trzymaj je gdziesn a boku i uzyj dopiero jak trzeba. W real time pobieranie za duzko kosztuje na telefonie.