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

基于SIMD优化12位整数数组位重排(CSI-2转DNG格式)

12位整数数组位重排的SIMD优化实现

位布局转换需求

原始MIPI CSI-2压缩格式的12位整数数组,每两个12位整数(A、B)占用3字节,位排列如下:

|           byte0           |            byte1          |           byte2         | etc..
| A11 A10 A9 A8 A7 A6 A5 A4 | B11 B10 B9 B8 B7 B6 B5 B4 | B3 B2 B1 B0 A3 A2 A1 A0 | etc..

需要转换为Adobe DNG兼容的位排列格式:

|           byte0           |            byte1          |           byte2         | etc..
| A11 A10 A9 A8 A7 A6 A5 A4 | A3 A2 A1 A0 B11 B10 B9 B8 | B7 B6 B5 B4 B3 B2 B1 B0 | etc..

现有逐字节实现

目前已实现逐3字节循环的处理代码,但性能无法满足需求:

void CSI2toBE12(uint8_t* pCSI2, uint8_t* pBE, uint8_t* pCSI2LineEnd)
{
    while (pCSI2 < pCSI2LineEnd) {
        pBE[0] = pCSI2[0];
        pBE[1] = ((pCSI2[2] & 0xf) << 4) | (pCSI2[1] >> 4);
        pBE[2] = ((pCSI2[1] & 0xf) << 4) | (pCSI2[2] >> 4);
        
        // 处理下一组12位像素对(3字节)
        pCSI2 += 3;
        pBE += 3;
    }
}

SIMD优化方案(基于SIMDe兼容intrinsics)

目标CPU为64位ARM Cortex-A72(树莓派Compute Module 4),利用SIMDe可同时兼容ARM NEON和x86 AVX2指令集,以下是批量处理的实现:

1. ARM NEON(适配A72)+ SIMDe实现

一次处理8组(24字节)数据,大幅降低循环分支开销并提升吞吐量:

#include <simde/x86/avx2.h>
#include <simde/arm/neon.h>

void CSI2toBE12_SIMD(uint8_t* pCSI2, uint8_t* pBE, uint8_t* pCSI2LineEnd) {
    // 批量处理24字节对齐的数据块
    while (pCSI2 + 24 <= pCSI2LineEnd) {
        // 加载24字节原始数据为3个8字节向量
        simde_uint8x8_t vec0 = simde_vld1_u8(pCSI2);
        simde_uint8x8_t vec1 = simde_vld1_u8(pCSI2 + 8);
        simde_uint8x8_t vec2 = simde_vld1_u8(pCSI2 + 16);

        // 定义半字节提取掩码
        const simde_uint8x8_t mask_low = simde_vdup_n_u8(0x0F);
        const simde_uint8x8_t mask_high = simde_vdup_n_u8(0xF0);

        // 拆分每个3字节组中的半字节
        simde_uint8x8_t byte1_high = simde_vshr_n_u8(simde_vand_u8(vec1, mask_high), 4);
        simde_uint8x8_t byte1_low = simde_vand_u8(vec1, mask_low);
        simde_uint8x8_t byte2_low = simde_vand_u8(vec2, mask_low);
        simde_uint8x8_t byte2_high = simde_vshr_n_u8(simde_vand_u8(vec2, mask_high), 4);

        // 重组目标格式的字节
        simde_uint8x8_t dst_vec1 = simde_vorr_u8(simde_vshl_n_u8(byte2_low, 4), byte1_high);
        simde_uint8x8_t dst_vec2 = simde_vorr_u8(simde_vshl_n_u8(byte1_low, 4), byte2_high);

        // 存储转换后的数据
        simde_vst1_u8(pBE, vec0);
        simde_vst1_u8(pBE + 8, dst_vec1);
        simde_vst1_u8(pBE + 16, dst_vec2);

        // 推进指针到下一个数据块
        pCSI2 += 24;
        pBE += 24;
    }

    // 处理剩余不足24字节的数据,复用原始逐字节逻辑
    while (pCSI2 < pCSI2LineEnd) {
        pBE[0] = pCSI2[0];
        pBE[1] = ((pCSI2[2] & 0xf) << 4) | (pCSI2[1] >> 4);
        pBE[2] = ((pCSI2[1] & 0xf) << 4) | (pCSI2[2] >> 4);
        
        pCSI2 += 3;
        pBE += 3;
    }
}

2. AVX2实现(兼容x86平台)

若需在x86平台运行,利用AVX2指令集实现批量处理,通过SIMDe保证与NEON代码的兼容性:

#include <simde/x86/avx2.h>

void CSI2toBE12_AVX2(uint8_t* pCSI2, uint8_t* pBE, uint8_t* pCSI2LineEnd) {
    while (pCSI2 + 24 <= pCSI2LineEnd) {
        // 加载24字节数据到3个128位向量
        simde_mm128i vec0 = simde_mm_loadu_si128((simde__m128i*)pCSI2);
        simde_mm128i vec1 = simde_mm_loadu_si128((simde__m128i*)(pCSI2 + 8));
        simde_mm128i vec2 = simde_mm_loadu_si128((simde__m128i*)(pCSI2 + 16));

        // 定义半字节提取掩码
        const simde_mm128i mask_low = simde_mm_set1_epi8(0x0F);
        const simde_mm128i mask_high = simde_mm_set1_epi8(0xF0);

        // 拆分半字节
        simde_mm128i byte1_high = simde_mm_srli_epi16(simde_mm_and_si128(vec1, mask_high), 4);
        simde_mm128i byte1_low = simde_mm_and_si128(vec1, mask_low);
        simde_mm128i byte2_low = simde_mm_and_si128(vec2, mask_low);
        simde_mm128i byte2_high = simde_mm_srli_epi16(simde_mm_and_si128(vec2, mask_high), 4);

        // 重组目标字节
        simde_mm128i dst_vec1 = simde_mm_or_si128(simde_mm_slli_epi16(byte2_low, 4), byte1_high);
        simde_mm128i dst_vec2 = simde_mm_or_si128(simde_mm_slli_epi16(byte1_low, 4), byte2_high);

        // 存储转换后的数据
        simde_mm_storeu_si128((simde__m128i*)pBE, vec0);
        simde_mm_storeu_si128((simde__m128i*)(pBE + 8), dst_vec1);
        simde_mm_storeu_si128((simde__m128i*)(pBE + 16), dst_vec2);

        pCSI2 += 24;
        pBE += 24;
    }

    // 处理剩余数据
    while (pCSI2 < pCSI2LineEnd) {
        pBE[0] = pCSI2[0];
        pBE[1] = ((pCSI2[2] & 0xf) << 4) | (pCSI2[1] >> 4);
        pBE[2] = ((pCSI2[1] & 0xf) << 4) | (pCSI2[2] >> 4);
        
        pCSI2 += 3;
        pBE += 3;
    }
}

优化说明

  • 批量处理:一次处理8组(24字节)数据,大幅减少循环分支的性能开销
  • SIMDe兼容:代码可直接在ARM NEON和x86 AVX2平台编译运行,无需额外修改
  • 内存对齐优化:若输入输出内存按16/32字节对齐,可将_loadu_/_storeu_替换为_load_/_store_进一步提升内存访问效率

内容的提问来源于stack exchange,提问作者Russell Newman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 03:37:56