You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用AVX2实现24位RGB转32位?SSSE3实现求AVX2优化方案

我之前刚好把SSSE3的RGB24转RGBA32代码升级到AVX2,踩过和你一样的坑,给你分享下完美解决的方案:

1. 解决_mm256_shuffle_epi8分lane的问题

AVX2的洗牌指令确实会独立处理高低128位lane,所以不能直接把SSSE3的掩码扩展成256位,得针对性设计掩码:

我们要实现的是每3字节的RGB后面插入一个零字节,对应到256位向量里,每个128位lane刚好处理4个像素(12字节→16字节)。所以掩码要分成两部分,低128位处理输入的前12字节,高128位处理输入的后12字节:

const __m256i shuffle_mask = _mm256_setr_epi8(
    // 低128位lane:4个像素,每个RGB后填0
    0, 1, 2, -1, 3, 4, 5, -1, 6, 7, 8, -1, 9, 10, 11, -1,
    // 高128位lane:另外4个像素,输入字节偏移12
    12, 13, 14, -1, 15, 16, 17, -1, 18, 19, 20, -1, 21, 22, 23, -1
);

这里-1对应0x80,会让洗牌指令输出零字节,完美符合你的需求。

2. 替换_mm_alignr_epi8的方案

原来SSSE3里用_mm_alignr_epi8处理跨128位向量的连续数据,AVX2里需要结合_mm256_permute2x128_si256和_mm256_alignr_epi8来实现跨256位lane的对齐:

  • _mm256_permute2x128_si256用来跨lane拼接两个向量的高/低128位部分
  • _mm256_alignr_epi8用来调整字节偏移,获取连续的24字节数据

比如处理跨向量的连续像素时,可以这么写:

__m256i prev = _mm256_loadu_si256((const __m256i*)rgb); // 加载第一个256位块
size_t i = 0;
const size_t batch_size = 8; // 每次处理8个像素

for (; i + batch_size <= num_pixels; i += batch_size) {
    __m256i curr = _mm256_loadu_si256((const __m256i*)(rgb + i * 3));
    // 拼接prev的高128位和curr的低128位,实现跨lane的连续数据
    __m256i combined = _mm256_permute2x128_si256(curr, prev, 0x21);
    // 对齐12字节,提取需要的24字节连续RGB数据
    __m256i aligned_rgb = _mm256_alignr_epi8(combined, prev, 12);
    // 洗牌转成RGBA
    __m256i rgba_data = _mm256_shuffle_epi8(aligned_rgb, shuffle_mask);
    // 输出结果
    _mm256_storeu_si256((__m256i*)(rgba + i), rgba_data);
    prev = curr;
}

这里的0x21参数是告诉指令:用curr的高128位和prev的低128位组成新的256位向量,配合12字节的对齐偏移,就能拿到跨向量的连续24字节RGB数据。

完整可运行的代码

如果你的输入是连续的内存块,且不需要处理跨向量的边缘情况(比如起始位置对齐),可以用更简洁的批量处理版本:

#include <immintrin.h>
#include <stddef.h>
#include <stdint.h>

void rgb24_to_rgba32_avx2(const uint8_t* rgb, uint32_t* rgba, size_t num_pixels) {
    const __m256i shuffle_mask = _mm256_setr_epi8(
        0, 1, 2, -1, 3, 4, 5, -1, 6, 7, 8, -1, 9, 10, 11, -1,
        12, 13, 14, -1, 15, 16, 17, -1, 18, 19, 20, -1, 21, 22, 23, -1
    );

    size_t i = 0;
    const size_t batch_size = 8;

    // 批量处理8个像素的块
    for (; i + batch_size <= num_pixels; i += batch_size) {
        const __m256i rgb_data = _mm256_loadu_si256((const __m256i*)(rgb + i * 3));
        const __m256i rgba_data = _mm256_shuffle_epi8(rgb_data, shuffle_mask);
        _mm256_storeu_si256((__m256i*)(rgba + i), rgba_data);
    }

    // 处理剩余的零散像素
    for (; i < num_pixels; ++i) {
        rgba[i] = (uint32_t)rgb[i*3] | ((uint32_t)rgb[i*3+1] << 8) | ((uint32_t)rgb[i*3+2] << 16);
    }
}

额外性能优化建议

如果你的输入内存是32字节对齐的,把_mm256_loadu_si256换成_mm256_load_si256,_mm256_storeu_si256换成_mm256_store_si256,能再提升不少性能。

内容的提问来源于stack exchange,提问作者Wiki Wong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:55:48