diff --git a/CMakeLists.txt b/CMakeLists.txt index 37619652..556241a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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}) diff --git a/cmake/config.h.in b/cmake/config.h.in index 3770935c..60cbe53a 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -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 diff --git a/cmake/cpu.cmake b/cmake/cpu.cmake index bc0dbc98..d1e28d25 100644 --- a/cmake/cpu.cmake +++ b/cmake/cpu.cmake @@ -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() diff --git a/src/dsp/Makefile.am b/src/dsp/Makefile.am index 766bb0a7..8d88ee7d 100644 --- a/src/dsp/Makefile.am +++ b/src/dsp/Makefile.am @@ -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 diff --git a/src/dsp/cpu.c b/src/dsp/cpu.c index 3145e190..3058942b 100644 --- a/src/dsp/cpu.c +++ b/src/dsp/cpu.c @@ -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) { diff --git a/src/dsp/dec.c b/src/dsp/dec.c index 537c7012..5ff3c0c2 100644 --- a/src/dsp/dec.c +++ b/src/dsp/dec.c @@ -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 } diff --git a/src/dsp/dec_wasm.c b/src/dsp/dec_wasm.c new file mode 100644 index 00000000..89166b6c --- /dev/null +++ b/src/dsp/dec_wasm.c @@ -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 diff --git a/src/dsp/dsp.h b/src/dsp/dsp.h index c4f57e4d..02bae2a8 100644 --- a/src/dsp/dsp.h +++ b/src/dsp/dsp.h @@ -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);