gpt4 book ai didi

performance - SIMD/SSE 新手 : simple image filtering

转载 作者:行者123 更新时间:2023-12-04 12:38:04 26 4
gpt4 key购买 nike

我对 SIMD/SSE 很陌生,我正在尝试做一些简单的图像过滤(模糊)。
下面的代码使用简单的 [1 2 1] 水平方向权重过滤 8 位灰度位图的每个像素。我一次创建 16 个像素的总和。

这段代码看起来很糟糕,至少对我来说,是其中有很多插入/提取,这不是很优雅,并且可能也会减慢一切。有没有更好的方法在转移时将数据从一个 reg 包装到另一个?

buf 是图像数据,16 字节对齐。
w/h 是宽度和高度,16 的倍数。

__m128i *p = (__m128i *) buf;
__m128i cur1, cur2, sum1, sum2, zeros, tmp1, tmp2, saved;
zeros = _mm_setzero_si128();
short shifted, last = 0, next;

// preload first row
cur1 = _mm_load_si128(p);
for (x = 1; x < (w * h) / 16; x++) {
// unpack
sum1 = sum2 = saved = cur1;
sum1 = _mm_unpacklo_epi8(sum1, zeros);
sum2 = _mm_unpackhi_epi8(sum2, zeros);
cur1 = tmp1 = sum1;
cur2 = tmp2 = sum2;
// "middle" pixel
sum1 = _mm_add_epi16(sum1, sum1);
sum2 = _mm_add_epi16(sum2, sum2);
// left pixel
cur2 = _mm_slli_si128(cur2, 2);
shifted = _mm_extract_epi16(cur1, 7);
cur2 = _mm_insert_epi16(cur2, shifted, 0);
cur1 = _mm_slli_si128(cur1, 2);
cur1 = _mm_insert_epi16(cur1, last, 0);
sum1 = _mm_add_epi16(sum1, cur1);
sum2 = _mm_add_epi16(sum2, cur2);
// right pixel
tmp1 = _mm_srli_si128(tmp1, 2);
shifted = _mm_extract_epi16(tmp2, 0);
tmp1 = _mm_insert_epi16(tmp1, shifted, 7);
tmp2 = _mm_srli_si128(tmp2, 2);
// preload next row
cur1 = _mm_load_si128(p + x);
// we need the first pixel of the next row for the "right" pixel
next = _mm_extract_epi16(cur1, 0) & 0xff;
tmp2 = _mm_insert_epi16(tmp2, next, 7);
// and the last pixel of last row for the next "left" pixel
last = ((uint16_t) _mm_extract_epi16(saved, 7)) >> 8;
sum1 = _mm_add_epi16(sum1, tmp1);
sum2 = _mm_add_epi16(sum2, tmp2);
// divide
sum1 = _mm_srli_epi16(sum1, 2);
sum2 = _mm_srli_epi16(sum2, 2);
sum1 = _mm_packus_epi16(sum1, sum2);
mm_store_si128(p + x - 1, sum1);
}

最佳答案

这种邻域操作一直是 SSE 的痛点,直到 SSE3.5(又名 SSSE3)出现,并且引入了 PALIGNR(_mm_alignr_epi8)。

但是,如果您需要与 SSE2/SSE3 向后兼容,您可以编写等效的宏或内联函数,该函数模拟 SSE2/SSE3 的 _mm_alignr_epi8,并在以 SSE3.5/SSE4 为目标时下降到 _mm_alignr_epi8。

另一种方法是使用未对齐的负载来获取移位的数据 - 这在较旧的 CPU 上相对昂贵(大约是对齐负载的两倍延迟和一半吞吐量),但这可能是可以接受的,具体取决于您每次加载进行的大量计算。它还有一个好处,即在当前的 Intel CPU(Core i7)上,与对齐的负载相比,未对齐的负载没有任何损失,因此您的代码在 Core i7 等上将非常高效。

关于performance - SIMD/SSE 新手 : simple image filtering,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3129842/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com