float4::set_wxy(以及其他set-swizzle操作)的更好的SSE2实现

A better SSE2 implementation for float4::set_wxy (and other set-swizzle ops)?

本文关键字:操作 SSE2 实现 set-swizzle 更好 及其他 set wxy float4      更新时间:2023-10-16

我正在用SSE2/AVX内部函数在C++中编写一个符合HLSL float4的类型,目前我正在HLSL中实现所有可用于float4设置的swizzle操作。我正试图找出一个最佳的SSE2实现来处理涉及(swizzle)设置2或3个组件的集合swizzle操作(因为用一个SSE shuffle操作实现4个组件的集swizzle是微不足道的)。例如,如果没有至少4/5个SSE混洗操作,我想不出更好的方法来实现say set_wxy,例如:

inline/__forceinline void float4::set_wxy(const float4& x)
{
    float4 tmp2 = *this;
    tmp2.set_wxyz(x);                         // set_wxyz = 1 x _mm_shuffle_ps
    const __m128 xyw_tmp = tmp2.zxyw().data;  // zxyw() = 1 x _mm_shuffle_ps
    const __m128 z_tmp = zxyw().data;         // zxyw() = 1 x _mm_shuffle_ps
    tmp2 = _mm_move_ss(xyw_tmp, z_tmp);
    set_zxyw(tmp2);                           // set_zxyw() = 1 x _mm_shuffle_ps
}

在不使用SSE2以外的操作的情况下,有人有更好的实现想法吗?因为我知道SSE4/AVX中的_mm_blend_ps,当通过预处理器条件可用时,我将使用它,但我希望至少支持仅SSE2的代码路径。提前感谢!

编辑:这个函数的行为示例是:

float4 k(5,5,5,5);
k.set_wxy(float4(1,2,3,4));
// now k == (2, 3, 5, 1)

基本上,set_wxy使用x、y、z的参数按此顺序设置w、x、y组件,保留原始z值。

您正试图模仿HLSL的这一行,对吧?

vec2.wxy = vec1.xyz;

使用_mm_shuffle_ps可以以某种有限的方式组合两个向量这一事实,您可以有所进展。这是我的尝试:

// xyzw is vec1, XYZW is vec2
__m128 xxZZ = _mm_shuffle_ps(vec1, vec2, _MM_SHUFFLE(2, 2, 0, 0));
__m128 ZxZx = _mm_shuffle_ps(xxZZ, xxZZ, _MM_SHUFFLE(0, 2, 0, 2));
__m128 yzZx = _mm_shuffle_ps(vec1, ZxZx, _MM_SHUFFLE(1, 0, 2, 1));
vec2 = yzZx;