在我的渲染引擎中,我已经使用glMapSubBuffer和孤立和围栏实现了三重缓冲来更新着色器缓冲区。在Windows中一切正常但是当我在Mac上运行我的引擎时会出现问题。当我为了等待我的缓冲区空闲而调用glClientWaitSync
时,它总是返回GL_TIMEOUT_EXPIRED
,因此我无法更新缓冲区并且引擎进入无限循环,等待它们到达免费。
我认为问题在于我如何实现三重缓冲,也因为我在使用它后没有获得如此多的性能。
基本上我已经这样做了:
然后,对于每个着色器,我调用一个绑定其缓冲区的函数,以便使用材质和模型的数据更新它们。我调用此函数传递一个索引,该索引告诉着色器的3个缓冲区中的哪一个要绑定。该索引在主程序执行的每个绘制调用时更新。我用来绑定缓冲区以进行更新的函数是函数A(见下文)
更新缓冲区后,我使用0
绘制对象,然后为刚刚与下面给出的函数B一起使用的缓冲区创建栅栏
功能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
开始给出每次例外,都会导致程序崩溃。
而且,最重要的是,我认为这不是解决这个问题的正确方法。
答案 0 :(得分:0)
您应该使用glClientWaitSync()
拨打GL_SYNC_FLUSH_COMMANDS_BIT
,至少在等待循环之前的第一次通话中。否则,GL可能永远不会实际处理挂起的命令,等待将永远持续。
请注意,使用glFlush
可能会更有效。引自OpenGL 4.5 core profile specification的第4.1.2节:
如果在
SYNC_FLUSH_COMMANDS_BIT
中设置flags
位,则sync
为ClientWaitSync
调用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>
。
因此只有在栅栏尚未发出信号时才会发出冲洗。理想情况下,您应该以这样的方式编写代码,即实际等待同步将是例外,而不是规则。