出于个人和娱乐目的,我正在使用 SSE(4.1) 编写一个 geom 库。
我花了最后 12 个小时试图理解处理行主要与列主要存储矩阵时的性能问题。
我知道 Dirext/OpenGL 矩阵是以行主顺序存储的,因此对我来说,将矩阵按行主顺序存储会更好,这样在将矩阵存储到 GPU/着色器或从 GPU/着色器加载矩阵时就不会进行转换。
但是,我做了一些分析,并且我通过专栏专业获得了更快的结果。
要使用行主变换矩阵变换一个点,它是 P' = P * M。而在列主变换矩阵中,它是 P' = M * P。
因此,在列专业中,它只是 4 点积,因此在行专业中,只有 4 个 SSE4.1 指令 (_mm_dp_ps ),我必须在转置矩阵上执行这 4 个点积。
10M 向量的性能结果
(30/05/2014@08:48:10)日志:[5](Vec.Mul.Matrix)= 76.216653 ms(行主要变换)
(30/05/2014@08:48:10)日志:[6](Matrix.Mul.Vec)= 61.554892 ms(列主要变换)
我尝试了几种方法来进行 Vec * Matrix 操作,使用或不使用 _MM_TRANSPOSE ,我发现最快的方法是这样的:
mssFloat Vec4::operator|(const Vec4& v) const //-- Dot Product
{
return _mm_dp_ps(m_val, v.m_val, 0xFF ).m128_f32[0];
}
inline Vec4 operator*(const Vec4& vec,const Mat4& m)
{
return Vec4( Vec4( m[0][0],m[1][0],m[2][0],m[3][0]) | vec
, Vec4( m[0][1],m[1][1],m[2][1],m[3][1]) | vec
, Vec4( m[0][2],m[1][2],m[2][2],m[3][2]) | vec
, Vec4( m[0][3],m[1][3],m[2][3],m[3][3]) | vec
);
}
我的类 Vec4 只是一个 __m128 m_val,在优化的 C++ 中,向量构造都是在 SSE 寄存器上有效完成的。
我的第一个猜测是,这种乘法不是最佳的。我是 SSE 的新手,所以我有点困惑如何优化它,我的直觉告诉我使用 shuffle 指令,但我想了解为什么它会更快。它会比分配更快地加载 4 shuffle __m128 ( __m128 m_val = _mm_set_ps(w, z, y, x); )
From https://software.intel.com/sites/landingpage/IntrinsicsGuide/ https://software.intel.com/sites/landingpage/IntrinsicsGuide/我找不到 mm_set_ps 的性能信息
编辑:我仔细检查分析方法,每个测试都以相同的方式完成,因此没有内存缓存差异。为了避免本地缓存,我正在对随机错误向量数组进行操作,每个测试的种子都是相同的。每次执行时仅进行 1 次测试,以避免内存缓存提高性能。