libyuv/source/row_wasm.cc
Frank Barchard eb8eda9c79 [libyuv] Add WASM SIMD128 and Relaxed SIMD for RAWToRGB24Row
Implement RAWToRGB24Row_WASMSIMD and RAWToRGB24Row_Any_WASMSIMD in
source/row_wasm.cc for RGB24ToRAW and RAWToRGB24 conversions:
- Process 16 pixels (48 bytes) per loop iteration using three 128-bit
  loads, three byte-wise shuffles, and four 2-way blends.
- Use wasm_i8x16_relaxed_swizzle when __wasm_relaxed_simd__ is enabled
  (compiling to a single vpshufb on x86 without bounds-checking
  overhead) and fall back to wasm_i8x16_swizzle for baseline SIMD128.
- Add kCpuHasWASM (0x100) and kCpuHasWASMSIMD (0x101) CPU feature
  flags and enable -msimd128 in BUILD.bazel, BUILD.gn, and
  CMakeLists.txt for WebAssembly targets.

Performance (RAWToRGB24_Opt, 1280x720, V8 d8):
CPU                     WASM C  SIMD128  Relaxed  SIMD Spd  Rlx Spd
-------------------------------------------------------------------
AMD Zen 4             595.0 us 137.0 us  84.0 us     4.34x    7.08x
AMD Zen 3             708.0 us 148.0 us 107.0 us     4.78x    6.62x
AMD Zen 5             375.0 us 107.0 us  67.0 us     3.50x    5.60x
ARM Neoverse-V2       638.0 us 118.0 us 116.0 us     5.41x    5.50x
ARM Neoverse-N1      1046.0 us 294.0 us 294.0 us     3.56x    3.56x
Intel Ice Lake        707.0 us 209.0 us 220.0 us     3.38x    3.21x
Intel Haswell        1110.0 us 344.0 us 360.0 us     3.23x    3.08x
Intel Emerald Rapids  519.0 us 207.0 us 208.0 us     2.51x    2.50x
Intel Sapphire Rapids 551.0 us 220.0 us 255.0 us     2.50x    2.16x
ARM Cortex-A53      14440.0 us 8660.0us 6920.0us     1.67x    2.09x
Intel Granite Rapids  453.0 us 225.0 us 221.0 us     2.01x    2.05x

Bug: 42271072
Test: libyuv_test --gunit_filter=*RAWToRGB24*:*RGB24ToRAW*:*Cpu*
Change-Id: Id902668263a2ab70aa300eeeea18851490c917b5
Reviewed-on: https://chromium-review.googlesource.com/c/libyuv/libyuv/+/8515581
Reviewed-by: richard winterton <rrwinterton@gmail.com>
Commit-Queue: Frank Barchard <fbarchard@google.com>
2026-10-05 17:45:41 -07:00

121 lines
4.7 KiB
C++

/*
* Copyright 2026 The LibYuv Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "libyuv/row.h"
#if !defined(LIBYUV_DISABLE_WASM) && defined(__wasm_simd128__)
#include <wasm_simd128.h>
#ifdef __cplusplus
namespace libyuv {
extern "C" {
#endif
#ifdef HAS_RAWTORGB24ROW_WASMSIMD
#ifdef __wasm_relaxed_simd__
#define LIBYUV_WASM_SWIZZLE wasm_i8x16_relaxed_swizzle
#else
#define LIBYUV_WASM_SWIZZLE wasm_i8x16_swizzle
#endif
static const uint8_t kRawToRGB24SwizzleTable[96] = {
2, 1, 0, 5, 4, 3, 8, 7, 6, 11, 10, 9, 14, 13, 12,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 1, 0, 128, 4, 3, 2, 7, 6, 5, 10, 9, 8, 13, 12,
11, 128, 15, 128, 1, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 2, 128, 128, 3, 2, 1, 6, 5, 4, 9, 8, 7, 12,
11, 10, 15, 14, 13, 14, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128};
void RAWToRGB24Row_WASMSIMD(const uint8_t* src_raw,
uint8_t* dst_rgb24,
int width) {
const uint8_t* shuf = kRawToRGB24SwizzleTable;
// Load shuffle masks into Wasm locals outside the loop so Binaryen's
// precompute-propagate pass does not sink v128.const into the loop.
asm("" : "+r"(shuf));
v128_t kShuf0_0 = wasm_v128_load(shuf);
v128_t kShuf0_1 = wasm_v128_load(shuf + 16);
v128_t kShuf1_1 = wasm_v128_load(shuf + 32);
v128_t kShuf1_02 = wasm_v128_load(shuf + 48);
v128_t kShuf2_2 = wasm_v128_load(shuf + 64);
v128_t kShuf2_1 = wasm_v128_load(shuf + 80);
while (width >= 32) {
// Prevent LLVM LSR from splitting constant load/store offsets into separate
// pointer induction variables.
asm("" : "+r"(src_raw), "+r"(dst_rgb24));
v128_t s0 = wasm_v128_load(src_raw);
v128_t s1 = wasm_v128_load(src_raw + 16);
v128_t s2 = wasm_v128_load(src_raw + 32);
v128_t s3 = wasm_v128_load(src_raw + 48);
v128_t s4 = wasm_v128_load(src_raw + 64);
v128_t s5 = wasm_v128_load(src_raw + 80);
v128_t s02 = wasm_i8x16_shuffle(s0, s2, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29);
v128_t s35 = wasm_i8x16_shuffle(s3, s5, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29);
v128_t d0 = wasm_v128_or(LIBYUV_WASM_SWIZZLE(s0, kShuf0_0),
LIBYUV_WASM_SWIZZLE(s1, kShuf0_1));
v128_t d1 = wasm_v128_or(LIBYUV_WASM_SWIZZLE(s1, kShuf1_1),
LIBYUV_WASM_SWIZZLE(s02, kShuf1_02));
v128_t d2 = wasm_v128_or(LIBYUV_WASM_SWIZZLE(s2, kShuf2_2),
LIBYUV_WASM_SWIZZLE(s1, kShuf2_1));
v128_t d3 = wasm_v128_or(LIBYUV_WASM_SWIZZLE(s3, kShuf0_0),
LIBYUV_WASM_SWIZZLE(s4, kShuf0_1));
v128_t d4 = wasm_v128_or(LIBYUV_WASM_SWIZZLE(s4, kShuf1_1),
LIBYUV_WASM_SWIZZLE(s35, kShuf1_02));
v128_t d5 = wasm_v128_or(LIBYUV_WASM_SWIZZLE(s5, kShuf2_2),
LIBYUV_WASM_SWIZZLE(s4, kShuf2_1));
wasm_v128_store(dst_rgb24, d0);
wasm_v128_store(dst_rgb24 + 16, d1);
wasm_v128_store(dst_rgb24 + 32, d2);
wasm_v128_store(dst_rgb24 + 48, d3);
wasm_v128_store(dst_rgb24 + 64, d4);
wasm_v128_store(dst_rgb24 + 80, d5);
src_raw += 96;
dst_rgb24 += 96;
width -= 32;
}
if (width > 0) {
asm("" : "+r"(src_raw), "+r"(dst_rgb24));
v128_t s0 = wasm_v128_load(src_raw);
v128_t s1 = wasm_v128_load(src_raw + 16);
v128_t s2 = wasm_v128_load(src_raw + 32);
v128_t s02 = wasm_i8x16_shuffle(s0, s2, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29);
v128_t d0 = wasm_v128_or(LIBYUV_WASM_SWIZZLE(s0, kShuf0_0),
LIBYUV_WASM_SWIZZLE(s1, kShuf0_1));
v128_t d1 = wasm_v128_or(LIBYUV_WASM_SWIZZLE(s1, kShuf1_1),
LIBYUV_WASM_SWIZZLE(s02, kShuf1_02));
v128_t d2 = wasm_v128_or(LIBYUV_WASM_SWIZZLE(s2, kShuf2_2),
LIBYUV_WASM_SWIZZLE(s1, kShuf2_1));
wasm_v128_store(dst_rgb24, d0);
wasm_v128_store(dst_rgb24 + 16, d1);
wasm_v128_store(dst_rgb24 + 32, d2);
}
}
#undef LIBYUV_WASM_SWIZZLE
#endif // HAS_RAWTORGB24ROW_WASMSIMD
#ifdef __cplusplus
} // extern "C"
} // namespace libyuv
#endif
#endif // !defined(LIBYUV_DISABLE_WASM) && defined(__wasm_simd128__)