在我的渲染引擎中,我使用 glMapSubBuffer 以及孤立和栅栏实现了三重缓冲来更新着色器缓冲区。在 Windows 中一切正常,但当我在 Mac 上运行引擎时出现问题。当我调用 glClientWaitSync
为了等待我的缓冲区空闲,它总是返回 GL_TIMEOUT_EXPIRED
,所以我无法更新我的缓冲区,引擎进入无限循环等待它们被释放。
我认为问题在于我如何实现三重缓冲,也因为我在使用它后并没有获得太多性能。
基本上我已经这样做了:
- 对于每个着色器,我检查它是否有缓冲区,如果有,我使用一个类来处理这些缓冲区的更新,这些缓冲区包含我在分析着色器时创建的 3 个缓冲区,并将 3 个栅栏设置为
0
。 (每个缓冲区一个) - 在我的渲染循环中,我为每个着色器设置数据,将模型分组以节省着色器切换,因此我使用每个着色器循环进行渲染。
然后,我为每个着色器调用一个绑定(bind)其缓冲区的函数,以便使用 Material 和模型的数据更新它们。我调用此函数传递一个索引,该索引指示要绑定(bind)着色器的 3 个缓冲区中的哪一个。该索引在主程序执行的每个绘图调用中更新。我用来绑定(bind)更新缓冲区的函数是函数 A(见下文)
更新缓冲区后,我使用
glDrawElementsInstanced(GL_TRIANGLES, mesh->GetFacesIndicesCount(), GL_UNSIGNED_INT, 0, _instances.size());
绘制对象然后我为刚刚与下面给出的函数 B 一起使用的缓冲区创建栅栏- 然后,对于刚刚使用的同一个着色器,可能会有更多数据,因此我重新执行第 3 点和第 4 步的步骤,直到着色器必须绘制的数据完成。
功能 A:
bool BindForUpdate(AUint bufferIndex)
{
if (!_created)
return false;
if(_fences[bufferIndex] != nullptr)
{
// This is the point where the rendering goes into infinite loop
unsinged int result = glClientWaitSync(_fences[bufferIndex], 0, BUFFERS_UPDATE_TIMEOUT);
while (result == GL_TIMEOUT_EXPIRED || result == GL_WAIT_FAILED)
result = glClientWaitSync(_fences[bufferIndex], 0, BUFFERS_UPDATE_TIMEOUT);
glDeleteSync(_fences[bufferIndex]);
}
glBindBufferBase(GL_UNIFORM_BUFFER, _bindingPoint, _ubos[bufferIndex]);
glBufferData(GL_UNIFORM_BUFFER, _bufferDataSize * _bufferLength, nullptr, GL_STREAM_DRAW);
_updateDataBuffer = (unsigned char*)glMapBufferRange(GL_UNIFORM_BUFFER, 0, _bufferDataSize, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
if (_updateDataBuffer == nullptr)
return false;
return true;
}
函数 B:
void SyncBuffers(unsinged int bufferIndex)
{
_fences[bufferIndex] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
}
我认为问题正是我进行三重缓冲的方式,因为我在同一个渲染周期中多次使用同一个缓冲区,因为每个渲染周期使用哪个缓冲区的索引改变一次,而不是每次我绑定(bind)着色器缓冲区。
我该如何解决这个问题?
我只是尝试在每次调用 glDrawElementsInstanced(GL_TRIANGLES, mesh->GetFacesIndicesCount(), GL_UNSIGNED_INT, 0, _instances.size());
后更改缓冲区索引而不是每次渲染调用只更改一次,但仍然是同样的问题。
我尝试强制 OpenGL 在 glDrawElementsInstanced
之后释放缓冲区打电话glFlush
它工作了很短的时间。我有 OS X 10.10,它与 glFlush
一起工作(仍然存在问题,因为有时 glFlush
在执行过程中会出现异常),但后来我更新到 OS X 10.11 和 glFlush
每次都开始给出异常,导致程序崩溃。
而且,最重要的是,我认为这根本不是解决这个问题的正确方法。
最佳答案
您应该使用 GL_SYNC_FLUSH_COMMANDS_BIT
调用 glClientWaitSync()
,至少在等待循环之前的第一次调用中。否则,GL 可能永远不会真正处理挂起的命令,等待将永远持续下去。
请注意,这可能比使用 glFlush
更有效。引自 OpenGL 4.5 core profile specification 的第 4.1.2 节:
if the
SYNC_FLUSH_COMMANDS_BIT
bit is set inflags
, andsync
is unsignaled whenClientWaitSync
is called, then the equivalent ofFlush
will be performed before blocking onsync
.
因此只有当栅栏还没有发出信号时才会发出同花顺。理想情况下,您将以实际等待同步的方式编写代码,这将是异常(exception),而不是规则。
关于c++ - glClientWaitSync 不适用于 MacOS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33473449/