glDrawArrays()/ glDrawElements()会导致奇怪的性能下降

时间:2011-12-05 18:14:31

标签: opengl-es opengl-es-2.0

我目前正在尝试使用OpenGL ES 2.0在移动设备(带有OMAP 3630 / PowerVR SGX 530的诺基亚N9)上进行一些GPGPU图像处理。基本上我的应用程序的管道将彩色图像上传到视频内存,将其转换为灰度,计算整体图像并在几个片段着色器的帮助下提取一些特征。


输出正确,但程序的运行时有点令人困惑。当我将相同的图像通过我的管道3次以上时,时间是这样的(在第3次定时保持不变之后):

RGB-to-gray conversion:     7.415769 ms
integral image computation: 818.450928 ms
feature extraction:         285.308838 ms

RGB-to-gray conversion:     1471.252441 ms
integral image computation: 825.012207 ms
feature extraction:         1.586914 ms

RGB-to-gray conversion:     326.080353 ms
integral image computation: 2260.498047 ms
feature extraction:         2.746582 ms

如果我排除特征提取,则积分图像计算的时间变为合理的:

RGB-to-gray conversion:     7.354737 ms
integral image computation: 814.392090 ms

RGB-to-gray conversion:     318.084717 ms
integral image computation: 812.133789 ms

RGB-to-gray conversion:     318.145752 ms
integral image computation: 812.103271 ms

如果我另外从管道中排除了积分图像计算,则会发生这种情况(也是合理的):

RGB-to-gray conversion: 7.751465 ms
RGB-to-gray conversion: 9.216308 ms
RGB-to-gray conversion: 8.514404 ms

我期望的时间更像是:

RGB-to-gray conversion:     ~8 ms
integral image computation: ~800 ms
feature extraction:         ~250 ms

基本上,时间与我的期望有两点不同:

  1. 当我扩展管道
  2. 时,rgb2gray转换需要300而不是8 ms
  3. 当我进一步扩展管道时,积分图像计算需要2200而不是800 ms
  4. 我怀疑着色器切换是1)性能下降的原因。但这真的有这么大的影响吗?特别是当考虑到特征提取步骤包含具有不同片段着色器和FBO开关的多次传递时,但仍然如预期的那样快。

    特别奇怪的是性能下降2.)在积分图像计算期间,因为它是一个多遍操作,只使用一个着色器和乒乓渲染目标。如果我为每次传球测量glDraw*()的性能,则在所有传球中只发生一次,并且总是在同一传球中(尽管在这传球中没有发生任何特殊情况)。

    我还怀疑内存限制是原因,因为我使用了很多纹理/ FBO来输出数据,但总而言之,我占用了大约6 MB的视频内存,实际上并没有那么多。 / p>


    我已经尝试glDrawElements()glDrawArrays()glDrawArrays()与VBO每次都有相同的结果。

    所有时间都被捕获:

    glFinish();
    timer.start();
    render();
    glFinish();
    timer.stop();
    

    如果我忽略了glFinish()的来电,时间是相同的。


    有没有人有想法,我可能做错了什么?我对OpenGL并不太懂,所以也许有人可以指出我应该注意的方向或事情。我知道如果没有任何代码示例,这很难回答,这就是为什么我要求相当一般的建议。如果你需要更多关于我正在做的事情的信息,我会很高兴提供一些代码或伪代码。我只是不想太夸大这个问题...


    修改

    我想我找到了导致性能下降的原因:它似乎是两个着色器之间的某种等待时间,其中OpenGL管道等待先前的片段着色器完成,然后将输出交给下一个片段着色器。我使用rgb2gray转换着色器进行了一些实验,可以分离出两种情况:

    1。)使用rgb2gray着色器的第二次渲染取决于第一次渲染的输出:

    |inImg| -> (rgb2gray) -> |outImg1| -> (rgb2gray) -> |outImg2|
    

    2。)第二次渲染不依赖:

    |inImg| -> (rgb2gray) -> |outImg1|  
                                       |inImg| -> (rgb2gray) -> |outImg2|
    

    显然,变量2。)很可能比1.)更快,但是,我不明白为什么管道在第一次执行时以合理的运行时间完成,但是有那些奇怪的延迟之后。

    另外我认为最后一个流水线步骤的运行时间测量总是不准确的,所以我假设~280 ms是一个更准确的特征提取步骤测量(不是〜3 ms)。

1 个答案:

答案 0 :(得分:2)

我认为问题可能出在测量方法上。定时单个GL命令甚至渲染是非常困难的,因为驱动程序将试图通过并行运行多个渲染的不同部分来保持GPU管道的所有阶段繁忙。由于这个原因,驱动程序可能忽略了glFinish并且只在必要时才等待硬件完成(例如渲染目标上的glReadPixels)。

如果驱动程序只是将它们添加到队列的末尾,那么单个渲染可能会很快完成,但如果需要等待队列中的空间并且必须等待较早的渲染完成,那么单个渲染可能会很慢。

更好的方法是运行大量的帧(例如1000)并测量所有帧的总时间。