IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> 《Unity Shader 入门精要学习记录》 -> 正文阅读

[游戏开发]《Unity Shader 入门精要学习记录》

在5.8章的拓展阅读中:读者可以在《GPU精粹2》中的GPU流程控制一章[1]中更加深入地了解为什么流程控制语句在GPU上会影响性能。

在34.1章中可看出

Let's start by discussing the most obvious form of flow control on GPUs. All current high-level shading languages for GPUs support traditional C-style explicit flow-control constructs, such as if-then-else, for, and while. The underlying implementations of these, however, are much different from their implementations on CPUs.

For example, consider the following code:

 if (a)    b = f();  else    b = g(); 

CPUs can easily branch based on the Boolean?a?and evaluate either the?f()?or?g()?functions. The performance characteristics of this branch are relatively easily understood: CPUs generally have long instruction pipelines, so it is important that the CPU be able to accurately predict whether a particular branch will be taken. If this prediction is done successfully, branching generally incurs a small penalty. If the branch is not correctly predicted, the CPU may stall for a number of cycles as the pipeline is flushed and must be refilled from the correct target address. As long as the functions?f()?and?g()?have a reasonable number of instructions, these costs aren't too high.

The latest GPUs, such as the NVIDIA GeForce 6 Series, have similar branch instructions, though their performance characteristics are slightly different. Older GPUs do not have native branching of this form, so other strategies are necessary to emulate these operations.

The two most common control mechanisms in parallel architectures are single instruction, multiple data (SIMD) and multiple instruction, multiple data (MIMD). All processors in a SIMD-parallel architecture execute the same instruction at the same time; in a MIMD-parallel architecture, different processors may simultaneously execute different instructions. There are three current methods used by GPUs to implement branching: MIMD branching, SIMD branching, and condition codes.

MIMD branching is the ideal case, in which different processors can take different data-dependent branches without penalty, much like a CPU. The NVIDIA GeForce 6 Series supports MIMD branching in its vertex processors.

SIMD branching allows branching and looping inside a program, but because all processors must execute identical instructions, divergent branching can result in reduced performance. For example, imagine a fragment program that decides the output value of each fragment by branching using conditions based on random input numbers. The fragments will randomly take different branches, which can cause processors that are running threads for fragments that do not take the branch to stall until other processors are finished running threads for fragments that do take the branch. The end result is that many fragments will take as long as both branches together, plus the overhead of the branch instruction. SIMD branching is very useful in cases where the branch conditions are fairly "spatially" coherent, but lots of incoherent branching can be expensive. NVIDIA GeForce FX GPUs support SIMD branching in their vertex processors, and NVIDIA GeForce 6 Series GPUs support it in their fragment processors.

Condition codes (predication) are used in older architectures to emulate true branching. If-then statements compiled to these architectures must evaluate both taken and not taken branch instructions on all fragments. The branch condition is evaluated and a condition code is set. The instructions in each part of the branch must check the value of the condition code before writing their results to registers. As a result, only instructions in taken branches write their output. Thus, in these architectures all branches cost as much as both parts of the branch, plus the cost of evaluating the branch condition. Branching should be used sparingly on such architectures. NVIDIA GeForce FX Series GPUs use condition-code branch emulation in their fragment processors.

谷歌翻译版本:

让我们从讨论 GPU 上最明显的流量控制形式开始。当前所有用于 GPU 的高级着色语言都支持传统的 C 风格显式流控制结构,例如 if-then-else、for 和 while。然而,这些的底层实现与它们在 CPU 上的实现有很大不同。

例如,考虑以下代码:

如果 (a) b = f(); 否则 b = g();

CPU 可以轻松地根据布尔值a进行分支并计算f()或g()函数。这个分支的性能特征比较容易理解:CPU一般都有很长的指令流水线,所以CPU能够准确预测是否会采用特定的分支是很重要的。如果这个预测成功完成,分支通常会招致一个小的惩罚。如果未正确预测分支,则 CPU 可能会在管道刷新时停顿多个周期,并且必须从正确的目标地址重新填充。只要函数f()和g()具有合理数量的指令,这些成本就不会太高。

最新的 GPU,例如 NVIDIA GeForce 6 系列,具有类似的分支指令,但它们的性能特征略有不同。较旧的 GPU 没有这种形式的原生分支,因此需要其他策略来模拟这些操作。

并行架构中两种最常见的控制机制是单指令多数据 (SIMD) 和多指令多数据 (MIMD)。SIMD 并行架构中的所有处理器同时执行相同的指令;在 MIMD 并行架构中,不同的处理器可以同时执行不同的指令。GPU 目前使用三种方法来实现分支:MIMD 分支、SIMD 分支和条件代码。

MIMD 分支是理想的情况,在这种情况下,不同的处理器可以采用不同的数据相关分支而不会受到惩罚,就像 CPU 一样。NVIDIA GeForce 6 系列在其顶点处理器中支持 MIMD 分支。

SIMD 分支允许在程序内部进行分支和循环,但由于所有处理器都必须执行相同的指令,因此不同的分支会导致性能降低。例如,想象一个片段程序,它通过使用基于随机输入数的条件进行分支来决定每个片段的输出值。片段将随机采用不同的分支,这会导致正在运行不采用分支的片段的线程的处理器停止,直到其他处理器完成为采用分支的片段运行线程。最终结果是许多片段将花费两个分支一起的时间,加上分支指令的开销。SIMD 分支在分支条件相当“空间”一致的情况下非常有用,但是许多不连贯的分支可能很昂贵。NVIDIA GeForce FX GPU 在其顶点处理器中支持 SIMD 分支,而 NVIDIA GeForce 6 系列 GPU 在其片段处理器中支持它。

条件代码(预测)在较旧的体系结构中用于模拟真正的分支。编译到这些架构的 if-then 语句必须评估所有片段上的已采用和未采用分支指令。评估分支条件并设置条件代码。分支的每一部分中的指令必须在将结果写入寄存器之前检查条件代码的值。结果,只有在所采取的分支中的指令写入它们的输出。因此,在这些架构中,所有分支的成本与分支的两个部分一样多,加上评估分支条件的成本。在此类架构上应谨慎使用分支。NVIDIA GeForce FX 系列 GPU 在其片段处理器中使用条件代码分支仿真。

着重点在与SIMD与MIMD对于GPU的控制语句的影响,大概说的就是如果使用控制语句多的话,GPU会有空闲的资源用不上并且不能使用,这也就导致了执行一个控制语句的开销过大。

在对Shader进行编辑的时候需要注意的事项:

我们不鼓励在Shader中使用流程控制语句(if-else、for和while),因为它们会降低GPU的并行处理操作(尽管在现代的GPU上已经有了改进)。若一定要用,则我们应该尽量把计算向流水线上端移动,例如把放在片元着色器中的计算放到顶点着色器中,或者直接在CPU中进行预计算,再把结果传递给Shader。

若一定要用的一些建议:

  • 分支判断语句中使用的条件变量最好是常数,即在Shader运行过程中不会发生变化;
  • 每个分支中包含的操作指令数尽可能少;
  • 分支的嵌套层数尽可能少。

在设计到除法计算的时候警惕除数不要为0,对那些除数可能为0的情况,强制截取到非0范围。

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-09-10 11:11:09  更:2021-09-10 11:11:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 18:29:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码