Самое быстрое 50% масштабирование (A) изображений RGB32 с использованием встроенных функций sse - PullRequest
5 голосов
/ 08 ноября 2011

Я хочу уменьшать изображения так быстро, как я могу в C ++. Эта статья описывает, как эффективно усреднить 32-битные изображения RGB до 50%.Это быстро и выглядит хорошо.

Я попытался изменить этот подход с помощью встроенных sse.Приведенный ниже код работает с включенным SSE или без него.Удивительно, однако, что ускорение незначительно.

Может кто-нибудь увидеть способ улучшения кода SSE.Две строки, создающие vars shuffle1 и shuffle2, кажутся подходящими кандидатами (с использованием некоторого умного сдвига или подобного).

Ответы [ 3 ]

8 голосов
/ 08 ноября 2011

Передача данных между регистрами общего назначения и регистрами SSE действительно медленная, поэтому вам следует воздерживаться от таких вещей, как:

__m128i shuffle1 = _mm_set_epi32( right.m128i_u32[2], right.m128i_u32[0], left.m128i_u32[2], left.m128i_u32[0]);
__m128i shuffle2 = _mm_set_epi32( right.m128i_u32[3], right.m128i_u32[1], left.m128i_u32[3], left.m128i_u32[1]);

Перемешивать значения в регистрах SSE с помощью соответствующих операций перемешивания.

Это должно быть то, что вы ищете:

__m128i t0 = _mm_unpacklo_epi32( left, right ); // right.m128i_u32[1] left.m128i_u32[1] right.m128i_u32[0] left.m128i_u32[0]
__m128i t1 = _mm_unpackhi_epi32( left, right ); // right.m128i_u32[3] left.m128i_u32[3] right.m128i_u32[2] left.m128i_u32[2]
__m128i shuffle1 = _mm_unpacklo_epi32( t0, t1 );    // right.m128i_u32[2] right.m128i_u32[0] left.m128i_u32[2] left.m128i_u32[0]
__m128i shuffle2 = _mm_unpackhi_epi32( t0, t1 );    // right.m128i_u32[3] right.m128i_u32[1] left.m128i_u32[3] left.m128i_u32[1]
4 голосов
/ 08 ноября 2011

Основная проблема заключается в использовании _mm_set_epi32 для выполнения ваших перемешиваний - в отличие от большинства встроенных функций SSE, это не отображается напрямую на одну инструкцию SSE - в таких случаях, как это, он генерирует много скалярного кода под капотом, и вызывает перемещение данных между памятью, регистрами общего назначения и регистрами SSE. Взгляните на использование соответствующих встроенных функций SSE shuffle.

Вторичная проблема заключается в том, что вы выполняете очень мало вычислений относительно количества загрузок и хранилищ. Это может привести к тому, что код будет ограничен по пропускной способности, а не по вычислениям, и вы можете не увидеть значительного улучшения производительности, даже с идеальным кодом SSE. Посмотрите на объединение большего количества операций в цикле, чтобы вы могли делать больше с вашими данными, пока они находятся в кэше.

4 голосов
/ 08 ноября 2011

Если встроенные функции SSE не имеют большого значения / не имеют значения, тогда код, вероятно, ограничен пропускной способностью памяти.

В вашем коде много загрузок и сохранений (_mm_set_epi32 - это нагрузка, как и очевидные) для небольшой работы.Если загрузки / хранилища преобладают во время выполнения, то никакие сложные инструкции не могут вас спасти.На современных процессорах, которые отличаются высокой степенью конвейерности и инструкциями по переупорядочению, он, вероятно, делает довольно хорошую работу, занимая весь процессор занятым в не-SSE версии вашего кода.несколько способов.Возможно, проще всего измерить реальную пропускную способность вашего алгоритма по сравнению только со скоростями загрузки / хранения вашей памяти.Вы также можете заметить некоторые различия, варьируя не только реализацию, но и размер входных данных, с резким увеличением, когда входные данные превышают размер каждого уровня кэша процессора.

...