补充概念帮助
在开始之前,我应该解释一下我没有也从未为 GPU 制造商工作过。我在下面说的某些内容可能实际上是错误的,但这是我作为程序员的理解方式。
下面是现代 GPU 的图像。此图显示了 8 个通用管道,每个管道包含 8 个队列,因此它可以在每个时钟周期处理 64 条指令单指令操作。
旧 GPU 有一个固定的不可编程管道,我们对这些并不真正感兴趣。中间 GPU 具有运行矢量程序的特定管道,以及用于像素着色的不同管道。现代 GPU 具有可以运行任何类型程序(包括曲面细分、计算等)的通用管道
仲裁和分配探测器决定哪些管道应该运行哪些程序,以及应该向它们发送哪些输入,以便每个周期都尽可能多地使用处理器。作为程序员,我们与这些无关,所以这对我来说是一个完全的黑匣子。
我们正在编写控制管道的程序。因此,想象一下 AA 探测器已决定使用 pipe0 作为像素着色器(我假设您的程序正在对颜色进行处理,因为您不担心舍入,这会导致顶点跳动)。然后它将选择需要相同程序的 8 个像素(参见纹理),并将它们加载到进程缓冲区中。然后,所有 8 个像素一次一条指令并行运行,直到程序完成,管道被交还给 AA 探测器以得到新的工作。如果需要该程序的像素少于 8 个,则管道在某些进程缓冲区为空的情况下运行,并且芯片未充分利用,对此您无能为力,但这就是缩小到单个像素对象的原因屏幕上所有具有不同纹理的东西都会杀死 GPU。
因此,在一个周期内,一个计算管道可以为 8 个像素执行 8 次运算或为 8 个像素执行 8 个 sin,但它必须线性地为每个像素运行每条指令,这就是 if 语句对于着色器程序如此复杂的原因。处理通过条件的像素,在处理通过的像素时,失败的像素仍然需要等待周期。
显然,我所说的每个像素点,都可能是一个顶点,也可能是一个 CU 元素。
我想在这里提到的唯一另一件事是精确度。当您降低精度时,它允许处理缓冲区被更密集地填充。因此,如果您在任何地方都使用半精度,而不是 GPU 每秒处理 64 个数字,它可以处理 128 个数字,依此类推。
这大致就是 GPU 的工作原理。我当然发现理解架构更能理解为什么着色器程序是这样的。