为什么在OpenGLES中glClear阻塞?

Tim*_*Tim 8 android opengl-es glsurfaceview opengl-es-2.0

我正试图描绘我的渲染器,我看到一些奇怪的剖析行为,我无法解释.

我正在使用glSurfaceView,我已设置连续渲染.

这就是我onDrawFrame()的结构

public void onDrawFrame(GL10 unused) {
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
    executeAllDrawCommands();
}
Run Code Online (Sandbox Code Playgroud)

这在轻负载下表现得很慢,所以我创建了一个计时器类并开始对其进行分析.我看到的东西让我很惊讶.

我对onDrawFrame方法进行了一些探测,如下所示:

public void onDrawFrame(GL10 unused) {
   swapTimer.end();

   clearTimer.start();
     GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
   clearTimer.end();

   drawTimer.start();
     executeAllDrawCommands();
   drawTimer.end();

   swapTimer.start();
}
Run Code Online (Sandbox Code Playgroud)

clearTimer测量调用glClear所需的时间,drawTimer测量运行所有绘制调用swapTimer所需的时间,并测量onDrawFrame退出和返回时的时间(调用eglSwapBuffers所需的时间).

当我跑一个非常轻载的场景时,我得到了一些我无法解释的奇怪数字:

swapTimer  : 20ms (average)
clearTimer : 11ms (average)
drawTimer  :  2ms (average)
Run Code Online (Sandbox Code Playgroud)

我预计交换时间有点大,因为我相信设备在~30fps时有vsync强制启用,但我不知道为什么实际的"清除"调用阻塞了11毫秒?我以为它应该发出一个异步命令并返回?

当我绘制一个更繁忙的场景时,数字会发生很大变化:

swapTimer  :  2ms (average)
clearTimer :  0ms (average)
drawTimer  : 44ms (average)
Run Code Online (Sandbox Code Playgroud)

在这个场景中,我的绘制调用花了很多时间,看起来它隐藏了很多vsync周期,并且清除调用上的块完全消失了.

有什么解释为什么glClear在我轻载的场景上阻挡了?

链接到我的'Timer'类源代码,以防有人怀疑我的测量技术:http://pastebin.com/bhXt368W

Wro*_*lai 10

我把glFinish(以及finishTimer.start()/ end()放在它周围),它总是需要一些时间远离glClear.相反,现在glFinish需要几毫秒,而glClear变得即时.

这解释了它.

当场景非常轻且图形渲染速度非常快时,使用新颜色清除和填充像素的时间将花费一些时间(总是需要时间,否则渲染器落后并且当前正在绘制新的东西).较新的Android设备具有填充限制.例如,Nexus One具有30 Hz的填充锁定 - 无论您的实际绘图速度有多快,屏幕都将以该频率同步.如果图形在30 Hz以下结束,则渲染器将与屏幕同步.这就是为什么你注意到这个延迟,即使你删除了这个glClear()电话,你也应该注意到这个延迟.渲染器在屏幕更新之前和之后更快.

当渲染器有许多要绘制的对象时,同步将暂停(给定繁忙场景的配置文件数据),因为渲染器现在在屏幕更新之后.

使用时glFinish(),它会消除glClear()函数否则会导致的时间,通过遵循填充逻辑,这意味着glFinish()现在是确保与屏幕同步的功能.

计算:

F = 1/T.

简单的场景:

F = 1/T = 1 /((20 + 11 + 2)*10 ^ -3)= ~30Hz

同步的延迟时间出现在您的探查器中.渲染器正在与屏幕同步.这意味着如果您删除glClear()glFinish()调用,延迟将出现在其他地方.

沉重的场景:

F = 1/T = 1 /((2 + 0 + 44)*10 ^ -3))= ~22Hz

同步器的延迟时间不会出现在您的探查器中.渲染器在屏幕的更新频率之后.

似乎这都与vsync有关

这似乎是正确的.