1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > OpenGL超级宝典学习笔记:着色器存储区块 原子内存操作 内存屏障

OpenGL超级宝典学习笔记:着色器存储区块 原子内存操作 内存屏障

时间:2022-07-04 13:42:16

相关推荐

OpenGL超级宝典学习笔记:着色器存储区块 原子内存操作 内存屏障

目录

♠ 着色器存储区块♥ 声明♥ 应用♥ 原子内存操作♥ 内存屏障♣ 什么是内存屏障♣ 在应用中使用屏障♣ 在着色器中使用屏障♠ 推送♠ 结语

♠ 着色器存储区块

我们在上一张已经简单的认识到了uniform统一变量和一致区块,这一章节我们学习一个新的着色器存储区块(shader storage block),它和uniform很像

一致性

1. 着色器存储区块和uniform都可以像着色器提供数据

2. 二者声明类似,着色器区块使用限定符buffer而非uniform

优点

1. 存储区块更大,几乎没有上限

2. 区别uniform,着色器存储区块可以被着色器修改

3. 存储区块还支持原子内存操作

缺点

1. 由于非常灵活,OpenGL难以真正优化对存储块的访问

♥ 声明

buffer限定符声明,支持std140std430打包限定符

layout (binding=0,std430) buffer color_block{vec4 out_color;};

♥ 应用

绑定到缓存和使用的方式和uniform几乎一样,区别是索引使用的是GL_SHADER_STORAGE_BUFFER

我们来看一个完整的演示示例吧,很简单,我们通过区块内的变量给三角形上色

注:该例子直接修改OpenGl超级宝典官方示例singletri.cpp,只需修改startup方法即可

virtual void startup(){static const char * vs_source[] ={"#version 450 core \n""\n"" \n""void main(void) \n""{\n"" const vec4 vertices[] = vec4[](vec4( 0.25, -0.25, 0.5, 1.0), \n""vec4(-0.25, -0.25, 0.5, 1.0), \n""vec4( 0.25, 0.25, 0.5, 1.0)); \n""\n"" gl_Position = vertices[gl_VertexID];\n""}\n"};static const char * fs_source[] ={"#version 450 core \n""\n""layout (binding=0,std430) buffer color_block \n""{\n"" vec4 out_color; \n""}; \n""\n""out vec4 color; \n""\n""void main(void) \n""{\n"" color = out_color; \n""}\n"};program = glCreateProgram();GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fs, 1, fs_source, NULL);glCompileShader(fs);GLuint vs = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vs, 1, vs_source, NULL);glCompileShader(vs);glAttachShader(program, vs);glAttachShader(program, fs);glLinkProgram(program);glGenVertexArrays(1, &vao);glBindVertexArray(vao);GLfloat sColor[] = { 1.0f, 0.5f, 0.0f, 1.0f };GLuint ssbo;glGenBuffers(1, &ssbo);glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);glBufferData(GL_SHADER_STORAGE_BUFFER, 4*8, NULL, GL_DYNAMIC_COPY);glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, ssbo, 0, 4 * 8);glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, 4 * 4, sColor);}

要点1:在该片段着色器中我们声明了一个着色器存储区块color_block,其存有唯一变量out_color,该变量会作为三角形颜色被赋值,注意了这里限定符是buffer,绑定缓存的索引是GL_SHADER_STORAGE_BUFFER

要点2:自定义颜色sColor,作为数值通过glBufferSubData接口更新到了区块内,以下是最终显示效果

♥ 原子内存操作

区别去unifom的只读特性,着色器区块允许对内存进行简单的读写,这其中包括的原子操作

什么是原子操作

是一段从内存读取的序列,可能会伴随内存的写入

原子操作的作用

保证了单次数据读写的安全性

原子操作可在其他调用有机会从内存读取数据之前,就完成读取-修改-写入循环以完成一次调用

♥ 内存屏障

只读数据没有任何问题,如果伴随写入数据,可能存在风险,风险大致分为以下三种

先写后读(RAW)风险

刚写入内存后,立即读取该位置的数据,根据系统架构,读写顺序可能会被重排,进而读写到错误数据

写后写(WAW)风险

在同一内存地址连续写入数据,根据系统架构,最后一次写入并不一定是最终写入内存的值

先读后写(WAR)风险

通常发生在并行系统中,读取和写入的顺序可能被重排,读取到后被写入的数据

内存屏障就是用来处理这些内存风险的工具

♣ 什么是内存屏障

相当于一个标记,告诉OpenGL,如果准备重新排序,必须完成屏障之前发送的命令,不要先执行后边的命令

♣ 在应用中使用屏障

函数

void glMemoryBarrier(GLbitfield barriers);

参数barriers不同的值代表不同的含义,例如:

GL_SHADER_STORAGE_BARRIER_BIT

屏障执行前的所有操作(尤其是写入),一定执行在屏障调用后的数据操作之前被完成

GL_UNIFORM_BARRIER_BIT

如果我们向缓存内写入的数据,在屏障执行后作为统一变量缓存,设置该选项

GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT

OpenGL会等待向缓存写入的着色器完成,然后通过顶点属性将这些缓存作为顶点数据源

♣ 在着色器中使用屏障

我们可以直接在着色器中使用屏障

void memoryBarrier();

已执行的读写函数会在该屏障执行完成前返回

♠ 推送

Github

/KingSun5

♠ 结语

若是觉得博主的文章写的不错,不妨关注一下博主,点赞一下博文,另博主能力有限,若文中有出现什么错误的地方,欢迎各位评论指摘。

👉 本文属于原创文章,转载请评论留言,并在转载文章头部著名作者出处👈

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。