Я пытаюсь оптимизировать мой альфа-код смешивания с помощью SIMD.SSE2, в частности.
Сначала я надеялся на SSE2, но на этом этапе я согласился бы на SSE4.2, если это будет проще.Причина в том, что если я использую SSE4.2 вместо SSE2, я исключаю значительное количество старых процессоров, которые могут выполнять этот код.Но в этот момент я пошел бы на компромисс.
Я блефовал спрайтом на экране.Все в полном 32-битном цвете, ARGB или BGRA, в зависимости от того, в каком направлении вы его читаете.
Я прочитал все другие, казалось бы, связанные вопросы по SO и все, что я мог найти в Интернете, но до сих пор не сделалсмог полностью обернуть мой мозг вокруг этой единственной концепции, и я был бы признателен за некоторую помощь.Я занимаюсь этим уже несколько дней.
Ниже мой код.Этот код работает, поскольку он производит визуальный эффект, который я хочу.Растровое изображение рисуется в фоновом буфере с альфа-смешением.Все выглядит хорошо и, как и ожидалось.
Но вы увидите, что, несмотря на то, что он работает, мой код полностью пропускает смысл SIMD.Он работает с каждым байтом по одному, точно так же, как если бы он был полностью сериализован, и поэтому код не видит преимущества в производительности по сравнению с моим более традиционным кодом, который работает только с одним пикселем за раз.С SIMD я, очевидно, хочу работать с 4 пикселями (или с каждым каналом в один пиксель - 128 бит) одновременно, параллельно.(Я профилирую, измеряя количество кадров, отображаемых в секунду.)
Я хочу просто запустить формулу один раз для каждого канала, т. Е. Смешать все красные каналы сразу, все зеленые каналы сразу, всесинего канала сразу и всего альфа-канала сразу.Или, в качестве альтернативы, каждый канал (RGBA) одного из пикселей одновременно.
Тогда я должен начать видеть все преимущества SIMD.
Мне кажется, что мне, вероятно, нужно кое-что сделатьс масками, но ничто из того, что я пробовал, не привело меня туда.
Я был бы очень признателен за помощь.
(Это внутренний цикл. Он обрабатывает только 4 пикселя. Я помещаю это внутрьцикла, где я перебираю более 4 пикселей за раз с XPixel + = 4.)
__m128i BitmapQuadPixel = _mm_load_si128((uint32_t*)Bitmap->Memory + BitmapOffset);
__m128i BackgroundQuadPixel = _mm_load_si128((uint32_t*)gRenderSurface.Memory + MemoryOffset);;
__m128i BlendedQuadPixel;
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// R G B A R G B A R G B A R G B A
// This is the red component of the first pixel.
BlendedQuadPixel.m128i_u8[0] = BitmapQuadPixel.m128i_u8[0] * BitmapQuadPixel.m128i_u8[3] / 255 + BackgroundQuadPixel.m128i_u8[0] * (255 - BitmapQuadPixel.m128i_u8[3]) / 255;
// This is the green component of the first pixel.
BlendedQuadPixel.m128i_u8[1] = BitmapQuadPixel.m128i_u8[1] * BitmapQuadPixel.m128i_u8[3] / 255 + BackgroundQuadPixel.m128i_u8[1] * (255 - BitmapQuadPixel.m128i_u8[3]) / 255;
// And so on...
BlendedQuadPixel.m128i_u8[2] = BitmapQuadPixel.m128i_u8[2] * BitmapQuadPixel.m128i_u8[3] / 255 + BackgroundQuadPixel.m128i_u8[2] * (255 - BitmapQuadPixel.m128i_u8[3]) / 255;
BlendedQuadPixel.m128i_u8[4] = BitmapQuadPixel.m128i_u8[4] * BitmapQuadPixel.m128i_u8[7] / 255 + BackgroundQuadPixel.m128i_u8[4] * (255 - BitmapQuadPixel.m128i_u8[7]) / 255;
BlendedQuadPixel.m128i_u8[5] = BitmapQuadPixel.m128i_u8[5] * BitmapQuadPixel.m128i_u8[7] / 255 + BackgroundQuadPixel.m128i_u8[5] * (255 - BitmapQuadPixel.m128i_u8[7]) / 255;
BlendedQuadPixel.m128i_u8[6] = BitmapQuadPixel.m128i_u8[6] * BitmapQuadPixel.m128i_u8[7] / 255 + BackgroundQuadPixel.m128i_u8[6] * (255 - BitmapQuadPixel.m128i_u8[7]) / 255;
BlendedQuadPixel.m128i_u8[8] = BitmapQuadPixel.m128i_u8[8] * BitmapQuadPixel.m128i_u8[11] / 255 + BackgroundQuadPixel.m128i_u8[8] * (255 - BitmapQuadPixel.m128i_u8[11]) / 255;
BlendedQuadPixel.m128i_u8[9] = BitmapQuadPixel.m128i_u8[9] * BitmapQuadPixel.m128i_u8[11] / 255 + BackgroundQuadPixel.m128i_u8[9] * (255 - BitmapQuadPixel.m128i_u8[11]) / 255;
BlendedQuadPixel.m128i_u8[10] = BitmapQuadPixel.m128i_u8[10] * BitmapQuadPixel.m128i_u8[11] / 255 + BackgroundQuadPixel.m128i_u8[10] * (255 - BitmapQuadPixel.m128i_u8[11]) / 255;
BlendedQuadPixel.m128i_u8[12] = BitmapQuadPixel.m128i_u8[12] * BitmapQuadPixel.m128i_u8[15] / 255 + BackgroundQuadPixel.m128i_u8[12] * (255 - BitmapQuadPixel.m128i_u8[15]) / 255;
BlendedQuadPixel.m128i_u8[13] = BitmapQuadPixel.m128i_u8[13] * BitmapQuadPixel.m128i_u8[15] / 255 + BackgroundQuadPixel.m128i_u8[13] * (255 - BitmapQuadPixel.m128i_u8[15]) / 255;
BlendedQuadPixel.m128i_u8[14] = BitmapQuadPixel.m128i_u8[14] * BitmapQuadPixel.m128i_u8[15] / 255 + BackgroundQuadPixel.m128i_u8[14] * (255 - BitmapQuadPixel.m128i_u8[15]) / 255;
_mm_store_si128((uint32_t*)gRenderSurface.Memory + MemoryOffset, BlendedQuadPixel);