glMapBufferRange() 下载完整的缓冲区?

Posted

技术标签:

【中文标题】glMapBufferRange() 下载完整的缓冲区?【英文标题】:glMapBufferRange() downloads full buffer? 【发布时间】:2014-06-27 03:22:07 【问题描述】:

我注意到调用一些 openGL 函数时会慢 15 毫秒。经过一些测试,我确实相信我缩小了问题的范围。我确实有几个 MBytes 的缓冲区(主要包含粒子)。有时我确实需要添加一些粒子。为此,我绑定缓冲区,获取当前粒子数以了解要写入的偏移量,然后写入粒子。正如预期的那样,放缓是在阅读部分。 (对于这个问题,假设在 CPU 端跟踪粒子数量是不可能的。)

glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
GLvoid* rangePtr = glMapBufferRange( //This function takes 15ms to return
    GL_ARRAY_BUFFER, 
    m_offsetToCounter, 
    sizeof(GLuint), 
    1);
if(rangePtr != NULL)
    value = *(GLuint*) rangePtr;
m_functions->glBindBuffer(GL_ARRAY_BUFFER, 0);

我假设通过提供一个非常有限的大小(这里是一个 GLuint),只会下载一个 GLuint。但是,通过将缓冲区的大小大幅减少到 200 KB,函数的执行时间会下降到 8 毫秒。

两个问题:

    glMapBufferRangeglGetBufferSubData 是否会下载完整的缓冲区,即使用户只要求其中的一部分? 数学不加起来,知道为什么吗?下载一个非常小的缓冲区还有 8 毫秒。执行时间方程看起来像 y = ax + b 其中 b 是 7-8 ms。当我在怀疑缓冲区大小之前试图找到问题的根源时,我还发现glUniform* 函数也需要大约 10 毫秒。但只是第一次打电话。如果有多个glUniform*一个接一个地调用,那么只有第一个会花费很多时间。其他都是瞬时的。并且当缓冲区将在读取中被访问时,也没有下载时间。 glUniform* 触发了什么?

我正在使用 Qt 5 API。我想首先确定我正确使用了 openGL,然后才考虑可能是 Qt 的层导致速度变慢并使用 glu/glut 重新实现整个程序。

【问题讨论】:

glMapBufferRange 的最后一个参数应该是一个符号常量。你为什么传入1 而不是GL_MAP_READ_BIT 不幸的是,GL_MAP_READ_BIT 没有在 Qt 5.2 OpenGL 模块中定义。我必须提供原始价值。但这不是这里的主题。 【参考方案1】:

8ms 听起来是一个非常长的时间……你如何衡量那个时间?

glMapBufferRange 和 glGetBufferSubData 确实会下载完整的缓冲区,即使用户只要求它的一部分?

OpenGL 规范没有定义实现缓冲区映射的方式。它可能是缓冲区内容的完整下载。它可能是单页 I/O-Memory 映射。它可能是使缓冲区对象的内容出现在主机进程地址空间中的任何东西。

数学没有加起来,知道为什么吗?

一方面,内存映射的最小尺寸是系统的页面尺寸。无论是通过完整的对象副本还是通过 I/O-Memory 映射或完全不同的方式来完成,您总是在处理至少几 kiB 大小的内存块。

我正在使用 Qt 5 API

可能是您使用的是 Qt5 OpenGL 函数类吗? AFAIK 这个类确实会按需加载函数指针,因此函数的第一次调用可能会触发一系列需要一些时间才能完成的操作。

【讨论】:

使用 QTime 对象测量时间。 start()elpased(),仅此而已。对于下载行为,既然你说它可能是任何东西,甚至是一艘游艇,我将为粒子使用一个缓冲区,该缓冲区将与许多小型哈希图缓冲区共享。这样我就永远不会下载重的部分(粒子列表)。不过,几 KBytes 的下载不应该花费 8 毫秒:/。我正在使用QOpenGLFunctions*。您认为使用 glu/glut 重新实现我的代码可能会给我一个惊喜吗? @agrum:你可以继续使用 Qt,但我建议你使用不同的函数加载器。像 GLEW 或更好的东西 [bitbucket.org/alfonse/glloadgen/wiki/Home](glloadgen).此外,我不确定 QTime 报告的值是否有点过于粗糙。人们通常希望为此使用高分辨率计时器。 我会坚持使用 QTime,因为它从来没有欺骗过我。但是,感谢您将我重定向到其他功能加载器。我会试试看。 @agrum:问题不在于QTime,而在于您衡量时间的方式。 GL 异步工作,但以这种方式映射缓冲区会触发同步,因此调用会阻塞,直到 GPU 完成。所以你测量的只是任何东西 @derhass:映射缓冲区不一定会引入同步点。如果它是只读映射并且缓冲区没有被用作 OpenGL 操作的目标,则不需要同步。此外,如果它是只写映射,则映射不会引入同步点(这与在之前已用作数据源的缓冲区对象上调用 glBuffer[Sub]Data 的情况相同;当然是 OpenGL 实现必须处理脏细节(创建阴影缓冲区等)。

以上是关于glMapBufferRange() 下载完整的缓冲区?的主要内容,如果未能解决你的问题,请参考以下文章

关于 glMapBufferRange

尝试使用opengl函数glMapBufferRange在python中制作外星人

着色器存储缓冲区对象的长度为零,glMapBufferRange 不起作用

JS动画公式

滑动抽屉中的缓动动画

div盒子的缓动函数封装