OpenGLES读写图像数据(内存与GPU)——使用PBO

news2024/9/21 1:37:53

一、什么是PBO

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

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

PBO(像素缓冲区对象) 类似于 VBO(顶点缓冲区对象),PBO 开辟的也是 GPU 缓存,而存储的是图像像素数据。
在这里插入图片描述

二、PBO的优势

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

PBO 类似于“以空间换时间”策略,在仅使用一个 PBO 的情况下,性能无法有效地提升,一般需要多个 PBO 交替配合使用。

不使用PBO加载纹理的情况:

在这里插入图片描述

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

使用PBO加载纹理的情况:

在这里插入图片描述

  • 如上图,内存中管的图像数据可以直接加载到 PBO 中,这个操作是由 CPU 控制。我们可以通过 glMapBufferRange 获取 PBO 对应 GPU 缓冲区的内存地址。

  • 将图像数据加载到 PBO 后,再将图像数据从 PBO 传输到纹理对象中完全是由 GPU 控制,不会占用 CPU 时钟周期。所以,绑定 PBO 后,执行 glTexImage2D (将图像数据从 PBO 传输到纹理对象) 操作,CPU 无需等待,可以立即返回。

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

三、如何使用PBO

1.创建PBO

PBO 的创建和初始化类似于 VBO ,以上示例表示创建 PBO ,并申请大小为 imgByteSize 的缓冲区。绑定为 GL_PIXEL_UNPACK_BUFFER 表示该 PBO 用于将像素数据从程序传送到 OpenGL 中;绑定为 GL_PIXEL_PACK_BUFFER 表示该 PBO 用于从 OpenGL 中读回像素数据。

int imgByteSize = m_Image.width * m_Image.height * 4;//RGBA格式

glGenBuffers(1, &uploadPboId);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboId);
glBufferData(GL_PIXEL_UNPACK_BUFFER, imgByteSize, 0, GL_STREAM_DRAW);

glGenBuffers(1, &downloadPboId);
glBindBuffer(GL_PIXEL_PACK_BUFFER, downloadPboId);
glBufferData(GL_PIXEL_PACK_BUFFER, imgByteSize, 0, GL_STREAM_DRAW);

2.使用多个PBO读写图像数据

从上面内容我们知道,加载图像数据到纹理对象时,CPU 负责将图像数据拷贝到 PBO ,而 GPU 负责将图像数据从 PBO 传送到纹理对象。因此,当我们使用多个 PBO 时,通过交换 PBO 的方式进行拷贝和传送,可以实现这两步操作同时进行。

①使用两个 PBO 加载图像数据到纹理对象的过程:

在这里插入图片描述

  • 如图所示,利用 2 个 PBO 加载图像数据到纹理对象,使用 glTexSubImage2D 通知 GPU 将图像数据从 PBO1 传送到纹理对象,同时 CPU 将新的图像数据复制到 PBO2 中。
int dataSize = m_RenderImage.width * m_RenderImage.height * 4;

//使用 `glTexSubImage2D` 将图像数据从 PBO1 传送到纹理对象
int index = m_FrameIndex % 2;
int nextIndex = (index + 1) % 2;

BEGIN_TIME("PBOSample::UploadPixels Copy Pixels from PBO to Textrure Obj")
glBindTexture(GL_TEXTURE_2D, m_ImageTextureId);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_UploadPboIds[index]);
//调用 glTexSubImage2D 后立即返回,不影响 CPU 时钟周期
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_RenderImage.width, m_RenderImage.height, GL_RGBA, GL_UNSIGNED_BYTE, 0);
END_TIME("PBOSample::UploadPixels Copy Pixels from PBO to Textrure Obj")

//更新图像数据,复制到 PBO 中
BEGIN_TIME("PBOSample::UploadPixels Update Image data")
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_UploadPboIds[nextIndex]);
glBufferData(GL_PIXEL_UNPACK_BUFFER, dataSize, nullptr, GL_STREAM_DRAW);
GLubyte *bufPtr = (GLubyte *) glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0,
                                               dataSize,
                                               GL_MAP_WRITE_BIT |
                                               GL_MAP_INVALIDATE_BUFFER_BIT);

LOGCATE("PBOSample::UploadPixels bufPtr=%p",bufPtr);
if(bufPtr)
{
    memcpy(bufPtr, m_RenderImage.ppPlane[0], static_cast<size_t>(dataSize));

    //update image data
    int randomRow = rand() % (m_RenderImage.height - 5);
    memset(bufPtr + randomRow * m_RenderImage.width * 4, 188,
    static_cast<size_t>(m_RenderImage.width * 4 * 5));
    glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
END_TIME("PBOSample::UploadPixels Update Image data")

②使用两个 PBO 从帧缓冲区读回图像数据的过程:

在这里插入图片描述

  • 如图所示,利用 2 个 PBO 从帧缓冲区读回图像数据,使用 glReadPixels 通知 GPU 将图像数据从帧缓冲区读回到 PBO1 中,同时 CPU 可以直接处理 PBO2 中的图像数据
//交换 PBO
int index = m_FrameIndex % 2;
int nextIndex = (index + 1) % 2;

//将图像数据从帧缓冲区读回到 PBO 中
BEGIN_TIME("DownloadPixels glReadPixels with PBO")
glBindBuffer(GL_PIXEL_PACK_BUFFER, m_DownloadPboIds[index]);
glReadPixels(0, 0, m_RenderImage.width, m_RenderImage.height, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
END_TIME("DownloadPixels glReadPixels with PBO")

// glMapBufferRange 获取 PBO 缓冲区指针
BEGIN_TIME("DownloadPixels PBO glMapBufferRange")
glBindBuffer(GL_PIXEL_PACK_BUFFER, m_DownloadPboIds[nextIndex]);
GLubyte *bufPtr = static_cast<GLubyte *>(glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0,
                                                       dataSize,
                                                       GL_MAP_READ_BIT));
if (bufPtr) {
    nativeImage.ppPlane[0] = bufPtr;
    //NativeImageUtil::DumpNativeImage(&nativeImage, "/sdcard/DCIM", "PBO");
    glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
}
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
END_TIME("DownloadPixels PBO glMapBufferRange")

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/548003.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

iOS开发提效cocoapods插件cocoapods-util

cocoapods-util介绍 cocoapods-util是一个iOS开发提效的cocoapods插件。 取名util的原因是我想做一个通用的插件&#xff0c;把一些iOS中常用的命令或问题整理起来。 插件中除了package命令是根据cocoapods-packager插件做了修改而来&#xff0c;其余命令都是属于自己总结开…

uwb高精度定位系统源码 UWB高精度定位技术原理与实现

uwb高精度定位系统 UWB高精度定位技术原理与实现 近些年物联网产业高速发展&#xff0c;越来越多的物联网终端连上了网络&#xff0c;实现了人与物&#xff0c;甚至物与物之间的互连互通。随着智能化要求的进一步提高和物联网应用的进一步拓展&#xff0c;除了互联互通&#x…

Doxygen源码分析:doxygen执行过程的拆解

Doxygen源码分析&#xff1a;doxygen执行过程的拆解 2023-05-19 23:09:17 ~ 2023-05-20 16:38:13 ChrisZZ imzhuofoxmailcom Hompage https://github.com/zchrissirhcz 文章目录 Doxygen源码分析&#xff1a;doxygen执行过程的拆解1. doxygen 版本2. doxygen 可执行程序的入口…

System V方案 — 共享内存

目录 System V方案 — 详述共享内存共享内存共享内存的原理共享内存数据结构共享内存函数实例 消息队列消息队列数据结构消息队列函数创建删除 信号量信号量数据结构信号量函数创建删除 进程互斥 总结 System V方案 — 详述共享内存 SystemV标准的进程间通信方式&#xff0c;是…

【react 全家桶】react-Hook(上)

本人大二学生一枚&#xff0c;热爱前端&#xff0c;欢迎来交流学习哦&#xff0c;一起来学习吧。 <专栏推荐> &#x1f525;&#xff1a;js专栏 &#x1f525;&#xff1a;vue专栏 &#x1f525;&#xff1a;react专栏 文章目录 14【react-Hook &#xff08;上&#x…

计算机网络基础知识(六)—— 什么是HTTP协议?你听我说

文章目录 01 | 基本概念02 | 工作原理 && 特点03 | URI && URL04 | 消息结构05 | 请求方法06 | http响应头信息07 | 状态码08 | HTTP的常见安全机制09 | HTTP的缓存机制10 | HTTP/2 && HTTP/3新特性11 | 面试中常见问题 超文本传输协议&#xff08;Hyp…

【前端知识】Cookie, Session,Token和JWT的发展及区别(四)

【前端知识】Cookie, Session,Token和JWT的发展及区别&#xff08;四&#xff09; 9. JWT9.1 JWT的背景及定义&#xff08;1&#xff09;JWT的字面理解&#xff08;2&#xff09;JWT与传统Token的区别 9.2 JWT的组成&#xff08;1&#xff09; Header&#xff08;头部&#xff…

【UDS】诊断故障代码老化机制

文章目录 简介相关术语1. 老化计数器 Ageing counter2. 诊断故障代码已老去 DTC aged3. 已老去计数器 Aged counter4. 操作循环 Operation cycle5. 诊断故障代码老化机制 DTC aging mechanism 总结 ->返回总目录<- 简介 诊断故障代码&#xff08;DTC&#xff09;一旦生…

【IDEA使用指南】使用Hibernate框架的Java项目,如何找到并打开 “Import Database Schema”窗口?

【IDEA使用指南】使用Hibernate框架的Java项目&#xff0c;如何找到并打开 “Import Database Schema”窗口&#xff1f; 背景&#xff1a; 使用 Hibernate 框架时&#xff0c;假如在 “Import Database Schema” 窗口&#xff08;如下图所示&#xff09;时&#xff0c;点击了…

day06_Java中的流程控制语句

流程控制 简单来讲所谓流程就是完成一件事情的多个步骤组合起来就叫做一个流程。在一个程序执行的过程中&#xff0c;各条语句的执行顺序对程序的结果是有直接影响的。我们必须清楚每条语句的执行流程。而且&#xff0c;很多时候要通过控制语句的执行顺序来实现我们想要的功能…

.Net6 使用aspose.cells23.5.0破译

一、测试代码 internal class Program { static void Main(string[] args) { WorkbookDesigner wb new WorkbookDesigner(new Workbook()); var style new CellsFactory().CreateStyle(); style.Borders.SetColor(C…

路径规划算法:基于缎蓝园丁鸟算法的路径规划算法- 附代码

路径规划算法&#xff1a;基于缎蓝园丁鸟优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于缎蓝园丁鸟优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能…

交换式以太网的诞生

电路交换&#xff0c;终端(电话)独占端线路自然而然&#xff0c;天经地义&#xff0c;可计算机收发的是数据包(即数据分组)&#xff0c;当多台终端接入到同一个共享介质的网络&#xff0c;所有终端可 “同时” 收发数据&#xff0c;一起统计复用网络&#xff0c;多台终端如何协…

Linux常用命令——htop命令

在线Linux命令查询工具 htop [非内部命令]一个互动的进程查看器&#xff0c;可以动态观察系统进程状况。 补充说明 htop命令 是Linux系统中的一个互动的进程查看器&#xff0c;一个文本模式的应用程序(在控制台或者X终端中)&#xff0c;需要ncurses。 与Linux传统的top相比…

【5.20】五、安全测试——概念与漏洞

目录 5.1 安全测试概述 5.1.1 什么是安全测试 5.1.2 安全测试的基本原则 5.2 常见的安全漏洞 5.2.1 SQL注入 5.2.2 XSS跨站脚本攻击 5.2.3 CSRF攻击 软件安全测试是软件测试的重要研究领域&#xff0c;它是保证软件能够安全使用的最主要手段&#xff0c;做好软件安全测试…

pg事务:multixact

什么是multixact&#xff1f; 在对同一行加锁时&#xff0c;元组上关联的事务ID可能有多个&#xff0c;pg将多个事务ID组合起来用一个MultiXactID来管理。TransactionId和MultiXactID是多对一的关系 multixactID跟TransactionId一样&#xff0c;也是32位&#xff0c;同样有wra…

Seata AT 模式理论学习及部分源码解析 | Spring Cloud 52

理论部分来自Seata官网&#xff1a;http://seata.io/zh-cn/docs/dev/mode/at-mode.html 一、前提 基于支持本地 ACID 事务的关系型数据库。Java 应用&#xff0c;通过 JDBC 访问数据库。 二、整体机制 两阶段提交协议的演变&#xff1a; 一阶段&#xff1a;业务数据和回滚日…

【SpringCloud组件——Ribbon(负载均衡)】

一、Ribbon主要作用在哪一环节&#xff1f; 流程讲解&#xff1a; 案例依然采用Eureka章节提供的案例&#xff0c;orderService根据服务名称发起请求&#xff0c;请求传达至Ribbon&#xff0c;此时Ribbon从Eureka中心拉取userService服务列表&#xff0c;Ribbon根据负载均衡算法…

组合预测模型 | ARIMA-WOA-CNN-LSTM时间序列预测(Python)

组合预测模型 | ARIMA-WOA-CNN-LSTM时间序列预测&#xff08;Python&#xff09; 目录 组合预测模型 | ARIMA-WOA-CNN-LSTM时间序列预测&#xff08;Python&#xff09;预测结果基本介绍程序设计参考资料 预测结果 基本介绍 ARIMA-WOA-CNN-LSTM是一种结合了传统时间序列模型和深…