英文原文地址

wiki解释

概述

OpenGL ARB_pixel_buffer_object 扩展与ARB_vertex_buffer_object.很相似。为了缓冲区对象不仅能存储顶点数据,还能存储像素数据,它简单地扩展了 ARB_vertex_buffer_object extension。储存像素数据的缓冲区对象称为Pixel Buffer Object (PBO)。ARB_pixel_buffer_object extension借鉴了VBO所有的框架和API,而且还多了两个"Target" 标签。这俩Target协助PBO储存管理器(OpenGL驱动)决定缓冲区对象的最佳位置: 系统内存、共享内存、显卡内存Target标志指明其上绑定的PBO的两种不同的用途:GL_PIXEL_PACK_BUFFER_ARB ——传递 OpenGL  中的像素数据到 PBO 中,以及GL_PIXEL_UNPACK_BUFFER_ARB ——从 PBO 中传回数据到 OpenGL。

例如,glReadPixels()和glGetTexImage()是 "pack" 像素操作, glDrawPixels(), glTexImage2D() ,glTexSubImage2D() 是 "unpack" 操作。当一个PBO绑定的Target为GL_PIXEL_PACK_BUFFER_ARB时, glReadPixels()是从 OpenGL 的帧缓冲区(FBO)读取像素数据,并将数据写(pack)入PBO中。当一个 PBO 绑定的Target为 GL_PIXEL_UNPACK_BUFFER_ARB时,glDrawPixels() 是从 PBO 读取(unpack)像素数据并复制到 OpenGL 帧缓冲区(FBO)中。

PBO的主要优点是可以通过 DMA (Direct Memory Access) 快速地在显卡上传递像素数据,而不影响CPU的时钟周期(中断)。另一个优势是它还具备异步 DMA 传输。让我们对比使用 PBO 前后的纹理传送方法。左侧图是从图像文件或视频中加载纹理。首先,资源被加载到系统内存(Client)中,然后使用 glTexImage2D() 函数从系统内存复制到 OpenGL 纹理对象中(Client->Server)。这两次数据传输(加载和复制)完全由 CPU 执行。

不使用PBO的纹理加载

使用PBO的纹理加载

和上图相反,原图像可以直接加载到PBO中,而PBO是由OpenGL控制的。虽然CPU有参与加载纹理到PBO,但不涉及将像素数据从PBO传输到纹理对象的工作,而是由GPU(OpenGL驱动)来负责PBO到纹理对象的数据传输的,这也就意味着OpenGL执行DMA传输操作不会占用CPU的时钟周期。此外,OpenGL还可以安排稍后执行的异步DMA传输。所以glTexImage2D()可以立即返回,CPU也无需等待像素数据的传输了,可以继续其他工作。

主要有两种优化像素数据传输性能的PBO方法:

1. streaming texture update

2.asynchronous read-back from the framebuffer.

创建PBO

以前说到,Pixel Buffer Object使用VBO的所有API。不同的是多了两个针对PBO的额外标志:GL_PIXEL_PACK_BUFFER_ARB和GL_PIXEL_UNPACK_BUFFER_ARB. GL_PIXEL_PACK_BUFFER_ARB 从OpenGL传送像素数据到你的程序中, GL_PIXEL_UNPACK_BUFFER_ARB 将像素数据从程序传送到OpenGL中。OpenGL使用这些标志来决定PBO最佳的内存位置。例如,上传纹理数据到FBO(unpack)时,使用显卡内存。读帧缓冲区(FBO)时,使用系统内存。OpenGL 驱动会参照target标志来决定PBO所在的内存位置。

创建一个PBO需要三个步骤:

1使用glGenBuffersARB()新建一个缓冲区对象
2使用glBindBufferARB()绑定一个缓冲区对象
3使用glBufferDataARB复制像素信息到缓冲区对象

如果让glBufferDataARB的数据源数组接收的指针为空指针,那么PBO仅分配数据的大小的内存空间。glBufferDataARB方法最后一个参数对PBO具有指导作用,它告诉PBO如何使用些缓冲区对象。GL_STREAM_DRAW_ARB (unpack)是 streaming texture upload 。GL_STREAM_READ_ARB (pack)是异步的帧缓冲区read-back。
更多细节,参见VBO。

PBO映射

PBO提供了一种内存映射机制,可以映射OpenGL控制的缓冲区对象到客户端的内存地址空间中。客户端可以使用glMapBufferARB(), glUnmapBufferARB()函数修改全部或部分缓冲区对象。


void* glMapBufferARB(GLenum target, GLenum access)GLboolean glUnmapBufferARB(GLenum target)

glMapBufferARB()返回一个指向缓冲区对象的指针,如果成功返回此指针,否则返回NULL。Target参数是GL_PIXEL_PACK_BUFFER_ARB 或GL_PIXEL_UNPACK_BUFFER_ARB。第二个参数,指定映射的缓冲区的访问方式:从PBO中读数据(GL_READ_ONLY_ARB),写数据到PBO中(GL_WRITE_ONLY_ARB) 或读写PBO(GL_READ_WRITE_ARB)。

注意如果GPU仍使用此缓冲区对象,glMapBufferARB()不会返回,直到GPU完成了对相应缓冲区对象的操作。为了避免等待,在使用glMapBufferARB之前,使用glBufferDataARB,并传入参数NULL。然后,OpenGL将废弃旧的缓冲区,为缓冲区分配新的内存。

缓冲区对象必须取消映射,可使用glUnmapBufferARB()。如果成功,glUnmapBufferARB()返回GL_TRUE 否则返回GL_FALSE。

例子:Streaming Texture Uploads

例子:两个PBO的Streaming texture上传

源码下载: pboUnpack.zip.
这个例子使用PBO,上传(uppack)streaming textures到OpenGL texture object.你可以通过空格键切换不同的传送模式:单个PBO,两个PBOs ,无PBO),并对比它们之间效率的差异。

在PBO模式下,每一帧都直接将源纹理写入映射的像素缓冲区(PBO)。然后,这些纹理数据使用glTexSubImage2D()函数,从PBO传送到纹理对象中。使用PBO,OpenGL可以在PBO和纹理对象之间执行异步DMA传输。这显著提高了纹理上传的性能。如果显卡支持异步的DMA操作,glTexSubImage2D()会立即返回。CPU无需等待纹理拷贝,便可以做其它事情

可以使用多个PBO来尽可能提升streaming传输性能。 图中表示同时使用两个PBO:glTexSubImage2D()从一个PBO中读取数据,同时将源纹理写入到另一个PBO当中。

第n帧,PBO1正被glTexSubImage2D()函数使用。而PBO2用于读取新的纹理。在第n+1帧时,2个PBO交换角色,并继续更新纹理。因为DMA传输的异步性,更新和复制可被同时执行。CPU将新纹理更新到一个PBO中,同时GPU从另一个PBO中复制纹理。


// "index" 用于从PBO中拷贝像素数据至texture object// "nextIndex" 用于更新另一个PBO中的像素数据index = (index + 1) % 2;nextIndex = (index + 1) % 2;// 绑定纹理glBindTexture(GL_TEXTURE_2D, textureId);// 绑定PBOglBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pboIds[index]);// 从PBO中拷贝像素数据至texture object// 使用offset替代ponter.glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, WIDTH, HEIGHT,GL_BGRA, GL_UNSIGNED_BYTE, 0);// 绑定另一个PBO,用texture source对它进行更新glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pboIds[nextIndex]);// 注意:glMapBufferARB()会引起同步问题// 如果GPU正在使用这块buffer, glMapBufferARB()将会等待// 直到GPU完成操作. 为了避免等待,你可以先调用// glBufferDataARB() ,并传入NULL指针, 然后再调用glMapBufferARB()。// 如果按照上面的方法调用的话, PBO之前存储的数据将会被丢弃,并且// glMapBufferARB() 将会立即返回一个新分配的指针,// 即使GPU仍然在使用之前的数据glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, DATA_SIZE, 0, GL_STREAM_DRAW_ARB);// 映射buffer object(PBO)到客户端内存GLubyte* ptr = (GLubyte*)glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB,GL_WRITE_ONLY_ARB);if(ptr){// 直接更新映射的bufferupdatePixels(ptr, DATA_SIZE);glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);// release the mapped buffer}// 在使用完PBO以后,通过ID 0 来释放PBO// 一旦绑定到0,所有的像素操作都将被重置glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);

例子:异步Read-back

下载源码:pboPack.zip.这个例子从帧缓冲区(左侧图)读取像素数据到PBO中,之后在右侧窗体中画出来,并修改图像的亮度。你可以按空格键打开或关闭PBO,来测试glReadPixels()函数的性能差异。传统的glReadPixels()阻塞渲染管线,直到所有的像素传输完毕。然后,它把控制权交给程序。使用PBO的glReadPixels()可使用异步DMA传输,立即返回,无需等待。因此程序(CPU)可执行其它操作,当GPU传输数据时。Asynchronous glReadPixels() with 2 PBOs此例子使用2个PBO。在第n帧时,程序使用glReadPixels()从OpenGL读取像素信息到PBO1中,在PBO2 中处理像素数据。读数据和处理数据是同时进行的。因为glReadPixels()在PBO1上立即返回,CPU可以在PBO2中处理数据而没有延迟。我们可以在每一帧中交换PBO1和PBO2。

// "index" 用于从FBO中读取像素到PBO// "nextIndex" 用于更新另一个PBO中的像素index = (index + 1) % 2;nextIndex = (index + 1) % 2;// 设置读取的目标framebufferglReadBuffer(GL_FRONT);// 从FBO中读取像素至PBO// glReadPixels()将会立刻返回glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[index]);glReadPixels(0, 0, WIDTH, HEIGHT, GL_BGRA, GL_UNSIGNED_BYTE, 0);// 映射PBO到客户端,并通过CPU处理其数据glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[nextIndex]);GLubyte* ptr = (GLubyte*)glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB,GL_READ_ONLY_ARB);if(ptr){processPixels(ptr, ...);glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);}// 重置PBO的像素操作glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);

OpenGL深入探索——像素缓冲区对象 (PBO)相关推荐

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

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

  2. 【OpenGL ES】帧缓冲区对象FBO

    1.FBO 使用OpenGL ES,一般要通过EGL来配置本地窗口系统,关于EGL的介绍可参照"[OpenGL ES]EGL简介"http://blog.csdn.net/ieea ...

  3. 【OpenGL】蓝宝书第八章——缓冲区对象:存储尽在掌握

    前言 缓冲区对象概念允许应用程序方便地将数据从一个渲染管线移动到另一个渲染管线,以及从一个对象绑定到另一个对象,它可以在无需CPU介入情况下完成.帧缓冲区对象能真正让我们控制像素,而不受操作系统环境影 ...

  4. 像素缓冲对象(PBO)

    OpenGL pixel_buffer_object 扩展非常接近 vertex_buffer_object. 它只是扩展出 vertex_buffer_object扩展,以便不仅将顶点数据并且将像素 ...

  5. OpenGL ES 3.0(六)缓冲区对象、PBO、FBO

    缓冲区对象 创建: Gluint pixBuffObjs[1]; glGenBuffers(1, pixBuffObjs); 绑定: glBindBuffer(GL_PIXEL_PACK_BUFFER ...

  6. OPenGL中的缓冲区对象

    引自:http://blog.csdn.net/mzyang272/article/details/7655464 在许多OpenGL操作中,我们都向OpenGL发送一大块数据,例如向它传递需要处理的 ...

  7. OpenGL ES之离屏渲染的帧缓冲区对象FBO的说明和使用

    一.什么是 FBO ? FBO(Frame Buffer Object)即帧缓冲区对象,实际上是一个可添加缓冲区的容器,可以为其添加纹理或渲染缓冲区对象(RBO). FBO 本身不能用于渲染,只有添加 ...

  8. OpenGL缓冲区对象之EBO

    简介 EBO(Element Buffer Object,也叫IBO:Index Buffer Object)索引缓冲区对象,这个缓冲区主要用来存储顶点的索引信息. 考虑这样一种情况,我们需要绘制一个 ...

  9. 【OpenGL】八、初始化 OpenGL 渲染环境 ( 导入 OpenGL 头文件 | 链接 OpenGL 库 | 将窗口设置为 OpenGL 窗口 | 设置像素格式描述符 | 渲染绘制 ) ★

    文章目录 一.导入 OpenGL 的两个头文件 二.链接 OpenGL 库 三.将 Windows 桌面窗口改成 OpenGL 窗口 四.获取窗口设备 五.设置像素格式描述符 六.设置像素格式 七.创 ...

最新文章

  1. 《用Python进行自然语言处理》第3章 加工原料文本
  2. 1.26 Java使用自定义包
  3. 跟着感觉走,不要冲动入手,到真正低点在入手
  4. Spring Boot(二)应用实例
  5. 区域数据导入功能(pinyin4J使用)
  6. 飞鸽传书局域网聊天工具
  7. 手机为什么取消了内存卡?
  8. 一步一步 IText.Sharp 之 Hello Word
  9. 【作业锦集】机器人学导论-空间变换及Matlab实现(part-1)
  10. IDEA 配置log4j
  11. win10 软路由_千元完美的家用低功耗软路由:J4125 迷你电脑GK41开箱体验!又是播放器,也是服务型AIO!...
  12. 合唱队形(c++DP)
  13. 计算机函数countifs使用,countifs函数的使用方法
  14. linux 清除swap 数据,linux清除swap
  15. 等保测评中web应用防火墙怎么选择?
  16. 《Python之禅》的翻译和解释
  17. 江南游——苏州行(2)
  18. 威纶tk6070ik与台达变频器vdf-s485通讯程序 自己编写的威纶触摸屏与台达变频器的通讯
  19. VB6.0 遇到“不能加载 MSCOMCTL.ocx“ 问题处理
  20. linux支持的笔记本无线网卡,用笔记本网卡CDLINUX支持30211版,加载成功,联想E40笔记本无线网卡!!!...

热门文章

  1. 6s手机为什么不显示4g网络连接服务器,苹果iPhone6S 设置4G网络的方法
  2. SCJP认证复习——经典题库
  3. 《两种文化》——读书报告
  4. [再寄小读者之数学篇](2014-07-16 凹函数与次线性性)
  5. 题目:中国有句俗话叫“三天打渔,两天晒网”,某人从2010年1月1日期开始“三天打渔,两天晒网” 问这个人在以后的某一天是“打渔”还是“晒网”。用C或着C++语言实现程序解决问题。
  6. python processpoolexecutor_理解Python的PoolExecutor
  7. 邻接矩阵,构造有向图、无向图、有向网、无向网,深度优先、广度优先遍历(C++图)
  8. 红旗 linux 8,中科红旗Asianux Server Linux 8有何突出之处,附新功能介绍
  9. 安装.Net应用程序(如B站弹幕姬)报错:参照的程序集没有安装在系统上。 (异常来自 HRESULT:0x800736B3)
  10. 音乐播放器微信小程序