我有一些不是真正的正弦函数,但它们比传统处理快得多,它们是简单的抛物函数。
在图形处理器上这比内置图形窦功能更快:
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;
}
答案 0 :(得分:3)
主要答案
绝对没有办法比任何显卡上的内置sin / cos函数更快。
着色器指示sin,cos&amp; tan是关于每个制造的图形卡的单周期指令。你当然不能购买一个不是单周期的显卡。
为了正确看待你的问题 - 在显卡上,需要花费相同的时间来获得多个2个数字(mul指令)和获得正弦(sin函数) - 单个GPU循环。
编写着色器时,请查看编译器的命令行选项。将有输出生成的汇编代码的选项,并且大多数编译器甚至提供最短路径(指令和周期数)和最长路径的总计。这些总数不能保证持续时间,因为像fetch这样的东西可以阻止管道,但是它们回答了你现在要问的那种问题。
着色器指令确实因卡而异,但我认为最长的单指令是4个GPU周期。
如果您查看了函数的着色器编译器程序集输出,那么您将调用大量指令,使用大量循环,然后询问它是否可以比单循环指令更快地执行。
图形芯片的全部目的是它们在运行指令集时非常快速且非常并行(但是这些指令可能在其他处理器上很复杂)。编程着色器时,请将代码集中在处理器的设计目标上。着色器编程与软件开发中其他地方的编程不同,但是一旦开始考虑计算周期,并最大限度地减少获取停顿,您很快就会开始打开着色器处理的真正功能。
祝你好运。
答案 1 :(得分:3)
补充概念帮助
在开始之前,我应该解释一下,我从未为GPU制造商工作过。我在下面说的一些事实可能是错误的,但这是我作为一名程序员的理解。
下面是现代GPU的图像。此图显示了8个通用管道,每个管道包含8个队列,因此它可以在每个时钟周期处理64个指令单指令操作。
旧的GPU有一个固定的非可编程管道,我们对它们并不感兴趣。 中GPU具有用于运行矢量程序的特定管道,以及用于像素着色的不同管道。 现代GPU具有通用管道,可以运行任何类型的程序(包括曲面细分,计算等)
仲裁和分配探测,决定哪些管道应该运行哪些程序,以及应该向它们发送什么输入,以便每个周期使用尽可能多的处理器。作为程序员,我们与这些无关,所以这对我来说是一个完整的黑盒子。
我们正在编写控制管道的程序。所以想象AA探测器决定使用pipe0作为像素着色器(我假设你的程序正在做一些颜色,因为你不担心舍入,这会导致顶点跳转)。然后它将选择需要相同程序的8个像素(请参阅纹理),并将它们加载到进程缓冲区中。然后,所有8个像素一次并行地运行一个指令,直到程序完成,并且管道被返回到AA探针以被给予新的作业。如果需要该程序的像素少于8个,则管道运行时某些进程缓冲区为空,并且芯片未得到充分利用,您无法做到这一点,但这就是缩小到单个像素对象的原因在屏幕上使用不同纹理的所有屏幕都会杀死GPU。
因此,在一个周期中,一个计算管道可以为8个像素执行8个muls,或者为8个像素执行8个sins,但是它必须线性地运行每个像素的每个指令,这就是if语句对着色器程序如此复杂的原因。处理通过条件的像素,失败的像素仍然必须等待处理传递像素的周期。
显然,我说过像素的每个地方,它可能是一个顶点或一个CU元素。
我能想到的另一件事就是精确度。当您降低精度时,它允许处理缓冲区更密集地填充。因此,如果您在任何地方使用半精度,而不是GPU每秒处理64个数字,它可以执行128,依此类推。
这大致就是GPU的工作原理。我当然发现理解这个架构让人更了解着色器程序为何如此。