OpenGL ES 2.0 render to texture bug on ARM MALI gpu

1.3k views Asked by At

Hy, I'm developing an app on android and I'm in the testing phase and I'm trying it out on different devices. I developed the app on a nexus 7.

When I run it on a arm mali gpu device the rendered textrue starts to blink / lagg like crazy. I use GLES20.GL_POINTS in the generated texture if I set the point size to 1 it blinks and it looks like there are artifacts in it, and if I set the point size to a bigger number like 10 it "laggs" meaning sometimes it shows a texture from a earlyer rendering.

Any idea what could cause this ?

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

This is my render to textue method:

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

This gets called on draw:

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

asdas

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

And after this I draw it to the screen

   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);
}
1

There are 1 answers

0
Reto Koradi On BEST ANSWER

It looks like there are a couple of problems with the ordering of your calls.

  1. At the start of createSmokeTexture(), there is this code sequence:

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

    Here, the framebuffer is cleared before it is completely set up by attaching the render targets with the glFramebufferTexture2D() and glFramebufferRenderbuffer() calls. This is most likely only a problem for the first frame, because at least in the code shown here, the render targets are never un-attached again. After that, the calls are just redundant. It would be much better to attach the render targets during setup.

  2. At the end of setTexture():

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

    Based on the sequence in draw(), this is called after the FBO rendering completed, and before using the resulting texture to draw to the main framebuffer. However, this glTexImage2D() call basically wipes out the content of the texture that was produced by the FBO rendering.

To fix both of these problems, remove the glFramebufferTexture2D() and glFramebufferRenderbuffer() from the first code sequence, and all but the glActiveTexture() and glBindTexture() calls from setTexture(). All of these should go to setupRenderToTexture() function, which then becomes:

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