为什么在OpenGLES中glClear阻塞?

时间:2012-09-01 01:38:15

标签: android opengl-es opengl-es-2.0 glsurfaceview

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

我正在使用glSurfaceView,我已经设置了连续渲染。

这就是我onDrawFrame()的结构

public void onDrawFrame(GL10 unused) {
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
    executeAllDrawCommands();
}

这在轻负载下表现得很慢,所以我创建了一个计时器类并开始对其进行分析。我对所见所闻感到非常惊讶。

我对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();
}

clearTimer衡量调用glClear所需的时间,drawTimer衡量运行所有绘制调用所需的时间,swapTimer衡量从onDrawFrame退出到何时退出的时间返回(调用eglSwapBuffers所需的时间)。

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

swapTimer  : 20ms (average)
clearTimer : 11ms (average)
drawTimer  :  2ms (average)

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

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

swapTimer  :  2ms (average)
clearTimer :  0ms (average)
drawTimer  : 44ms (average)

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

有没有解释为什么glClear会在我轻载的场景中阻挡?

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

1 个答案:

答案 0 :(得分: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)= ~30 Hz

同步的延迟时间出现在您的探查器中。渲染器正在与屏幕同步。这意味着,如果您移除glClear()glFinish()来电,延迟就会出现在其他地方。

沉重的场景

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

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

  

似乎这与vsync

有关

这似乎是正确的。