Здравствуйте уважаемые. Давно у нас не было интересных задачек. Сообщение будет в нескольких частях (ограничение на размер поста) Я тут на днях чет по приколу понял что в инете толком нету ничего. Решил написать свой код на базе SSE2 В общем есть базовая реализация на плюсах. Я ее написал чисто как эталон. Базовый код фукнции он такой Вход - данные в порядке BGRA Выход - данные в порядке UYVY Код (C++): void rgb32_yuv422_std(uint32_t width, uint32_t height, const uint8_t* RGBA, uint8_t* YUV) { const uint8_t* rgb_ptr1 = nullptr; uint8_t* y_ptr1 = nullptr; for (int y = 0; y < height; y+=1) { rgb_ptr1 = RGBA + y * width * 4; y_ptr1 = YUV + y * width * 2; for (int x = 0; x < width; x += 2) { y_ptr1[1] = clampV(((66 * (rgb_ptr1[2]) + 129 * (rgb_ptr1[1]) + 25 * (rgb_ptr1[0]) + 128) >> 8) + 16); y_ptr1[0] = clampV(((-38 * (rgb_ptr1[2]) - 74 * (rgb_ptr1[1]) + 112 * (rgb_ptr1[0]) + 128) >> 8) + 128); y_ptr1[2] = clampV(((112 * (rgb_ptr1[2]) - 94 * (rgb_ptr1[1]) - 18 * (rgb_ptr1[0]) + 128) >> 8) + 128); y_ptr1[3] = clampV(((66 * (rgb_ptr1[6]) + 129 * (rgb_ptr1[5]) + 25 * (rgb_ptr1[4]) + 128) >> 8) + 16); rgb_ptr1 += 8; y_ptr1 += 4; } } }
Далее я сделал процедуру на SSE2 (тоже С++ код, но в целом он полностью иммитирует асм за счет интриников) Спойлер: SSE2 convert Код (C++): void rgb32_yuv422_sse2(uint32_t width, uint32_t height, const uint8_t* RGBA, uint8_t* YUV) { int x, y; for (y = 0; y < height - 1; y += 2) { const uint8_t* rgb_ptr1 = RGBA + y * width * 4, * rgb_ptr2 = RGBA + (y + 1) * width * 4; uint8_t* y_ptr1 = YUV + y * width * 2, * y_ptr2 = YUV + (y + 1) * width * 2; for (x = 0; x < (width - 31); x += 32) { // ITC BT.709 __m128i r_16, g_16, b_16, b_32_lo, b_32_hi, g_32_lo, g_32_hi, r_32_lo, r_32_hi; __m128i y1_16, y1_16_2, y2_16, y2_16_2, cb1_16, cb2_16, cr1_16, cr2_16; __m128i y_32_lo, y_32_hi; __m128i tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8; __m128i UYVY1, UYVY2, UYVY3, UYVY4, UYVYLo, UYVYHi; __m128i mask = _mm_set_epi8(14, 15, 13, 14, 11, 12, 9, 10, 7, 8, 5, 6, 3, 4, 1, 2); __m128i mask_cx = _mm_set_epi8(15, 14, 11, 10, 7, 6, 3, 2, 13, 12, 9, 8, 5, 4, 1, 0); __m128i rgb1 = LOAD_SI128((const __m128i*)(rgb_ptr1)); __m128i rgb2 = LOAD_SI128((const __m128i*)(rgb_ptr1 + 16)); __m128i rgb3 = LOAD_SI128((const __m128i*)(rgb_ptr1 + 32)); __m128i rgb4 = LOAD_SI128((const __m128i*)(rgb_ptr1 + 48)); __m128i rgb5 = LOAD_SI128((const __m128i*)(rgb_ptr2)); __m128i rgb6 = LOAD_SI128((const __m128i*)(rgb_ptr2 + 16)); __m128i rgb7 = LOAD_SI128((const __m128i*)(rgb_ptr2 + 32)); __m128i rgb8 = LOAD_SI128((const __m128i*)(rgb_ptr2 + 48)); tmp1 = _mm_unpacklo_epi8(rgb1, rgb2); tmp2 = _mm_unpackhi_epi8(rgb1, rgb2); tmp3 = _mm_unpacklo_epi8(rgb3, rgb4); tmp4 = _mm_unpackhi_epi8(rgb3, rgb4); rgb1 = _mm_unpacklo_epi8(tmp1, tmp2); rgb2 = _mm_unpackhi_epi8(tmp1, tmp2); rgb3 = _mm_unpacklo_epi8(tmp3, tmp4); rgb4 = _mm_unpackhi_epi8(tmp3, tmp4); tmp1 = _mm_unpacklo_epi8(rgb1, rgb2); tmp2 = _mm_unpackhi_epi8(rgb1, rgb2); tmp3 = _mm_unpacklo_epi8(rgb3, rgb4); tmp4 = _mm_unpackhi_epi8(rgb3, rgb4); tmp5 = _mm_unpacklo_epi8(rgb5, rgb6); tmp6 = _mm_unpackhi_epi8(rgb5, rgb6); tmp7 = _mm_unpacklo_epi8(rgb7, rgb8); tmp8 = _mm_unpackhi_epi8(rgb7, rgb8); rgb5 = _mm_unpacklo_epi8(tmp5, tmp6); rgb6 = _mm_unpackhi_epi8(tmp5, tmp6); rgb7 = _mm_unpacklo_epi8(tmp7, tmp8); rgb8 = _mm_unpackhi_epi8(tmp7, tmp8); tmp5 = _mm_unpacklo_epi8(rgb5, rgb6); tmp6 = _mm_unpackhi_epi8(rgb5, rgb6); tmp7 = _mm_unpacklo_epi8(rgb7, rgb8); tmp8 = _mm_unpackhi_epi8(rgb7, rgb8); b_16 = _mm_unpacklo_epi8(tmp1, _mm_setzero_si128()); g_16 = _mm_unpackhi_epi8(tmp1, _mm_setzero_si128()); r_16 = _mm_unpacklo_epi8(tmp2, _mm_setzero_si128()); b_32_lo = _mm_unpacklo_epi16(b_16, _mm_setzero_si128()); b_32_hi = _mm_unpackhi_epi16(b_16, _mm_setzero_si128()); g_32_lo = _mm_unpacklo_epi16(g_16, _mm_setzero_si128()); g_32_hi = _mm_unpackhi_epi16(g_16, _mm_setzero_si128()); r_32_lo = _mm_unpacklo_epi16(r_16, _mm_setzero_si128()); r_32_hi = _mm_unpackhi_epi16(r_16, _mm_setzero_si128()); y_32_lo = _mm_add_epi32(_mm_mullo_epi32(r_32_lo, _mm_set1_epi32(66)), _mm_mullo_epi32(g_32_lo, _mm_set1_epi32(129))); y_32_lo = _mm_add_epi32(y_32_lo, _mm_mullo_epi32(b_32_lo, _mm_set1_epi32(25))); y_32_lo = _mm_add_epi32(y_32_lo, _mm_set1_epi32(128)); y_32_lo = _mm_srai_epi32(y_32_lo, 8); y_32_lo = _mm_add_epi32(y_32_lo, _mm_set1_epi32(16)); y_32_hi = _mm_add_epi32(_mm_mullo_epi32(r_32_hi, _mm_set1_epi32(66)), _mm_mullo_epi32(g_32_hi, _mm_set1_epi32(129))); y_32_hi = _mm_add_epi32(y_32_hi, _mm_mullo_epi32(b_32_hi, _mm_set1_epi32(25))); y_32_hi = _mm_add_epi32(y_32_hi, _mm_set1_epi32(128)); y_32_hi = _mm_srai_epi32(y_32_hi, 8); y_32_hi = _mm_add_epi32(y_32_hi, _mm_set1_epi32(16)); y1_16 = _mm_packs_epi32(y_32_lo, y_32_hi); cb1_16 = _mm_add_epi16(_mm_mullo_epi16(r_16, _mm_set1_epi16(-38)), _mm_mullo_epi16(g_16, _mm_set1_epi16(-74))); cb1_16 = _mm_add_epi16(cb1_16, _mm_mullo_epi16(b_16, _mm_set1_epi16(112))); cb1_16 = _mm_add_epi16(cb1_16, _mm_set1_epi16(128)); cb1_16 = _mm_srai_epi16(cb1_16, 8); cb1_16 = _mm_add_epi16(cb1_16, _mm_set1_epi16(128)); cb1_16 = _mm_shuffle_epi8(cb1_16, mask_cx); cr1_16 = _mm_add_epi16(_mm_mullo_epi16(r_16, _mm_set1_epi16(112)), _mm_mullo_epi16(g_16, _mm_set1_epi16(-94))); cr1_16 = _mm_add_epi16(cr1_16, _mm_mullo_epi16(b_16, _mm_set1_epi16(-18))); cr1_16 = _mm_add_epi16(cr1_16, _mm_set1_epi16(128)); cr1_16 = _mm_srai_epi16(cr1_16, 8); cr1_16 = _mm_add_epi16(cr1_16, _mm_set1_epi16(128)); cr1_16 = _mm_shuffle_epi8(cr1_16, mask_cx); y1_16_2 = _mm_shuffle_epi8(y1_16, mask); b_16 = _mm_unpacklo_epi8(tmp5, _mm_setzero_si128()); g_16 = _mm_unpackhi_epi8(tmp5, _mm_setzero_si128()); r_16 = _mm_unpacklo_epi8(tmp6, _mm_setzero_si128()); b_32_lo = _mm_unpacklo_epi16(b_16, _mm_setzero_si128()); b_32_hi = _mm_unpackhi_epi16(b_16, _mm_setzero_si128()); g_32_lo = _mm_unpacklo_epi16(g_16, _mm_setzero_si128()); g_32_hi = _mm_unpackhi_epi16(g_16, _mm_setzero_si128()); r_32_lo = _mm_unpacklo_epi16(r_16, _mm_setzero_si128()); r_32_hi = _mm_unpackhi_epi16(r_16, _mm_setzero_si128()); y_32_lo = _mm_add_epi32(_mm_mullo_epi32(r_32_lo, _mm_set1_epi32(66)), _mm_mullo_epi32(g_32_lo, _mm_set1_epi32(129))); y_32_lo = _mm_add_epi32(y_32_lo, _mm_mullo_epi32(b_32_lo, _mm_set1_epi32(25))); y_32_lo = _mm_add_epi32(y_32_lo, _mm_set1_epi32(128)); y_32_lo = _mm_srai_epi32(y_32_lo, 8); y_32_lo = _mm_add_epi32(y_32_lo, _mm_set1_epi32(16)); y_32_hi = _mm_add_epi32(_mm_mullo_epi32(r_32_hi, _mm_set1_epi32(66)), _mm_mullo_epi32(g_32_hi, _mm_set1_epi32(129))); y_32_hi = _mm_add_epi32(y_32_hi, _mm_mullo_epi32(b_32_hi, _mm_set1_epi32(25))); y_32_hi = _mm_add_epi32(y_32_hi, _mm_set1_epi32(128)); y_32_hi = _mm_srai_epi32(y_32_hi, 8); y_32_hi = _mm_add_epi32(y_32_hi, _mm_set1_epi32(16)); y2_16 = _mm_packs_epi32(y_32_lo, y_32_hi); cb2_16 = _mm_add_epi16(_mm_mullo_epi16(r_16, _mm_set1_epi16(-38)), _mm_mullo_epi16(g_16, _mm_set1_epi16(-74))); cb2_16 = _mm_add_epi16(cb2_16, _mm_mullo_epi16(b_16, _mm_set1_epi16(112))); cb2_16 = _mm_add_epi16(cb2_16, _mm_set1_epi16(128)); cb2_16 = _mm_srli_epi16(cb2_16, 8); cb2_16 = _mm_add_epi16(cb2_16, _mm_set1_epi16(128)); cb2_16 = _mm_shuffle_epi8(cb2_16, mask_cx); cr2_16 = _mm_add_epi16(_mm_mullo_epi16(r_16, _mm_set1_epi16(112)), _mm_mullo_epi16(g_16, _mm_set1_epi16(-94))); cr2_16 = _mm_add_epi16(cr2_16, _mm_mullo_epi16(b_16, _mm_set1_epi16(-18))); cr2_16 = _mm_add_epi16(cr2_16, _mm_set1_epi16(128)); cr2_16 = _mm_srli_epi16(cr2_16, 8); cr2_16 = _mm_add_epi16(cr2_16, _mm_set1_epi16(128)); cr2_16 = _mm_shuffle_epi8(cr2_16, mask_cx); y2_16_2 = _mm_shuffle_epi8(y2_16, mask); y1_16_2 = _mm_shuffle_epi8(y1_16_2, mask_cx); UYVYLo = _mm_unpacklo_epi8(cr1_16, y1_16_2); UYVYLo = _mm_slli_epi32(UYVYLo, 16); y1_16 = _mm_shuffle_epi8(y1_16, mask_cx); UYVYHi = _mm_unpacklo_epi8(cb1_16, y1_16); UYVY1 = _mm_add_epi8(UYVYHi, UYVYLo); y2_16_2 = _mm_shuffle_epi8(y2_16_2, mask_cx); UYVYLo = _mm_unpacklo_epi8(cr2_16, y2_16_2); UYVYLo = _mm_slli_epi32(UYVYLo, 16); y2_16 = _mm_shuffle_epi8(y2_16, mask_cx); UYVYHi = _mm_unpacklo_epi8(cb2_16, y2_16); UYVY2 = _mm_add_epi8(UYVYHi, UYVYLo); b_16 = _mm_unpacklo_epi8(tmp3, _mm_setzero_si128()); g_16 = _mm_unpackhi_epi8(tmp3, _mm_setzero_si128()); r_16 = _mm_unpacklo_epi8(tmp4, _mm_setzero_si128()); b_32_lo = _mm_unpacklo_epi16(b_16, _mm_setzero_si128()); b_32_hi = _mm_unpackhi_epi16(b_16, _mm_setzero_si128()); g_32_lo = _mm_unpacklo_epi16(g_16, _mm_setzero_si128()); g_32_hi = _mm_unpackhi_epi16(g_16, _mm_setzero_si128()); r_32_lo = _mm_unpacklo_epi16(r_16, _mm_setzero_si128()); r_32_hi = _mm_unpackhi_epi16(r_16, _mm_setzero_si128()); y_32_lo = _mm_add_epi32(_mm_mullo_epi32(r_32_lo, _mm_set1_epi32(66)), _mm_mullo_epi32(g_32_lo, _mm_set1_epi32(129))); y_32_lo = _mm_add_epi32(y_32_lo, _mm_mullo_epi32(b_32_lo, _mm_set1_epi32(25))); y_32_lo = _mm_add_epi32(y_32_lo, _mm_set1_epi32(128)); y_32_lo = _mm_srai_epi32(y_32_lo, 8); y_32_lo = _mm_add_epi32(y_32_lo, _mm_set1_epi32(16)); y_32_hi = _mm_add_epi32(_mm_mullo_epi32(r_32_hi, _mm_set1_epi32(66)), _mm_mullo_epi32(g_32_hi, _mm_set1_epi32(129))); y_32_hi = _mm_add_epi32(y_32_hi, _mm_mullo_epi32(b_32_hi, _mm_set1_epi32(25))); y_32_hi = _mm_add_epi32(y_32_hi, _mm_set1_epi32(128)); y_32_hi = _mm_srai_epi32(y_32_hi, 8); y_32_hi = _mm_add_epi32(y_32_hi, _mm_set1_epi32(16)); y1_16 = _mm_packs_epi32(y_32_lo, y_32_hi); cb1_16 = _mm_add_epi16(_mm_mullo_epi16(r_16, _mm_set1_epi16(-38)), _mm_mullo_epi16(g_16, _mm_set1_epi16(-74))); cb1_16 = _mm_add_epi16(cb1_16, _mm_mullo_epi16(b_16, _mm_set1_epi16(112))); cb1_16 = _mm_add_epi16(cb1_16, _mm_set1_epi16(128)); cb1_16 = _mm_srai_epi16(cb1_16, 8); cb1_16 = _mm_add_epi16(cb1_16, _mm_set1_epi16(128)); cb1_16 = _mm_shuffle_epi8(cb1_16, mask_cx); cr1_16 = _mm_add_epi16(_mm_mullo_epi16(r_16, _mm_set1_epi16(112)), _mm_mullo_epi16(g_16, _mm_set1_epi16(-94))); cr1_16 = _mm_add_epi16(cr1_16, _mm_mullo_epi16(b_16, _mm_set1_epi16(-18))); cr1_16 = _mm_add_epi16(cr1_16, _mm_set1_epi16(128)); cr1_16 = _mm_srai_epi16(cr1_16, 8); cr1_16 = _mm_add_epi16(cr1_16, _mm_set1_epi16(128)); cr1_16 = _mm_shuffle_epi8(cr1_16, mask_cx); y1_16_2 = _mm_shuffle_epi8(y1_16, mask); b_16 = _mm_unpacklo_epi8(tmp7, _mm_setzero_si128()); g_16 = _mm_unpackhi_epi8(tmp7, _mm_setzero_si128()); r_16 = _mm_unpacklo_epi8(tmp8, _mm_setzero_si128()); b_32_lo = _mm_unpacklo_epi16(b_16, _mm_setzero_si128()); b_32_hi = _mm_unpackhi_epi16(b_16, _mm_setzero_si128()); g_32_lo = _mm_unpacklo_epi16(g_16, _mm_setzero_si128()); g_32_hi = _mm_unpackhi_epi16(g_16, _mm_setzero_si128()); r_32_lo = _mm_unpacklo_epi16(r_16, _mm_setzero_si128()); r_32_hi = _mm_unpackhi_epi16(r_16, _mm_setzero_si128()); y_32_lo = _mm_add_epi32(_mm_mullo_epi32(r_32_lo, _mm_set1_epi32(66)), _mm_mullo_epi32(g_32_lo, _mm_set1_epi32(129))); y_32_lo = _mm_add_epi32(y_32_lo, _mm_mullo_epi32(b_32_lo, _mm_set1_epi32(25))); y_32_lo = _mm_add_epi32(y_32_lo, _mm_set1_epi32(128)); y_32_lo = _mm_srai_epi32(y_32_lo, 8); y_32_lo = _mm_add_epi32(y_32_lo, _mm_set1_epi32(16)); y_32_hi = _mm_add_epi32(_mm_mullo_epi32(r_32_hi, _mm_set1_epi32(66)), _mm_mullo_epi32(g_32_hi, _mm_set1_epi32(129))); y_32_hi = _mm_add_epi32(y_32_hi, _mm_mullo_epi32(b_32_hi, _mm_set1_epi32(25))); y_32_hi = _mm_add_epi32(y_32_hi, _mm_set1_epi32(128)); y_32_hi = _mm_srai_epi32(y_32_hi, 8); y_32_hi = _mm_add_epi32(y_32_hi, _mm_set1_epi32(16)); y2_16 = _mm_packs_epi32(y_32_lo, y_32_hi); cb2_16 = _mm_add_epi16(_mm_mullo_epi16(r_16, _mm_set1_epi16(-38)), _mm_mullo_epi16(g_16, _mm_set1_epi16(-74))); cb2_16 = _mm_add_epi16(cb2_16, _mm_mullo_epi16(b_16, _mm_set1_epi16(112))); cb2_16 = _mm_add_epi16(cb2_16, _mm_set1_epi16(128)); cb2_16 = _mm_srli_epi16(cb2_16, 8); cb2_16 = _mm_add_epi16(cb2_16, _mm_set1_epi16(128)); cb2_16 = _mm_shuffle_epi8(cb2_16, mask_cx); cr2_16 = _mm_add_epi16(_mm_mullo_epi16(r_16, _mm_set1_epi16(112)), _mm_mullo_epi16(g_16, _mm_set1_epi16(-94))); cr2_16 = _mm_add_epi16(cr2_16, _mm_mullo_epi16(b_16, _mm_set1_epi16(-18))); cr2_16 = _mm_add_epi16(cr2_16, _mm_set1_epi16(128)); cr2_16 = _mm_srli_epi16(cr2_16, 8); cr2_16 = _mm_add_epi16(cr2_16, _mm_set1_epi16(128)); cr2_16 = _mm_shuffle_epi8(cr2_16, mask_cx); y2_16_2 = _mm_shuffle_epi8(y2_16, mask); y1_16_2 = _mm_shuffle_epi8(y1_16_2, mask_cx); UYVYLo = _mm_unpacklo_epi8(cr1_16, y1_16_2); UYVYLo = _mm_slli_epi32(UYVYLo, 16); y1_16 = _mm_shuffle_epi8(y1_16, mask_cx); UYVYHi = _mm_unpacklo_epi8(cb1_16, y1_16); UYVY3 = _mm_add_epi8(UYVYHi, UYVYLo); y2_16_2 = _mm_shuffle_epi8(y2_16_2, mask_cx); UYVYLo = _mm_unpacklo_epi8(cr2_16, y2_16_2); UYVYLo = _mm_slli_epi32(UYVYLo, 16); y2_16 = _mm_shuffle_epi8(y2_16, mask_cx); UYVYHi = _mm_unpacklo_epi8(cb2_16, y2_16); UYVY4 = _mm_add_epi8(UYVYHi, UYVYLo); SAVE_SI128((__m128i*)(y_ptr1), UYVY1); SAVE_SI128((__m128i*)(y_ptr1 + 16), UYVY3); SAVE_SI128((__m128i*)(y_ptr2), UYVY2); SAVE_SI128((__m128i*)(y_ptr2 + 16), UYVY4); rgb_ptr1 += 64; rgb_ptr2 += 64; rgb1 = LOAD_SI128((const __m128i*)(rgb_ptr1)); rgb2 = LOAD_SI128((const __m128i*)(rgb_ptr1 + 16)); rgb3 = LOAD_SI128((const __m128i*)(rgb_ptr1 + 32)); rgb4 = LOAD_SI128((const __m128i*)(rgb_ptr1 + 48)); rgb5 = LOAD_SI128((const __m128i*)(rgb_ptr2)); rgb6 = LOAD_SI128((const __m128i*)(rgb_ptr2 + 16)); rgb7 = LOAD_SI128((const __m128i*)(rgb_ptr2 + 32)); rgb8 = LOAD_SI128((const __m128i*)(rgb_ptr2 + 48)); tmp1 = _mm_unpacklo_epi8(rgb1, rgb2); tmp2 = _mm_unpackhi_epi8(rgb1, rgb2); tmp3 = _mm_unpacklo_epi8(rgb3, rgb4); tmp4 = _mm_unpackhi_epi8(rgb3, rgb4); rgb1 = _mm_unpacklo_epi8(tmp1, tmp2); rgb2 = _mm_unpackhi_epi8(tmp1, tmp2); rgb3 = _mm_unpacklo_epi8(tmp3, tmp4); rgb4 = _mm_unpackhi_epi8(tmp3, tmp4); tmp1 = _mm_unpacklo_epi8(rgb1, rgb2); tmp2 = _mm_unpackhi_epi8(rgb1, rgb2); tmp3 = _mm_unpacklo_epi8(rgb3, rgb4); tmp4 = _mm_unpackhi_epi8(rgb3, rgb4); tmp5 = _mm_unpacklo_epi8(rgb5, rgb6); tmp6 = _mm_unpackhi_epi8(rgb5, rgb6); tmp7 = _mm_unpacklo_epi8(rgb7, rgb8); tmp8 = _mm_unpackhi_epi8(rgb7, rgb8); rgb5 = _mm_unpacklo_epi8(tmp5, tmp6); rgb6 = _mm_unpackhi_epi8(tmp5, tmp6); rgb7 = _mm_unpacklo_epi8(tmp7, tmp8); rgb8 = _mm_unpackhi_epi8(tmp7, tmp8); tmp5 = _mm_unpacklo_epi8(rgb5, rgb6); tmp6 = _mm_unpackhi_epi8(rgb5, rgb6); tmp7 = _mm_unpacklo_epi8(rgb7, rgb8); tmp8 = _mm_unpackhi_epi8(rgb7, rgb8); b_16 = _mm_unpacklo_epi8(tmp1, _mm_setzero_si128()); g_16 = _mm_unpackhi_epi8(tmp1, _mm_setzero_si128()); r_16 = _mm_unpacklo_epi8(tmp2, _mm_setzero_si128()); b_32_lo = _mm_unpacklo_epi16(b_16, _mm_setzero_si128()); b_32_hi = _mm_unpackhi_epi16(b_16, _mm_setzero_si128()); g_32_lo = _mm_unpacklo_epi16(g_16, _mm_setzero_si128()); g_32_hi = _mm_unpackhi_epi16(g_16, _mm_setzero_si128()); r_32_lo = _mm_unpacklo_epi16(r_16, _mm_setzero_si128()); r_32_hi = _mm_unpackhi_epi16(r_16, _mm_setzero_si128()); y_32_lo = _mm_add_epi32(_mm_mullo_epi32(r_32_lo, _mm_set1_epi32(66)), _mm_mullo_epi32(g_32_lo, _mm_set1_epi32(129))); y_32_lo = _mm_add_epi32(y_32_lo, _mm_mullo_epi32(b_32_lo, _mm_set1_epi32(25))); y_32_lo = _mm_add_epi32(y_32_lo, _mm_set1_epi32(128)); y_32_lo = _mm_srai_epi32(y_32_lo, 8); y_32_lo = _mm_add_epi32(y_32_lo, _mm_set1_epi32(16)); y_32_hi = _mm_add_epi32(_mm_mullo_epi32(r_32_hi, _mm_set1_epi32(66)), _mm_mullo_epi32(g_32_hi, _mm_set1_epi32(129))); y_32_hi = _mm_add_epi32(y_32_hi, _mm_mullo_epi32(b_32_hi, _mm_set1_epi32(25))); y_32_hi = _mm_add_epi32(y_32_hi, _mm_set1_epi32(128)); y_32_hi = _mm_srai_epi32(y_32_hi, 8); y_32_hi = _mm_add_epi32(y_32_hi, _mm_set1_epi32(16)); y1_16 = _mm_packs_epi32(y_32_lo, y_32_hi); cb1_16 = _mm_add_epi16(_mm_mullo_epi16(r_16, _mm_set1_epi16(-38)), _mm_mullo_epi16(g_16, _mm_set1_epi16(-74))); cb1_16 = _mm_add_epi16(cb1_16, _mm_mullo_epi16(b_16, _mm_set1_epi16(112))); cb1_16 = _mm_add_epi16(cb1_16, _mm_set1_epi16(128)); cb1_16 = _mm_srai_epi16(cb1_16, 8); cb1_16 = _mm_add_epi16(cb1_16, _mm_set1_epi16(128)); cb1_16 = _mm_shuffle_epi8(cb1_16, mask_cx); cr1_16 = _mm_add_epi16(_mm_mullo_epi16(r_16, _mm_set1_epi16(112)), _mm_mullo_epi16(g_16, _mm_set1_epi16(-94))); cr1_16 = _mm_add_epi16(cr1_16, _mm_mullo_epi16(b_16, _mm_set1_epi16(-18))); cr1_16 = _mm_add_epi16(cr1_16, _mm_set1_epi16(128)); cr1_16 = _mm_srai_epi16(cr1_16, 8); cr1_16 = _mm_add_epi16(cr1_16, _mm_set1_epi16(128)); cr1_16 = _mm_shuffle_epi8(cr1_16, mask_cx); y1_16_2 = _mm_shuffle_epi8(y1_16, mask); b_16 = _mm_unpacklo_epi8(tmp5, _mm_setzero_si128()); g_16 = _mm_unpackhi_epi8(tmp5, _mm_setzero_si128()); r_16 = _mm_unpacklo_epi8(tmp6, _mm_setzero_si128()); b_32_lo = _mm_unpacklo_epi16(b_16, _mm_setzero_si128()); b_32_hi = _mm_unpackhi_epi16(b_16, _mm_setzero_si128()); g_32_lo = _mm_unpacklo_epi16(g_16, _mm_setzero_si128()); g_32_hi = _mm_unpackhi_epi16(g_16, _mm_setzero_si128()); r_32_lo = _mm_unpacklo_epi16(r_16, _mm_setzero_si128()); r_32_hi = _mm_unpackhi_epi16(r_16, _mm_setzero_si128()); y_32_lo = _mm_add_epi32(_mm_mullo_epi32(r_32_lo, _mm_set1_epi32(66)), _mm_mullo_epi32(g_32_lo, _mm_set1_epi32(129))); y_32_lo = _mm_add_epi32(y_32_lo, _mm_mullo_epi32(b_32_lo, _mm_set1_epi32(25))); y_32_lo = _mm_add_epi32(y_32_lo, _mm_set1_epi32(128)); y_32_lo = _mm_srai_epi32(y_32_lo, 8); y_32_lo = _mm_add_epi32(y_32_lo, _mm_set1_epi32(16)); y_32_hi = _mm_add_epi32(_mm_mullo_epi32(r_32_hi, _mm_set1_epi32(66)), _mm_mullo_epi32(g_32_hi, _mm_set1_epi32(129))); y_32_hi = _mm_add_epi32(y_32_hi, _mm_mullo_epi32(b_32_hi, _mm_set1_epi32(25))); y_32_hi = _mm_add_epi32(y_32_hi, _mm_set1_epi32(128)); y_32_hi = _mm_srai_epi32(y_32_hi, 8); y_32_hi = _mm_add_epi32(y_32_hi, _mm_set1_epi32(16)); y2_16 = _mm_packs_epi32(y_32_lo, y_32_hi); cb2_16 = _mm_add_epi16(_mm_mullo_epi16(r_16, _mm_set1_epi16(-38)), _mm_mullo_epi16(g_16, _mm_set1_epi16(-74))); cb2_16 = _mm_add_epi16(cb2_16, _mm_mullo_epi16(b_16, _mm_set1_epi16(112))); cb2_16 = _mm_add_epi16(cb2_16, _mm_set1_epi16(128)); cb2_16 = _mm_srli_epi16(cb2_16, 8); cb2_16 = _mm_add_epi16(cb2_16, _mm_set1_epi16(128)); cb2_16 = _mm_shuffle_epi8(cb2_16, mask_cx); cr2_16 = _mm_add_epi16(_mm_mullo_epi16(r_16, _mm_set1_epi16(112)), _mm_mullo_epi16(g_16, _mm_set1_epi16(-94))); cr2_16 = _mm_add_epi16(cr2_16, _mm_mullo_epi16(b_16, _mm_set1_epi16(-18))); cr2_16 = _mm_add_epi16(cr2_16, _mm_set1_epi16(128)); cr2_16 = _mm_srli_epi16(cr2_16, 8); cr2_16 = _mm_add_epi16(cr2_16, _mm_set1_epi16(128)); cr2_16 = _mm_shuffle_epi8(cr2_16, mask_cx); y2_16_2 = _mm_shuffle_epi8(y2_16, mask); // now we have all bytes for CbYCrY y1_16_2 = _mm_shuffle_epi8(y1_16_2, mask_cx); UYVYLo = _mm_unpacklo_epi8(cr1_16, y1_16_2); UYVYLo = _mm_slli_epi32(UYVYLo, 16); y1_16 = _mm_shuffle_epi8(y1_16, mask_cx); UYVYHi = _mm_unpacklo_epi8(cb1_16, y1_16); UYVY1 = _mm_add_epi8(UYVYHi, UYVYLo); y2_16_2 = _mm_shuffle_epi8(y2_16_2, mask_cx); UYVYLo = _mm_unpacklo_epi8(cr2_16, y2_16_2); UYVYLo = _mm_slli_epi32(UYVYLo, 16); y2_16 = _mm_shuffle_epi8(y2_16, mask_cx); UYVYHi = _mm_unpacklo_epi8(cb2_16, y2_16); UYVY2 = _mm_add_epi8(UYVYHi, UYVYLo); b_16 = _mm_unpacklo_epi8(tmp3, _mm_setzero_si128()); g_16 = _mm_unpackhi_epi8(tmp3, _mm_setzero_si128()); r_16 = _mm_unpacklo_epi8(tmp4, _mm_setzero_si128()); b_32_lo = _mm_unpacklo_epi16(b_16, _mm_setzero_si128()); b_32_hi = _mm_unpackhi_epi16(b_16, _mm_setzero_si128()); g_32_lo = _mm_unpacklo_epi16(g_16, _mm_setzero_si128()); g_32_hi = _mm_unpackhi_epi16(g_16, _mm_setzero_si128()); r_32_lo = _mm_unpacklo_epi16(r_16, _mm_setzero_si128()); r_32_hi = _mm_unpackhi_epi16(r_16, _mm_setzero_si128()); y_32_lo = _mm_add_epi32(_mm_mullo_epi32(r_32_lo, _mm_set1_epi32(66)), _mm_mullo_epi32(g_32_lo, _mm_set1_epi32(129))); y_32_lo = _mm_add_epi32(y_32_lo, _mm_mullo_epi32(b_32_lo, _mm_set1_epi32(25))); y_32_lo = _mm_add_epi32(y_32_lo, _mm_set1_epi32(128)); y_32_lo = _mm_srai_epi32(y_32_lo, 8); y_32_lo = _mm_add_epi32(y_32_lo, _mm_set1_epi32(16)); y_32_hi = _mm_add_epi32(_mm_mullo_epi32(r_32_hi, _mm_set1_epi32(66)), _mm_mullo_epi32(g_32_hi, _mm_set1_epi32(129))); y_32_hi = _mm_add_epi32(y_32_hi, _mm_mullo_epi32(b_32_hi, _mm_set1_epi32(25))); y_32_hi = _mm_add_epi32(y_32_hi, _mm_set1_epi32(128)); y_32_hi = _mm_srai_epi32(y_32_hi, 8); y_32_hi = _mm_add_epi32(y_32_hi, _mm_set1_epi32(16)); y1_16 = _mm_packs_epi32(y_32_lo, y_32_hi); cb1_16 = _mm_add_epi16(_mm_mullo_epi16(r_16, _mm_set1_epi16(-38)), _mm_mullo_epi16(g_16, _mm_set1_epi16(-74))); cb1_16 = _mm_add_epi16(cb1_16, _mm_mullo_epi16(b_16, _mm_set1_epi16(112))); cb1_16 = _mm_add_epi16(cb1_16, _mm_set1_epi16(128)); cb1_16 = _mm_srai_epi16(cb1_16, 8); cb1_16 = _mm_add_epi16(cb1_16, _mm_set1_epi16(128)); cb1_16 = _mm_shuffle_epi8(cb1_16, mask_cx); cr1_16 = _mm_add_epi16(_mm_mullo_epi16(r_16, _mm_set1_epi16(112)), _mm_mullo_epi16(g_16, _mm_set1_epi16(-94))); cr1_16 = _mm_add_epi16(cr1_16, _mm_mullo_epi16(b_16, _mm_set1_epi16(-18))); cr1_16 = _mm_add_epi16(cr1_16, _mm_set1_epi16(128)); cr1_16 = _mm_srai_epi16(cr1_16, 8); cr1_16 = _mm_add_epi16(cr1_16, _mm_set1_epi16(128)); cr1_16 = _mm_shuffle_epi8(cr1_16, mask_cx); y1_16_2 = _mm_shuffle_epi8(y1_16, mask); b_16 = _mm_unpacklo_epi8(tmp7, _mm_setzero_si128()); g_16 = _mm_unpackhi_epi8(tmp7, _mm_setzero_si128()); r_16 = _mm_unpacklo_epi8(tmp8, _mm_setzero_si128()); b_32_lo = _mm_unpacklo_epi16(b_16, _mm_setzero_si128()); b_32_hi = _mm_unpackhi_epi16(b_16, _mm_setzero_si128()); g_32_lo = _mm_unpacklo_epi16(g_16, _mm_setzero_si128()); g_32_hi = _mm_unpackhi_epi16(g_16, _mm_setzero_si128()); r_32_lo = _mm_unpacklo_epi16(r_16, _mm_setzero_si128()); r_32_hi = _mm_unpackhi_epi16(r_16, _mm_setzero_si128()); y_32_lo = _mm_add_epi32(_mm_mullo_epi32(r_32_lo, _mm_set1_epi32(66)), _mm_mullo_epi32(g_32_lo, _mm_set1_epi32(129))); y_32_lo = _mm_add_epi32(y_32_lo, _mm_mullo_epi32(b_32_lo, _mm_set1_epi32(25))); y_32_lo = _mm_add_epi32(y_32_lo, _mm_set1_epi32(128)); y_32_lo = _mm_srai_epi32(y_32_lo, 8); y_32_lo = _mm_add_epi32(y_32_lo, _mm_set1_epi32(16)); y_32_hi = _mm_add_epi32(_mm_mullo_epi32(r_32_hi, _mm_set1_epi32(66)), _mm_mullo_epi32(g_32_hi, _mm_set1_epi32(129))); y_32_hi = _mm_add_epi32(y_32_hi, _mm_mullo_epi32(b_32_hi, _mm_set1_epi32(25))); y_32_hi = _mm_add_epi32(y_32_hi, _mm_set1_epi32(128)); y_32_hi = _mm_srai_epi32(y_32_hi, 8); y_32_hi = _mm_add_epi32(y_32_hi, _mm_set1_epi32(16)); y2_16 = _mm_packs_epi32(y_32_lo, y_32_hi); cb2_16 = _mm_add_epi16(_mm_mullo_epi16(r_16, _mm_set1_epi16(-38)), _mm_mullo_epi16(g_16, _mm_set1_epi16(-74))); cb2_16 = _mm_add_epi16(cb2_16, _mm_mullo_epi16(b_16, _mm_set1_epi16(112))); cb2_16 = _mm_add_epi16(cb2_16, _mm_set1_epi16(128)); cb2_16 = _mm_srli_epi16(cb2_16, 8); cb2_16 = _mm_add_epi16(cb2_16, _mm_set1_epi16(128)); cb2_16 = _mm_shuffle_epi8(cb2_16, mask_cx); cr2_16 = _mm_add_epi16(_mm_mullo_epi16(r_16, _mm_set1_epi16(112)), _mm_mullo_epi16(g_16, _mm_set1_epi16(-94))); cr2_16 = _mm_add_epi16(cr2_16, _mm_mullo_epi16(b_16, _mm_set1_epi16(-18))); cr2_16 = _mm_add_epi16(cr2_16, _mm_set1_epi16(128)); cr2_16 = _mm_srli_epi16(cr2_16, 8); cr2_16 = _mm_add_epi16(cr2_16, _mm_set1_epi16(128)); cr2_16 = _mm_shuffle_epi8(cr2_16, mask_cx); y2_16_2 = _mm_shuffle_epi8(y2_16, mask); y1_16_2 = _mm_shuffle_epi8(y1_16_2, mask_cx); UYVYLo = _mm_unpacklo_epi8(cr1_16, y1_16_2); UYVYLo = _mm_slli_epi32(UYVYLo, 16); y1_16 = _mm_shuffle_epi8(y1_16, mask_cx); UYVYHi = _mm_unpacklo_epi8(cb1_16, y1_16); UYVY3 = _mm_add_epi8(UYVYHi, UYVYLo); y2_16_2 = _mm_shuffle_epi8(y2_16_2, mask_cx); UYVYLo = _mm_unpacklo_epi8(cr2_16, y2_16_2); UYVYLo = _mm_slli_epi32(UYVYLo, 16); y2_16 = _mm_shuffle_epi8(y2_16, mask_cx); UYVYHi = _mm_unpacklo_epi8(cb2_16, y2_16); UYVY4 = _mm_add_epi8(UYVYHi, UYVYLo); SAVE_SI128((__m128i*)(y_ptr1 + 32), UYVY1); SAVE_SI128((__m128i*)(y_ptr1 + 48), UYVY3); SAVE_SI128((__m128i*)(y_ptr2 + 32), UYVY2); SAVE_SI128((__m128i*)(y_ptr2 + 48), UYVY4); rgb_ptr1 += 64; rgb_ptr2 += 64; y_ptr1 += 64; y_ptr2 += 64; } } }
проект я прикреплю - там чтение BMP файла и всякая другая хрень, чтоб удобно было тестировать) Сразу скажу, тестировал на 4к изображении, иначе слишком быстро все. (файл тут : https://drive.google.com/drive/folders/1EJhI7f-EDmdYHDNLHn7Gp4ZFVtwl2ccU?usp=share_link ). Там же находится код проекта и бинарники В коде проекта есть комментарии в оптимизациооном кернеле (тут тупо не влезли) для валидности теста в плане того , чтоб процессор успел поднять частоты - просто в цикле запуск конвертации (100 или более раз) потом деление этого времени на кол-во запусков. Запускать так rgb_yuv_sse.exe test4k.bmp result.yuv 100 (для запуска оптимизации) rgb_yuv_sse.exe test4k.bmp result.yuv 100 1 (для запуска оригинала) 100 - кол-во повторений Оборудование AMD Ryzen 9 7900X - частота - 5.6 Ггц. Память DDR5 5200 результаты такие Для 100 запусков Оригинал : 13.1 мс Оптимизация: 3.8 мс Для 1 запуска Оригинал : 14 мс Оптимизация: 5 мс По сути это топорный вариант, с пакетной обработкой. Хитростей там почти нет. В общем, если кто захочет попробовать себя - сделать быстрее, велком. Там есть еще простор. Я пока не буду спешить выкладывать еще более оптимизированный вариант. Да и просто кто хочет пообщаться подкинуть идей. PS. YUV можно смотреть например этой тулой. https://github.com/IENT/YUView
Слава богу, WASM, вроде, потихоньку начинает приходить в себя и возвращение TermoSINteZ'а с тредом по оптимизации - яркий тому пример. А-то, я уже для себя закон вывел - чем больше человек знает и чем больше у него опыта, тем меньше его постов можно увидеть на WASM. А сомнения по поводу того, что наш уважаемый Синоби даоса много чего знает у меня отпали примерно после этого поста ( https://wasm.in/threads/vyvesti-trassu-vyzovov-dll.33122/page-4#post-407075 ).
GRAFik, Дело не в знаниях, и опыте, а в нехватке времени, что-то интересное написать. Но не отвлекаемся от темы )
Что-то как-то очень много кода для таких простых вычислений. У меня, например, RGBA в HSLA (float-float) перевод выглядит так: native-версия: https://github.com/lsp-plugins/lsp-.../private/dsp/arch/generic/graphics.h#L93-L138 x86 SSE2: https://github.com/lsp-plugins/lsp-...rivate/dsp/arch/x86/sse2/graphics.h#L346-L541 ARM32 NEON: https://github.com/lsp-plugins/lsp-...arch/arm/neon-d32/graphics/colors.h#L339-L537 AArch64 ASIMD: https://github.com/lsp-plugins/lsp-...rch/aarch64/asimd/graphics/colors.h#L318-L505
SadKo, Здорово. А много кода - потому что просто пакетная обработка сделана. В цикле обрабатывается сразу 128 байт, при чем по две строчки сразу - так кеш лучше заполняется. Но как я и говорил. Можете показать ваш вариант ) если конечно не лень будет
Мне, честно, писать сейчас перекодирование нет никакой мотивации, увы. Будет жизненно необходимая для меня задача - сяду и напишу, и так постоянно приходится упражняться с оптимизациями под SIMD, при чём под несколько архитектур . Вся lsp-dsp-lib на этом построена: https://github.com/lsp-plugins/lsp-dsp-lib Кстати, интересный ещё момент не указали: почему RGBA 8 байт занимает? Вроде как по байту на каждую компоненту должно быть достаточно. 128/8 = 16 пикселей за одну итерацию обрабатываете, верно? В таком случае охотно поверю, что код учетверился в длине за счёт того, что больше данных за раз грузите. Но оправдано ли это? Если вы используете чисто SSE2, то в наборе у вас 8 XMM-регистров, и с вашим подходом будет постоянный своп XMM-регистров в память и назад. Именно поэтому я INTRINSIC'и не перевариваю и предпочитаю pure asm.
О! Еще один хороший человек - музыкант и программист в одном лице, напомнил о себе! Правда я чувствую себя перед ним немного виноватым - обещал я ему, вроде как, что-то, но не судьба. Владимир, простите подлеца, если сможете. Не получилось у меня отремонтировать/востановить свой бывший HD, а с нуля все писать, восстанавливать и вспоминать - времени свободного не было. В принципе, если сильно нужно, я могу попробовать отважится на сей подвиг. А что у вас нового из VST-плагинов появилось? Вы по прежднему пишите только для Линукса, а Windows игнорируете? И еще интересно, решили ли вы проблемы портирования с ГУИ и, вообще, есть ли проблемы у вас с ГУИ? Так же интересует не изменили ли вы свое отношение к JUCE? Помню, вроде, у вас были к этому фреймворку претензии.
Что-то не припомню, что вы мне обещали. Да много чего появилось. Недавно уже релиз 1.2.6 состоялся: https://github.com/sadko4u/lsp-plugins/releases/tag/1.2.6 Про поддержку Windows - мы близко. Гуй уже портирован. Даже собирается под Windows, но тестировать работу пока не тестировал.
да он занимает 4 байта, но вы не совсем правильно поняли возможно. имелось ввиду что оно читается по 8 байт, потмоу что - первые RGBA - Это YUV компонента (альфа канал игнорится), а вторые RGBA - это следующая YUV только из нее берется только Y . В итоге выходит UYVY )