Unity中Shader指令优化

文章目录

  • 前言
  • 解析一下不同运算、条件、函数所需的指令数
    • 1、常数基本运算
    • 2、变量基本运算
    • 3、条件语句、循环 和 函数


前言

上一篇文章中,我们解析了Shader解析后的代码。我们在这篇文章中来看怎么实现Shader指令优化

  • Unity中Shader指令优化(编译后指令解析)

解析一下不同运算、条件、函数所需的指令数

1、常数基本运算

在DirectX平台,常数运算是不占指令数的。但是,稳妥起见我们最好自己计算好常数计算的结果。防止其他平台认为常数运算需要占指令。

  • Shader片元着色器中:

fixed4 frag (v2f i) : SV_Target
{
//常数基本计算
return 2 * 3;
}

  • 编译后只有一个赋值给输出结果的指令:

ps_4_0
dcl_output o0.xyzw
0: mov o0.xyzw, l(6.000000,6.000000,6.000000,6.000000)
1: ret

定义临时存储变量,也是不消耗指令数的,对性能没有影响

  • Shader片元着色器中:

fixed4 frag (v2f i) : SV_Target
{
//常数基本计算
fixed4 c = 0.2 * 3 / sin(4);
fixed4 c1 = c;
return c1;
}

  • 编译后同样只有一个赋值给输出结果的指令:

ps_4_0
dcl_output o0.xyzw
0: mov o0.xyzw, l(-0.792809,-0.792809,-0.792809,-0.792809)
1: ret

2、变量基本运算

变量的基本运算,是会使用GPU计算指令的。因为变量在计算前是未知的,会预留计算指令

  • Shader中:
  1. 属性面板定义一个四维向量

_Value(“Value”,Vector) = (0,0,0,0)

  1. 片元着色器中,使用该变量进行 加法 计算

fixed4 frag (v2f i) : SV_Target
{
//2、变量基本运算
float a = _Value.x;
float b = _Value.y;
float c = _Value.z;
float d = _Value.w;
float e = 1 + a;
return e;
}

  • 编译后(使用了加指令):

ps_4_0
dcl_constantbuffer CB0[3], immediateIndexed
dcl_output o0.xyzw
0: add o0.xyzw, cb0[2].xxxx, l(1.000000, 1.000000, 1.000000, 1.000000)
1: ret

  1. 变量进行减法运算

e = 1 - a;

  • 编译后(使用了加指令):

ps_4_0
dcl_constantbuffer CB0[3], immediateIndexed
dcl_output o0.xyzw
0: add o0.xyzw, -cb0[2].xxxx, l(1.000000, 1.000000, 1.000000, 1.000000)
1: ret

  1. 变量进行乘法运算(这里测试乘法,别使用 1 或 2,会自动转化为加法)

e = 3 * a

  • 编译后(使用了乘指令):

ps_4_0
dcl_constantbuffer CB0[3], immediateIndexed
dcl_output o0.xyzw
0: mul o0.xyzw, cb0[2].xxxx, l(3.000000, 3.000000, 3.000000, 3.000000)
1: ret

  1. 变量进行除法运算

e = 3 / a

  • 编译后(使用了除法指令):

ps_4_0
dcl_constantbuffer CB0[3], immediateIndexed
dcl_output o0.xyzw
0: div o0.xyzw, l(3.000000, 3.000000, 3.000000, 3.000000), cb0[2].xxxx
1: ret

  1. 变量进行多个相同运算

e = 3 * a * b;

  • 编译后:

ps_4_0
dcl_constantbuffer CB0[3], immediateIndexed
dcl_output o0.xyzw
dcl_temps 1
0: mul r0.x, cb0[2].x, cb0[2].y
1: mul o0.xyzw, r0.xxxx, l(3.000000, 3.000000, 3.000000, 3.000000)
2: ret

  1. 变量进行乘加运算,对性能优化特别重要(特殊)

e = 3 * a + b;

  • 编译后,会使用乘加指令(把乘法和加法合并成一个指令)

ps_4_0
dcl_constantbuffer CB0[3], immediateIndexed
dcl_output o0.xyzw
0: mad o0.xyzw, cb0[2].xxxx, l(3.000000, 3.000000, 3.000000, 3.000000), cb0[2].yyyy
1: ret

3、条件语句、循环 和 函数

  1. 条件语句

if(i.uv.x < 0.5)
{
i.uv.x = 1;
}
else
{
i.uv.x = 0;
}
return i.uv.x;

在这里插入图片描述

  • 编译后:

在这里插入图片描述
这里我们可以使用 step 函数来替代 该 条件语句
替代后,虽然编译结果一样的。但是,这是因为 条件语句 的程序体太简单
如果遇到比较复杂的 条件语句,我们可以使用 结合 step 和 算法的方法 把条件语句剔除

使用 step 函数后:

return step(0.5,i.uv.x);

  • 编译后
    在这里插入图片描述
  1. 循环语句

float e = 0;
for(int i = 0;i < 5;i++)
{
e += 0.1;
}
return e;

  • 编译后:

在这里插入图片描述

  1. mad指令优化:

优化前:

float e = (a + b) * (a - b);
return e;

  • 编译后:

在这里插入图片描述
优化后:

float e = a * a * (-b * b);
return e;

  • 编译后:

在这里插入图片描述

  1. 透过编译后的代码来直观的看出函数的内部执行(这里使用 normalize 来测试)

一维向量(常数):

float e = normalize(a);
return e;

  • 编译后:

在这里插入图片描述
多维向量归一化(编译后会使用点乘)

float e = normalize(_Value);
return e;

  • 编译后:

在这里插入图片描述

  1. abs(如果abs传入的是单一参数,就不会多用指令。但是传入式子,会多用指令)

传入式子:

float e = abs(a * b);
return e;

  • 编译后:

在这里插入图片描述
传入单一参数:

float e = abs(a) * abs(b);
return e;

  • 编译后:

在这里插入图片描述

  1. 负号可以适当的移到变量中

移动前:

float e = -dot(a,a);
return e;

  • 编译后:

在这里插入图片描述

移动后:

float e = dot(-a,a);
return e;

  • 编译后:

在这里插入图片描述

  1. 尽量把同一维度的向量进行结合运算

结合前:

float3 e = _Value.xyz * a * b * _Value.yzw * c * d;
return fixed4(e,1);

  • 编译后:

在这里插入图片描述

结合后:

float3 e = (_Value.xyz * _Value.yzw) * (a * b * c * d);
return fixed4(e,1);

  • 编译后:

在这里插入图片描述

  1. asin / atan / acos开销很大,尽量不要使用 (这里使用asin测试)

float e = asin(a);
return e;

  • 编译后
    在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【深度学习实验】图像处理(四):PIL——自定义图像数据增强操作(图像合成;图像融合(高斯掩码))

文章目录 一、实验介绍二、实验环境1. 配置虚拟环境2. 库版本介绍 三、实验内容0. 导入必要的库1. PIL基础操作2~4. 随机遮挡、随机擦除、线性混合5. 图像合成5.1 原理5.2 实现5.3 效果展示 6. 图像融合6.1 原理6.2 实现6.3 效果展示 一、实验介绍 在深度学习任务中&#xff0c…

MySQL进阶_EXPLAIN重点字段解析

文章目录 第一节.准备1.1 版本信息1.2 准备 第二节.type2.1 system2.2 const2.3 eq_ref2.4 ref2.5 ref_or_null2.6 index_merge2.7 unique_subquery2.8 range2.9 index2.10 all 第三节. Extra3.1 No tables used3.2 No tables used3.3 Using where3.4 No matching min/max row3…

【数据结构高阶】AVL树

上期博客我们讲解了set/multiset/map/multimap的使用&#xff0c;下面我们来深入到底层&#xff0c;讲解其内部结构&#xff1a; 目录 一、AVL树的概念 二、AVL树的实现 2.1 节点的定义 2.2 数据的插入 2.2.1 平衡因子的调整 2.2.1.1 调整平衡因子的规律 2.2.2 子树的旋…

JavaEE 多线程

JavaEE 多线程 文章目录 JavaEE 多线程引子多线程1. 特性2. Thread类2.1 概念2.2 Thread的常见构造方法2.3 Thread的几个常见属性2.4 启动一个线程2.5 中断一个线程2.6 等待一个线程2.7 获取当前线程引用2.8 休眠当前线程 3. 线程状态 引子 当进入多线程这一块内容时&#xff…

2023-12-03 LeetCode每日一题(可获得的最大点数)

2023-12-03每日一题 一、题目编号 1423. 可获得的最大点数二、题目链接 点击跳转到题目位置 三、题目描述 几张卡牌 排成一行&#xff0c;每张卡牌都有一个对应的点数。点数由整数数组 cardPoints 给出。 每次行动&#xff0c;你可以从行的开头或者末尾拿一张卡牌&#x…

使用OpenMVS重建模型

1、数据格式转换 首先将生成的稠密点云以及图片信息转换成openmvs支持的.mvs文件。在openmvs_sample中的bin文件内打开终端 作者&#xff1a;舞曲的小水瓶 https://www.bilibili.com/read/cv25019877/ 出处&#xff1a;bilibili interfaceCOLMAP.exe -i D:\desktop\test\toy\…

【Linux服务器Java环境搭建】05 Node JS安装及环境变量配置

【Linux服务器Java环境搭建】01购买云服务器以及在服务器中安装Linux系统 【Linux服务器Java环境搭建】02 通过xftp和xshell远程连接云服务器 【Linux服务器Java环境搭建】03 Git工具安装 【Linux服务器Java环境搭建】04 JDK安装&#xff08;JAVA环境安装&#xff09; 【Linux服…

flink源码分析 - 命令行参数解析-CommandLineParser

flink版本: flink-1.11.2 调用位置: org.apache.flink.runtime.entrypoint.StandaloneSessionClusterEntrypoint#main 代码位置: flink核心命令行解析器: org.apache.flink.runtime.entrypoint.parser.CommandLineParser /** Licensed to the Apache Software Foundati…

基于OpenAPI工具包以及LSTM的CDN网络流量预测

基于LSTM的CDN网络流量预测 本案例是基于英特尔CDN以及英特尔 OpenAPI Intel Extension for TensorFlow* Intel oneAPIDPC Library 的网络流量预测&#xff0c;CDN是构建在现有网络基础之上的智能虚拟网络&#xff0c;目的是将源站内容分发至最接近用户的节点&#xff0c;使用…

unity学习笔记17

一、动画组件 Animation Animation组件是一种更传统的动画系统&#xff0c;它使用关键帧动画。你可以通过手动录制物体在时间轴上的变换来创建动画。 一些重要的属性&#xff1a; 1. 动画&#xff08;Animation&#xff09;&#xff1a; 类型&#xff1a; Animation组件允许…

使用Prometheus监控Padavan路由器

Prometheus监控Padavan路由器 1、背景 近期在Synology&#xff08;群辉&#xff09;中安装一套Prometheus监控程序&#xff0c;目前已经监控Synology&#xff0c;然后家中有有路由器&#xff08;Padavan&#xff09;型号&#xff0c;也准备使用PrometheusGrafan进行监控。 ‍…

采集工具-免费采集器下载

在当今信息时代&#xff0c;互联网已成为人们获取信息的主要渠道之一。对于研究者和开发者来说&#xff0c;如何快速准确地采集整个网站数据是至关重要的一环。以下将从九个方面详细探讨这一问题。 确定采集目标 在着手采集之前&#xff0c;明确目标至关重要。这有助于确定采集…

冲突域和广播域

文章目录 冲突域广播域 冲突域 在网络内部两个数据帧同时进行传输时&#xff0c;产生与发生冲突的区域&#xff0c;所有共享介质都是一个冲突域。冲突域时基于第一层&#xff0c;物理层的。 集线器和中继器因为都在物理层&#xff0c;没有MAC地址表&#xff0c;所以不能隔离冲…

数据结构之堆排序以及Top-k问题详细解析

个人主页&#xff1a;点我进入主页 专栏分类&#xff1a;C语言初阶 C语言程序设计————KTV C语言小游戏 C语言进阶 C语言刷题 数据结构初阶 欢迎大家点赞&#xff0c;评论&#xff0c;收藏。 一起努力 目录 1.前言 2.堆排序 2.1降序排序 2.2时间复杂…

Prime 1.0

信息收集 存活主机探测 arp-scan -l 或者利用nmap nmap -sT --min-rate 10000 192.168.217.133 -oA ./hosts 可以看到存活主机IP地址为&#xff1a;192.168.217.134 端口探测 nmap -sT -p- 192.168.217.134 -oA ./ports UDP端口探测 详细服务等信息探测 开放端口22&#x…

【Vulnhub 靶场】【HackathonCTF: 2】【简单】【20210620】

1、环境介绍 靶场介绍&#xff1a;https://www.vulnhub.com/entry/hackathonctf-2,714/ 靶场下载&#xff1a;https://download.vulnhub.com/hackathonctf/Hackathon2.zip 靶场难度&#xff1a;简单 发布日期&#xff1a;2021年06月20日 文件大小&#xff1a;2.6 GB 靶场作者&…

54.多级缓存

目录 一、传统缓存的问题、多级缓存方案。 二、JVM进程缓存。 1&#xff09;进程缓存和缓存。 2&#xff09;导入商品案例。 1.安装MySQL 2.导入SQL 3.导入Demo工程 4.导入商品查询页面 3&#xff09;初识Caffeine&#xff08;就是在springboot学过的注解方式的cache&…

NAND Flash和NOR Flash的异同

NAND Flash和NOR Flash是两种常见的闪存类型。 NOR Flash是Intel于1988年首先开发出来的存储技术&#xff0c;改变了原先由EPROM和EEPROM一统天下的局面。 NAND Flash是东芝公司于1989年发布的存储结构&#xff0c;强调降低每比特的成本&#xff0c;更高的性能&#xff0c;并…

栈和队列OJ题——15.循环队列

15.循环队列 622. 设计循环队列 - 力扣&#xff08;LeetCode&#xff09; * 解题思路&#xff1a; 通过一个定长数组实现循环队列 入队&#xff1a;首先要判断队列是否已满&#xff0c;再进行入队的操作&#xff0c;入队操作需要考虑索引循环的问题&#xff0c;当索引越界&…

网络接口规范

1、基本物理层: a) RJ45接口作为最基本的网络接口之一有两种形式&#xff1a;对于百兆网口有4条线&#xff0c;2对差分线&#xff1b;对于千兆网口有4对差分线。RJ45水晶头是有8个凹槽和8个触点&#xff08;8p8c&#xff09;的接头&#xff0c;分为集成网络变压器和非集成网络变…