x86 - 混合 32 位 Alpha channel 所需的 Intel 内在函数

标签 x86 sse alpha simd intrinsics

我有一个 32 位 RGBA 图像缓冲区。我们假设它是 1920x1080——典型的从左到右、从上到下的 RAW 缓冲区。

这就是我想要快速执行的操作:从这个源缓冲区创建两个新缓冲区...

  1. “FILL”缓冲区... RGB 值与原始缓冲区的值匹配。 Alpha 值将变得不透明 (0xff)
  2. “KEY”缓冲区...每个 RGB 值都与原始缓冲区的 alpha 值匹配。 Alpha 值将是不透明的 (0xff)

对于输入缓冲区的每个像素,我的(慢)解决方案如下:

u_int32_t pixel = *srcPtr++;  // grab the source 32-bit pixel value
*fillPtr++ = pixel | 0xff;  // FILL: keep only the RGB channels (alpha = 0xff)
pixel &= 0xff;              // KEY: grab just the alpha value
*keyPtr++ = (pixel<<24) | (pixel<<16) | (pixel<<8) | 0xff; // KEY: xfer alpha to RGB, alpha = 0xff

可以假设源缓冲区是 16 字节对齐的。

一些初步测试显示,在 1920x1080 图像上,此时钟约为 8 毫秒 - Intel Xeon E5、六核、12MB L3 缓存、3.5Ghz。

有人可以提供他们的 SSE3 内在专业知识来加快速度吗?

最佳答案

听起来这就是你想要的基础——它一次处理四个像素。

void split_pixels(__m128i src, __m128i *fill, __m128i *key)
{
    __m128i const alphamask = _mm_set_epi8(-1, 0, 0, 0, -1, 0, 0, 0,
                                           -1, 0, 0, 0, -1, 0, 0, 0);
    __m128i const fillmask = _mm_set_epi8(-1, 15, 15, 15, -1, 12, 12, 12,
                                          -1, 7, 7, 7, -1, 3, 3, 3);

    _mm_stream_si128(fill, _mm_or_si128(src, alphamask));
    _mm_stream_si128(key, _mm_or_si128(_mm_shuffle_epi8(src, fillmask), alphamask));
}

它使用 SSE 混洗指令,该指令根据寄存器中的索引对字节进行混洗。它还使用流存储,因为您无法在缓存中容纳三个 1080p 缓冲区。流媒体商店很挑剔,可能有帮助也可能没有帮助,具体取决于您正在做的其他事情,所以我会对这些进行基准测试。

请注意,这个问题受到内存带宽的高度瓶颈,因此虽然它可能比普通 C 版本运行得更快,但它的运行速度可能不会快 4 倍。您可以在商店之前捆绑的处理越多,执行速度就越快。

关于x86 - 混合 32 位 Alpha channel 所需的 Intel 内在函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25539308/

相关文章:

assembly - 为什么传统模式下的 syscall/sysret 被认为是 "sufficiently poorly designed"?

c++ - 如何知道SSE2是否在opencv中被激活

c - 计算网格上连接组的相邻空点的有效方法

linux - 为什么在将数据从寄存器移动到内存时需要使用 [ ](方括号),而其他方式则不需要?

intel - 是否可以创建大数组 AVX/SSE 值

swift - 如何快速编辑背景图像的不透明度

c++ - 如何将叠加透明度应用于 RGBA 图像

css - 修改 LESS 变量的 alpha 不透明度

c - 基于堆栈的缓冲区溢出中的段错误

将 16 字节字符串与 SSE 进行比较