OpenGL Pixel Buffer Object (PBO)

Overview

OpenGL pixel_buffer_object 扩展非常接近 vertex_buffer_object。它只是扩展出 vertex_buffer_object扩展,以便不仅将顶点数据并且将像素数据也存储到缓冲区对象中。这种存储像素数据的缓冲对象称为像素缓冲对象(PBO)。 pixel_buffer_object扩展借用了所有 VBO 框架和 API,此外还添加了 2 个额外的“target”令牌。这些令牌协助 PBO 内存管理器(OpenGL 驱动程序)确定缓冲对象的最佳位置;系统内存、共享内存或显存。此外,target令牌定义了绑定的 PBO 将用于 2 个不同的操作:GL_PIXEL_PACK_BUFFER 将像素数据传输到 PBO,或 GL_PIXEL_UNPACK_BUFFER将像素数据从 PBO 传输。

例如,glReadPixels()glGetTexImage() 是“pack”像素操作,而 glDrawPixels()glTexImage2D()glTexSubImage2D() 是“unpack”操作。当 PBO 与 GL_PIXEL_PACK_BUFFER 令牌绑定时,glReadPixels()从 OpenGL 帧缓冲区读取像素数据并将数据写入(打包)到 PBO。当 PBO 与 GL_PIXEL_UNPACK_BUFFER 令牌绑定时,glDrawPixels()从 PBO 读取(解包)像素数据并将它们复制到 OpenGL 帧缓冲区。

PBO 的主要优点是通过 DMA(直接内存访问)与图形卡进行快速像素数据传输,而无需占用 CPU 周期。而且,PBO 的另一个优点是异步 DMA 传输。

让我们将传统的纹理传输方法与使用像素缓冲区对象进行比较。下图左侧是从图像源(图像文件或视频流)加载纹理数据的常规方式。材质源首先加载到系统内存中,然后使用 glTexImage2D() 从系统内存复制到 OpenGL 纹理对象。这 2 个传输过程(加载和复制)都由 CPU 执行。

相反,在右侧图中,图像源可以直接加载到 PBO 中,该 PBO 由 OpenGL 控制。 CPU 仍然涉及将源加载到 PBO,但不会将像素数据从 PBO 传输到纹理对象。相反,GPU(OpenGL 驱动程序)管理将数据从 PBO 复制到纹理对象。这意味着 OpenGL 在不浪费 CPU 周期的情况下执行 DMA 传输操作。此外,OpenGL 可以安排异步 DMA 传输以供以后执行。因此,`glTexImage2D()` 立即返回,CPU 可以执行其他操作而无需等待像素传输完成。

有两种主要的 PBO 方法可以提高像素数据传输的性能:流式纹理更新(streaming texture update)和从帧缓冲区异步回读(asynchronous read_back from the framebuffer)。

Creating PBO

如前所述,Pixel Buffer Object 借用了Vertex Buffer Object 的所有 API。唯一的区别是 PBO 有 2 个额外的令牌:GL_PIXEL_PACK_BUFFERGL_PIXEL_UNPACK_BUFFER

GL_PIXEL_PACK_BUFFER 用于将像素数据从 OpenGL 传输到您的应用程序,而 GL_PIXEL_UNPACK_BUFFER表示将像素数据从应用程序传输到 OpenGL。OpenGL 参考这些标记来确定 PBO 的最佳内存空间,例如,用于上传(unpacking)纹理的显存,或用于读取(pack)帧缓冲区的系统内存。但是,这些目标标记只是举例。 具体实现时OpenGL 驱动程序为您决定合适的位置。

Creating a PBO requires 3 steps:

  1. 使用glGenBuffers()生成一个新的缓冲区对象。
  2. 使用 glBindBuffer()绑定缓冲区对象。
  3. 使用 glBufferData()将像素数据复制到缓冲区对象。

如果在glBufferData() 中指定指向源数组的为 NULL 指针,则 PBO 仅分配具有给定数据大小的内存空间。 glBufferData() 的最后一个参数是 PBO 的另一个性能提示,用于提供如何使用缓冲区对象。

GL_STREAM_DRAW用于流式纹理上传,GL_STREAM_READ 用于异步帧缓冲区回读。

请查看 VBO文档 以获取更多详细信息。

Mapping PBO

PBO 提供了一种内存映射机制,将OpenGL 控制的缓冲区对象映射到客户端的内存地址空间。因此,客户端可以使用glMapBuffer()glUnmapBuffer()修改缓冲区对象的一部分或整个缓冲区。

void* glMapBuffer(GLenum target, GLenum access)GLboolean glUnmapBuffer(GLenum target)

如果映射成功,glMapBuffer()将返回指向缓冲区对象的指针。否则返回NULL。target参数是 GL_PIXEL_PACK_BUFFERGL_PIXEL_UNPACK_BUFFER。第二个参数,access 指定如何处理映射的缓冲区;从 PBO 读取数据 (GL_READ_ONLY),将数据写入 PBO (GL_WRITE_ONLY),或两者 (GL_READ_WRITE)。

如果 GPU 仍在使用缓冲区对象,则 glMapBuffer() 将不会返回,直到 GPU 使用相应的缓冲区对象完成其工作。为了避免这种停顿(等待),请在 glMapBuffer() 之前使用 NULL 指针调用 glBufferData()。然后,OpenGL 将丢弃旧缓冲区,并为缓冲区对象分配新的内存空间。

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

Others

为了最大化流传输性能,您可以使用多个像素缓冲区对象。该图显示同时使用 2 个 PBO; glTexSubImage2D()从 PBO 复制像素数据,同时将纹理源写入另一个 PBO。对于第 n 帧,PBO 1 用于 glTexSubImage2D(),PBO 2 用于获取新的纹理源。对于第 n+1 帧,2 个像素缓冲区正在切换角色并继续更新纹理。由于异步 DMA 传输,更新和复制过程可以同时执行。 CPU 将纹理源更新到 PBO,而 GPU 从另一个 PBO 复制纹理。

传统的 glReadPixels() 会阻塞管道并等待所有像素数据传输完毕。然后,它将控制权返回给应用程序。相反,带有 PBO 的 glReadPixels() 可以调度异步 DMA 传输并立即返回而不会停顿。因此,应用程序 (CPU) 可以立即执行其他进程,同时通过 OpenGL (GPU) 使用 DMA 传输数据。此演示使用 2 个像素缓冲区。在第 n 帧,应用程序使用 glReadPixels() 将像素数据从 OpenGL 帧缓冲区读取到 PBO 1,并在 PBO 2 中处理像素数据。这些读取和处理可以同时执行,因为 glReadPixels() 到 PBO 1 立即返回,CPU 立即开始处理 PBO 2 中的数据。并且,我们在每一帧上在 PBO 1 和 PBO 2 之间交替。

OpenGL PBO学习相关推荐

  1. opengl基础学习专题 (二) 点直线和多边形

    题外话 随着学习的增长,越来越觉得自己很水.关于上一篇博文中推荐用一个 学习opengl的 基于VS2015的 simplec框架.存在 一些问题. 1.这个框架基于VS 的Debug 模式下,没有考 ...

  2. OpenGL开发学习指南二(glfw+glad)

    在上一篇文章中博主介绍了freeglut+glew的环境配置,本文介绍glfw+glad的环境配置 本系列教程将使用本文的opengl开发库 开发工具 VS2017 glfw源码:源码地址 CMake ...

  3. 【eoe特刊】第二十七期 OpenGL ES学习及项目解析

    经过一个月征稿.编辑,新的一版特刊终于出炉了. 本次特刊的制作,改变以往的制作方式,完全取自网友的独自的风格. 在只有一个主题的前提下,完全是通过社区的热心的网友,根据自己的想法,自行设计,自由发挥, ...

  4. OpenGL入门学习[二] 绘制简单的几何图形

    OpenGL入门学习[二] 本次课程所要讲的是绘制简单的几何图形,在实际绘制之前,让我们先熟悉一些概念. 一.点.直线和多边形 我们知道数学(具体的说,是几何学)中有点.直线和多边形的概念,但这些概念 ...

  5. OpenGL 开始学习指南

    近期需要做一个涌潮的预报与仿真模拟,为了使模型更具有真实感,且逼真,使用起来更灵活.感觉还是得从基础的OpenGL学习.鉴于Direct3D技术存在的众多不确定性,且评论不太好的原因,决定用OpenG ...

  6. 最全面的openGL 入门学习

    自己在找openGL学习资料的时候,找到此篇openGL入门学习(虽然不是移动开发,但给我提供了非常好的思路),所以转一下让更多人知道,本文来自http://www.cppblog.com/doing ...

  7. Android OpenGL ES 学习(十一) –渲染YUV视频以及视频抖音特效

    OpenGL 学习教程 Android OpenGL ES 学习(一) – 基本概念 Android OpenGL ES 学习(二) – 图形渲染管线和GLSL Android OpenGL ES 学 ...

  8. OpenGL入门学习 (转)

    OpenGL入门学习 (转) 说起编程作图,大概还有很多人想起TC的#include <graphics.h>吧? 但是各位是否想过,那些画面绚丽的PC游戏是如何编写出来的?就靠TC那可怜 ...

  9. OpenGL入门学习[三]

    OpenGL入门学习[三] http://xiaxveliang.blog.163.com/blog/static/2970803420126246501930/ OpenGL入门学习[十一] 我们在 ...

最新文章

  1. 如何更改PostgreSQL用户密码?
  2. Python基础----python的使用(二)
  3. 最大整数(Noip1998连接多位数)
  4. mysql cluster 设置单向复制_mysql5.6做单向主从复制Replication
  5. 模板方法(钩子函数)设计模式
  6. @ComponentScan.Filter type的类型
  7. java访问数据库方式_java数据库访问(二)—JDBC方式(配合连接池)
  8. java 1.8环境变量_java1.8安装及环境变量配置教程
  9. 《编码规范和测试方法——C/C++版》作业 ·006——设计模式 · 模板方法
  10. git21天打卡-day8 本地分支push到远程服务器
  11. HTML技巧篇——禁止网页元素被右击、拖动、选中、复制
  12. 双料大奖 | 奇点云获评「年度数字化创新最佳实践奖」「年度数字化服务最值得信赖品牌奖」
  13. long tail(长尾理论)
  14. IP协议详解【IP报文头部结构、IP分片、IP路由、IP转发】
  15. Linux下rsh服务配置
  16. SGD(随机梯度下降)
  17. 多校区网络直播系统解决方案
  18. 关于“知识共享”的几个基本概念
  19. JavaWeb(9) I18N国际化
  20. 编程中的心流模式flow

热门文章

  1. 外卖O2O硝烟初起巨头们各自是啥思路?
  2. Ceph用户:中国用户统计表(2018年度)
  3. 小花梨的字符串 ——java 美登杯
  4. 【电子电路基础实验】LED点阵(上--硬件部分)
  5. 【并行计算-CUDA开发】GPU 的硬体架构
  6. 网上看到一个提供WebService的地方,如果作webService测试,不妨试试
  7. 开源的Linux QQ
  8. 网络安全等级保护备案申请指南(杭州)
  9. Connection to node -1 (/ip:9092) could not be established. Broker may not be available.
  10. 华为机试——翻译电话号码