【问题标题】:Why is glClear blocking in OpenGLES?为什么 glClear 在 OpenGLES 中阻塞?
【发布时间】:2012-08-26 19:06:21
【问题描述】:

我正在尝试分析我的渲染器,但我看到了一些我无法解释的奇怪分析行为。

我正在使用 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,但我不知道为什么实际的“清除”调用会阻塞 11 毫秒?我以为它只是应该发出一个异步命令并返回?

当我画一个更繁忙的场景时,数字变化很大:

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

在这个场景中,我的绘图调用花费了很多时间,以至于它看起来隐藏了很多垂直同步周期,并且清除调用上的阻塞完全消失了。

有什么解释为什么 glClear 会阻塞我的轻负载场景吗?

如果有人怀疑我的测量技术,请链接到我的“计时器”类源代码:http://pastebin.com/bhXt368W

【问题讨论】:

  • 您可以尝试在 clearTimer.start() 方法之前调用 GLES20.glFinish() 看看时间如何变化吗?
  • 我放了一个glFinish(和它周围的finishTimer.start()/end()),它总是远离glClear。相反,现在 glFinish 需要一些毫秒数,并且 glClear 变得即时。看起来这一切都与 vsync 有关,虽然我很惊讶地看到 glClear 中出现了 vsync 时间。

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


【解决方案1】:

我放了一个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有关

这似乎是正确的。

【讨论】:

    猜你喜欢
    • 2012-10-31
    • 2017-07-30
    • 2012-04-15
    • 2012-08-23
    • 2012-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-24
    相关资源
    最近更新 更多