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ę?