Add preliminary support of targeting Wasm

This builds on the work on portable-intrinsics branch:

- define WEBP_ENABLE_WASM_SIMD to enable WebAssembly optimizations, this
defines a constant (WEBP_USE_WASM_SIMD) that we can use in the future to
enable Wasm SIMD intrinsics
- build dwebp with JS build
- add a placeholder dec_wasm.c file, we don't do any special
initialization so it will fall back to c functions
- add Wasm to cpu checks, it needs to come before all checks since the
Emscripten toolchain will emulate x86 systems

Change-Id: I12de720304ff19fff82c8d100defbc60353787a9
This commit is contained in:
Zhi An Ng 2021-11-05 09:34:44 -07:00
parent 6b1d18c362
commit ed665a15e8
8 changed files with 81 additions and 10 deletions

View File

@ -22,6 +22,9 @@ if(NOT EMSCRIPTEN)
endif()
option(WEBP_ENABLE_SIMD "Enable any SIMD optimization."
${WEBP_ENABLE_SIMD_DEFAULT})
# Emscripten supports SSE builds using its compatibility headers, by default it
# will use SSE4 if WEBP_ENABLE_WASM_SIMD is OFF and WEBP_ENABLE_SIMD is ON.
option(WEBP_ENABLE_WASM_SIMD "Enable WebAssembly SIMD optimizations" OFF)
option(WEBP_BUILD_ANIM_UTILS "Build animation utilities." ON)
option(WEBP_BUILD_CWEBP "Build the cwebp command line tool." ON)
option(WEBP_BUILD_DWEBP "Build the dwebp command line tool." ON)
@ -48,7 +51,6 @@ endif()
if(WEBP_BUILD_WEBP_JS)
set(WEBP_BUILD_ANIM_UTILS OFF)
set(WEBP_BUILD_CWEBP OFF)
set(WEBP_BUILD_DWEBP OFF)
set(WEBP_BUILD_GIF2WEBP OFF)
set(WEBP_BUILD_IMG2WEBP OFF)
set(WEBP_BUILD_VWEBP OFF)
@ -80,6 +82,9 @@ include(GNUInstallDirs)
if(WEBP_ENABLE_SWAP_16BIT_CSP)
add_definitions(-DWEBP_SWAP_16BIT_CSP=1)
endif()
if(WEBP_ENABLE_WASM_SIMD)
add_definitions(-DWEBP_ENABLE_WASM_SIMD)
endif()
if(NOT WEBP_BITTRACE STREQUAL "0")
add_definitions(-DBITTRACE=${WEBP_BITTRACE})

View File

@ -108,6 +108,9 @@
/* Set to 1 if JPEG library is installed */
#cmakedefine WEBP_HAVE_JPEG 1
/* Set to 1 if Wasm SIMD is supported */
#cmakedefine WEBP_HAVE_WASM_SIMD
/* Set to 1 if NEON is supported */
#cmakedefine WEBP_HAVE_NEON

View File

@ -36,9 +36,9 @@ function(webp_check_compiler_flag WEBP_SIMD_FLAG ENABLE_SIMD)
endfunction()
# those are included in the names of WEBP_USE_* in c++ code.
set(WEBP_SIMD_FLAGS "SSE41;SSE2;MIPS32;MIPS_DSP_R2;NEON;MSA")
set(WEBP_SIMD_FLAGS "WASM_SIMD;SSE41;SSE2;MIPS32;MIPS_DSP_R2;NEON;MSA")
set(WEBP_SIMD_FILE_EXTENSIONS
"_sse41.c;_sse2.c;_mips32.c;_mips_dsp_r2.c;_neon.c;_msa.c")
"_wasm.c;_sse41.c;_sse2.c;_mips32.c;_mips_dsp_r2.c;_neon.c;_msa.c")
if(MSVC AND CMAKE_C_COMPILER_ID STREQUAL "MSVC")
# With at least Visual Studio 12 (2013)+ /arch is not necessary to build SSE2
# or SSE4 code unless a lesser /arch is forced. MSVC does not have a SSE4
@ -53,9 +53,9 @@ if(MSVC AND CMAKE_C_COMPILER_ID STREQUAL "MSVC")
set(SIMD_DISABLE_FLAGS)
else()
set(SIMD_ENABLE_FLAGS
"-msse4.1;-msse2;-mips32;-mdspr2;-mfpu=neon;-mmsa")
"-msimd128;-msse4.1;-msse2;-mips32;-mdspr2;-mfpu=neon;-mmsa")
set(SIMD_DISABLE_FLAGS
"-mno-sse4.1;-mno-sse2;;-mno-dspr2;;-mno-msa")
"-mno-simd128;-mno-sse4.1;-mno-sse2;;-mno-dspr2;;-mno-msa")
endif()
set(WEBP_SIMD_FILES_TO_NOT_INCLUDE)
@ -77,7 +77,12 @@ math(EXPR WEBP_SIMD_FLAGS_RANGE "${WEBP_SIMD_FLAGS_LENGTH} - 1")
foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
# With Emscripten 2.0.9 -msimd128 -mfpu=neon will enable NEON, but the
# source will fail to compile.
if(EMSCRIPTEN AND ${I_SIMD} GREATER_EQUAL 2)
if(EMSCRIPTEN AND ${I_SIMD} GREATER_EQUAL 5)
break()
endif()
# Emscripten supports SSE via compat headers, if WEBP_ENABLED_WASM_SIMD is
# specified skip testing those (because it will succeed).
if (EMSCRIPTEN AND ${I_SIMD} GREATER_EQUAL 1 AND ${WEBP_ENABLE_WASM_SIMD})
break()
endif()
@ -91,6 +96,7 @@ foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE})
webp_check_compiler_flag(${WEBP_SIMD_FLAG} ${WEBP_ENABLE_SIMD})
if(NOT WEBP_HAVE_${WEBP_SIMD_FLAG})
list(GET SIMD_ENABLE_FLAGS ${I_SIMD} SIMD_COMPILE_FLAG)
# This enables using Emscripten's SSE compatibility headers.
if(EMSCRIPTEN)
set(SIMD_COMPILE_FLAG "-msimd128 ${SIMD_COMPILE_FLAG}")
endif()

View File

@ -13,6 +13,7 @@ noinst_LTLIBRARIES += libwebpdsp_mips32.la
noinst_LTLIBRARIES += libwebpdspdecode_mips32.la
noinst_LTLIBRARIES += libwebpdsp_mips_dsp_r2.la
noinst_LTLIBRARIES += libwebpdspdecode_mips_dsp_r2.la
noinst_LTLIBRARIES += libwebpdspdecode_wasm.la
if BUILD_LIBWEBPDECODER
noinst_LTLIBRARIES += libwebpdspdecode.la
@ -106,6 +107,8 @@ libwebpdspdecode_mips_dsp_r2_la_SOURCES += yuv_mips_dsp_r2.c
libwebpdspdecode_mips_dsp_r2_la_CPPFLAGS = $(libwebpdsp_mips_dsp_r2_la_CPPFLAGS)
libwebpdspdecode_mips_dsp_r2_la_CFLAGS = $(libwebpdsp_mips_dsp_r2_la_CFLAGS)
libwebpdspdecode_wasm_la_SOURCES = dec_wasm.c
libwebpdsp_sse2_la_SOURCES =
libwebpdsp_sse2_la_SOURCES += cost_sse2.c
libwebpdsp_sse2_la_SOURCES += enc_sse2.c

View File

@ -26,8 +26,10 @@
// SSE2 detection.
//
// Skip SSE detection if using Wasm SIMD build.
#if defined(WEBP_USE_WASM_SIMD)
// apple/darwin gcc-4.0.1 defines __PIC__, but not __pic__ with -fPIC.
#if (defined(__pic__) || defined(__PIC__)) && defined(__i386__)
#elif (defined(__pic__) || defined(__PIC__)) && defined(__i386__)
static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) {
__asm__ volatile (
"mov %%ebx, %%edi\n"
@ -69,8 +71,10 @@ static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) {
#endif
// Skip xgetbv definition if using Wasm SIMD build.
#if defined(WEBP_USE_WASM_SIMD)
// NaCl has no support for xgetbv or the raw opcode.
#if !defined(__native_client__) && (defined(__i386__) || defined(__x86_64__))
#elif !defined(__native_client__) && (defined(__i386__) || defined(__x86_64__))
static WEBP_INLINE uint64_t xgetbv(void) {
const uint32_t ecx = 0;
uint32_t eax, edx;
@ -100,7 +104,13 @@ static WEBP_INLINE uint64_t xgetbv(void) {
#define xgetbv() 0U // no AVX for older x64 or unrecognized toolchains.
#endif
#if defined(__i386__) || defined(__x86_64__) || defined(WEBP_HAVE_MSC_CPUID)
#if defined(WEBP_USE_WASM_SIMD)
static int wasmCPUInfo(CPUFeature feature) {
if (feature != kWasmSIMD) return 0;
return 1;
}
VP8CPUInfo VP8GetCPUInfo = wasmCPUInfo;
#elif defined(__i386__) || defined(__x86_64__) || defined(WEBP_HAVE_MSC_CPUID)
// helper function for run-time detection of slow SSSE3 platforms
static int CheckSlowModel(int info) {

View File

@ -740,6 +740,7 @@ extern void VP8DspInitNEON(void);
extern void VP8DspInitMIPS32(void);
extern void VP8DspInitMIPSdspR2(void);
extern void VP8DspInitMSA(void);
extern void VP8DspInitWasmSIMD(void);
WEBP_DSP_INIT_FUNC(VP8DspInit) {
VP8InitClipTables();
@ -831,6 +832,11 @@ WEBP_DSP_INIT_FUNC(VP8DspInit) {
if (VP8GetCPUInfo(kMSA)) {
VP8DspInitMSA();
}
#endif
#if defined(WEBP_USE_WASM_SIMD)
if (VP8GetCPUInfo(kWasmSIMD)) {
VP8DspInitWasmSIMD();
}
#endif
}

32
src/dsp/dec_wasm.c Normal file
View File

@ -0,0 +1,32 @@
// Copyright 2021 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING 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.
// -----------------------------------------------------------------------------
//
// WebAssembly (Wasm) version of some decoding functions.
//
// This will contain Wasm implementation of some decoding functions.
#include "./dsp.h"
#if defined(WEBP_USE_WASM_SIMD)
//------------------------------------------------------------------------------
// Entry point
extern void VP8DspInitWasmSIMD(void);
WEBP_TSAN_IGNORE_FUNCTION void VP8DspInitWasmSIMD(void) {
// TODO(crbug.com/v8/12371): No special implementation for Wasm yet, will be
// added later.
}
#else
WEBP_DSP_INIT_STUB(VP8DspInitWasmSIMD)
#endif // WEBP_USE_WASM_SIMD

View File

@ -80,6 +80,11 @@ extern "C" {
#endif
#endif
#if (defined(EMSCRIPTEN) || defined(WEBP_HAVE_WASM_SIMD)) && \
defined(__wasm_simd128__) && defined(WEBP_ENABLE_WASM_SIMD)
#define WEBP_USE_WASM_SIMD
#endif
// WEBP_HAVE_* are used to indicate the presence of the instruction set in dsp
// files without intrinsics, allowing the corresponding Init() to be called.
// Files containing intrinsics will need to be built targeting the instruction
@ -257,7 +262,8 @@ typedef enum {
kNEON,
kMIPS32,
kMIPSdspR2,
kMSA
kMSA,
kWasmSIMD
} CPUFeature;
// returns true if the CPU supports the feature.
typedef int (*VP8CPUInfo)(CPUFeature feature);