【unity】shader优化总结-转载

分为三个部分:Unity官方文档,GDC,个人经验。

Unity Manual

1.计算量优化。着色器进行的计算和处理越多,对性能的影响越大。针对不影响最终效果但依然进行计算的无效代码,进行移除操作。计算的频率也会影响游戏的性能。通常,像素着色器比顶点着色器的执行次数要多。在可能的情况下,将计算从像素着色器移动到顶点着色器,或将它们完全在着色器移除,在脚本中计算并传递给着色器。

2.表面着色器优化。Unity提供的表面着色器非常适合编写与光照交互的着色器。针对特定情况设置关键字以使着色器效率更高或减小体积:

  • approxview使用逐顶点而不是逐像素的规范化观察向量。虽然是近似值,通常足够使用。
  • 镜面反射着色器类型使用halfasview更快。计算半角向量并逐顶点进行规范化,并且光照函数使用半角向量而不是观察向量作为参数。
  • noforwardadd着色器仅完全支持前向渲染中的一个定向光源。其余的光源仍然可以有逐顶点光照或球谐的效果。减少了着色器大小,即使存在多个灯光始终只渲染一次。
  • noambient禁用着色器的环境光和球谐光照。

3.计算精度优化。当使用CG / HLSL编写着色器时,存在三种基本的数字类型:float(32bits)half(16bits)fixed(11bits)

  • 对于世界空间位置和纹理坐标,使用float精度。
  • 对于其他一切(矢量,HDR颜色等),首先使用half精度,必要时增加精度。
  • 对于纹理数据的非常简单的操作,使用fixed精度。

实际上,应该使用哪种数据精度取决于平台和GPU。一般来说:

  • 所有现代桌面级GPU总是以完全float精度进行计算,float/half/fixed在底层是完全相同的。因此在Unity编辑器中(即使切换为移动平台),难以确定半/固定精度是否足够,因此请始终在目标设备上测试着色器以获得准确的结果。
  • 移动GPU具有实际half精度支持。通常更快,并且使用更少的功率来进行计算。
  • Fixed精度通常仅对较旧的移动GPU有效。大多数现代GPU(支持OpenGL ES 3.0或Metal)内部处理fixedhalf精度完全相同。

4.Alpha Testing优化。固定函数AlphaTest - 或其可编程等价函数clip()- 在不同平台上具有不同的性能表现:

  • 通常,在大多数平台上使用它来移除的完全透明像素时,有些许性能优势。
  • 但是,在iOS和某些使用PowerVR GPU的Android设备上,alpha testing是资源密集型的。不要试图在这些平台上使用它进行性能优化,会导致游戏运行速度比平常慢。

5.Color Mask优化。在某些平台上(主要是iOS和Android设备中的移动GPU),使用ColorMask忽略某些通道(例如ColorMask RGB)可能是资源密集型的,因此请在必要时才使用。

GDC

GDC2013和GDC2014上介绍了DX10和DX11上PC和Console上的底层着色语言优化,将优化放在减少着色器指令数量上面。

GDC2013:http://www.humus.name/Articles/Persson_LowLevelThinking.pdf

GDC2014:http://www.humus.name/Articles/Persson_LowlevelShaderOptimization.pdf

个人认为,在PC和Console平台上对于指令数量的优化意义并不大。但是在移动平台,指令数量的优化还是有必要。虽然SM3.0指令数量已经基本不会对着色器编写复杂度进行限制,但是如果要求支持SM2.0,96条指令数量要求十分严苛。

由于着色器指令的优化与硬件(HW)关系密切,因此我们需要根据硬件厂商提供的相关文档进行优化。移动平台的三大GPU品牌,分别是PowerVR,Mali,Adreno。PowerVR有专门的GLSL优化文档,Mali和Adreno也有相关文档提到这部分内容。

 但这样做,必然会增加着色器变体数量,因为我们要使用关键字来选择执行不同的代码,这会生成不同的着色器变体。

根据PowerVR Low Level GLSL Optimisation,我这里列举一些优化的方式。至于Mali和Adreno的优化,需要参考其开发文档进行。

通常来讲,在PowerVR上的Shader性能取决于执行Shader的周期次数。PowerVR Rogue架构提供了多种选择用于在USC ALU管线中的单一周期执行多个指令。

从下图可以看到,在一个周期内,可以执行最多三个Phase。为了高效的利用ALU,按照下面的规则,重新排列我们的GLSL代码是明智的。

指令优化

1.MAD

上图可以知道,MAD和MUL/ADD均占用一个Phase,但是MAD却执行了a*b+c的计算,这想当于一个Phase执行了一次乘法和加法。将表达式是改为MAD形式,会减少50%的周期消耗。

2.Division

将除法写为乘以除数的倒数(rcp)的形式,对优化有帮助。同样的,简化表达式也会获得额外的性能增加。

3.Sign

sign(x)的计算是这样的:返回 -1 if x<0; 0 if x =0;1 if x >0.

如果不需要x=0的情况,那么最好的方式是自己实现。

4.Rcp/Rsqrt/Sqrt

在PowerVR Rogue架构中,倒数操作是直接一条指令支持的。

rsqrt()也同样是硬件支持的。

sqrt()在另一方面是以1/(1/sqrt(x))的方式实现的,因此它占用两个循环。

一般来说用替代的实现x*1/sqrt(x)实现sqrt的功能。

同样是两个周期,使用替代实现更好的唯一情形是结果会被测试。在这种情况下,测试指令刚好放入第二条指令中。

5.Abs/Neg/Saturate

在PowerVR架构中,修饰符如abs(),neg()和clamp(…,0.0,1.0)(相当于saturate())的优势是很重要的,因为在特定的情况下,他们没有消耗。abs()和neg()如果用于操作的输入,是无消耗的。在这种情况下,他们被编译器转换成无消耗的修饰。saturate()相反,当用于操作的输出的时候,被转换为无消耗的修饰。

但是对于复杂的或者采样/插值指令却不符合这个规则。换句话说,对于纹理采样输出,或者复杂的指令输出,saturate()并不是无消耗的。当这些函数没有使用时,它们可能会引入额外的mov指令,这些指令可能会影响着色器的循环计数。

使用clamp(…,0.0,1.0)而不是min(…,1.0)和max(…,0.0)也有利于优化。这令原有的测试指令变为saturate修饰符。

之后,对于复杂函数,他们被译为多个操作并且因此在这个情形下,修饰符的位置就十分重要。比如,规范化函数normalize(),它的实现。

正如所看到的,在这种情况下,最好是对最终乘法的一个输入取负,而不是所有情况下的都对输入取负,或者创建一个临时的负值输入:

6.Exp/Log

在PowerVR Rogue架构,2^n操作是一条指令支持的操作。

Log2()同样。

Exp()与Exp2()的实现不同,占用两个循环。

Pow(x,y)的实现如下,需要三个周期。

7.Sin/Cos/Sinh/Cosh

Sin,Cos,Sinh,Cosh在PowerVR架构上有适度的四个周期的低消耗。它们被分解为fred*2+fsinc+一个条件。

8.Asin/Acos/Atan/Degrees/Radians

如果实现了数学表达式的简化,之后的这些函数通常不会被用到。因此,它们并不会精确的映射到硬件。这意味着这些函数有者非常高的消耗,并且在任何时候都应该避免使用。

Asin()耗费多达67个周期。

Acos()耗费多达79个周期。

Atan()依然比较耗,但是如果需要的话还是可以使用的。

虽然degrees和radians只有一个周期,但如果只使用弧度进行计算,通常是可以避免的。

9.Vector*Matrix

Vector*Matrix有一个相对比较合理的开销,不管需要发生的计算数量。优化例如会知道w=1的优势,但并不会降低开销。

10.Mixed Scalar/Vector math

Normalize()/length()/distance()/reflect()等函数内部通常会包含许多的函数调用例如dot()。知道这些函数是如何实现的是一个优势。

例如,如果我们知道两个操作有共享的子表达式,我们可以减少周期数量。然而,这只在如果输入顺序允许的情况下发生。

手动的展开这些复杂的函数有时可以帮助编译器优化代码。

同样的,在展开形式组合向量和标量指令也可能得到优化。

下面列举一些复杂指令的展开形式。

cross()可以扩展为:

distance()可以扩展为:

dot()可以扩展为:

faceforward()可以扩展为:

length()可以扩展为:

normalize()可以扩展为:

reflect()可以扩展为:

refract()可以扩展为:

11.Operation grouping

将标量和向量操作分别组合是有利于优化的。这样编译器可以将更多的操作打包到单一的周期中。

FP16概述

1.FP16精度和转化

当简化的精度满足的时候,FP16的管线工作的不错。然而,依然建议经常检查优化后的结果会不会出现精度瑕疵。当16位的浮点精度硬件可用,并且着色器使用中精度的时候,16位与32位的转化使用修饰符是无开销的,因为被USC ALU管线包含了它。

然而,当着色器不使用16位指令或者例如早期的Rogue硬件硬件不包含16位浮点管线,指令只会在常规的32位管线执行并且因此也不会有转化发生。

2.FP6 SOP/MAD operation

FP16 SOP/MAD管线是PowerVR ALU管线最强大的地方之一。如果使用得当。它允许开发者打包更多到操作到单一周期中。这可以提高性能并降低功率消耗。

单一周期的FP16 SOP/MAD操作可以被以下的伪代码描述:

输入应用各种修饰符(abs(),negete(),oneminus())和输出应用clamp()也是合适的。下一小节介绍如何完全的利用FP16 SOP/MAD管线。

3.利用FP16 SOP/MAD管线

PowerVR Rogue架构有一个强大的为常规图形操作优化的FP16管线。这节描述了如何利用FP16管线。注意转换输入到FP16之后转换输出到FP32是零开销很重要。

对SOP/MAD你有许多的选择。在一个周期中,你可以执行2个SOP操作或2个MAD操作或1个MAD+1个SOP操作。二选一的,你可以在单一周期执行4个FP16 MAD操作。

在单一周期执行4个MAD:

SOP表示乘法的结果之间选择一个操作的点积之和:

这里OP可以是一个加法,减法,min()或者max():

你也可以对输入应用取负,abs()或者clamp()(saturate)中的任一:

最后,你也可以对最终结果应用clamp()(saturate):

在应用完所有的知识之后,我们可以通过使用单一周期的任何事情来炫耀我们的管线功率:

经验

1.将一些计算烘焙到纹理

具体来讲,就是使用纹理读取的方式减轻运算量。在一般硬件,采样操作占用一个周期。如果将BRDF的D/F/G等计算烘焙到一张RGBA的四个通道中,我们只需要计算输入的几个点积结果以及粗糙度等参数,通过采样纹理得到计算结果(或者是中间结果)。这部分的操作比较灵活。在不追求计算精确的情况下,以空间换时间。

2.计算转移的思考

由Unity的官方手册优化建议第一条,我们可以知道,在Shader编写中,我们可以知道有些计算,在不影响表现的情况下,是可以放到三个部分中的,顶点着色器,片段着色器以及脚本中。顶点着色器和片段着色器,分别是逐顶点和逐像素来进行计算的。而脚本中,是每一帧计算的(Update函数)。
那把计算放到哪里更能优化性能?Unity的官方文档给出的建议的脚本优于顶点着色器优于像素着色器。

在不考虑剔除的情况下:

顶点着色器:逐顶点计算,计算次数等于顶点数。
片段着色器:逐像素计算,计算次数等于像素数。
脚本:逐帧计算,每帧计算一次。
从计算次数上来看效率,脚本>顶点着色器>片段着色器。

然而区别是,顶点着色器和片段着色器是Shader内部的计算,运行在GPU上。计算从片段着色器移动至顶点着色器使得性能得到优化是没有疑问的。而脚本的计算则是运行在CPU上,计算得到的结果传递给GPU也会有性能的开销。
举两个极端的例子:
模型1:超高精度模型,模型顶点数1000W。(Nvidia的技术展示Demo)
模型2:Quad,模型顶点数4。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/432236.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《操作系统真相还原》读书笔记四:安装nasm

下载链接&#xff1a;https://www.nasm.us/pub/nasm/releasebuilds/2.13.03/ 下载-解压-安装 tar zxvf nasm-2.13.03.tar.gz ./configure --prefix/home/truthos/nasm/toolchain/make && makeinstall执行make install export PATH/home/truthos/nasm/toolchain/bin:…

用自适应K-Means的差分进化算法解决有容量的电动汽车(EV)路由问题(2023)

Solving the Capacitated Electric Vehicle (EV) Routing Problem by The Differential Evolutionary Algorithm with Adaptive K-Means 摘要 本文旨在解决限制电能和工作量的路由问题&#xff0c;称为电容式电动汽车路由问题&#xff08;CEVRP&#xff09;。这个问题的目的是…

《 前端挑战与未来:如何看待“前端已死”》

在技术领域,时常会有一些激进的言论引发热议,比如近年来不少人声称“前端已死”。这样的言论引发了广泛的讨论和反思。本文将从几个方向探讨这个话题:为什么会出现“前端已死”的言论、如何看待这种说法、前端技术的未来发展趋势以及前端人如何应对这场职位突围战。 为什么会…

代码训练LeetCode(1)合并有序数组详解

代码训练(1)LeetCode之合并两个有序数组 Author: Once Day Date: 2024年3月5日 漫漫长路&#xff0c;才刚刚开始… 全系列文章可参考专栏: 十年代码训练_Once-Day的博客-CSDN博客 参考文章: 88. 合并两个有序数组 - 力扣&#xff08;LeetCode&#xff09;力扣 (LeetCode) …

【BUG】Windows状态栏总卡死解决办法

屋漏偏逢连夜雨&#xff0c;正在赶deadline呢&#xff0c;Windows状态老卡死&#xff0c;一时间崩溃。 解决办法&#xff1a; 右键状态栏新闻和咨询关掉 这个烧笔新闻与资讯我真服了

Ubantu 18.04 如何映射IP到公网,外网可以访问

介绍一种简单的方式&#xff0c;就是通过路由侠 inux 系统安装路由侠&#xff0c;可通过两种方式进行&#xff0c;一种是通过直接脚本安装&#xff0c;一种是通过 Docker 安装。 windows下载地址&#xff1a;路由侠-局域网变公网 方式一&#xff1a;通过脚本安装 1、获取安…

赵珊珊Go语言汇编视频课程

本课程由赵珊珊老师倾情打造&#xff0c;旨在深入解析Go语言与汇编语言结合的高级主题。学员将系统学习Go语言底层实现原理&#xff0c;掌握汇编代码优化技巧&#xff0c;为高性能、高并发应用开发奠定坚实基础&#xff0c;助力学员在软件工程领域取得更大成功。 课程大小&…

Ajax+Axios+前后端分离+YApi+Vue-ElementUI组件+Vue路由+nginx【全详解】

目录 一.Ajax技术 二. Axios 三.前后台分离开发介绍 四. YAPI 五.前端工程化 六.vue工程的目录结构 七.Vue项目核心文件 八.Vue组件库ElementUI AboutView.vue最终代码 AboutView.vue最终代码 九.Vue路由 十.案例 十一.nginx介绍 一.Ajax技术 1.Ajax概述 Ajax: 全…

excel 动态列导出

excel动态列&#xff0c;只好用poi来写了&#xff0c;也并不复杂&#xff0c;一样就这个件事情抽像为几步&#xff0c;就是套路了&#xff0c;开发效率就上去了。 1 准备空模板 导出操作与excel模板的导出一样&#xff0c;可以参考excel导出标准化 2 自定义SheetWriteHandler …

Redis面试问题纯享版

基础内容 1、简单介绍以下你了解的Redis 2、对比一下Redis和Memcache的异同&#xff1f; 3、为什么MySQL选用Redis作为缓存&#xff1f; 4、详细聊聊你对Redis各种数据类型的了解&#xff1f; 5、Redis中五种基本数据类型的底层数据结构是什么样的&#xff1f; Redis线程模型…

图书推荐|Word文稿之美

让你的文档从平凡到出众&#xff01; 本书内容 《Word文稿之美》是一本全面介绍Word排版技巧和应用的实用指南。从初步认识数字排版到高效利用模板、图文配置和表格与图表的排版技巧&#xff0c;再到快速修正错误和保护文件&#xff0c;全面系统地讲解数字排版的技术和能力&…

【Linux】编译器gcc | make | Makefile | 模拟进度条 | gitee

目录 1. 编译器 gcc 1.1 背景知识 1.2 gcc如何完成 2.1 Makefile背景 2.2 Makefile原理 2.3 Makefile常用符号 3. 模拟倒计时 4. 模拟进度条 5. 使用 git 命令行 5.1 安装 git 5.2 创建项目下载到本地 5.3 推送本地代码到远端仓库 1. 编译器 gcc 1.1 背景知识 预处…

stm32学习笔记:I2C通信外设原理(未完)

软件实现和硬件实现 串口通信为异步时序&#xff0c;用软件实现很麻烦&#xff0c;基本上用硬件实现 而I2C协议通信为同步时序&#xff0c;软件实现简单且灵活&#xff0c;硬件实现比较麻烦&#xff0c;故软件比较常用 但I2C硬件实现功能比较大&#xff0c;执行效率高&#xff…

Electron-builder打包安装包——编译篇

突然有一天想打包个桌面程序&#xff0c;没有打包过&#xff0c;经过九牛二虎之力终于打包出来&#xff0c;在此感谢那些热于分享的前辈&#xff01; 本篇只讲打包运行和出现的问题 一、准备工作&#xff1a;提前下载相关资源包&#xff0c;否则在国内环境下可能因为网络问题…

python+django_vue旅游酒店预订出行订票系统pycharm项目lw

a.由于对管理信息方面的内容了解尚浅且没有足够的经验&#xff0c;因而很难对数据庞大的线上旅行信息管理系统建立完善的数据库。 b.线上旅行信息管理系统拥有很大的信息量&#xff0c;其中包括数据库的前期开发和后期更新&#xff0c;因此对数据库的安全性&#xff0c;一致性和…

【Java】CAP理论以及它的实际应用案例

目录 简介 不是所谓的“3 选 2” CAP 实际应用案例 总结 CAP 理论/定理起源于 2000年&#xff0c;由加州大学伯克利分校的Eric Brewer教授在分布式计算原理研讨会&#xff08;PODC&#xff09;上提出&#xff0c;因此 CAP定理又被称作 布鲁尔定理&#xff08;Brewer’s the…

html标签之表格标签,程序员必看

突破困境&#xff1a; 1. 提升学历 前端找工作&#xff0c;学历重要吗&#xff1f; 重要。谁要是告诉你不重要那一定是在骗你。现实情况是大专吃紧&#xff0c;本科够用&#xff0c;硕士占优&#xff0c;大专以下找到工作靠运气和 戳这里领取完整开源项目&#xff1a;【一线大…

嵌入式面试

1.关键字static的作用是什么&#xff1f;为什么static变量只初始化一次&#xff1f; 1&#xff09;修饰局部变量&#xff1a;使得变量变成静态变量&#xff0c;存储在静态区&#xff0c;存储在静态区的数据周期和程序相同&#xff0c; 在main函数开始前初始化&#xff0c;在退…

HTML入门:05HTML多媒体

HTML入门&#xff1a;05HTML多媒体 1 video标签1.1 控制按钮&#xff1a;controls1.2 宽度和高度&#xff1a;width和heightt1.3 预载&#xff1a;preload1.4 静音&#xff1a;muted1.5 自动播放&#xff1a;autoplay1.6 无限循环&#xff1a;loop1.7 poster 2 audio标签 在早期…

从零学习Linux操作系统 第三十二部分 ansible中剧本的应用

一、什么是playbook及playbook的组成 1.Playbook的功能 playbook 是由一个或多个play组成的列表 Playboot 文件使用YAML来写的 play就是一个个模块用列表的方式体现出来 playbook的语法是用YAML的预防进行书写的 2.YAML 简介 是一种表达资料序列的格式&#xff0c;类似XM…