4

这些标准暗示从我的第一个gl命令开始渲染并与其他命令并行继续进行渲染。glBufferSubData只要对象当前未在使用中,某些功能(例如指示加载)就可以在渲染期间发生。这引入了“框架”的逻辑概念,尽管标准中从未明确提及。

所以我的问题是什么定义了这个逻辑框架?也就是说,哪些调用划分了游戏,这样我就可以gl再次开始调用而不干扰前一帧?

例如,使用您最终调用的 EGL eglSwapBuffers(大多数实现都有某种交换命令)。从逻辑上讲,这是一帧和下一帧之间的边界。但是,这会调用块来支持垂直同步,这意味着在它返回之前您不能发出新命令。然而,文档暗示您可以在另一个线程中返回之前开始发出新命令(前提是您不接触任何正在使用的缓冲区)。

即使交换命令仍在前一个缓冲区上阻塞,我如何才能开始向下一个缓冲区发出命令?我想在 GPU 处理旧帧时开始为下一帧流式传输数据(特别是,我将有两个顶点缓冲区,专门为此目的交换每个帧,并在 OpenGL 文档中提到)。

4

1 回答 1

12

OpenGL没有“框架”的概念,无论是逻辑的还是其他的。

OpenGL 真的很简单:每条命令的执行都好像所有先前的命令都事先完成了一样。

注意关键短语“好像”。假设您从缓冲区对象渲染,然后立即修改其数据。像这样:

glBindVertexArray(someVaoThatUsesBufferX);
glDrawArrays(...);
glBindBuffer(GL_ARRAY_BUFFER, BufferX);
glBufferSubData(GL_ARRAY_BUFFER, ...);

这在 OpenGL 中是 100% 合法的。关于这将如何运作,没有任何警告、问题、担忧等。该glBufferSubData调用将像glDrawArrays命令完成一样执行。

您唯一需要考虑的是规范未指定的一件事:性能

实现完全可以检测到您正在修改可能正在使用的缓冲区,因此会停止 CPUglBufferSubData直到从该缓冲区完成渲染。OpenGL 实现需要执行此操作或执行其他操作,以防止实际源缓冲区在使用时被修改。

因此,根据规范, OpenGL 实现尽可能异步执行命令。只要外界看glDrawArrays不出还没有画完任何东西,实现就可以为所欲为。如果您在绘图命令之后立即发出一个glReadPixels,则管道将不得不停止。你可以做到,但不能保证性能。

这就是为什么 OpenGL 被定义为一个封闭的盒子。这为实现提供了很大的自由,可以尽可能地异步。每次访问 OpenGL 数据都需要一个 OpenGL 函数调用,它允许实现检查该数据是否实际可用。如果没有,它就会停止。

摆脱停顿是缓冲区对象失效可能的原因之一。它有效地告诉 OpenGL 你想要孤立缓冲区的数据存储。这就是缓冲区对象可用于像素传输的原因;它允许传输异步发生。这就是栅栏同步对象存在的原因,以便您可以判断资源是否仍在使用中(可能用于GL_UNSYNCHRONIZED_BIT缓冲区映射)。等等。

但是,这会调用块来支持垂直同步,这意味着在它返回之前您不能发出新命令。

谁说的?缓冲区交换命令可能会停止。它可能不会。它是实现定义的,可以通过某些命令进行更改。for eglSwapBuffersonly 的文档说它执行刷新,这可能会使 CPU 停止,但不是必须的。

于 2012-08-20T09:05:18.307 回答