GLSL:标量与矢量性能

时间:2016-09-14 12:47:07

标签: performance opengl glsl vectorization

所有现代GPU都具有标量架构,但着色语言提供各种矢量和矩阵类型。我想知道,GLSL源代码的标量化或矢量化如何影响性能。例如,让我们定义一些“标量”点:

float p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y;
p0x = 0.0f; p0y = 0.0f;
p1x = 0.0f; p1y = 0.61f;
p2x = 0.9f; p2y = 0.4f;
p3x = 1.0f; p3y = 1.0f;

和它们的向量等价物:

vec2 p0 = vec2(p0x, p0y);
vec2 p1 = vec2(p1x, p1y);
vec2 p2 = vec2(p2x, p2y);
vec2 p3 = vec2(p3x, p3y);

有了这些要点,以下哪些数学上等效的代码会运行得更快?

标量代码:

position.x = -p0x*pow(t-1.0,3.0)+p3x*(t*t*t)+p1x*t*pow(t-1.0,2.0)*3.0-p2x*(t*t)*(t-1.0)*3.0;
position.y = -p0y*pow(t-1.0,3.0)+p3y*(t*t*t)+p1y*t*pow(t-1.0,2.0)*3.0-p2y*(t*t)*(t-1.0)*3.0;

或它的等价矢量:

position.xy = -p0*pow(t-1.0,3.0)+p3*(t*t*t)+p1*t*pow(t-1.0,2.0)*3.0-p2*(t*t)*(t-1.0)*3.0;

或者他们会在现代GPU上运行速度相等吗?

以上代码只是一个例子。这种“可矢量化”代码的现实例子可能会执行更加繁重的计算,而更多的输入变量来自全局in,制服和顶点属性。

2 个答案:

答案 0 :(得分:2)

您最好的选择是对您认为可以与此代码一起使用的所有系统(即GPU)进行基准测试,并使用Vectorized代码更快地确定哪些系统更快,并且使用Scalarized代码更快。然后你编写代码的两个版本(或者更可能是多个版本),并根据正在使用的GPU /驱动程序编写运行时逻辑来切换正在使用的版本。

当然,这是一个巨大的麻烦。大多数程序员不会这样做; GPGPU程序员通常只有一个服务器/ GPU节点类型,因此他们的代码将专门针对单一架构进行定制。与此同时,在AAA游戏工作室(这是另一个有预算和人力来解决这类任务的地方),他们通常只是让NVidia和AMD彻底解决这个问题,NVidia / AMD会更好地写出来,这些游戏使用的Shaders的更优化版本,将它们添加到他们的驱动程序中,并告诉驱动程序替换为更好的Shaders而不是任何Gearbox / Bethesda /任何试图加载的人。

重要的是,对于您的用例,您最好的选择是专注于使代码更易于维护;这将节省你更多的时间,并且会让你的程序运行得更好,比任何“过早优化”都要好(我们很清楚,基本上就是你正在做的事情)。

答案 1 :(得分:1)

矢量化版本不太可能变慢 - 在最坏的情况下,它可能会被编译器替换为标量版本。

然而,它可能会更快。是否更快将在很大程度上取决于代码是否分支 - 如果没有分支,则更容易将处理提供给多个SIMD通道而不是代码分支。编译器非常聪明,并且可能能够发现标量版本也可以发送到多个SIMD通道......但编译器更有可能使用矢量化版本尽其所能地完成其工作。它们也很聪明,有时可以在有限分支的情况下保持SIMD通道的供电,因此即使使用分支代码,您最好使用矢量化版本。