computer shader是在显卡上运行的程序,在正常的渲染管道之外。被用于大量并行的gpu算法,或加速部分游戏渲染。想要高效利用他们,最好深入的理解cpu机制和并行算法。还有DirectCompute,OpenGL Compute,CUDA或openCL。
unity 的compute shader很像DX11 DirectCompute技术。能工作的平台有:
1. windows,有Dx11或Dx12显卡Api,shader model 4.5 gpu;
2. 用metal显卡api的macOS和ios;
3. Android linux和windows有Vulkan Api;
4. 现代openGL平台(openGL 4.3在linux和windows;gl es 3.1在安卓)。注意mac os x不支持opengl 4.3;
5. 现代控制台(sony ps4和微软xbox one)
运行时判断是否支持compute shader可以用SystemInfo.supportsComputeShaders。

compute shader资源

类似于普通的shader,compute shader在工程里也是资源文件,.compute扩展名。他们是用Dx11风格的hlsl语言缩写。用#pragma 编译指令指定哪些很少被当成compute shader核心编译,如下:

#pragma kernel KMain
[numthreads(8, 8, 1)]
void KMain(uint2 groupId : SV_GroupID, uint2 groupThreadId : SV_GroupThreadID, uint2 dispatchThreadId : SV_DispatchThreadID)
{// Upper-left pixel coordinate of quad that this thread will readint2 threadUL = (groupThreadId << 1) + (groupId << 3) - 4;// Downsample the blockfloat2 offset = float2(threadUL);float4 p00 = _Source.SampleLevel(sampler_LinearClamp, (offset                    + 0.5) * _Size.zw, 0.0);float4 p10 = _Source.SampleLevel(sampler_LinearClamp, (offset + float2(1.0, 0.0) + 0.5) * _Size.zw, 0.0);float4 p01 = _Source.SampleLevel(sampler_LinearClamp, (offset + float2(0.0, 1.0) + 0.5) * _Size.zw, 0.0);float4 p11 = _Source.SampleLevel(sampler_LinearClamp, (offset + float2(1.0, 1.0) + 0.5) * _Size.zw, 0.0);// Store the 4 downsampled pixels in LDSuint destIdx = groupThreadId.x + (groupThreadId.y << 4u);Store2Pixels(destIdx     , p00, p10);Store2Pixels(destIdx + 8u, p01, p11);GroupMemoryBarrierWithGroupSync();// Horizontally blur the pixels in LDSuint row = groupThreadId.y << 4u;BlurHorizontally(row + (groupThreadId.x << 1u), row + groupThreadId.x + (groupThreadId.x & 4u));GroupMemoryBarrierWithGroupSync();// Vertically blur the pixels in LDS and write the result to memoryBlurVertically(dispatchThreadId, (groupThreadId.y << 3u) + groupThreadId.x);
}

表示kMain函数被当作compute shader编译,以及:

// test.compute#pragma kernel FillWithRedRWTexture2D<float4> res;[numthreads(1,1,1)]
void FillWithRed (uint3 dtid : SV_DispatchThreadID)
{res[dtid.xy] = float4(1,0,0,1);
}

语言是标准dx 11 hlsl语言。一个compute shader资源文件必须包含至少一个会被调用的compute kernel。可以有多个,写多行#pragma语句即可。
当用#pragma时,注意同一行加“// 。。”这种注释会产生编译错误。
#pragma后面可以跟这个shader编译需要的宏

#pragma kernel KernelOne SOME_DEFINE DEFINE_WITH_VALUE=1337
#pragma kernel KernelTwo OTHER_DEFINE

调用compute shader

  1. 在你的脚本中,定义一个ComputeShader类型的变量,给这个资源一个引用。
    如下在resource类里定义ComputeShader,如下:
public sealed class ComputeShaders{public ComputeShader exposureHistogram;public ComputeShader lut3DBaker;public ComputeShader texture3dLerp;public ComputeShader gammaHistogram;public ComputeShader waveform;public ComputeShader vectorscope;public ComputeShader multiScaleAODownsample1;public ComputeShader multiScaleAODownsample2;public ComputeShader multiScaleAORender;public ComputeShader multiScaleAOUpsample;public ComputeShader gaussianDownsample;}
  1. 在resource界面,将compute shader赋过来:
  2. 调用代码如下:先设置参数,再用ComputeShader.Dispatch方法调用。从unity脚本文档里查ComputeShader类的使用。如下CommandBuffer用

public void DispatchCompute(ComputeShader computeShader, int kernelIndex, int threadGroupsX, int threadGroupsY, int threadGroupsZ);
调用computeShader:

void PushUpsampleCommands(CommandBuffer cmd, int lowResDepth, int interleavedAO, int highResDepth, int? highResAO, RenderTargetIdentifier dest, Vector3 lowResDepthSize, Vector2 highResDepthSize, bool invert = false){var cs = m_Resources.computeShaders.multiScaleAOUpsample;int kernel = cs.FindKernel(highResAO == null? invert? "main_invert": "main": "main_blendout");float stepSize = 1920f / lowResDepthSize.x;float bTolerance = 1f - Mathf.Pow(10f, m_Settings.blurTolerance.value) * stepSize;bTolerance *= bTolerance;float uTolerance = Mathf.Pow(10f, m_Settings.upsampleTolerance.value);float noiseFilterWeight = 1f / (Mathf.Pow(10f, m_Settings.noiseFilterTolerance.value) + uTolerance);cmd.SetComputeVectorParam(cs, "InvLowResolution", new Vector2(1f / lowResDepthSize.x, 1f / lowResDepthSize.y));cmd.SetComputeVectorParam(cs, "InvHighResolution", new Vector2(1f / highResDepthSize.x, 1f / highResDepthSize.y));cmd.SetComputeVectorParam(cs, "AdditionalParams", new Vector4(noiseFilterWeight, stepSize, bTolerance, uTolerance));cmd.SetComputeTextureParam(cs, kernel, "LoResDB", lowResDepth);cmd.SetComputeTextureParam(cs, kernel, "HiResDB", highResDepth);cmd.SetComputeTextureParam(cs, kernel, "LoResAO1", interleavedAO);if (highResAO != null)cmd.SetComputeTextureParam(cs, kernel, "HiResAO", highResAO.Value);cmd.SetComputeTextureParam(cs, kernel, "AoResult", dest);int xcount = ((int)highResDepthSize.x + 17) / 16;int ycount = ((int)highResDepthSize.y + 17) / 16;cmd.DispatchCompute(cs, kernel, xcount, ycount, 1);}

和compute shader联系紧密的是compute buffer,用法如下

if (m_Data == null)m_Data = new ComputeBuffer(m_NumBins, sizeof(uint));var compute = context.resources.computeShaders.gammaHistogram;var cmd = context.command;cmd.BeginSample("GammaHistogram");// Clear the buffer on every frame as we use it to accumulate values on every frameint kernel = compute.FindKernel("KHistogramClear");cmd.SetComputeBufferParam(compute, kernel, "_HistogramBuffer", m_Data);cmd.DispatchCompute(compute, kernel, Mathf.CeilToInt(m_NumBins / (float)m_ThreadGroupSizeX), 1, 1);

另外,其他用法请搜索文档。
RenderTextures也可以从compute shader写入,如果设置随机访问权限的话。查询RenderTexture.enableRandomWrite。

compute shader中的texture 采样

在unity中,贴图和采样器不是分开的事物。所以要在compute shader中使用采样器的话,需要遵循下面的unity专门的规则:
1. 和贴图名称用同样的名称,如贴图名为Texture2D MyTex,则SamplerState samplerMyTex。这样,sampler会被初始化为该贴图的过滤模式,wrap模式,异向模式。
2. 用预定于的采样器,名称必须带有Linear或Point(过滤模式)和Clamp或Repeat(wrap模式)。比如SamplerState MyLinearClampSamplers创建一个linear过滤模式和Clamp wrap模式的采样器。更多的内容查询SamplerState

跨平台支持

像正常shader一样,unity能把compute shader从hlsl转换成其他shader语言。所以,为了最简单的跨平台编译,你可以用hlsl写compute shader。然而有几个因素需要考虑。

跨平台最好的实践

Dx 11支持许多其他平台不支持的行为(比如metal 或OpenGL ES)。所以,你需要保证你的shader在其他支持能力低的平台上工作正常。下面几个问题要注意:
1. 内存溢出访问。Dx11 读的时候会返回0,不会出问题。但很少支持的平台可能会gpu崩溃。另外,dx11的一些技巧,比如buffer大小和你的线程组数量是无关的,[ 试图从缓冲区的开始或结束读取相邻的数据元素,以及类似的不兼容性。
2. 初始化你的资源,新的缓冲区和贴图内容是未定义的。一些平台可能全是0,其他的可能是任意东西,包括为空。
3. 绑定你的compute shader需要的所有资源。即使你确定地知道这个shader在他的当前状态下由于分支原因不会用到这个资源,你仍然需要确定这个资源绑定到shader上。

特定平台的差异

  1. Metal(ios或tvOS平台)不支持贴图上的原子操作。Metal也不支持buffer上的GetDimensions查询。将buffer大小当成常量传给shader如果必要的话。
  2. openGL ES3.1(安卓、ios或txOS平台)一次只支持4个compute buffer。实际实现可能支持更多,但是如果开发openGL ES,你应该将相关的数据分组放到一个结构里,而不是每种数据放到自己的buffer里。

hlsl-only和glsl-only compute shader

一般,compute shader文件是用hlsl写的,被自动编译或翻译到所有必要的平台。然而,可以阻止将它翻译到其他语言,或者手动写glsl compute shader。
下面的内容只应用于hlsl-only和glsl-only compute shader,而不是跨平台编译。因为这些内容会导致compute shader从一些平台排除。
1.被CGPROGRAM和ENDCG包围的 compute shader不能被非hlsl平台处理;
2. 被GLSLPROGRAM和ENDGLSL包围的compute shader被当作glsl处理,逐字排除。你要注意,自动翻译的shader的buffer遵循hlsl数据布局,手动写的glsl shader遵循glsl布局规则。

compute shader相关推荐

  1. android device monitor命令行窗口在哪里_Vulkan在Android使用Compute shader

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

  2. OpenGL Compute Shader计算着色器的实例

    OpenGL Compute Shader计算着色器 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 // #define USE_GL3W #include &l ...

  3. OpenGL Compute Shader Raytracing 计算着色器光线追踪的实例

    OpenGL Compute Shader Raytracing 计算着色器光线追踪 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 // #define USE_ ...

  4. OpenGL Compute Shader Particle System计算着色器粒子系统的实例

    OpenGL Compute Shader Particle System计算着色器粒子系统 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include &l ...

  5. OpenGL Compute Shader Image Processing计算着色器图像处理的实例

    OpenGL Compute Shader Image Processing计算着色器图像处理 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include & ...

  6. Compute Shader次世代优化方案

    这是侑虎科技第498篇文章,感谢作者凯奥斯供稿.欢迎转发分享,未经作者授权请勿转载.如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨.(QQ群:793972859) 作者主页:https://z ...

  7. OpenGL ES3.1使用计算着色器(Compute Shader)

    OpenGL ES3.1使用计算着色器(Compute Shader) 1.基本介绍 OpenGL ES从3.1版本开始支持计算着色器         工作模型有全局工作组和本地工作组,全局工作组包含 ...

  8. Directx 计算着色器(compute shader)

    原文 :http://www.cnblogs.com/Ninputer/archive/2009/12/11/1622190.html 博者注:计算着色器调试(http://msdn.microsof ...

  9. opengl使用compute shader的生成纹理,解决残影的问题

    在做AR云渲染的项目中,经常会有残影出现,定位问题吧. 在我们项目中,使用到了compute shader来定制一些纹理的输出,每帧的写纹理可能没有覆盖纹理的每个像素,这样就造成了问题,下一帧的渲染这 ...

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

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

最新文章

  1. 网络推广计划浅析外链发布要遵循的几点小技巧!
  2. linux_软件安装策略和升级策略
  3. Spring Cloud【Finchley】-03将微服务注册到Eureka Server上 + 为Eureka Server添加用户认证
  4. 大学期间承接软件项目的一些个人观点
  5. hdu 5570(数学期望)
  6. python 查询sqlserver 视图_SQL Server查看视图定义总结
  7. eplise怎么连接数据库_eclipse连接mysql
  8. 石头剪刀布小游戏开发的需求说明
  9. 微软发布了Visual Stduio 2010 RTM版本的虚拟机vhd文件,包含样例和动手实验(免费)...
  10. 求最大和 java_三种算法求最大子段和问题——Java实现
  11. 为什么人们常说“十个创业九个死”?
  12. 13 万字 C 语言从入门到精通保姆级教程2021 年版
  13. python定时任务启动与停止_Python启动定时任务
  14. 洛必达法则及极限问题总结
  15. Openwrt下ipk包的安装、卸载与更新
  16. git 删除历史记录
  17. google 企业邮箱 smtp pop3设置
  18. 海信Vidda S65 2023款和2020款有什么区别?哪个更好
  19. 逻辑回归(Logistic Regression)原理(理论篇)
  20. 【C语言面试复试汇总】

热门文章

  1. 介绍几款低代码生成器,神器
  2. 海康大华宇视硬件NVR通过GB28181注册接入到LiveGBS国标流媒体服务后通道显示为0如何处理
  3. STM32 USB Mass Storage 例程调试笔记
  4. [iOS]在xib中设置YYLabel自适应高度
  5. params.c:Parameter() - Ignoring badly formed line in configuration file: ignore errors 解决方法
  6. C/C++的刷题练习之牛客网,一个友好的网站
  7. USB Type C 接口引脚详解
  8. JUCE框架教程(8)——DSP Module基础
  9. 爬取淘宝买家秀,sign值的生成
  10. 数码照片的Photoshop清晰化处理漫谈-photoshop-Photoshop-天极Yesky