在 Android 上使用 FBO 进行慢速 OpenGL ES 渲染到纹理乒乓球

Posted

技术标签:

【中文标题】在 Android 上使用 FBO 进行慢速 OpenGL ES 渲染到纹理乒乓球【英文标题】:Slow OpenGL ES Render-to-texture ping pong with FBO on Android 【发布时间】:2015-03-19 22:28:44 【问题描述】:

我使用 Qt 进行了渲染到纹理测试,并在 macOS 和 android 上运行它。 该测试创建 2 个纹理和一个 FBO,然后在循环中附加交替纹理作为渲染目标。 不过,在 Android 上,代码出奇地慢。在三星 Galaxy Tab S 上,它比我的 Mac 慢大约 30-40 倍,所以我怀疑有问题。 片段着色器中的实际代码似乎并不重要。

在 glBindFramebuffer 之后添加 glClear 会使其更快一些,但仍然很慢。关于在哪里寻找原因的任何线索?

// create textures
glEnable(GL_TEXTURE_2D);
GLuint tex1, tex2;

// define texture properties
glGenTextures(1, &tex1);
glBindTexture(GL_TEXTURE_2D, tex1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER_EXT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER_EXT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1280, 800, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);

// define texture properties
glGenTextures(1, &tex2);
glBindTexture(GL_TEXTURE_2D, tex2);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER_EXT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER_EXT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1280, 800, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);

// create framebuffer
GLuint fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glClear(GL_COLOR_BUFFER_BIT);

// create program
QGLShaderProgram program;
program.addShaderFromSourceFile(QGLShader::Fragment, ":/shaders/fshader.glsl");
program.addShaderFromSourceFile(QGLShader::Vertex, ":/shaders/vshader.glsl");
program.link();
program.bind();

//
float vertices[16];
int i = 0;
vertices[i++] = 0.0f; vertices[i++] = 0.0f; vertices[i++] = 0.0; vertices[i++] = 1.0;
vertices[i++] = 0.0f; vertices[i++] = 1280.0f; vertices[i++] = 0.0; vertices[i++] = 0.0;
vertices[i++] = 1280.0f; vertices[i++] = 0.0f; vertices[i++] = 1.0; vertices[i++] = 1.0;
vertices[i++] = 1280.0f; vertices[i++] = 1280.0f; vertices[i++] = 1.0; vertices[i++] = 0.0;
int vertexLocation = program.attributeLocation("a_position");
program.enableAttributeArray(vertexLocation);
glVertexAttribPointer(vertexLocation, 2, GL_FLOAT, GL_FALSE, 4*sizeof(float), (const void *)vertices);
int texcoordLocation = program.attributeLocation("a_texcoord");
program.enableAttributeArray(texcoordLocation);
glVertexAttribPointer(texcoordLocation, 2, GL_FLOAT, GL_FALSE, 4*sizeof(float), (const void *)(vertices + 2));

QMatrix4x4 textureMatrix, modelViewMatrix;

// do loop test
int count = 10000;
bool swapped = false;
cout << "Start fbo test" << endl;
QTime myTimer;
myTimer.start();

textureMatrix.setToIdentity();
program.setUniformValue("textureMatrix", textureMatrix);

modelViewMatrix.setToIdentity();
program.setUniformValue("modelViewProjectionMatrix", modelViewMatrix);

program.setUniformValue("srcTex", 0);

for(int i = 0; i < count; i++)

    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                              GL_TEXTURE_2D, swapped? tex2 : tex1, 0);

    // check completeness
    GLenum status;
    status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    switch(status)
    
        case GL_FRAMEBUFFER_COMPLETE:
            break;
        default:
            log("Framebuffer error");
    

    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, swapped? tex1 : tex2);

    // draw slab
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    swapped = !swapped;

这是顶点着色器:

#ifdef GL_ES
// Set default precision to medium
precision mediump int;
precision mediump float;
#endif

uniform mat4 modelViewProjectionMatrix;
uniform mat4 textureMatrix;

attribute vec4 a_position;
attribute vec2 a_texcoord;

varying vec2 v_texcoord;

void main()

    // Calculate vertex position in screen space
    gl_Position = modelViewProjectionMatrix* a_position;
    v_texcoord = vec4(textureMatrix * vec4(a_texcoord, 0.0, 1.0)).xy;

片段着色器:

#ifdef GL_ES
// Set default precision to medium
precision mediump int;
precision mediump float;
#endif

uniform sampler2D srcTex;

varying vec2 v_texcoord;

void main(void)

    vec4 f = texture2D(srcTex, v_texcoord);
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);

【问题讨论】:

这里是移动 GPU 性能的有用指南:seas.upenn.edu/~pcozzi/OpenGLInsights/…。 不确定它是否与您的性能有关,但您正在绘制一个比显示器大得多的多边形。没有应用变换的可见坐标范围(并且您似乎只在发布的代码中应用恒等变换)在两个坐标方向上都是 [-1.0, 1.0],而您使用范围 [0.0, 1280.0] 中的坐标。 【参考方案1】:

使用两个 FBO,每个都绑定到单独的纹理,而不是在循环内交换。如果您不想在纹理中保留内容,请在循环内 glBindFramebuffer() 之后调用 glClear()

【讨论】:

以上是关于在 Android 上使用 FBO 进行慢速 OpenGL ES 渲染到纹理乒乓球的主要内容,如果未能解决你的问题,请参考以下文章

Android OpenGL 1.1 FBO 和 VBO 支持

Framebuffer FBO渲染到纹理很慢,在Android上使用OpenGL ES 2.0,为啥?

设备上的 Android Studio 慢速调试

为啥在使用 FBO 进行多重采样时,OpenGL 会使我的场景变亮?

在 Windows 上使用 jCIFS 列出慢速文件

在移动客户端上使用 Microsoft Sync Framework 进行慢速 SQL 同步