c – 如何优化“u [0] * v [0] u [2] * v [2]”与SSE或GLSL的代
我有以下功能(从开源项目
“recast navigation”):
/// 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; 解决方法
在纸上尝试了几件事后,我想出了可能为您工作的东西.它是SSE中功能的适当并行化/矢量化实现.
然而,它需要数据重组,因为我们将一次对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! 现在我们有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] 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上 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |