使用PBO异步上传纹理时生成Mipmap卡顿,该如何优化?
优化方案
方案1:双缓冲PBO+延迟生成Mipmap
- 维护2个PBO交替执行上传任务:当前帧把数据拷贝到空闲PBO后不立刻执行
glGenerateMipMap,等到下1-2帧再对已经完成上传的纹理执行Mipmap生成,利用帧间时间差完全掩盖同步开销 - 该方案最多引入1~2帧的渲染延迟,对视频类应用的观感几乎没有影响
方案2:手动预分配Mipmap层级 + 计算着色器异步生成Mipmap
- 初始化阶段改用
glTexStorage2D预分配所有Mipmap层级的显存,替代原来的glTexImage2D,显存分配效率更高 - 纹理通过PBO异步上传完成后,不调用会阻塞主机端的
glGenerateMipMap,而是绑定计算着色器逐层级向下采样生成各级Mipmap,计算着色器任务会在GPU队列异步执行,不会阻塞主机线程 - 目前桌面端OpenGL4.3以上、移动端OpenGLES3.1以上都支持计算着色器特性,适配范围足够覆盖绝大多数视频应用的运行设备
方案3:按需触发Mipmap生成
- 如果你的视频场景下,纹理显示的缩放比例长期固定在大于1的状态(也就是永远只用到最上层的Mipmap),可以临时关闭Mipmap,只有当检测到视图缩放比例小于1的时候再触发Mipmap生成,大幅降低同步函数的触发频率
现有代码可立刻落地的优化点
你当前的代码存在额外的无用开销,修改后可以直接降低阻塞程度:
- 纹理参数重复赋值:初始化阶段
GL_TEXTURE_MIN_FILTER和GL_TEXTURE_MAG_FILTER都被赋值了两次,直接删掉多余的GL_NEAREST赋值行即可 - 每次循环重复调用
glBufferData重置PBO会额外触发显存释放和分配:可以改用glInvalidateBufferData替代,或者直接给glMapBufferRange传入GL_MAP_INVALIDATE_BUFFER_BIT参数,不需要每次都重新分配PBO显存 - 修正PBO映射逻辑错误:你当前代码调用
glMapBufferRange之后立刻解绑PBO,memcpy写入的是悬空指针,会导致未定义行为,修正后的逻辑参考:
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); // 加INVALIDATE标识,告诉驱动旧的PBO内容不需要保留 mapped_buffer_ = (GLubyte*) glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, width_ * height_ * channel_, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); memcpy(mapped_buffer, pointer, height_ * width_ * channel_); glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); // 必须调用,否则PBO数据无效 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_RGB, GL_UNSIGNED_BYTE, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
内容的提问来源于stack exchange,提问作者hao li
相关产品推荐
相关产品推荐

