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 eglSwapBuffers
only 的文档说它执行刷新,这可能会使 CPU 停止,但不是必须的。