用OpenGL的Image特性实现纹理数据的直接读写操作

时间:2025-02-20 07:42:37

OpenGL的Image特性简介

Image是在OpenGL 4.2成为core标准的,大概目标是用于通用计算,因此它只能在Compute Shader和Fragment Shader里使用。它跟一个特定的纹理绑定在一起,所进行的操作会直接影响这个纹理。
纹理在glsl里是sampler,是只能读不能写的,以前要实现通用计算的数据输出,就得建一个FBO,绑定一张跟源纹理一样大的新纹理,把计算结果画上去。这样的绘制有其局限性,比方说读取数据可以用纹理坐标指定,但是写入数据的位置却是不能任意指定的,只能是当前绘制的像素,在许多方面有其不便之处。
Image的引入就使得事情变得比较简单了。Image绑定的纹理可以直接指定Image坐标写入,使得更为复杂的操作成为可能。不过由于坐标可以任意指定,就可能出现两组数据同时指定同一个坐标的可能,造成访问冲突。因此Image还有一个Atomic操作的机制用于解决访问冲突。
Compute Shader由于其特殊性,不会对当前的Color Buffer进行任何写入,因此数据的输出必然要借助Image,大概这是Image出现的一个最重要的原因吧。

Image的使用

OpenGL环境端

Image定义

首先一张纹理是必须的。纹理生成之后,使用glBindImageTexture命令来建立一个Image。原型如下:

void glBindImageTexture​(GLuint unit​, GLuint texture​, GLint level​, GLboolean layered​, GLint layer​, GLenum access​, GLenum format​)

这里有几个重要参数。
其中要重点注意的是unit,这个参数可以看成是Image的编号。Wiki里说只有Compute Shader和Fragment Shader支持非零个Image Unit,意思就是只有这两个Shader才能用Image的意思了吧。具体支持几个可以用GL_MAX_*_IMAGE_UNIFORMS来查询,星号指的是Shader。一般而言,编号从0开始呗,至少能用8个,一般也够了吧。
另外一个就是access,有GL_READ_ONLY