c++ - glClientWaitSync 不适用于 MacOS

标签 c++ opengl

在我的渲染引擎中,我使用 glMapSubBuffer 以及孤立和栅栏实现了三重缓冲来更新着色器缓冲区。在 Windows 中一切正常,但当我在 Mac 上运行引擎时出现问题。当我调用 glClientWaitSync为了等待我的缓冲区空闲,它总是返回 GL_TIMEOUT_EXPIRED ,所以我无法更新我的缓冲区,引擎进入无限循环等待它们被释放。

我认为问题在于我如何实现三重缓冲,也因为我在使用它后并没有获得太多性能。

基本上我已经这样做了:

  1. 对于每个着色器,我检查它是否有缓冲区,如果有,我使用一个类来处理这些缓冲区的更新,这些缓冲区包含我在分析着色器时创建的 3 个缓冲区,并将 3 个栅栏设置为 0。 (每个缓冲区一个)
  2. 在我的渲染循环中,我为每个着色器设置数据,将模型分组以节省着色器切换,因此我使用每个着色器循环进行渲染。
  3. 然后,我为每个着色器调用一个绑定(bind)其缓冲区的函数,以便使用 Material 和模型的数据更新它们。我调用此函数传递一个索引,该索引指示要绑定(bind)着色器的 3 个缓冲区中的哪一个。该索引在主程序执行的每个绘图调用中更新。我用来绑定(bind)更新缓冲区的函数是函数 A(见下文)

  4. 更新缓冲区后,我使用 glDrawElementsInstanced(GL_TRIANGLES, mesh->GetFacesIndicesCount(), GL_UNSIGNED_INT, 0, _instances.size()); 绘制对象然后我为刚刚与下面给出的函数 B 一起使用的缓冲区创建栅栏

  5. 然后,对于刚刚使用的同一个着色器,可能会有更多数据,因此我重新执行第 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 in flags, and sync is unsignaled when ClientWaitSync is called, then the equivalent of Flush will be performed before blocking on sync.

因此只有当栅栏还没有发出信号时才会发出同花顺。理想情况下,您将以实际等待同步的方式编写代码,这将是异常(exception),而不是规则。

关于c++ - glClientWaitSync 不适用于 MacOS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33473449/

相关文章:

用于以通用方式返回序列的 C++ API

c++ - 在 glReadPixels 调用后丢失

javascript - WebGL/OpenGL : comparing the performance

opengl - GLSL 全局变量

opengl - 阴影映射中的偏置矩阵混淆

c++ - 角度 > 180 的不规则多边形的内角

c++ - 解析 C++ 中的结构并在其中搜索值

使用二维数组的 C++ 编码

c++ - SWIG - 包装 std::pair 字符串时内存泄漏

c++ - OpenGL boolean 统一?