平常我们使用的Shader有顶点着色器、几何着色器、片段着色器,这几个都是为光栅化图形渲染服务的,OpenGL 4.3之后新出了一个Compute Shader,用于通用计算并行加速,现在对其进行介绍。

  

  介绍Compute Shader之前需要先介绍一下ImageTexture

    普通的Texture在GLSL中只能进行读取(sampler采样获取数据),写入则必须在Fragment Shader中写入帧缓冲绑定的附件Texture当前像素中,不能随意指定位置写入,并且不能同时读写同一张纹理(我试过不行,有博客同样说不行,应该是不行吧)。

  1、生成Texture

void WKS::ImageTexture::setupTexture() {
glGenTextures(, &this->textureID);
glBindTexture(GL_TEXTURE_2D, this->textureID);
glTexStorage2D(GL_TEXTURE_2D, , GL_RGBA32F, width, height);
// turn off filtering and wrap modes
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glBindTexture(GL_TEXTURE_2D, );
}

  注意,要是用 glTexStorage2D()生成固定大小纹理,不能使用glTexImage2D()

  2、生成ImageTexture

glBindImageTexture(, this->inputTexture, , GL_FALSE, , GL_READ_ONLY, GL_RGBA32F);

  inputTexture对应1、中生成的Texture纹理ID。第一个参数是ImageTexture绑定点,与texture纹理绑定点应该不重合。

  3、GLSL中声明

layout (rgba32f, binding = ) uniform image2D input_image;

  补充:ImageTexture底层是Texture,那么在Host上可以进行访问

    a、初始化,传入数据

void WKS::ImageTexture::Transfer2Texture(float* data) {
glBindTexture(GL_TEXTURE_2D, this->textureID);
glTexSubImage2D(GL_TEXTURE_2D, , , , width, height, GL_RGBA, GL_FLOAT, data);
}

    b、读取数据

float* WKS::Texture::GetTextureData(GLuint width, GLuint height, GLuint channels, GLuint texID) {
float* data = new float[width * height * channels];
glBindTexture(GL_TEXTURE_2D, texID);
if(channels==) glGetTexImage(GL_TEXTURE_2D, , GL_RED, GL_FLOAT, data);
if(channels==) glGetTexImage(GL_TEXTURE_2D, , GL_RGB, GL_FLOAT, data);
if (channels == ) glGetTexImage(GL_TEXTURE_2D, , GL_RGBA, GL_FLOAT, data);
glBindTexture(GL_TEXTURE_2D, );
return data;
}

  现在来介绍Compute Shader

#version  core
layout (local_size_x=, local_size_y=) in; uniform float v[]; layout (rgba32f, binding = ) uniform image2D input_image;
layout (rgba32f, binding = ) uniform image2D output_image; shared vec4 mat_shared[][]; void main(void)
{
ivec2 pos=ivec2(gl_GlobalInvocationID.xy);
mat_shared[pos.x][pos.y]=imageLoad(input_image,pos);
barrier();
vec4 data=mat_shared[pos.x][pos.y];
data.r=v[]+data.r;
data.g=v[]+data.g;
data.b=v[]+data.b;
data.a=v[]+data.a;
imageStore(output_image,pos.xy,data);
}

  

  计算由一个一个计算单元完成,layout (local_size_x=16, local_size_y=16) in; 是表示本地工作组的由16*16的计算单元组成,本地工作组可以共享Shadered变量。
  多个本地工作组构成全局工作组,由:
glDispatchCompute(, , );

  启动计算,参数表示全局工作组的维度(以本地工作组为单位),(1,1,1)表示只有一个本地工作组。

  注意:Compute Shader 只有一个阶段(渲染一般是vertex+fragment 2个阶段),编译类型选择GL_COMPUTE_SHADER

Shader(const char* computePath) :programId()
{
std::vector<ShaderFile> fileVec;
fileVec.push_back(ShaderFile(GL_COMPUTE_SHADER, computePath));
loadFromFile(fileVec);
}

  

  示例:

  对一个4*4的vec4矩阵的所有元素加上vec4(0, 0.1,0.2,0.3)

  初始化:

void SceneRendering::setupAddData() {
int num = * * ;
this->inputData = new float[num];
for (int i = ; i < num; i++) inputData[i] = i;
for (int i = ; i < ; i++) v[i] = i*0.1f;
shader_add = new Shader("./Shader/add.comp");
WKS::ImageTexture* texturePtr = new WKS::ImageTexture(, );
this->inputTexture = texturePtr->GetTextureID();
this->outputTexture = (new WKS::ImageTexture(, ))->GetTextureID();
texturePtr->Transfer2Texture(inputData);
}

  调用Compute Shader:

void SceneRendering::performCompute() {
this->shader_add->use();
this->shader_add->setVecN("v", , v);
glBindImageTexture(, this->inputTexture, , GL_FALSE, , GL_READ_ONLY, GL_RGBA32F);
glBindImageTexture(, this->outputTexture, , GL_FALSE, , GL_WRITE_ONLY, GL_RGBA32F);
glDispatchCompute(, , );
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
glFinish();
}

  主函数调用,结果输出:

   glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 我们现在不使用模板缓冲//Compute Shader
this->performCompute();
float* data = WKS::Texture::GetTextureData(, , , this->outputTexture);
int index = ;
for (int i = ; i < ; i++) {
for (int j = ; j < ; j++) {
std::cout << "(" <<data[index]<<","<<data[index+]<<","<<data[index+]<<","<<data[index+]<< ")" << " ";
index += ;
}
std::cout << std::endl;
}
std::cout<< std::endl;
free(data);

  图片:

  

  

  

OpenGL 之 Compute Shader(通用计算并行加速)的更多相关文章

  1. 使用Compute Shader加速Irradiance Environment Map的计算

    Irradiance Environment Map基本原理 Irradiance Environment Map(也叫Irradiance Map或Diffuse Environment Map), ...

  2. OpenGL Compute Shader靠谱例子及读取二进制Shader,SPIR-V

    学OpenGL以来一直苦恼没有像DX那样可以读取二进制Shader使用的方法,除去有时不想公开自己写的牛逼Shader的心理(虽然目前还从没写过什么牛逼的Shader), 主要是不用现场编译,加快读取 ...

  3. Compute Shader基础

    ComputeShader:     GPGPU:General Purpose GPU Programming,GPU通用计算,利用GPU的并行特性.大量并行无序数据的少分支逻辑适合GPGPU.平台 ...

  4. 【原创翻译】初识Unity中的Compute Shader

    一直以来都想试着自己翻译一些东西,现在发现翻译真的很不容易,如果你直接把作者的原文按照英文的思维翻译过来,你会发现中国人读起来很是别扭,但是如果你想完全利用中国人的语言方式来翻译,又怕自己理解的不到位 ...

  5. 聊聊如何正确向Compute Shader传递数组

    0x00 前言 前一段时间去英国出差,发现Unity Brighton 办公室的手绘地图墙很漂亮,在这里分享给大家. 在这篇文章中,我们选择了过去几周Unity官方社区交流群以及UUG社区群中比较有代 ...

  6. Vulkan在Android使用Compute shader

    oeip 相关功能只能运行在window平台,想移植到android平台,暂时选择vulkan做为图像处理,主要一是里面有单独的计算管线且支持好,二是熟悉下最新的渲染技术思路. 这个 demo(git ...

  7. Compute Shader

    [Compute Shader] 1.Similar to regular shaders, compute shaders are Asset files in your project, with ...

  8. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十三章:计算着色器(The Compute Shader)

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十三章:计算着色器(The Compute Shader) 代码工程 ...

  9. OpenGL进行简单的通用计算实例

    博主作为OpenGL新手,最近要用OpenGL进行并行的数据计算,突然发现这样的资料还是很少的,大部分资料和参考书都是讲用OpenGL进行渲染的.好不容易找到一本书<GPGPU编程技术,从Ope ...

随机推荐

  1. 【Python3网络爬虫开发实战】 分析Ajax爬取今日头条街拍美图

    前言本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理.作者:haoxuan10 本节中,我们以今日头条为例来尝试通过分析Ajax请求 ...

  2. jquery (内置遍历数组的函数,事件)

    内置遍历数组的函数: 1. $.map(array, function() { }); 取到数组或者对象array中每一项进行遍历  然后在function中处理: var attr = [1,2,3 ...

  3. C++构造函数的几种使用方法

    在C++中,有一种特殊的成员函数,他的名字和类相同,没有返回值,不需要用户显示调用,用户也无法调用,而是在创建对象的时候自动执行. 这种特殊的函数就是构造函数 Constructor 构造函数的名字与 ...

  4. Ubuntu 18.04 美化配置

    网上很多关于Ubuntu 18.04 美化的配置,但每个人遇见的问题都有些不太一样, 现将本人配置的过程整理如下 更新源为阿里云 找到Software & Updates,将源更新为阿里云的源 ...

  5. 使用 Vue + TypeScript 时项目中常用的装饰器

    目录 一.@Component 装饰器 1)父组件 2)子组件 二. @Emit 装饰器 1)父组件 2)子组件 三. @Model 装饰器 1)父组件 2)子组件 四. @Prop 装饰器 1)父组 ...

  6. 《Java基础知识》Java内部类及其实例化

    在 Java 中,允许在一个类(或方法.语句块)的内部定义另一个类,称为内部类(Inner Class),有时也称为嵌套类(Nested Class). 内部类和外层封装它的类之间存在逻辑上的所属关系 ...

  7. Python—执行系统命令的四种方法

    一.os.system方法 这个方法是直接调用标准C的system() 函数,仅仅在一个子终端运行系统命令,而不能获取命令执行后的返回信息. os.system(cmd)的返回值.如果执行成功,那么会 ...

  8. 软件开发工具(第11章:Eclipse CDT开发常用功能)

    一.自定义编辑器 C/C++首选项设置(重点.记忆.应用) 单击菜单栏中的窗口(Window)菜单, 选择首选项(Preferences)选项,在 弹出的对话框左侧部分,展开C/C++树 形菜单. 外 ...

  9. jQuery使用工具集

    //jq-util.js$.extend({ Util:{ /* 浏览器 */ browser:{ IE: !!document.all, IE6: !!document.all && ...

  10. 想精通分布式以及高并发架构?那你得先搞定ZooKeeper架构原理!

    Zookeeper是分布式一致性问题的工业解决方案,是Apache Hadoop下解决分布式一致性的一个组件,后被分离出来成为Apache的顶级项目. 工程来源:是雅虎公司内部项目,据说雅虎内部很多项 ...