英特尔内在函数需要调整32位alpha通道

时间:2014-08-28 01:20:00

标签: x86 sse alpha simd intrinsics

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

这是我想要快速做的事情:从这个源缓冲区创建两个新的缓冲区......

  1. “FILL”Buffer ... RGB值与原始缓冲区的值匹配。 alpha值将变为不透明(0xff)
  2. “KEY”缓冲区...每个RGB值与原始缓冲区的alpha值匹配。 alpha值将是不透明的(0xff)
  3. 对于输入缓冲区的每个像素,我的(慢)解决方案如下:

    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图像上的时钟大约为8ms - Intel Xeon E5,hex-core,12MB L3缓存,3.5Ghz。

    有人可以提供他们的SSE3教学专业知识来提高一些加速度吗?

2 个答案:

答案 0 :(得分:2)

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

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 shuffle指令,它通过寄存器中的索引对字节进行混洗。它还使用流媒体存储,因为您无法在缓存中容纳三个1080p缓冲区。流媒体商店很挑剔,可能会或可能没有帮助,这取决于你正在做什么,所以我会对那些进行基准测试。

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

答案 1 :(得分:0)

除了Cory的回答,您还可以尝试多个线程。即使这是使用多个线程can increase the throughput for a single socket system by up to a factor of two进行内存绑定(在多插槽系统上甚至更多)。

您可以使用OpenMP

执行此类操作
#pragma omp parallel for
for(int i=0; i<height; i++) {
    for(int j=0; <width; j+=4) {
        split_pixels(&src[i*width+j], &fill[i*width+j], &key[i*width+j])
    }
}