Моделирование функциональности packusdw с помощью SSE2

Я реализую функцию быстрого преобразования x888 -> 565 пикселей в pixmanв соответствии с описанным алгоритмом Intel [pdf] . Их код преобразует x888 -> 555, а я хочу преобразовать в 565. К сожалению, преобразование в 565 означает, что установлен старший бит, а это означает, что я не могу использовать инструкции пакета насыщения со знаком. Инструкция unsigned pack, packusdw, не добавлялась до SSE4.1. Я хотел бы реализовать его функциональность с помощью SSE2 или найти другой способ сделать это.

Эта функция принимает два регистра XMM, содержащих 4 32-битных пикселя каждый, и выводит один регистр XMM, содержащий 8 преобразованных пикселей RGB565.

static force_inline __m128i
pack_565_2packedx128_128 (__m128i lo, __m128i hi)
{
    __m128i rb0 = _mm_and_si128 (lo, mask_565_rb);
    __m128i rb1 = _mm_and_si128 (hi, mask_565_rb);

    __m128i t0 = _mm_madd_epi16 (rb0, mask_565_pack_multiplier);
    __m128i t1 = _mm_madd_epi16 (rb1, mask_565_pack_multiplier);

    __m128i g0 = _mm_and_si128 (lo, mask_green);
    __m128i g1 = _mm_and_si128 (hi, mask_green);

    t0 = _mm_or_si128 (t0, g0);
    t1 = _mm_or_si128 (t1, g1);

    t0 = _mm_srli_epi32 (t0, 5);
    t1 = _mm_srli_epi32 (t1, 5);

    /* XXX: maybe there's a way to do this relatively efficiently with SSE2? */
    return _mm_packus_epi32 (t0, t1);
}

Идеи, которые я придумал:

  • Вычитание 0x8000, _mm_packs_epi32, повторное добавление 0x8000 к каждому 565 пикселю. Я пробовал это, но я не могу заставить это работать.

     t0 = _mm_sub_epi16 (t0, mask_8000);
    t1 = _mm_sub_epi16 (t1, mask_8000);
    t0 = _mm_packs_epi32 (t0, t1);
    вернуть _mm_add_epi16 (t0, mask_8000);
    
  • Перемешивать данные вместо упаковки. Работает для MMX, но, поскольку 16-битное перемешивание SSE работает только со старшими или младшими 64-битными битами, это может привести к путанице.

  • Сохраните старшие биты, обнулите их, выполните пакет, а затем восстановите их. Кажется довольно грязным.

Есть ли другой (надеюсь, более эффективный) способ сделать это?

6
задан Paul R 14 June 2012 в 07:47
поделиться