为切实加强 网站建设,100人公司局域网搭建,昆明网站建设首选公司,制作地图的网站前言 本篇在讲什么 本篇为蓝宝书学习笔记 着色器存储区块 原子内存操作 内存屏障 本篇适合什么 适合初学Open的小白 本篇需要什么 对C语法有简单认知 对OpenGL有简单认知 最好是有OpenGL超级宝典蓝宝书 依赖Visual Studio编辑器 本篇的特色 具有全流程的图文教学 重… 前言 本篇在讲什么 本篇为蓝宝书学习笔记 着色器存储区块 原子内存操作 内存屏障 本篇适合什么 适合初学Open的小白 本篇需要什么 对C语法有简单认知 对OpenGL有简单认知 最好是有OpenGL超级宝典蓝宝书 依赖Visual Studio编辑器 本篇的特色 具有全流程的图文教学 重实践轻理论快速上手 提供全流程的源码内容 ★提高阅读体验★ ♠ 一级标题 ♥ 二级标题 ♣ 三级标题 ♦ 四级标题 目录♠ 着色器存储区块♥ 声明♥ 应用♥ 原子内存操作♥ 内存屏障♣ 什么是内存屏障♣ 在应用中使用屏障♣ 在着色器中使用屏障♠ 推送♠ 结语♠ 着色器存储区块
我们在上一张已经简单的认识到了uniform统一变量和一致区块这一章节我们学习一个新的着色器存储区块(shader storage block)它和uniform很像
一致性
1. 着色器存储区块和uniform都可以像着色器提供数据 2. 二者声明类似着色器区块使用限定符buffer而非uniform
优点
1. 存储区块更大几乎没有上限 2. 区别uniform着色器存储区块可以被着色器修改 3. 存储区块还支持原子内存操作
缺点
1. 由于非常灵活OpenGL难以真正优化对存储块的访问 ♥ 声明
用buffer限定符声明支持std140和std430打包限定符
layout (binding0,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 \nvoid 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 \nlayout (binding0,std430) buffer color_block \n{ \n vec4 out_color; \n}; \n \nout vec4 color; \n \nvoid 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
https://github.com/KingSun5♠ 结语
若是觉得博主的文章写的不错不妨关注一下博主点赞一下博文另博主能力有限若文中有出现什么错误的地方欢迎各位评论指摘。 本文属于原创文章转载请评论留言并在转载文章头部著名作者出处