三维向量运算SSE/SSE2优化

减小字体 增大字体作者:chaos  来源:本站整理  发布时间:2009-12-04 15:49:00
要使用SSE,必须先确认你的编译器是否支持新的指令集。VC6 sp6、VC.net、.net 2003、ICL、GCC 、nasm 都支持SSE指令集。我推荐使用ICL,它的优化做得最棒,生成的指令最紧凑、效率最高。使用SSE有两种途径,一是直接编写汇编代码,但难度较大,需要有一定的汇编经验;二是使用SSE intrinsic,一种直接在C/C++里使用SSE指令的伪函数调用。在图形运算的核心环节上、如raytrace核心,我建议使用汇编,这样才能极大地体现出SSE的优势、与x86指令混合使用,并充分使用它的并行性。而在大多数场合下则推荐使用intrinsic,它的可读性高,而且编译器会在最后把函数调用替换成SSE指令,这样既不需要写内嵌汇编代码,又可以保证代码的执行效率。

下面将通过几个简单的运算例子介绍SSE intrinsic的使用。首先,使用SSE需要一个新的头文件

#include <xmmintrin.h>
里面定义了一个新的数据类型,__m128,这是一个128位、4个32位单精度浮点数的结构,如果你正在使用VC.net,你会看到它是一个关键字,被当作一种基本数据类型。要是你不打算使用汇编SSE,那么就没必要深究编译器在幕后到底如何处理__m128类型的数据,你只需要知道里面能存放四个float,而这四个float可以进行并行运算。

在定义了__m128后,文件声明一大堆对__m128进行运算的函数,如_mm_add_ps、_mm_sub_ps等等,这就是SSE运算指令的声明。使用SSE优化在这些声明的帮助下变得非常简单,如计算两个向量之和,平时需要每一个元素进行一次加法运算,现在只需要简单地:
__m128 a , b , c;
c = _mm_add_ps( a , b );

这样等价于:
float a[4] , b[4] , c[4];
for( int i = 0 ; i < 4 ; ++ i )
    c[i] = a[i] + b[i];

但前者的运算是并行的,在一般情况下效率远比后者要高。况且在描述复杂的运算的时候,如:
       a = b * c + d / e;
则可以直接写成:
__m128 a = _mm_add_ps( _mm_mul_ps( b , c ) , _mm_div_ps( d , e ) );

咋看之下,很多效率至上的人马上就会大叫"昂贵的函数调用啊!Bad smell code!"。其实我正要告诉你,我也是效率至上派的。前面已经说过了,这些看上去貌似函数的调用实际上并非函数,而是所谓intrinsic,它们在编译优化中将被解释为单条或多条SSE指令,而且编译器会自动调节调用顺序以使其最大并行效率。
不过除了直接使用这些intrinsic以外,我们还可以把它们封装到类里面,重载运算符,这样就可以把运算写成可读性更强的算术式。如果你不愿意自己动手封装,也可以使用Intel封装好了的F32vec4类,它提供了完备的运算符重载,完全使用SSE,非常方便。
虽然Intel封装好的类已经很完善了,但还有一大堆数学运算需要我们自己动手进行编写,如内积(点积)和外积(叉积)。

首先来看一个比较实用的运算,求倒数。求倒数在很多数学库里都有专门的优化,通常原理都是先求出一个近似值,然后通过Newton-Raphson逼近法求出较精确值,下面的代码摘自NV的fastmath.cpp:

上一页  [1] [2] [3] [4] [5] [6]  下一页

  • 好的评价 如果您觉得此文章好,就请您
      100%(2)
  • 差的评价 如果您觉得此文章差,就请您
      0%(0)
   评论摘要(共 0 条,得分 0 分,平均 0 分) 查看完整评论

用户名:   验证码:

分 值:100分 85分 70分 55分 40分 25分 10分 1分

内 容:

      若文章有错误,请将右边打钩通知管理员

关于本站 - 友情连接 - 网站地图 - 我要留言