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



我试图渲染一个点云(>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状态是否发生了变化,导致了这种滞后?

您对OpenGL做出了承诺。然后你违背了你的诺言。OpenGL因此惩罚了你。

你告诉OpenGL你将如何使用这个缓冲区对象:

GL_STATIC_DRAW

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

然后你读了它。你做了你向OpenGL承诺不会做的事情。

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

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

现代OpenGL有一个缓冲区对象创建API,其中不再允许说谎。您可以指定可以在缓冲区上使用的操作,OpenGL实现会使所有其他访问失败,从而使您坚持这一点。

如果您使用缓冲区存储API,那么尝试使用glGetBufferSubData从缓冲区读取很可能会而不是导致API只是打乱内存。防止存储混乱是这个API的一半要点。如果您仍然从实现中获得这种减慢的效果,那么在OpenGL中可能无法阻止它。

最有效的选择(除了使用Vulkan,在那里你可以完全控制内存(是根本不尝试从OpenGL中读取它。也就是说,不要把GPU存储当作你需要一些数据时可以读取的东西。如果您需要使用CPU上的数据,请将其保留在那里。也就是说,在CPU内存中也保留一份副本。

最新更新