我有一个 32 位 RGBA 图像缓冲区。我们假设它是 1920x1080——典型的从左到右、从上到下的 RAW 缓冲区。
这就是我想要快速执行的操作:从这个源缓冲区创建两个新缓冲区...
- “FILL”缓冲区... RGB 值与原始缓冲区的值匹配。 Alpha 值将变得不透明 (0xff)
- “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/