在我转换为SSE的一些代码中,我预先形成一些光线跟踪,使用__m128数据类型一次跟踪4条光线。
在我确定首先击中哪些对象的方法中,我遍历所有对象,测试交叉点并创建一个掩码,表示哪些光线的交叉点比先前找到的要早。
我还需要维护与最佳命中时间相对应的对象id的数据。我这样做是通过维护一个名为objectNo的__m128数据类型来实现的,并且我使用从交叉时间确定的掩码来更新objectNo,如下所示:
objectNo = _mm_blendv_ps(objectNo,_mm_set1_ps((float)pobj->getID()),mask);
其中pobj-> getID()将返回一个表示当前对象id的整数。进行此演员表并使用混音似乎是更新所有4条光线的objectNo的最有效方法。
在测试所有交叉点之后,我尝试单独提取objectNo并使用它们来访问数组以注册交集。最常见的是我尝试过这个:
int o0 = _mm_extract_ps(objectNo, 0);
prv_noHits[o0]++;
然而,这与EXC_BAD_ACCESS崩溃,因为提取值为1.0的浮点数会转换为值为1065353216的int。
如何正确地将__m128打包成可用于索引数组的整数?
答案 0 :(得分:4)
有两个SSE2转换内在函数似乎可以做你想要的:
_mm_cvtps_epi32()
_mm_cvttps_epi32()
这些将4个单精度FP转换为4个32位整数。第一个用圆角来做。第二个使用截断。
所以他们可以像这样使用:
int o0 = _mm_extract_epi32(_mm_cvtps_epi32(objectNo), 0);
prv_noHits[o0]++;
编辑:根据您的目标,我觉得可以更好地优化如下:
__m128i ids = _mm_set1_epi32(pobj->getID());
// The mask will need to change
objectNo = _mm_blend_epi16(objectNo,ids,mask);
int o0 = _mm_extract_epi32(objectNo, 0);
prv_noHits[o0]++;
此版本摆脱了不必要的转换。但是你需要使用不同的蒙版矢量。
编辑2:这是一种方式,您无需更换面具:
__m128 ids = _mm_castsi128_ps(_mm_set1_epi32(pobj->getID()));
objectNo = _mm_blendv_ps(objectNo,ids,mask);
int o0 = _mm_extract_ps(objectNo, 0);
prv_noHits[o0]++;
请注意,_mm_castsi128_ps()
内在函数不会映射任何指令。这只是从__m128i
到__m128
的一点点数据类型转换,以解决C / C ++中的“类型性”。