调配 32 位 alpha 通道所需的 Intel 内在函数

Posted

技术标签:

【中文标题】调配 32 位 alpha 通道所需的 Intel 内在函数【英文标题】:Intel intrinsics needed for swizzling 32-bit alpha channel 【发布时间】:2014-08-28 01:20:00 【问题描述】:

我有一个 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 图像(英特尔至强 E5、六核、12MB 三级高速缓存、3.5Ghz)上,此时钟大约为 8 毫秒。

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

【问题讨论】:

Cory.. 我没有尝试任何来自 SSE-land 的东西,因为我只是粗略地意识到它的存在。 【参考方案1】:

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

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 倍。您可以在存储之前捆绑的处理越多,它的执行速度就越快。

【讨论】:

为什么说流媒体商店“挑剔”? 该死...我知道我应该得到 8 核和 25MB 缓存 ;-) 说真的,非常感谢 - 我会试一试并报告。跨度> 【参考方案2】:

除了 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])
    

【讨论】:

如果我使用多个线程,我会在 Mac 上使用 dispatch_apply 和 GCD(Grand Central Dispatch)。我的经验是,除非 L3 缓存足够大以容纳源/目标缓冲区,否则跨多个内核条带化工作只会带来最小的收益。

以上是关于调配 32 位 alpha 通道所需的 Intel 内在函数的主要内容,如果未能解决你的问题,请参考以下文章

Unity ShadersTransparency —— 使用alpha通道创建透明效果

“错误:此 Java 实例不支持 32 位 JVM。” [1] “请安装所需的版本。”

MT4中的Alpha 32位(位图对象)

如何在png里删除alpha通道

ARGB与RGBRGBA的区别

PS 制作RGBA四通道 TGA格式图片