SSE2 颜色混合

问题描述 投票:0回答:1

我有一个代码进行简单的颜色混合:

  dr = (((dr-sr)*sa)>>8) + sr;
  dg = (((dg-sg)*sa)>>8) + sg;
  db = (((db-sb)*sa)>>8) + sb;

其中

sr,sg,sb
是源颜色,
sa
是源 Alpha,
dr,dg,db
是帧缓冲区中已有的颜色。

现在显然这段代码是最大的瓶颈,因为它是针对数百万像素完成的,所以我尝试使用 GCC/Clang 的 SSE 内在函数来优化它:

__m128 srgb = _mm_cvtepi32_ps(_mm_setr_epi32(sb,sg,sr,0));
__m128 drgb = _mm_cvtepi32_ps(_mm_shuffle_epi8(_mm_set1_epi32(dst_rgb),imask));
__m128 msa = _mm_set1_ps((float)sa*(1.0f/255.0f));
__m128 r1 = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(drgb,srgb), msa), srgb);
__m128 r2 = _mm_cvtps_epi32(r1);
dst_rgb = _mm_extract_epi32(_mm_shuffle_epi8(r2,omask),0);

我必须使用浮点数,因为 GCC 的 SSE 内在函数似乎没有正确的 int32 乘法来执行

color * sa
。我也不能真正在 XMM 寄存器中使用 _mm_set1_epi32(src_rgb) 和源颜色,因为 sr、sg、sb 在混合之前会通过多个查找表。 AVX2 确实支持具有收集操作的查找表,但 SSE2 似乎不支持。

不幸的是,它只会减慢代码速度。也许我做错了什么,或者 SSE 的 FPU 无法与整数运算符竞争?也许我应该使用 MMX,或者 MMX 在现代 CPU 上甚至更慢?我已打开 -march=native -O3 -ffast-math 选项。

@harold 建议使用完整的整数 SIMD 版本,但它仍然比非 SSE 慢:

static uint8_t imask_[] = { 12+0, 0xff, 0xff, 0xff
                           , 8+1, 0xff, 0xff, 0xff
                           , 4+2, 0xff, 0xff, 0xff
                           ,   3, 0xff, 0xff, 0xff};
static uint8_t omask_[] = {0,4,8,12
                          ,0xff, 0xff, 0xff, 0xff
                          ,0xff, 0xff, 0xff, 0xff
                          ,0xff, 0xff, 0xff, 0xff};
#define imask (*(__m128i*)imask_)
#define omask (*(__m128i*)omask_)
    /* ... */
__m128 msa = _mm_set1_epi32(sa<<8);
__m128 srgb = _mm_setr_epi32(sb,sg,sr,0);
__m128 drgb = _mm_shuffle_epi8(_mm_set1_epi32(DC),imask);
__m128 r2 = _mm_add_epi16(_mm_mulhi_epu16(_mm_sub_epi16(drgb,srgb), msa), srgb);
DC = _mm_extract_epi32(_mm_shuffle_epi8(r2,omask),0);

更新: 我通过将 src_color 直接加载到 SSE 寄存器中,在可能的情况下使用 __m128 srgb = _mm_shuffle_epi8(_mm_set1_epi32(c),sse_imsk),成功地从整数 SSE 代码中挤出了一些 2-3 FPS,这比 _mm_setr_epi32 更快。与提供 4-6 FPS 的 8 像素循环展开相比,仍然不是一个巨大的改进。

gcc x86 clang sse intrinsics
1个回答
0
投票

您尝试对通道进行矢量化,而单独处理通道可能会有所帮助。尝试对像素进行矢量化。由于无论如何您都必须一次处理许多像素,因此您可以一次加载/解包 8 个像素(假设每个通道 8 位,中间结果 16 位)。

也就是说,仅将源 R 分量加载到 SSE 寄存器中,然后将 G 和 B 分量放入其他寄存器中(目标像素相同)。如果你没有用完寄存器,那么你就做对了:)

© www.soinside.com 2019 - 2024. All rights reserved.