glClientWaitSync无法在MacOS上运行

时间:2015-11-02 08:28:34

标签: c++ opengl

在我的渲染引擎中,我已经使用glMapSubBuffer和孤立和围栏实现了三重缓冲来更新着色器缓冲区。在Windows中一切正常但是当我在Mac上运行我的引擎时会出现问题。当我为了等待我的缓冲区空闲而调用glClientWaitSync时,它总是返回GL_TIMEOUT_EXPIRED,因此我无法更新缓冲区并且引擎进入无限循环,等待它们到达免费。

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

基本上我已经这样做了:

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

  4. 更新缓冲区后,我使用0绘制对象,然后为刚刚与下面给出的函数B一起使用的缓冲区创建栅栏

  5. 然后,对于刚使用的相同着色器,可能会有更多数据,所以我重新执行第3点和第4点的步骤,直到着色器必须绘制完成的数据。
  6. 功能A:

    glDrawElementsInstanced(GL_TRIANGLES, mesh->GetFacesIndicesCount(), GL_UNSIGNED_INT, 0, _instances.size());

    功能B:

    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;
    }
    

    我认为这个问题正是我做三重缓冲的方式,因为我在同一个渲染周期中多次使用相同的缓冲区,因为每个渲染周期使用哪个缓冲区的索引会改变一次而不是每个时间我绑定着色器缓冲区。

    我怎么能解决这个问题?

    我只是在每次调用void SyncBuffers(unsinged int bufferIndex) { _fences[bufferIndex] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); } 后尝试更改缓冲区索引,而不是每次渲染调用只更改一次,但仍然是同样的问题。

    我尝试强制OpenGL在glDrawElementsInstanced(GL_TRIANGLES, mesh->GetFacesIndicesCount(), GL_UNSIGNED_INT, 0, _instances.size());调用glDrawElementsInstanced后释放缓冲区并且它工作了很短的时间。我有OS X 10.10并且它与glFlush一起工作(仍有问题,因为有时glFlush在执行期间发出异常),但后来我更新到OS X 10.11并且glFlush开始给出每次例外,都会导致程序崩溃。

    而且,最重要的是,我认为这不是解决这个问题的正确方法。

1 个答案:

答案 0 :(得分:0)

您应该使用glClientWaitSync()拨打GL_SYNC_FLUSH_COMMANDS_BIT,至少在等待循环之前的第一次通话中。否则,GL可能永远不会实际处理挂起的命令,等待将永远持续。

请注意,使用glFlush可能会更有效。引自OpenGL 4.5 core profile specification的第4.1.2节:

  

如果在SYNC_FLUSH_COMMANDS_BIT中设置flags位,则syncClientWaitSync   调用Flush时无信号,则相当于   sync阻止之前将执行<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <fragment android:id="@+id/fragment_container" android:layout_centerHorizontal="true" android:layout_width="match_parent" android:layout_height="match_parent" android:name="com.yourorg.fragment.EmptyFragment" /> </RelativeLayout>

因此只有在栅栏尚未发出信号时才会发出冲洗。理想情况下,您应该以这样的方式编写代码,即实际等待同步将是例外,而不是规则。