Framebuffer FBO рендерится на текстуру очень медленно, используя OpenGL ES 2.0 на Android, почему?

Я программирую игру для Android 2d, используя opengl es 2.0. После того, как я рисую свои спрайты в буфер, я рисую источники света в FBO и пытаюсь снова смешать их с задним буфером. Когда я рисую FBO в кадровом буфере, даже прозрачном без какого-либо цвета, частота кадров падает с 60 до 30 на Samsung Galaxy w (у него adreno 205 как gpu). Я искал везде и пробовал все, даже если я рисую один спрайт на сцене и смешиваю прозрачную текстуру FBO с экраном, частота кадров падает. Я пробовал другие игры со световыми эффектами на этом телефоне, и они работают нормально, почти все игры на этом телефоне хороши, я думаю, что они также используют кадровый буфер. На Galaxy SII (mali 400 gpu) работает нормально, я новичок в opengl, поэтому я считаю, что я где-то ошибаюсь, я делюсь своим кодом.

// Create a framebuffer and renderbuffer
GLES20.glGenFramebuffers(1, fb, offset);
GLES20.glGenRenderbuffers(1, depthRb, offset);

// Create a texture to hold the frame buffer
GLES20.glGenTextures(1, renderTex, offset);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, renderTex[offset]);

GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA,
                    screenWidth, screenHeight, 0,
                    GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE,
                    null);


GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
                       GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
                       GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
                       GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
                       GLES20.GL_LINEAR);

//bind renderbuffer
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, depthRb[offset]);

GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16,
                             screenWidth, screenHeight);

// bind the framebuffer
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fb[offset]);

// specify texture as color attachment
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
                              GLES20.GL_TEXTURE_2D, renderTex[offset], 0);

// specify depth_renderbufer as depth attachment
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT,
                                 GLES20.GL_RENDERBUFFER, depthRb[0]);

// Check FBO status.
int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);

if ( status == GLES20.GL_FRAMEBUFFER_COMPLETE )
{
    Log.d("GLGame framebuffer creation", "Framebuffer complete");
}


// set default framebuffer
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);

Я делаю это один раз при создании поверхности. Не уверен, если это правильно. Я сохраняю идентификаторы текстур и кадрового буфера, чтобы переключаться на них, когда мне это нужно. Мой код для рисования:

GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
ShaderProgram program = glgame.getProgram();

//put vertices in the floatbuffer
mTriangleVertices.put(vertices, 0, len);
mTriangleVertices.flip();

GLES20.glVertexAttribPointer(program.POSITION_LOCATION, 2, GLES20.GL_FLOAT, false,
                             TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);

//preparing parameter for texture position
mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
GLES20.glEnableVertexAttribArray(program.POSITION_LOCATION);

//preparing parameter for texture coords
GLES20.glVertexAttribPointer(program.TEXTURECOORD_LOCATION, 2, GLES20.GL_FLOAT,
                             false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES,
                             mTriangleVertices);

//set projection matrix
GLES20.glEnableVertexAttribArray(program.TEXTURECOORD_LOCATION);
GLES20.glUniformMatrix4fv(program.MATRIX_LOCATION, 1, false, matrix, 0);

//draw triangle with indices to form a rectangle
GLES20.glDrawElements(GLES20.GL_TRIANGLES, numSprites * 6, GLES20.GL_UNSIGNED_SHORT,
                      indicesbuf);

//clear buffers
mTriangleVertices.clear();
mVertexColors.clear();

Все отображается правильно на экране, но производительность ухудшается, когда я рисую текстуру FBO. Большое спасибо за Вашу помощь. Я очень много работал над этим и не нашел решения.

1 ответ

Решение

В соответствии с документами qualcomm, после каждого glbindframebuffer необходимо указывать, что это проблема, связанная с мозаичной архитектурой. Если вы переключаете кадровые буферы, данные должны копироваться из fastmem в обычную память для сохранения текущего кадрового буфера и из slowmem в fast mem для получения содержимое нового связанного фрейма, в случае, если вы очищаете сразу после glbind, никакие данные не копируются из slowmem в fastmem, и вы экономите время, но вам нужно часто переделывать конвейер рендеринга, чтобы он не читал данные назад и вперед между медленным и медленным быстрая память, поэтому старайтесь делать glclear после каждой привязки, и это должно помочь, вы также можете использовать adreno profiler для получения дополнительной информации о проблемных вызовах, но я сомневаюсь, что это поможет с adreno200. Я пытаюсь получить два буфера для размытия, и я заканчивая 10fps, вызов bindframebuffer может занять до 20 мсек, если он не очищен, если это так, он должен заканчиваться на 2 мс.

Другие вопросы по тегам