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

如何用SIMD优化AssemblyScript中的Box Blur算法循环?

AssemblyScript中SIMD优化Box Blur循环方案

核心优化逻辑

原代码逐像素处理RGB分量,每次仅操作单个字节,效率低下。利用WebAssembly SIMD的128位向量能力,可一次并行处理4个像素的对应分量,将循环次数压缩至原有的1/4,同时借助CPU并行运算大幅提升执行速度。

优化后代码

// 预计算直径的浮点倒数,用乘法替代除法提升效率
const invDiameter = 1.0 / diameter;
const invDiameterVec = v128.splat(invDiameter as f32);

// 初始化向量累加器,存储4个像素的R/G/B累加值
let rAccum = v128.splat(0 as i32);
let gAccum = v128.splat(0 as i32);
let bAccum = v128.splat(0 as i32);

// 按4个像素为一组处理,步长设为4
for (let column: i16 = x + deviationBase + 1; column < x + width - deviationBase; column += 4) {
  // 计算当前组的加载位置:右侧进入模糊窗口的4个像素、左侧离开窗口的4个像素
  const addPixelPos = rowPosition + (column + deviationBase) * 4;
  const subPixelPos = rowPosition + (column - deviationBase) * 4;
  
  // 批量加载4个像素的RGBA数据(128位向量)
  const addPixels = v128.load<u8>(addPixelPos);
  const subPixels = v128.load<u8>(subPixelPos);
  
  // 从RGBA向量中提取4个像素的R/G/B分量
  const addR = v128.shuffle(addPixels, addPixels, [0, 4, 8, 12]);
  const addG = v128.shuffle(addPixels, addPixels, [1, 5, 9, 13]);
  const addB = v128.shuffle(addPixels, addPixels, [2, 6, 10, 14]);
  
  const subR = v128.shuffle(subPixels, subPixels, [0, 4, 8, 12]);
  const subG = v128.shuffle(subPixels, subPixels, [1, 5, 9, 13]);
  const subB = v128.shuffle(subPixels, subPixels, [2, 6, 10, 14]);
  
  // 将u8分量转换为i32,避免累加溢出
  const addR_i32 = v128.extend_low_u8_to_i32(addR);
  const addG_i32 = v128.extend_low_u8_to_i32(addG);
  const addB_i32 = v128.extend_low_u8_to_i32(addB);
  
  const subR_i32 = v128.extend_low_u8_to_i32(subR);
  const subG_i32 = v128.extend_low_u8_to_i32(subG);
  const subB_i32 = v128.extend_low_u8_to_i32(subB);
  
  // 并行执行累加/减法操作
  rAccum = v128.add(rAccum, addR_i32);
  gAccum = v128.add(gAccum, addG_i32);
  bAccum = v128.add(bAccum, addB_i32);
  
  rAccum = v128.sub(rAccum, subR_i32);
  gAccum = v128.sub(gAccum, subG_i32);
  bAccum = v128.sub(bAccum, subB_i32);
  
  // 将累加值转换为浮点,乘以倒数计算平均值
  const rAvg_f32 = v128.mul(v128.convert_i32x4_to_f32x4(rAccum), invDiameterVec);
  const gAvg_f32 = v128.mul(v128.convert_i32x4_to_f32x4(gAccum), invDiameterVec);
  const bAvg_f32 = v128.mul(v128.convert_i32x4_to_f32x4(bAccum), invDiameterVec);
  
  // 将浮点平均值转换回u8
  const rAvg_u8 = v128.convert_f32x4_to_u8x16(rAvg_f32);
  const gAvg_u8 = v128.convert_f32x4_to_u8x16(gAvg_f32);
  const bAvg_u8 = v128.convert_f32x4_to_u8x16(bAvg_f32);
  
  // 重新组合RGBA向量(A分量设为255)
  const outputPixels = v128.shuffle(rAvg_u8, gAvg_u8, [
    0, 1, 2, 255,  // 第一个像素:R, G, B, A(255)
    4, 5, 6, 255,  // 第二个像素
    8, 9, 10, 255, // 第三个像素
    12, 13, 14, 255// 第四个像素
  ]);
  
  // 批量写入4个像素的结果
  v128.store(rowPosition + column * 4, outputPixels);
}

// 处理剩余不足4个的像素(避免宽度非4倍数时的边界错误)
let rScalar: i32 = v128.extract_lane(rAccum, 0);
let gScalar: i32 = v128.extract_lane(gAccum, 0);
let bScalar: i32 = v128.extract_lane(bAccum, 0);
for (; column < x + width - deviationBase; column++) {
  rScalar += load<u8>(rowPosition + (column + deviationBase) * 4);
  gScalar += load<u8>(rowPosition + (column + deviationBase) * 4 + 1);
  bScalar += load<u8>(rowPosition + (column + deviationBase) * 4 + 2);
  
  rScalar -= load<u8>(rowPosition + (column - deviationBase) * 4);
  gScalar -= load<u8>(rowPosition + (column - deviationBase) * 4 + 1);
  bScalar -= load<u8>(rowPosition + (column - deviationBase) * 4 + 2);
  
  store<u8>(rowPosition + column * 4, (rScalar / diameter) as u8);
  store<u8>(rowPosition + column * 4 + 1, (gScalar / diameter) as u8);
  store<u8>(rowPosition + column * 4 + 2, (bScalar / diameter) as u8);
}

关键优化点解释

  1. SIMD启用:编译时必须添加--simd参数,AssemblyScript才会生成SIMD指令,目标环境需支持WebAssembly SIMD(现代浏览器、Node.js均兼容)。
  2. 向量化累加:用v128向量替代标量存储R/G/B累加值,一次并行处理4个像素的累加操作,避免循环迭代开销。
  3. 批量加载/存储:v128.load/v128.store一次处理16字节(4个RGBA像素),替代原代码多次单字节操作,大幅减少内存访问次数。
  4. 分量提取:通过v128.shuffle从RGBA向量中分离R/G/B分量,确保向量运算仅针对目标分量进行。
  5. 溢出避免:将u8分量转换为i32类型累加,避免u8范围(0-255)导致的溢出错误,计算完成后再转换回u8。
  6. 除法优化:预计算直径的浮点倒数,用向量乘法替代除法,SIMD乘法的执行效率远高于除法。
  7. 边界处理:针对宽度非4倍数的情况,单独处理剩余像素,保证结果正确性。

内容的提问来源于stack exchange,提问作者Kevin Baving

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 15:31:58