Framebuffer FBO 渲染到纹理很慢,在 Android 上使用 OpenGL ES 2.0,为什么? [英] Framebuffer FBO render to texture is very slow, using OpenGL ES 2.0 on Android, why?

查看:33
本文介绍了Framebuffer FBO 渲染到纹理很慢,在 Android 上使用 OpenGL ES 2.0,为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 opengl es 2.0 编写一个 Android 2d 游戏.在将精灵绘制到后台缓冲区后,我将灯光绘制到 FBO 并尝试再次将其混合到后台缓冲区.当我将 FBO 绘制到帧缓冲区时,即使没有任何颜色,帧率也会从 60 下降到 30(三星 Galaxy w(它的 GPU 为 adreno 205)).我到处搜索并尝试了所有方法,即使我在场景中绘制单个精灵并将透明的 FBO 纹理混合到屏幕上也会导致帧率下降.我在该手机上尝试了其他带有灯光效果的游戏,它们运行良好,几乎所有游戏在该手机上都运行良好,我相信它们也使用了帧缓冲区.在 Galaxy SII(mali 400 gpu)上运行良好,我对 opengl 很陌生,所以我相信我在某个地方犯了错误,我分享了我的代码.

I am programming an Android 2d game using opengl es 2.0. After I draw my sprites to the backbuffer I draw lights to a FBO and try to blend it to the back buffer again. When I draw the FBO to the framebuffer, even trasparent without any color, the framerates drops from 60 to 30 on a Samsung Galaxy w (it has an adreno 205 as gpu). I searched everywhere and tried everything, even if I draw a single sprite on the scene and blend a trasparent FBO texture to the screen the framerate drops. I tried other games with lighting effects on that phone and they run fine, almost every game is fine on that phone, I believe they use the framebuffer as well. On the Galaxy SII (mali 400 gpu) runs fine, I am quite new to opengl so I believe I am making a mistake somewhere, I share my code.

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

我在表面创建时这样做过一次.不确定是否正确.我保留纹理和帧缓冲区 ID,以便在需要时切换到它们.我的绘图代码:

I do this once on surface creation. Not sure if is correct. I keep the texture and framebuffer ids to switch to them when I need. My drawing code:

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 纹理时,性能就被破坏了.非常感谢您的帮助.我为此非常努力,但没有找到解决方案.

Everything is rendered on screen correctly, but the performance are ruined just when I draw the FBO texture. Thank you very much for your help. I worked very hard on this and didn't find a solution.

推荐答案

根据 qualcomm 文档,你需要在每个 glbindframebuffer 之后进行 glclear,这是一个与平铺架构相关的问题,如果你正在切换帧缓冲区,数据需要被复制从 fastmem 到普通内存以保存当前帧缓冲区,从 slowmem 到 fast mem 以获取新绑定帧的内容,以防您在 glbind 之后清除没有数据从 slowmem 复制到 fastmem 并且您节省了时间,但您需要重新设计你的渲染管道经常,所以它会避免在慢速和快速内存之间来回读取数据,所以尝试在每次绑定后执行 glclear 并且它应该会有所帮助,你也可以使用 adreno profiler 来获取有关有问题的调用的其他信息,但我怀疑它将对 adreno200 有所帮助,我正在尝试获取两个用于模糊的缓冲区,并且以 10fps 结束,如果未清除,则 bindframebuffer 调用最多可能需要 20 毫秒,如果是,则应在 2 毫秒结束.

According to qualcomm docs, you need to glclear after every glbindframebuffer, this is a problem related to tiled architecture, if you are switching framebuffers, data need to get copied from fastmem to normal memory to save current framebuffer and from slowmem to fast mem to get contents of newly binded frame, in case you are clearing just after glbind no data is copied from slowmem to fastmem and you are saving time, but you need to redesign your render pipeline often, so it will avoid reading data back and forth between slow and fast memory, so try to do glclear after each bind and it should help, you can also use adreno profiler to get additional information about problematic calls, but i doubt it will help with adreno200 i am trying to get two buffers for blur and i am ending with 10fps, bindframebuffer call can take up to 20msec if its not cleared, if it is it should end at 2ms.

这篇关于Framebuffer FBO 渲染到纹理很慢,在 Android 上使用 OpenGL ES 2.0,为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆