OpenGL 之 Compute Shader(通用计算并行加速)

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

  

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

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

  1、生成Texture

void WKS::ImageTexture::setupTexture() {
    glGenTextures(1, &this->textureID);
    glBindTexture(GL_TEXTURE_2D, this->textureID);
    glTexStorage2D(GL_TEXTURE_2D, 1, 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, 0);
}

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

  2、生成ImageTexture

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

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

  3、GLSL中声明

layout (rgba32f, binding = 0) uniform image2D input_image;

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

    a、初始化,传入数据

void WKS::ImageTexture::Transfer2Texture(float* data) {
    glBindTexture(GL_TEXTURE_2D, this->textureID);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 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==1)    glGetTexImage(GL_TEXTURE_2D, 0, GL_RED, GL_FLOAT, data);
    if(channels==3) glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_FLOAT, data);
    if (channels == 4) glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, data);
    glBindTexture(GL_TEXTURE_2D, 0);
    return data;
}

  现在来介绍Compute Shader

#version 430 core
layout (local_size_x=16, local_size_y=16) in;

uniform float v[4];

layout (rgba32f, binding = 0) uniform image2D input_image;
layout (rgba32f, binding = 1) uniform image2D output_image;

shared vec4 mat_shared[16][16];

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[0]+data.r;
    data.g=v[1]+data.g;
    data.b=v[2]+data.b;
    data.a=v[3]+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);

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

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

Shader(const char* computePath) :programId(0)
    {
        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 = 4 * 4 * 4;
    this->inputData = new float[num];
    for (int i = 0; i < num; i++) inputData[i] = i;
    for (int i = 0; i < 4; i++) v[i] = i*0.1f;
    shader_add = new Shader("./Shader/add.comp");
    WKS::ImageTexture* texturePtr = new WKS::ImageTexture(4, 4);
    this->inputTexture = texturePtr->GetTextureID();
    this->outputTexture = (new WKS::ImageTexture(4, 4))->GetTextureID();
    texturePtr->Transfer2Texture(inputData);
}

  调用Compute Shader:

void SceneRendering::performCompute() {
    this->shader_add->use();
    this->shader_add->setVecN("v", 4, v);
    glBindImageTexture(0, this->inputTexture, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
    glBindImageTexture(1, this->outputTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
    glDispatchCompute(1, 1, 1);
    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(4, 4, 4, this->outputTexture);
    int index = 0;
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            std::cout << "(" <<data[index]<<","<<data[index+1]<<","<<data[index+2]<<","<<data[index+3]<< ")" << " ";
            index += 4;
        }
        std::cout << std::endl;
    }
    std::cout<< std::endl;
    free(data);

  图片:

  

  

  

原文地址:https://www.cnblogs.com/chen9510/p/12000320.html

时间: 2024-10-18 02:57:16

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

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

Irradiance Environment Map基本原理 Irradiance Environment Map(也叫Irradiance Map或Diffuse Environment Map),属于Image Based Lighting技术中的一种. Irradiance Map的详细定义可参考GPU Gems 2  Chapter 10."Real-Time Computation of Dynamic Irradiance Environment Maps".简单说来就是一

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

一直以来都想试着自己翻译一些东西,现在发现翻译真的很不容易,如果你直接把作者的原文按照英文的思维翻译过来,你会发现中国人读起来很是别扭,但是如果你想完全利用中国人的语言方式来翻译,又怕自己理解的不到位,反而与作者的愿意相悖.所以我想很多时候,国内的译者也是无奈吧,下次再看到译作也会抱着一些感同身受的态度去读.这是我第一次翻译整篇文章,能力有限,望见谅,翻译不好的地方也希望大家指出来. 其实ComputeShader在Unity中出现已经有蛮长的一段时间了,因为自己一直对Shader比较感兴趣,所

Unity3D Compute Shader 新解 简单体绘制技术与点吸引【三】

Unity3D Compute Shader 新解体绘制技术与吸收[三] 1.Compute Shader是一个DX11的大特点,显然它真的开放了GPU的运算 2.Compute Shader的价值也是非常大的,在科学.工程.医学.各种应用上显而易见 3.GPU的浮点运算和精度比CPU高几个数量级,而且GPU的并行运算的结构.指令不会冗长的等待 这几天听了恩雅的 "Waters Show The Hidden Heart"音乐,当时耳机烂成一坨,我就像他们放Hi歌一样放了出来,于是有人

unity3d 从零开始compute shader

开始用compute shader 我喜欢vertex/fragment shaders的简单,他们只是做一件事(把顶点和颜色输出到屏幕上去),他们做得非常好,但是有时这种简单限制了你,当你的cpu拼了命的循环那些矩阵,算出并储存在贴图上... Compute Shader 解决了这个问题,我将在今天说明它的基础,我将通过一个unity自己的例子告诉你,使用structured buffer的数据在compute shader中工作 Compute Shader能用来控制粒子群的位置 什么是co

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

0x00 前言 前一段时间去英国出差,发现Unity Brighton 办公室的手绘地图墙很漂亮,在这里分享给大家. 在这篇文章中,我们选择了过去几周Unity官方社区交流群以及UUG社区群中比较有代表性的几个问题,总结在这里和大家进行分享.主要涵盖了UGUI.Lighting.Profiler.Shader Graph.SRP.Compute Shader.GLES等领域. 同时,也欢迎大家加入我们这个讨论干货的官方技术群,交流看法分享经验. Unity官方社区交流群:629212643 0x

Unity3D Compute shader 新解粒子堆积矩阵【二】

Unity3D Compute shader 新解粒子堆积矩阵[二] 1.Compute Shader都出来了好些年了,幸好Unity3D 加入了该特性,当然U3D本着易开发操作平台,在u3d中实现compute shader起来是相当轻松的. 2.除了Compute Shader,还有 Vertex shader,Geometry shader,Fragment shader ; Tesselation shader,Domain shader,Hull Shader ,如果你觉得有一种都想学

OpenGL 5: Shader画心形

初始化Open Program的四个函数: GLuint shaderProgram = glCreateProgram(); glLinkProgram(shaderProgram); glValidateProgram(shaderProgram); glUseProgram(shaderProgram); 这样创建并使用了一个Open GL Program ,这里是用来装 GL shader的,所以要把shader附加到Program上去, 也需要四个函数: GLuint shaderOb

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

博主作为OpenGL新手,最近要用OpenGL进行并行的数据计算,突然发现这样的资料还是很少的,大部分资料和参考书都是讲用OpenGL进行渲染的.好不容易找到一本书<GPGPU编程技术,从OpenGL.CUDA到OpenCL>,里面对并行处理的发展进行了系统性的介绍,还是很不错的.小白博主很兴奋,看完书中第三章后恍然大悟了很多,就贴出书中代码3-3的例子,实现一番,并用一副图片数据做了实现. 实现环境:Window7 32bit, VS2013+OpenGL3.3+GLEW+GLFW. Ope

GLSL 在OpenGL中向shader传递信息【转】

http://blog.csdn.net/hgl868/article/details/7872219 引言 一个OpenGL程序可以用多种方式和shader通信.注意这种通信是单向的,因为shader的输出只能是渲染到某些目标,比如颜色和深度缓存. OpenGL的部分状态可以被shader访问,因此程序改变OpenGL某些状态就可以与shader进行通信了.例如一个程序想把光的颜色传给shader,可以直接调用OpenGL接口,就像使用固定功能流水线时做的那样. 不过,使用OpenGL状态并不