【问题标题】:OpenGL ES 2.0 render to texture bug on ARM MALI gpuARM MALI gpu 上的 OpenGL ES 2.0 渲染到纹理错误
【发布时间】:2014-12-12 19:03:52
【问题描述】:

嘿, 我正在android上开发一个应用程序,我正处于测试阶段,我正在不同的设备上试用它。我在 nexus 7 上开发了该应用程序。

当我在 arm mali gpu 设备上运行它时,渲染的 textrue 开始疯狂地闪烁/滞后。 如果我将点大小设置为 1,我在生成的纹理中使用 GLES20.GL_POINTS早期渲染的纹理。

知道是什么原因造成的吗?

private void setupRenderToTexture() {
    fb = new int[1];
    depthRb = new int[1];
    renderTex = new int[2];
    // generate
    GLES20.glGenFramebuffers(1, fb, 0);
    GLES20.glGenRenderbuffers(1, depthRb, 0);
    GLES20.glGenTextures(1, renderTex, 0);
    // create render buffer and bind 16-bit depth buffer
    GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, depthRb[0]);
    GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, texW, texH);
}

这是我渲染到文本的方法:

   private void createSmokeTexture() {
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fb[0]);
    GLES20.glClearColor(0.48f, 0.48f, 0.48f, 0.0f);
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
    GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, renderTex[0], 0);
    GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, depthRb[0]);
    //background counts
    renderscriptSmokeStep_involke();

    GLES20.glUseProgram(mProgramSmoke);
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
    mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramSmoke, "u_MVPMatrix");
    mMVMatrixHandle = GLES20.glGetUniformLocation(mProgramSmoke, "u_Move");
    mTextureUniformHandle = GLES20.glGetUniformLocation(mProgramSmoke, "u_Texture");
    smokeParticleSizeUniformHandle = GLES20.glGetUniformLocation(mProgramSmoke, "u_PointSize");
    maximumDensityHandler = GLES20.glGetUniformLocation(mProgramSmoke, "u_MaximumDensity");

    cellDensityHandle = GLES20.glGetAttribLocation(mProgramSmoke, "a_Age");
    smokeStartPositionHandle = GLES20.glGetAttribLocation(mProgramSmoke, "a_Position");

    Matrix.setIdentityM(mMoveMatrix, 0);
    Matrix.translateM(mMoveMatrix, 0, positionX, positionY, 0);
    Matrix.multiplyMM(mMoveMatrix, 0, Render.mModelMatrix, 0, mMoveMatrix, 0);

    GLES20.glUniform1f(smokeParticleSizeUniformHandle, PARTICLE_SIZE);
    GLES20.glUniform1f(maximumDensityHandler, MAXIMUM_DENSITY);
    GLES20.glUniform1i(mTextureUniformHandle, 0);
    GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mMoveMatrix, 0);
    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, Render.m2dProjectionMatrix, 0);

    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, particlePosBuffer);
    GLES20.glEnableVertexAttribArray(smokeStartPositionHandle);
    GLES20.glVertexAttribPointer(smokeStartPositionHandle, 2, GLES20.GL_FLOAT, false, 0, 0);

    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);

    GLES20.glEnableVertexAttribArray(cellDensityHandle);
    GLES20.glVertexAttribPointer(cellDensityHandle, 1, GLES20.GL_FLOAT, false, 0, cellDensity);

    // Draw the point.
    GLES20.glDrawArrays(GLES20.GL_POINTS, 0, NUM_PARTICLES);
}

这在绘图时被调用:

   public void draw(){
    createSmokeTexture();
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
    setTexture(renderTex[0]);
    drawSmokeToScreen();
}

阿斯达斯

    private void setTexture(int texture) {
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
    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);
    GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, texW, texH, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
}

然后我把它画到屏幕上

   private void drawSmokeToScreen() {
    GLES20.glUseProgram(mProgramHandle);
    mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVPMatrix");
    mMVMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_Move");
    positionHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Position");
    textureHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_TexCoordinate");

    GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, Render.mModelMatrix, 0);
    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, Render.m2dProjectionMatrix, 0);

    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, fullDrawSurfice.getPositionDataIndex());
    GLES20.glEnableVertexAttribArray(positionHandle);
    GLES20.glVertexAttribPointer(positionHandle, 2, GLES20.GL_FLOAT, false, 0, 0);

    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, fullDrawSurfice.getTextureDataIndex());
    GLES20.glEnableVertexAttribArray(textureHandle);
    GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false, 0, 0);

    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);

    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
}

【问题讨论】:

  • 要检查的一点是支持的点大小。使用glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, ...)。实现不需要支持大于 1 的点大小。除此之外,人们可能无法仅对问题的描述提供太多帮助。这可能是驱动程序错误,或者您的代码中恰好没有在其他架构上显示任何症状的问题。
  • @RetoKoradi 很高兴知道这不是必需的,我检查过并且该设备支持它。你是对的,我会在几分钟内输入一些代码。这是我的,我没有在不同架构上开发的经验,所以我不知道要检查什么

标签: android opengl-es-2.0 render-to-texture mali


【解决方案1】:

您的通话顺序似乎存在一些问题。

  1. createSmokeTexture()的开头,有这样的代码序列:

    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fb[0]);
    GLES20.glClearColor(0.48f, 0.48f, 0.48f, 0.0f);
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
    GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
            GLES20.GL_TEXTURE_2D, renderTex[0], 0);
    GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT,
            GLES20.GL_RENDERBUFFER, depthRb[0]);
    

    在这里,通过使用glFramebufferTexture2D()glFramebufferRenderbuffer() 调用附加渲染目标,帧缓冲区在完全设置之前被清除。这很可能只是第一帧的问题,因为至少在此处显示的代码中,渲染目标永远不会再次取消附加。在那之后,电话只是多余的。在设置过程中附加渲染目标会更好。

  2. setTexture()结尾:

    GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, texW, texH, 0,
            GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
    

    基于draw() 中的序列,在FBO 渲染完成后调用此函数,在使用生成的纹理绘制到主帧缓冲区之前调用。但是,这个glTexImage2D() 调用基本上会清除 FBO 渲染生成的纹理内容。

要解决这两个问题,请从第一个代码序列中删除glFramebufferTexture2D()glFramebufferRenderbuffer(),并从setTexture() 中删除除glActiveTexture()glBindTexture() 之外的所有调用。所有这些都应该转到setupRenderToTexture()函数,然后变成:

GLES20.glGenTextures(1, renderTex, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, renderTex[0]);
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);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, texW, texH, 0,
        GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);

// create render buffer and bind 16-bit depth buffer
GLES20.glGenRenderbuffers(1, depthRb, 0);
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, depthRb[0]);
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER,
        GLES20.GL_DEPTH_COMPONENT16, texW, texH);

GLES20.glGenFramebuffers(1, fb, 0);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
        GLES20.GL_TEXTURE_2D, renderTex[0], 0);
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT,
        GLES20.GL_RENDERBUFFER, depthRb[0]);

【讨论】:

    猜你喜欢
    • 2012-01-16
    • 1970-01-01
    • 2014-10-28
    • 2016-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多