我正在编写一个小型图形 3D 应用程序,以了解 Clang 矢量和矩阵扩展(如果我阅读正确版本的文档,矩阵似乎仍在开发中)。
我不确定如何使用这些类型编写最有效的矩阵向量乘法代码。使用:
typedef float float4 __attribute__((ext_vector_type(4)));
typedef float m4x4 __attribute__((matrix_type(4, 4)));
文档说(关于访问矩阵元素的索引):
第一个指定行数,第二个指定列数。
Column
|
v
Row->| M00 M01 M02 M03 |
| M10 M11 M12 M13 |
| M20 M21 M22 X23 |
| M30 M31 M32 M33 |
所以我知道执行 m[2][3] (其中 m 是 m4x4),会给我在上面的矩阵中注意到 X 的元素。
然后(关于元素在内存中的布局方式):
矩阵类型值的元素按列主序排列,无需填充。
所以我从这篇文章中得知,如果我能看看元素在内存中的存储方式,我会得到:
M00 M10 M20 M30 - M01 M11 M21 M31 - M02 M12 M22 M32 - M03 M13 X23 M33
到目前为止我做对了吗?
然后我假设如果我想在 mat-float4 乘法中提高效率,我需要按照它们在内存中的布局方式访问元素,所以这样做:
m4x3 m;
float4 v = {0.2, 0.3, 0.4, 1};
float4 res = {
v.x * m[0][0] + v.y * m[1][0] + v.z * m[2][0] + v.w * m[3][0],
v.x * m[0][1] + v.y * m[1][1] + v.z * m[2][1] + v.w * m[3][1],
v.x * m[0][2] + v.y * m[1][2] + v.z * m[2][2] + v.w * m[3][2],
1 // ignore w element for now
}
当然,我可以使用
__builtin_matrix_column_major_load
之类的方法在 m[0][0]、m[0][1]、... 中加载正确的值。
我是否把事情过于复杂化了,或者这里的顺序应该重要吗?上面的等式实际上比:
更好吗?float4 res = {
v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2] + v.w * m[0][3],
v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2] + v.w * m[1][3],
v.x * m[2][0] + v.y * m[2][1] + v.z * m[2][2] + v.w * m[2][3],
1 // ignore w element for now
}
(假设我在调用
__builtin_matrix_column_major_load
之前已经调换了元素。
现在我知道这些类型目前正在开发中。但我知道这些类型的全部意义在于利用 SIMD 指令。如果我这样做:
float4 a = {...};
float4 b = {...};
float4 c = a + b;
然后将 4 个浮点数
a
添加到 4 个浮点数 b
会在一个周期内发生吗?因此,关于 mat-float4 乘法,因为我在代码中单独调用 float4 和 m4x4 的元素,所以在这种特殊情况下我似乎不会利用任何优化?
所以我的第二个问题:有更好的方法吗?
__m128
中,并使用这些元素通过额外的 SIMD 指令(例如 _mm_add_ps
和 mm_mul_ps
)来获得矩阵元素乘以向量的元素。如有任何反馈或建议,我们将不胜感激。我这样做是为了了解这些新的内置类型的练习。
万一有人现在发现这个。
typedef float float4 __attribute__((ext_vector_type(4)));
typedef float float4x4 __attribute__((matrix_type(4, 4)));
float4 mulmv4(float4x4 mat, float4 vec) {
typedef float float4x1 __attribute__((matrix_type(4, 1)));
float4 dst;
float4x1 col = __builtin_matrix_column_major_load((float *)&vec, 4, 1, 4);
__builtin_matrix_column_major_store(mat * col, (float *)&dst, 4);
return dst;
}
转换为“矩阵”列并定义乘积。这确实应该是内置的,尽管就像你所说的 Clang 矩阵类型 正在开发中。
顺便说一句,您可以将相同的概念应用于 ext_vector_types 的点积,因为据我所知,它也不是内置的。 Dot 会将 float1x4 乘以 float4x1(按此顺序)。