【优化技巧】 SIMD - Single Instruction Multiple Data

SIMD - Single Instruction Multiple Data 

现代微处理器中使用一条指令进行多个数据运算的技术

对于矢量运算和矩阵运算可以迅速地执行

被广泛运用于游戏引擎的数学库中


对于矢量和矩阵的运算(比如使用矩阵对矢量进行变换)

将四个浮点数打包进入128bit的寄存器

于是对于加法和乘法,可以使用一条指令对四个浮点数同时进行运算


四个浮点数可以个别读写

但是速度较慢(因为需要在FPU和SSE的寄存器之间传输数据)

因此应尽量避免普通float运算和SIMD运算的混合使用。

而在使用SIMD做运算时就应尽量将数据保存在SSE寄存器中做运算

即使是标量与向量的运算,也将标量复制为4份同时进行运算


在 Visual Studio 中 (为了区分两个下划线,博主手动在两条下划线之间添加了一个空格方便您查看)

使用内建的 _ _m128 类型的数据即可使用这个优化的方法 

以 _ _m128 类型作为自动变量或者参数时编译器会将他直接置于SSE寄存器中


注意,_ _m128 类型在内存中时

要将其地址以 16 字节对齐,即是变量地址最低有效半字节需为 0x0

使用自动变量时编译器会自动进行管理

但是动态分配时则需要程序猿手动保证哦~


操作_ _m128 类型时需要包含 xmmintrin.h 头文件中的内部函数

下面例子将两个 1X4 的数组内容相加并输出

_ _declspec(align(16)) 使变量使用16字节进行内存对齐

#include 
#include 

_ _declspec(align(16))  float A[] = {1.0f, 2.0f, 3.0f, 4.0f};
_ _declspec(align(16))  float B[] = {4.0f, 3.0f, 2.0f, 1.0f};
_ _declspec(align(16))  float C[4] = {0.0f};

int main(void)
{
        _ _m128  a  =  _mm_load_ps(A);
        _ _m128  b  =  _mm_load_ps(B);

        _ _m128  c  = _mm_add_ps(a, b);
        _mm_store_ps(C, c);

        printf("%.2f, %.2f, %.2f, %.2f\n", C[0], C[1], C[2], C[3]);

	return 0;
}

在3D游戏中

常在3D向量末尾添加一个元素(通常为1.0)作为齐次坐标

于是3D向量就成了一个 1X4 的矩阵

而仿射矩阵为 4X4 矩阵

使用 1X4 矩阵与 4X4 矩阵进行乘法运算

其结果即是对坐标进行矩阵变换后的坐标


使用 SIMD 对运算进行优化

技巧在于将齐次坐标和矩阵的行或列分别视为一个 _ _m128 中的四个元素

将齐次坐标中的 xyzw 每一个分别填充一个 _ _m128 

将矩阵中每一行的四个元素填充一个 _ _m128

// 使用矩阵对矢量进行变换 - SIMD 方法
inline __m128 TransformVectorByMatrix_Quick(
	const __m128 &mvec, 
	const __m128 &mmline1,
	const __m128 &mmline2,
	const __m128 &mmline3,
	const __m128 &mmline4)
{
	__m128 mrowx = _mm_mul_ps(mmline1, _mm_shuffle_ps(mvec, mvec, _MM_SHUFFLE(0, 0, 0, 0)));
	__m128 mrowy = _mm_mul_ps(mmline2, _mm_shuffle_ps(mvec, mvec, _MM_SHUFFLE(1, 1, 1, 1)));
	__m128 mrowz = _mm_mul_ps(mmline3, _mm_shuffle_ps(mvec, mvec, _MM_SHUFFLE(2, 2, 2, 2)));
	__m128 mroww = _mm_mul_ps(mmline4, _mm_shuffle_ps(mvec, mvec, _MM_SHUFFLE(3, 3, 3, 3)));

	__m128 result0 = _mm_add_ps(mrowx, mrowy);
	__m128 result1 = _mm_add_ps(mrowz, mroww);
	
	return _mm_add_ps(result0, result1);
}

















你可能感兴趣的:(编程技巧干货)