当前位置: 首页 > news >正文

Android OpenGL ES 3.0 PBO像素缓冲区对象

1.什么是PBO

OpenGL PBO(Pixel Buffer Object),被称为像素缓冲区对象,主要被用于异步像素传输操作。PBO 仅用于执行像素传输,不连接到纹理,且与 FBO (帧缓冲区对象)无关。

OpenGL PBO(像素缓冲区对象) 类似于 VBO(顶点缓冲区对象),PBO 开辟的也是 GPU 缓存,而存储的是图像数据。

PBO 绑定相关的 Target 标签有 2 个:

  • GL_PIXEL_UNPACK_BUFFER:将PBO绑定到这个上边,glTexImage2D和glTexSubImage2D() 表示从PBO中解包像素数据并恢复到帧缓冲区

  • GL_PIXEL_PACK_BUFFER:将PBO绑定到这个上边时,glReadPixels()表示从帧缓冲区中读取数据并打包进PBO

2.为什么要使用PBO

处理高分辨率的图像时,图像数据在内存和显存之前拷贝往往会造成性能瓶颈,而利用 PBO 可以在一定程度上解决这个问题。

使用 PBO 可以在 GPU 的缓存间快速传递像素数据,不影响 CPU 时钟周期,除此之外,PBO 还支持异步传输。

传统的方式:从文件中加载纹理,图像数据首先被加载到 CPU 内存中,然后通过 glTexImage2D 函数将图像数据从 CPU 内存复制到 OpenGL 纹理对象中 (GPU 内存),两次数据传输(加载和复制)完全由 CPU 执行和控制。

使用PBO的方式:可以通过 glMapBufferRange 获取 PBO 对应 GPU 缓冲区的内存地址。将图像数据加载到 PBO 后,再将图像数据从 PBO 传输到纹理对象中完全是由 GPU 控制,不会占用 CPU 时钟周期。所以,绑定 PBO 后,执行 glTexImage2D (将图像数据从 PBO 传输到纹理对象) 操作,CPU 无需等待,可以立即返回。

通过对比这两种(将图像数据传送到纹理对象中)方式,可以看出,利用 PBO 传输图像数据,省掉了一步 CPU 耗时操作(将图像数据从 CPU 内存复制到 纹理对象中)

3.PBO的使用

3.1PBO的创建
/**
 * 创建PBO 用于读取纹理上的像素数据
 * StreamRead 流的方式读取
 */
m_PBOfst = new MSOpenGLBuffer(MSOpenGLBuffer::PixelPackBuffer,MSOpenGLBuffer::StreamRead);
m_PBOsnd = new MSOpenGLBuffer(MSOpenGLBuffer::PixelPackBuffer,MSOpenGLBuffer::StreamRead);
//构造函数
MSOpenGLBuffer::MSOpenGLBuffer(MSOpenGLBuffer::Type type, MSOpenGLBuffer::UsagePattern usage)
                        :m_bufferType(type),m_usage(usage),m_buffSize(0)
{
    glGenBuffers(1, &m_buffID);

}

创建方式是GL_PIXEL_PACK_BUFFER,用于从纹理上读取像素数据,用于流的方式进行读取。

3.2PBO设置bufferData
m_PBOfst->Bind();
m_PBOfst->SetBufferData(nullptr,m_nResolution.x*m_nResolution.y*4);
m_PBOfst->Release();

m_PBOsnd->Bind();
m_PBOsnd->SetBufferData(NULL,m_nResolution.x * m_nResolution.y * 4); 
m_PBOsnd->Release();
//Bind 函数
void MSOpenGLBuffer::Bind()
{
    glBindBuffer(m_bufferType, m_buffID);
}
//release函数
void MSOpenGLBuffer::Release()
{
    glBindBuffer(m_bufferType, 0);
}

void MSOpenGLBuffer::SetBufferData(const GLvoid *data, GLsizeiptr size)
{
    if (size > m_buffSize) {
        m_buffSize = size;
        glBufferData(m_bufferType, size, data, m_usage);
    } else {
        glBufferSubData(m_bufferType, 0, size, data);
    }
}

给连个PBO设置BufferData

3.3通过PBO进行数据读取
/**
 * 通过m_currIdx 来控制 两个PBO交替控制
 */
void MSGLScene::processPBOReadPixels() {
    glReadBuffer(GL_FRONT);
    if(m_currIdx == 0){
        readPixelsFromPBO(m_PBOfst,m_PBOsnd);
        m_currIdx =1;
    }else{
        readPixelsFromPBO(m_PBOsnd,m_PBOfst);
        m_currIdx =0;
    }
}

void MSGLScene::readPixelsFromPBO(MSOpenGLBuffer *fstBuff, MSOpenGLBuffer *sndBuff) {

    int w = m_nResolution.x;
    int h = m_nResolution.y;

    fstBuff->Bind();
    glReadPixels(0,0,w,h,GL_RGBA,GL_UNSIGNED_BYTE,0);

    //READ
    sndBuff->Bind();
    void* data= glMapBufferRange(GL_PIXEL_PACK_BUFFER,0,w*h*4,GL_MAP_READ_BIT);
    if (data){
        MSVideoWriter::GetInstance()->WriteVideoFrameWithRgbData((const unsigned char*)data);
    }

    glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
    glBindBuffer(GL_PIXEL_PACK_BUFFER,0);

}

通过两个PBO交替读取数据,glMapBufferRange读取到结果就是:从纹理上读取到的RBG数据,此时数据就可以交给FFmpeg或者MediaCodec进行编码,并进行视频合成了。

相关文章:

  • 腾讯T4级架构师用21个项目带你吃透379页深度学习TensorFlow实践pdf
  • Eureka服务注册发现原理
  • RK3399平台开发系列讲解(中断篇)中断控制器驱动初始化
  • 【Redis】Redis的持久化
  • LibreOJ_10010
  • 数据增强
  • 一文搞懂堆外内存(模拟内存泄漏)
  • 还在调API写所谓的AI“女友”,唠了唠了,教你基于python咱们“new”一个(深度学习)
  • Win7纯净版系统镜像64位介绍
  • Kali系统MSF模块暴力破解MySQL弱口令漏洞
  • [附源码]java毕业设计疫情环境下的酒店管理系统
  • kafka配置外网访问
  • java每一练(3)
  • Java学习----前端4
  • ABAP中 delete 语句的使用
  • cesium火箭发射,模型控制,模型动画,模型移动
  • http请求走私漏洞原理,利用,检测,防护
  • Docker学习(3)—— 将容器转化为新的镜像,并将新镜像发布到阿里云公共仓库或私有仓库
  • cpu天梯图2022年11月 cpu排行榜天梯图2022
  • Linux的基本协议与他的堂兄堂弟
  • 细粒度图像分类论文研读-2017
  • [深度学习] python基础支持汇总
  • JSP文件上传
  • Numpy入门[16]——choose函数实现条件筛选
  • [go学习笔记.第十八章.数据结构] 1.基本介绍,稀疏数组,队列(数组实现),链表
  • [附源码]计算机毕业设计校园服装租赁系统Springboot程序
  • 全国天然气锅炉价格_天然气冷凝油
  • 蒸汽 冷凝_冷凝型真空热水锅炉
  • 太原乐山燃气锅炉_斯大燃气热水锅炉控制器