使用多个像素缓冲区对象更新视频纹理时出现卡顿
Posted
技术标签:
【中文标题】使用多个像素缓冲区对象更新视频纹理时出现卡顿【英文标题】:Stutter when updating Video Texture using multiple Pixel Buffer Objects 【发布时间】:2013-12-10 11:32:49 【问题描述】:我有一个应用程序,它使用 FFMPEG(在单独的线程中)解码视频文件,并在另一个线程中使用 PBO 渲染此纹理。所有的 PBO do-hickey 都发生在以下函数中:
void DynamicTexture::update()
if(!_isDirty)
return;
/// \todo Check to make sure that PBOs are supported
if(_usePbo)
// In multi PBO mode, we keep swapping between the PBOs
// We use one PBO to actually set the texture data that we will upload
// and the other we use to update/modify. Once modification is complete,
// we simply swap buffers
// Unmap the PBO that was updated last so that it can be released for rendering
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _pboIds[_currentPboIndex]);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
Util::GLErrorAssert();
// bind the texture
glBindTexture(GL_TEXTURE_2D, _textureId);
Util::GLErrorAssert();
// copy pixels from PBO to texture object
// Use offset instead of pointer.
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _width, _height,
(_channelCount==4)?GL_RGBA:GL_RGB,
GL_UNSIGNED_BYTE, 0);
Util::GLErrorAssert();
// Now swap the pbo index
_currentPboIndex = (++_currentPboIndex) % _numPbos;
// bind PBO to update pixel values
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _pboIds[_currentPboIndex]);
Util::GLErrorAssert();
// map the next buffer object into client's memory
// Note that glMapBuffer() causes sync issue.
// If GPU is working with this buffer, glMapBuffer() will wait(stall)
// for GPU to finish its job
GLubyte* ptr = (GLubyte*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
Util::GLErrorAssert();
if(ptr)
// update data directly on the mapped buffer
_currentBuffer = ptr;
Util::GLErrorAssert();
else
printf("Unable to map PBO!");
assert(false);
// It is good idea to release PBOs with ID 0 after use.
// Once bound with 0, all pixel operations behave normal ways.
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
Util::GLErrorAssert();
// If a callback was registered, call it
if(_renderCallback)
(*_renderCallback)(this);
else
glBindTexture(GL_TEXTURE_2D, _textureId);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
_width, _height, (_channelCount==4)?GL_RGBA:GL_RGB,
GL_UNSIGNED_BYTE,
&(_buffer[0])
);
Util::GLErrorAssert();
// Reset the dirty flag after updating
_isDirty = false;
在解码线程中,我只需更新 _currentBuffer 并将 _isDirty 标志设置为 true。该函数在渲染线程中调用。
当我使用单个 PBO 时,即上述代码中的 _numPbos=1 时,渲染工作正常,没有任何卡顿。但是,当我使用多个 PBO 时,视频中会出现明显的卡顿。您可以找到我使用 _numPbos=2 here 渲染 5 个视频的示例。我使用的 PBO 数量越多,口吃就越严重。
理论上,我正在更新的缓冲区和用于渲染的缓冲区是不同的,所以应该不会出现这种故障。我想使用双/三缓冲来提高渲染性能。
我正在寻找一些关于可能出现问题的指针/提示。
【问题讨论】:
【参考方案1】:我不知道,如果这是你的问题,但在你打电话后:
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _pboIds[_currentPboIndex]);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
Util::GLErrorAssert();
你在打电话
glBindTexture
但您仍在使用索引_currentPboIndex
处的缓冲区。
在我的代码中,我有两个索引 - index 和 nextIndex
在初始化中我设置
index = 0;
nextIndex = 1;
比我的更新管道是这样的:
index = (index + 1) % 2;
nextIndex = (nextIndex + 1) % 2;
uint32 textureSize = sizeof(RGB) * width * height;
GL_CHECK( glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo[nextIndex]) );
GL_CHECK( glBufferData(GL_PIXEL_UNPACK_BUFFER, textureSize, 0, GL_STREAM_DRAW_ARB) );
GL_CHECK( gpuDataPtr = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, textureSize, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT) );
//update data gpuDataPtr
GL_CHECK( glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB) );
//bind texture
GL_CHECK( glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, pbo[index]) );
GL_CHECK( glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
width, height, glFormat, GL_UNSIGNED_BYTE, 0) );
GL_CHECK( glBindBufferARB(type, 0) );
【讨论】:
不,这不是问题所在。调用 glUnmapBuffer 并不意味着缓冲区对象不再有效。它只是让驱动程序在 GPU 内存中移动缓冲区。只有它在客户端空间中的映射会失效。以上是关于使用多个像素缓冲区对象更新视频纹理时出现卡顿的主要内容,如果未能解决你的问题,请参考以下文章