Nexus 5上GLSurfaceView帧率问题

5
我有一个示例应用程序(完整源代码),它使用MediaCodec对相机帧进行编码,并在GLSurfaceView上显示。
Systrace确认每秒进行30个绘制调用:

Systrace screenshot

然而,一个屏幕录制(.mp4, YouTube)显示,表面帧率明显较低。简而言之,我的编码和显示循环执行以下操作:
  • 使MediaCodec Surface输入EGL上下文成为当前
  • 将相机帧绘制到MediaCodec EGL表面上
  • 使GLSurfaceView EGL上下文成为当前
  • 将相同的相机帧绘制到GLSurfaceView上
在Galaxy Nexus LTE和Nexus 7(都是AOSP 4.4),应用程序表现如预期。到目前为止,只有Nexus 5在屏幕上绘制的帧数和实际帧数之间存在差异...我祈祷我不是疯了。

screenrecord 命令会增加相当大的开销 -- surfaceflinger 需要使用 GLES 为虚拟显示合成所有层 -- 这可能会对帧率产生不利影响。在 screenrecord 运行时查看 systrace。 - fadden
我在没有屏幕录制的情况下也遇到了这个问题。在N5和我尝试过的其他设备之间存在天壤之别。 - dbro
1
类似的问题(可能有解决方法):https://dev59.com/ZXnZa4cB1Zd3GeqPv-dc - fadden
1
谢谢!我正在研究这个问题。顺便说一下,我有一个关于N5上我的应用程序的系统跟踪(16MB。当我从该URL加载时,Chrome会崩溃,但在本地打开时不会...)。还值得注意的是,我所有的测试设备都在4.4上,只有N5在我的应用程序中出现了这个问题。 - dbro
1
在查看SurfaceView顶部附近的代码行时,您可以看到其队列中有多少缓冲区。由于缓冲区源未使队列得到满足,因此SurfaceFlinger没有绘制任何内容--在surfaceflinger行中,您可以看到它进行合成、等待vsync(17ms)、合成、等待3x vsync,并重复此过程。有很多CPU正在运行,但其中大部分似乎是PackageManager。Thread-445显示在调用awaitImage()之间需要30-40毫秒,而这通常需要20毫秒才能返回。某些东西肯定已经阻塞了工作。 - fadden
显示剩余2条评论
1个回答

11

我成功地复制了这种行为,我的GL向导办公室同事找出了问题所在。

基本上,其中一个EGL上下文没有注意到纹理内容的变化,因此它继续渲染旧数据。我们认为它会偶尔更新,因为它有一组缓冲区,通过这些缓冲区循环,最终会重新使用你正在查看的缓冲区。

我通过更新纹理渲染器类来解决了我的代码中的问题,改变了这个:

GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureID);

变成这个:

GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureID);

取消绑定和重新绑定会使驱动程序选择正确的缓冲区。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接