返回

以实力雄辩:“Android OpenGL 渲染图像读取”界独领风骚的解决方案

Android

OpenGL ES 2.0 和 3.0中的读取图像方式

glReadPixels()函数

glReadPixels() 是 OpenGL ES 的 API ,OpenGL ES 2.0 和 3.0 均支持。 使用非常方便,下面一行代码即可搞定,但是效率也是最低的。 当调用 glReadPixels 时,首先会影响 CPU 时钟周期,同时 GPU 会等待当前帧绘制完成,读取的像素由 glReadPixels() 在绘制操作执行结束后从帧缓冲区中读出。代码如下:

void readPixel(int x, int y, int width, int height, GLint format, GLint type, void * pixels)

通过纹理读取图像

该方法的思路与前面提到的使用glReadPixels()读取帧缓冲区的方式类似,不同之处在于使用纹理缓冲区替代帧缓冲区。使用纹理读取数据,首先必须将数据复制到一个纹理中,然后再通过纹理读取数据,可以将纹理想象成一块内存区域,而纹理对象就是一块内存空间的指针。

通过缓冲区对象读取图像

在OpenGL中,帧缓冲区不仅可以用纹理来创建,还可以使用缓冲区对象(Pixel Buffer Objects,简称PBO)来创建。PBO 是一种特殊的缓冲区,它允许 CPU 和 GPU 同时访问。 通过 PBO 读取数据,分为四个步骤:

  1. 创建一个 PBO 并绑定它。
  2. 调用 glReadPixels()将像素从帧缓冲区复制到 PBO。
  3. 将 PBO 的内容复制到系统内存。
  4. 解绑 PBO。

Android OpenGL 渲染图像读取方案比较

性能比较

下表是三种读取图像方式的性能比较。

方式 优缺点
glReadPixels() 最简单,效率最低
通过纹理读取图像 比glReadPixels()快,但需要额外的内存复制
通过缓冲区对象读取图像 速度最快,但需要额外的编程开销

内存占用比较

下表是三种读取图像方式的内存占用比较。

方式 优缺点
glReadPixels() 最少
通过纹理读取图像 比glReadPixels()多,但可以复用
通过缓冲区对象读取图像 最多,但可以复用

易用性比较

下表是三种读取图像方式的易用性比较。

方式 优缺点
glReadPixels() 最简单
通过纹理读取图像 比glReadPixels()复杂,但可以复用
通过缓冲区对象读取图像 最复杂,但可以复用

结论

从性能、内存占用和易用性三个方面综合来看,通过缓冲区对象读取图像是最优的方案。它不仅速度最快,而且内存占用最少,易用性也最好。

附录

参考资料