9

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

我正在使用 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

4

1 回答 1

11

我放了一个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-09-02T12:51:06.877 回答