从 GPU 到 RAM 的大量传输后渲染缓慢?

Posted

技术标签:

【中文标题】从 GPU 到 RAM 的大量传输后渲染缓慢?【英文标题】:Slow rendering after large transfer from GPU to RAM? 【发布时间】:2020-09-25 14:45:30 【问题描述】:

我试图渲染一个点云(>1 亿点),我将所有数据传输到 GPU 并使用缓冲区名称来访问它。一切正常,直到我实现了一个需要我将所有数据传输回 RAM 的功能。

这就是我将数据传递给 GPU 的方式:

glBindVertexArray(vao);

// some data
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * GetSize()  * 3, &vertices[0], GL_STATIC_DRAW); // pos

// some attributes
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); // pos

...
// some other code
...

glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);

glDisableVertexAttribArray(0);

// Clear the contents in the RAM
vertices.clear();
vertices.shrink_to_fit();

然后,我需要一个函数来恢复数据以保存更改,这就是我所做的:

// restore data back to RAM
// this code was called for >4000 times

glBindBuffer(GL_ARRAY_BUFFER, c.vbo);
c.vertices.clear();
c.vertices.resize(c.sizeg);
glGetBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(glm::vec3) * c.sizeg, &c.vertices[0].position.x);

之后,每次我需要渲染该点云时,程序都会挂起。

我删除了所有其他代码来测试这段代码,而这段数据传输代码正是导致延迟的原因

感觉每次我尝试渲染导致 GPU 挂起的数据时,GPU 内部都会有大量的数据副本。但是,当我将数据从 GPU 传回 RAM 后,原来在 GPU 内的数据保持不变,我认为渲染应该和以前一样平滑,但事实并非如此。

导致这种延迟的 OpenGL 状态是否发生了变化?

【问题讨论】:

每次发生延迟时,我都注意到 GPU 的 3D 和 Windows 资源管理器中的复制性能急剧下降,这暗示了我的 GPU 在延迟期间还有其他事情要做而不是绘图跨度> 【参考方案1】:

您对 OpenGL 做出了承诺。然后你违背了诺言。所以OpenGL为此惩罚了你。

你告诉 OpenGL 这是怎么回事you were going to use this buffer object:

GL_STATIC_DRAW

这意味着您告诉 OpenGL 您将写入缓冲区 (DRAW) 但不会从中读取。你说你会很少给它写信(STATIC)。因此,OpenGL 实现尽职尽责地将缓冲区对象的存储空间放置在一个最适合 GPU 访问但不适合 CPU 访问的位置。

然后你从中读取。你做了你答应 OpenGL 你不会做的事情。

现在,人们(很多 人)一直在违背对 OpenGL 实现的这些承诺。如此多的实现基本上不再相信它们。也就是说,他们不会听你你要对缓冲区做什么,而是关注你实际做什么

实现看到您从缓冲区中读取。所以它假设你打算有规律地这样做。因此,它现在将缓冲区的存储转移到一个更适合 CPU 读取的位置......但 不太适合 GPU 读取。

现代 OpenGL 有一个buffer object creation API where lying is no longer permitted。您指定可以在缓冲区上使用哪些操作,OpenGL 实现将通过使所有其他访问失败来让您坚持下去。

如果您使用缓冲区存储 API,那么尝试使用 glGetBufferSubData 从缓冲区读取数据很可能不会导致 API 只是随机播放内存。防止存储洗牌是这个 API 的一半。如果您仍然从您的实现中获得这种减慢效果,那么您可能无法在 OpenGL 中阻止它。

最有效的替代方法(除了使用您可以完全控制内存的 Vulkan)是根本不尝试从 OpenGL 中读取它。也就是说,不要将 GPU 存储视为您需要一些数据时可以读回的东西。如果您需要使用 CPU 上的数据,请将其保留。也就是说,在 CPU 内存中也保留一份副本。

【讨论】:

以上是关于从 GPU 到 RAM 的大量传输后渲染缓慢?的主要内容,如果未能解决你的问题,请参考以下文章

渲染流水线中CPU和GPU之间的通信

一个操作让游戏内存立减50+%-CocosCreator性能优化之压缩纹理

为托管和流式传输音频/视频文件创建 .ram、.wvx、.m3u 文件的优势?

通过 Windows 中的常规文件传输 1-2 兆字节的数据 - 是不是比通过 RAM 慢?

为啥 Rails 渲染视图如此缓慢?

如何使用 GPU 高效地渲染和处理视频流?