androidopengl-esopengl-es-2.0gpumali

Repeated frames on Android Mali-400


On Android devices with Mali-400 GPU (Samsung Galaxy S II, Samsung Galaxy S3 Mini, Samsung Galaxy Note II), at random times the screen will start showing repeated frames.

Example from 0:51 until 1:01 on the following video https://www.youtube.com/watch?v=5-p6Oy0BZmg

It seems as if new frames aren't being rendered, and what was in the old buffer is being shown again. The game continues to advance behind the repeated frames.

This doesn't happen on other GPUs.

I read about using glFlush or glFinish, but GLSurfaceView takes care of this when doing eglSwapBuffers after onDrawFrame.

I've read about quirks of Mali-400, like is better to use varying for texture coords, or to use lowp, but it doesn't help. Here are the shaders for reference:

Vertex shader:

//  Vertex Shader

attribute vec4 position;
attribute vec4 colorModelIn;
attribute vec4 colorVertexIn;

varying lowp vec4 colorOut;

uniform mat4 modelViewProjectionMatrix;
uniform mat4 modelMatrix;

attribute vec2 TexCoordIn;
varying lowp vec2 TexCoordOut;

uniform bool bUseVertexColor;

void main()
{
    if( bUseVertexColor ){
        colorOut = colorVertexIn * colorModelIn;
    } else {
        colorOut = colorModelIn;
    }
    TexCoordOut = TexCoordIn;
    gl_Position = modelViewProjectionMatrix * modelMatrix * position;
}

Fragment shader:

//  Fragment shader

varying lowp vec4 colorOut;

varying lowp vec2 TexCoordOut;
uniform sampler2D Texture;

uniform bool bUseTexture;

void main()
{
    if( bUseTexture ){
        gl_FragColor = colorOut * texture2D(Texture, TexCoordOut);
    } else {
        gl_FragColor = colorOut;
    }
}

I'm aware that these shaders aren't optimal, and that I'm going down the path of reproducing the fixed pipeline.

The rendering goes back to normal after some time, or after touching the screen. The only reason I can think for going back to normal when touching is that I use color-coding to detect the touched object. I render an image to the back buffer and glReadPixels from it. Then, overwrite the back buffer with the normal game image.

I'm out of ideas on how to attack this problem.

EDIT

After following Muzza's advice I started to log GL errors. glGetInteger and glBindBuffer report out-of-memory.

Above I said that the problem solves itself after a while. When that happens these appear in the logs:

01-23 21:57:52.956: D/WebView(9860): onSizeChanged - w:480 h:75
01-23 21:57:53.126: D/TilesManager(9860): new EGLContext from framework: 40e00bd0 
01-23 21:57:53.126: D/GLWebViewState(9860): Reinit shader
01-23 21:57:53.171: D/GLWebViewState(9860): Reinit transferQueue

Solution

  • This can happen if the OpenGL state becomes invalid in some way. The graphics drivers can just skip frames entirely. Check Logcat to see if there is any output from the drivers, and add glGetError() calls throughout your code to see if any error comes up there.