在具有 Mali-400 GPU 的 Android 设备(三星 Galaxy S II、三星 Galaxy S3 Mini、三星 Galaxy Note II)上,屏幕会随机开始显示重复帧。
以下视频中从 0:51 到 1:01 的示例https://www.youtube.com/watch?v=5-p6Oy0BZmg
似乎新帧没有被渲染,而旧缓冲区中的内容又被显示出来了。游戏在重复的帧后面继续前进。
这不会发生在其他 GPU 上。
我读过有关使用 glFlush 或 glFinish 的信息,但 GLSurfaceView 在 onDrawFrame 之后执行 eglSwapBuffers 时会处理这个问题。
我读过关于 Mali-400 的怪癖,比如最好将变量用于纹理坐标,或者使用 lowp,但这无济于事。以下是供参考的着色器:
顶点着色器:
// 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
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;
}
}
我知道这些着色器不是最佳的,而且我正在沿着重现固定管道的道路前进。
渲染在一段时间后或在触摸屏幕后恢复正常。我认为触摸时恢复正常的唯一原因是我使用颜色编码来检测触摸的对象。我将图像渲染到后台缓冲区并从中获得 glReadPixels。然后,用正常的游戏图像覆盖后台缓冲区。
我不知道如何解决这个问题。
编辑
在遵循 Muzza 的建议后,我开始记录 GL 错误。glGetInteger 和 glBindBuffer 报告内存不足。
上面我说过一段时间后问题会自行解决。发生这种情况时,这些会出现在日志中:
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