/// Derives the dot product of two vectors on the xz-plane. (@p u . @p v) /// @param[in] u A vector [(x,y,z)] /// @param[in] v A vector [(x,z)] /// @return The dot product on the xz-plane. /// /// The vectors are projected onto the xz-plane,so the y-values are ignored. inline float dtVdot2D(const float* u,const float* v) { return u[0]*v[0] + u[2]*v[2]; }
我通过VS2010 cpu性能测试运行它,并告诉我,在这个功能的所有重写代码库代码中,u [0] * v [0] u [2] * v [2]是cpu最热的.
cpu如何优化(例如通过SSE或GLSL like GLM (if it is easier or faster and appropriate in such case))这行?
编辑:呼叫出现的上下文:
bool dtClosestHeightPointTriangle(const float* p,const float* a,const float* b,const float* c,float& h) { float v0[3],v1[3],v2[3]; dtVsub(v0,c,a); dtVsub(v1,b,a); dtVsub(v2,p,a); const float dot00 = dtVdot2D(v0,v0); const float dot01 = dtVdot2D(v0,v1); const float dot02 = dtVdot2D(v0,v2); const float dot11 = dtVdot2D(v1,v1); const float dot12 = dtVdot2D(v1,v2); // Compute barycentric coordinates const float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01); const float u = (dot11 * dot02 - dot01 * dot12) * invDenom; const float v = (dot00 * dot12 - dot01 * dot02) * invDenom;
解决方法
然而,它需要数据重组,因为我们将一次对4个三角形进行并行处理.
我会分步骤,并在这里和那里使用指令名称,但请使用C内在函数(_mm_load_ps(),_mm_sub_ps()等,它们在VC中的xmmintrin.h) – 当我说这个注册这个只是__m128.
步骤1.
我们根本不需要Y坐标,所以我们设置了X和Z对的指针.每次呼叫至少提供4对(即4个三角形).我将每个X和Z对称为一个顶点.
第2步.
使用MOVAPS(要求将指针与16位对齐)将每个指针指向的前两个顶点加载到寄存器中.
从a加载的寄存器将如下所示:[a0.x,a0.z,a1.x,a1.z]
步骤3.
现在,使用单个减法指令,可以一次计算2个顶点的增量(v0,v1,v2).
计算v0,v1和v2不仅对于前2个三角形,而且对于后者2!
如我所说,每个输入应该共提供4个顶点,或8个浮点数.只需重复步骤2和3的数据.
现在我们有2对vx寄存器,每对包含2个三角形的结果.我将它们称为vx_0(第一对)和vx_1(第二对),其中x为0到2.
步骤4.
点产品.为了平行重心计算(稍后),我们需要在1个单个寄存器中的每个4个三角形的每个点积的结果.
所以在这里你可以计算dot01,我们会做同样的事情,但是一次就是4个三角形.每个v-register包含2个向量的结果,所以我们从它们的乘法开始.
让我们说你的点积函数中的u和v参数现在是v0_0和v1_0(为了计算dot01):
乘以u和v得到:[(v0_0.x0)*(v1_0.x0),(v0_0.z0)*(v1_0.z0),(v0_0.x1)*(v1_0.x1),(v0_0.z1)* (v1_0.z1)]
这可能会因为.x0 / .z0和.x1 / .z1而引起混乱,但是请看第2步中加载的内容:a0,a1.
如果到现在仍然感觉到模糊,拿起一张纸,从一开始写下来.
接下来,对于相同的点积,仍然执行v0_1和v1_1的乘法(即第二对三角形).
现在我们有2个寄存器,2个X& Z对每个(总共4个顶点),乘以并准备加在一起以形成4个单独的点积. SSE3有一个这样做的指令,它被称为HADDPS:
xmm0 = [A,B,C,D]
xmm1 = [E,F,G,H]
HADDPS xmm0,xmm1这样做:
xmm0 = [A B,C D,E F,G H]
这将是X& Z对从我们的第一个寄存器,从第二个寄存器,将它们添加在一起,并将它们存储在目标寄存器的第一个,第二个,第三个和第四个组件中. Ergo:在这一点上,我们已经有了所有4个三角形的特殊点阵
**现在对所有的点产品重复此过程:dot00等. **
步骤5.
最后的计算(根据提供的代码我可以看到)是重心的东西.这是您的代码中的100%标量计算.但是现在您的输入不是标量点产品结果(即单个浮点数),它们是SSE向量/寄存器,其中4个三角形中的每一个都具有点积.
因此,如果您使用对所有4个浮点运算的并行SSE操作进行向量化,则最终将最终得到4个高度的1个寄存器(或结果),每个三角形1个.
因为我的午餐休息已经过去了,因为我不会拼出这一个,但是鉴于我给出的设置/想法是最后一步,不应该很难弄清楚.
我知道这个想法有点延伸,需要一些喜欢上面的代码,也许有一些质量好的铅笔和纸张,但是它会很快(如果你愿意,你甚至可以添加OpenMP ).
祝你好运 :)
(和原谅我的模糊的解释,我可以鞭打的功能,如果需要=))
UPDATE
我已经写了一个实现,并没有像我预期的那样去,主要是因为Y组件涉及到你最初粘贴在你的问题中的代码段(我查看了).我在这里做的不仅仅是要求您将所有点重新排列到XZ对,并且每4进给一次,而且还会为每个4个三角形的Y值提供3个指针(点A,B和C).从本地角度看,这是最快的.我仍然可以修改它,要求从被调查者的最后的侵入性更改,但请让我知道什么是可取的.
然后一个免责声明:这段代码是直截了当的(我发现与SSE编译器工作相当),他们可以重新组织,看到合适,x86 / x64 cpu也占据了他们的份额).另外命名,这不是我的风格,它不是任何人,只是做它你认为合适.
希望它有帮助,如果不是,我会很乐意再次来过.如果这是一个商业项目,我也可以选择让我在船上我猜;)
无论如何,我把它放在了pastebin:http://pastebin.com/20u8fMEb上