OpenGL 编程指南学习资料以及我整理的代码下载地址https://pan.baidu.com/s/1bqrcspD
文中提到的代码为下载文件中的“OpenGL编程指南 VS2015代码.zip”文件,代码也可以到github上下载:https://github.com/Kylewlk/OpenGL-Programming-Guide-8th-Edition-Code
11 内存
纹理存储通用数据
通过采样器texture函数可以获取纹理,获取的时候是通过纹理(u, v)坐标,u,v的范围[0, 1]之间,读取是openGL会自动选择mip,缩放,插值等等。这里纹理存储通用数据是直接操作纹理的内存,直接读取纹理某一mip的数据,使用的坐标也是int类型,范围为纹理对应的长宽。
读取存储步骤
- 通过函数glBindImageTexture将需要操作的纹理绑定到图像单元。
- 在着色器中声明图像单元,可以通过布局限定符绑定图像单元,如下:
layout (binding = 1, rgba32f) uniform image2D,
也可以通过glUniform1i设置纹理单元。
3. 通过imageStore修改数据,通过imageLoad读取数据,读取和存储时使用的坐标不应超过当前图像单元的长宽。
通过imageStore写入数据后,因为纹理的数据已经修改了,通过采样器去读取纹理也可以读取到纹理数据。
- 代码工程11.1-01ImageTex,程序先在纹理中通过imageStore存储了四个球的图像数据,然后再绘制出来,结果:
缓存对象
着色器可以读取和写入缓存对象,因为缓存对象可以自定义数据类型,而且程序也可以很容易的使用glMapBuffer操作,其比纹理内存更加灵活。
使用步骤
- 在着色器中声明缓存layout (std430, binding = 0) buffer bufferObject{}
- 创建缓存对象
- 将缓存对象通过函数glBindBufferBase绑定到缓存对象单元
- 在着色器中直接通过变量读取和写入缓存数据。
缓存对象最后一个数组变量可以不设置长度,不设置时,数组长度会自动映射绑定的缓存。
- 代码11.2-01BufferObject,结果:
原子操作和同步
原子操作与C++语言中类似,可以通过原子操作函数一步完成读取和写入的操作,防止多线程同时修改数据时造成数据异常。
同步
因为GPU渲染本身是一个高并发过程,不同于CPU中同时只有几条线程(与CPU核数有关)执行,其内部会有几百甚至上千个着色器同时执行,其同步方式也与C++有很大的不同。
栅栏Fence,可保证栅栏前的GPU都已经执行完成,使用glClientWaitSync进行等待
内存屏障memoryBarrier,可以保证修改内存后其他执行程序读取到最新的值。glMemoryBarrier可保证该函数前命令前修改的数据可以被函数后命令读取到。