Wprowadzam szybką funkcję konwersji x888 -> 565 pikseli w pixman zgodnie z algorytmem opisanym jako by Intel [pdf]. Ich kod konwertuje x888 -> 555, podczas gdy ja chcę przekonwertować na 565. Niestety, konwersja do 565 oznacza, że ustawiony jest wysoki bit, co oznacza, że nie mogę używać instrukcji zestawu sygnatur nasycenia. Niepodpisana instrukcja packus packwd została dodana dopiero w wersji SSE4.1. Chciałbym wdrożyć jego funkcjonalność za pomocą SSE2 lub znaleźć inny sposób na to.Symulowanie funkcjonalności packusdw z SSE2
Ta funkcja pobiera dwa rejestry XMM zawierające 4 32-bitowe piksele i wyprowadza pojedynczy rejestr XMM zawierający 8 przekonwertowanych pikseli 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);
}
Pomysły Myślałem o:
odjęcie 0x8000, _mm_packs_epi32, ponowne dodanie do każdego 0x8000 565 pikseli. Próbowałem tego, ale nie mogę tego zrobić.
t0 = _mm_sub_epi16 (t0, mask_8000); t1 = _mm_sub_epi16 (t1, mask_8000); t0 = _mm_packs_epi32 (t0, t1); return _mm_add_epi16 (t0, mask_8000);
Przetasuj dane zamiast je pakować. Działa dla MMX, ale odkąd 16-bitowe tasowanie SSE działa tylko na 64-bitowych high lub low, byłby brudny.
Zapisz wysokie bity, ustaw je na zero, zrób pakiet, następnie przywróć je. Wydaje się dość niechlujny.
Czy jest jakiś inny (mam nadzieję, wydajniejszy) sposób, w jaki mógłbym to zrobić?
Perfect! Wielkie dzięki. Wątpię, by można to było zrobić bardziej efektywnie. – mattst88