Shader第二十八讲 Compute Shaders
http://blog.sina.com.cn/s/blog_471132920102w97k.html
首先简单介绍GPGPU programming
和CPU Random Memory Accesses(随机内存获取)不同,GPU是用平行架构处理 大量的并行数据,例如vertex和fragment就是分开计算的。使用GPU并利用这种特性来进行非图形计算被称为GPGPU编程(General Purpose GPU Programming)。大量并行无序数据的少分支逻辑(少if)适合GPGPU,例如粒子间互不影响的粒子系统。GPGPU平台或接口有DirectCompute,OpenCL,CUDA等。 从此图可以看出 CPU和GPU之间的数据传输是瓶颈。故当使用GPGPU时,对Texture的逐像素处理不需要传回CPU,因而速度比较快。
Compute Shader
Compute Shader下文简称cs
【概念】Compute Shaders是在GPU运行却又在普通渲染管线之外的程序。用于运行 GPGPU program。
平行算法被拆分成 很多线程组,而线程组包含很多线程。例如一个线程处理一个像素点。而一定要注意这种处理是无序的随机的,并不一定是固定的处理顺序,例如不一定是从左到右挨个处理像素点。
线程组
A Thread Group 运行在一个GPU单元 (A single multiprocesser),如果GPU有16个 multiprocesser,那么程序至少要分成16个 Thread Group使得每个multiprocesser都参与计算。 组之间不分享内存。 线程 一个线程组包含n个线程,每32个thread称为一个warp(nvidia:warp=32 ,ati:wavefront=64,因此未来此数字可能会更高)。从效率考虑,一个线程组包含的线程数最好的warp的倍数,256是一个比较合适的数字。 实现步骤】 (1)在compute shader里 通过对贴图或者buffer进行数据读写 (2)在cs脚本里设置shader的贴图或者buffer并运行【规则语法】
1 Compute Shaders的文件后缀为.compute
2 使用#pragma指出内核。
一个 Compute Shader至少需要一个内核。
例如 #pragma kernel FillWithRed
也可以接宏定义
#pragma kernel KernelOne SOME_DEFINE DEFINE_WITH_VALUE=1337 #pragma kernel KernelTwo OTHER_DEFINE
3 函数语法
下面通过一个完整简单的ComputeShader演示
- #pragma kernel FillWithRed
- RWTexture2D< float4 > res;
-
- [numthreads(1,1,1)]
- void FillWithRed (uint3 id : SV_DispatchThreadID)
- {
- res[id.xy] = float4(1,0,0,1);
- }
这一段代码只是输出红色至res贴图.
一 前缀
在核的前缀用三个纬度,定义了一个线程组内线程的数量,如果只用2个纬度那么,最后一个参数为1即可 [numthreads(thread_group_size_x,thread_group_size_y,1)] 【buffer】 例如顶点缓冲就是一种buffer,很多时候我们去定义struct数组并作为buffer传入cs 自己定义buffer(必须是固定size): struct Data { float x; }; StructuredBuffer< Data > b; RWStructuredBuffer< Data > b; buffer的添加是 text