0

我有一些函数不是真正的正弦函数,但它们比传统处理要快得多,它们是简单的抛物线函数。

这在图形处理器上是否会比内置图形 sinus 函数更快:

    float  par (float xx){////// sinus approximation
        half xd =((fmod(abs(xx), 2.4)) - 1.2);
        if ( fmod (abs(xx) , 4.8)  > 2.4) { xd=(-xd*xd)+2.88;}
        else {xd = xd*xd;}
        xd = -xd*0.694444444+1;
        if (  (xx<0) ) { xd=-xd;}
        return xd;
    }
4

2 回答 2

3

补充概念帮助

在开始之前,我应该解释一下我没有也从未为 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 的工作原理。我当然发现理解架构更能理解为什么着色器程序是这样的。 现代图形芯片的架构

于 2013-09-21T10:56:32.617 回答
3

主要答案

您的函数绝对不会比任何显卡上的内置 sin/cos 函数更快。

着色器指令 sin 、cos 和 tan 是几乎所有制造过的显卡上的单周期指令。您今天当然不能购买不是单周期的显卡。

为了正确看待您的问题 - 在显卡上,多个 2 个数字(mul 指令)与获得正弦(正弦函数)所需的时间相同 - 单个 GPU 周期。

在编写着色器时,请查看编译器的命令行选项。将有输出生成的汇编代码的选项,大多数编译器甚至提供最短路径(指令和周期数)和最长路径的总数。这些总数不能保证持续时间,因为诸如 fetch 之类的事情可能会使管道停止,但它们回答了您现在提出的问题类型。

着色器指令确实因卡而异,但我认为最长的单条指令是 4 个 GPU 周期。

如果您查看函数的着色器编译器汇编输出,您正在调用大量指令,使用大量周期,然后询问它是否可以比单周期指令更快地执行。

图形芯片的全部目的是它们在运行指令集时非常快速且非常并行(无论这些指令在其他处理器上可能多么复杂)。在对着色器进行编程时,将代码重点放在处理器的设计用途上。着色器编程与您在其他软件开发中进行的编程的思维方式不同,但是一旦您开始考虑计算周期数并最大限度地减少获取停顿,您很快就会开始发掘着色器处理的真正威力。

祝你好运。

于 2013-09-21T05:18:30.123 回答