• Opengl Fence 内部实现


    背景:

    opengl 跨线程渲染的时候,避免了不了使用Fence机制其使用也很简单,今天我们就从源码角度看下Fence到底做了啥

    Fence

    C++
    GL_APICALL GLsync GL_APIENTRY glFenceSync(GLenum condition, GLbitfield flags)
    GL_APICALL void GL_APIENTRY glDeleteSync(GLsync sync)
    GL_APICALL GLenum GL_APIENTRY glClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
     

    今天就从这个3个方法来看下源码里具体的实现

    glFenceSync

    C++
    GL_APICALL GLsync GL_APIENTRY glFenceSync(GLenum condition, GLbitfield flags)

    {
            TRACE("(GLenum condition = 0x%X, GLbitfield flags = %X)", condition, flags);

          

            es2::Context *context = es2::getContext();

            if(context)
            {
                    return context->createFenceSync(condition, flags);
            }

            return nullptr;
    }

    createFenceSync

    C++
    GLsync Context::createFenceSync(GLenum condition, GLbitfield flags)
    {
            GLuint handle = mResourceManager->createFenceSync(condition, flags);

            return reinterpret_cast(static_cast(handle));
    }
        GLuint ResourceManager::createFenceSync(GLenum condition, GLbitfield flags)
        {
                GLuint name = mFenceSyncNameSpace.allocate();
       
                FenceSync *fenceSync = new FenceSync(name, condition, flags);
                fenceSync->addRef();
       
                mFenceSyncNameSpace.insert(name, fenceSync);
       
                return name;
        }
       

    可以看的出来这个fenc指针最终存储在mResourceManager这个对象里边,而mResourceManager是可以通过共享context被另外一个线程context持有的,所以fence指针另外线程是可以访问到的

    glClientWaitSync

    一般AddFence后会在另外一个线程调用glClientWaitSync 等待完成,那我们就看下它是怎么实现的

    C++
    GL_APICALL GLenum GL_APIENTRY glClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
    {
            TRACE("(GLsync sync = %p, GLbitfield flags = %X, GLuint64 timeout = %llu)", sync, flags, timeout);

            if((flags & ~(GL_SYNC_FLUSH_COMMANDS_BIT)) != 0)
            {
                    error(GL_INVALID_VALUE);
            }

            es2::Context *context = es2::getContext();

            if(context)
            {
                    es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);

                    if(fenceSyncObject)
                    {
                            return fenceSyncObject->clientWait(flags, timeout);
                    }
                    else
                    {
                            return error(GL_INVALID_VALUE, GL_FALSE);
                    }
            }

            return GL_FALSE;
    }

    接下来看下fenceSyncObject->clientWait这个实现

    C++
    GLenum FenceSync::clientWait(GLbitfield flags, GLuint64 timeout)
    {
            // The current assumtion is that no matter where the fence is placed, it is
            // done by the time it is tested, which is similar to Context::flush(), since
            // we don't queue anything without processing it as fast as possible.
            return GL_ALREADY_SIGNALED;
    }
     

    我看到这个开源库是没实现这个方法的,这里比较遗憾

    glDeleteSync

    这个就很简单了

    C++
    GL_APICALL void GL_APIENTRY glDeleteSync(GLsync sync)
    {
            TRACE("(GLsync sync = %p)", sync);

            es2::Context *context = es2::getContext();

            if(context)
            {
                    context->deleteFenceSync(sync);
            }
    }
        void Context::deleteFenceSync(GLsync fenceSync)
        {
                // The spec specifies the underlying Fence object is not deleted until all current
                // wait commands finish. However, since the name becomes invalid, we cannot query the fence,
                // and since our API is currently designed for being called from a single thread, we can delete
                // the fence immediately.
                mResourceManager->deleteFenceSync(static_cast(reinterpret_cast(fenceSync)));
        }
            void ResourceManager::deleteFenceSync(GLuint fenceSync)
            {
                    FenceSync *fenceObject = mFenceSyncNameSpace.remove(fenceSync);
           
                    if(fenceObject)
                    {
                            fenceObject->release();
                    }
            }
                void Object::release()
                {
                        if(dereference() == 0)
                        {
                                delete this;
                        }
                }

    当引用计数是0的时候,会清楚这个资源,也就是一旦调用Delete共享context线程,与原线程都不用使用了Fence了

  • 相关阅读:
    批量处理图片:轻松转换JPG到TIFF,优化你的图片管理“
    电阻:分压造成的流血事件
    2023南华大学计算机考研信息汇总
    Google Earth Engine——全球陆地冰层空间数据的介绍(内含常见错误)
    阿里云国际版云服务器Linux系统数据恢复操作步骤
    中学化学教学参考杂志社中学化学教学参考编辑部2022年第12期目录
    LuatOS-SOC接口文档(air780E)-- i2s - 数字音频
    玩转Mysql系列 - 第14篇:详解事务
    DATA AI Summit 2022提及到的对 aggregate 的优化
    java计算机毕业设计郑工社团交流服务信息平台源码+mysql数据库+系统+lw文档+部署
  • 原文地址:https://blog.csdn.net/c553110519/article/details/126611275