使用多个像素缓冲区对象更新视频纹理时断言

时间:2013-12-10 11:32:49

标签: opengl video

我有一个应用程序使用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 个答案:

答案 0 :(得分:1)

我不知道,如果这是你的问题,但在你打电话之后:

 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _pboIds[_currentPboIndex]);
 glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
 Util::GLErrorAssert();

您正在致电

glBindTexture

但是你仍在使用索引为_currentPboIndex的缓冲区。

在我的代码中,我有两个索引 - index和nextIndex

在init中我设置

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