From 4b219713375613c684230c223fcc10d7cd51f58f Mon Sep 17 00:00:00 2001 From: James Zern Date: Thu, 22 Jun 2017 16:22:44 -0700 Subject: [PATCH] add dec_wasm.c stub + basic cmake support for targeting native code generation using portable intrinsics / wasm (WebAssembly). integrating this into the webp_js path will be left until the implementation is more complete. Change-Id: I3e751b511f6d671da5ba8afc88ca412f31f097b0 --- CMakeLists.txt | 14 ++++++++++---- README.webp_js | 5 +++++ cmake/cpu.cmake | 10 ++++++++++ src/dsp/Makefile.am | 5 +++++ src/dsp/cpu.c | 6 ++++++ src/dsp/dec.c | 6 ++++++ src/dsp/dec_wasm.c | 29 +++++++++++++++++++++++++++++ src/dsp/dsp.h | 8 +++++--- 8 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 src/dsp/dec_wasm.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 1199ba68..cef31733 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,7 @@ project(libwebp C) # Options for coder / decoder executables. option(WEBP_ENABLE_SIMD "Enable any SIMD optimization." ON) +option(WEBP_ENABLE_WASM "Enable WebAssembly optimizations." OFF) option(WEBP_BUILD_CWEBP "Build the cwebp command line tool." OFF) option(WEBP_BUILD_DWEBP "Build the dwebp command line tool." OFF) option(WEBP_BUILD_GIF2WEBP "Build the gif2webp conversion tool." OFF) @@ -13,7 +14,7 @@ option(WEBP_BUILD_WEBP_JS "Emscripten build of webp.js." OFF) option(WEBP_EXPERIMENTAL_FEATURES "Build with experimental features." OFF) option(WEBP_ENABLE_SWAP_16BIT_CSP "Enable byte swap for 16 bit colorspaces." OFF) -if(WEBP_BUILD_WEBP_JS) +if(WEBP_BUILD_WEBP_JS OR WEBP_ENABLE_WASM) set(WEBP_ENABLE_SIMD OFF) endif() @@ -37,6 +38,9 @@ string(REGEX MATCH "[0-9.]+" WEBP_VERSION ${SOURCE_FILE}) if(WEBP_ENABLE_SWAP_16BIT_CSP) add_definitions(-DWEBP_SWAP_16BIT_CSP) endif() +if(WEBP_ENABLE_WASM) + add_definitions(-DWEBP_USE_WASM) +endif() ################################################################################ # Android only. @@ -162,9 +166,11 @@ math(EXPR WEBP_SIMD_FILES_TO_INCLUDE_RANGE foreach(I_FILE RANGE ${WEBP_SIMD_FILES_TO_INCLUDE_RANGE}) list(GET WEBP_SIMD_FILES_TO_INCLUDE ${I_FILE} FILE) list(GET WEBP_SIMD_FLAGS_TO_INCLUDE ${I_FILE} SIMD_COMPILE_FLAG) - set_source_files_properties(${FILE} PROPERTIES - COMPILE_FLAGS ${SIMD_COMPILE_FLAG} - ) + if(NOT ${SIMD_COMPILE_FLAG} STREQUAL "NOTFOUND") + set_source_files_properties(${FILE} PROPERTIES + COMPILE_FLAGS ${SIMD_COMPILE_FLAG} + ) + endif() endforeach() # Build the executables if asked for. diff --git a/README.webp_js b/README.webp_js index 04f4970b..76a46037 100644 --- a/README.webp_js +++ b/README.webp_js @@ -31,6 +31,11 @@ using Emscripten and CMake. - that's it! Upon completion, you should have the webp.js and webp.js.mem files generated. + - Note this generates both webp_js and webp_wasm without any SIMD enabled due + to bugs with this toolchain associated with the SSE2 code. + -DWEBP_ENABLE_WASM is currently meant to generate native (x86, arm) + executables (dwebp, cwebp) and is incompatible with -DWEBP_BUILD_WEBP_JS. + The callable JavaScript function is WebPToSDL(), which decodes a raw WebP bitstream into a canvas. See webp_js/index.html for a simple usage sample. diff --git a/cmake/cpu.cmake b/cmake/cpu.cmake index 94c021a1..f8218414 100644 --- a/cmake/cpu.cmake +++ b/cmake/cpu.cmake @@ -116,3 +116,13 @@ foreach(I_SIMD RANGE ${WEBP_SIMD_FLAGS_RANGE}) endif() endif() endforeach() + +## Add *_wasm.c files if enabled. +if(WEBP_ENABLE_WASM) + file(GLOB SIMD_FILES "${CMAKE_CURRENT_LIST_DIR}/../" + "src/dsp/*_wasm.c" + ) + foreach(FILE ${SIMD_FILES}) + list(APPEND WEBP_SIMD_FILES_TO_INCLUDE ${FILE}) + endforeach() +endif() diff --git a/src/dsp/Makefile.am b/src/dsp/Makefile.am index 4605d2fb..cb69f8a8 100644 --- a/src/dsp/Makefile.am +++ b/src/dsp/Makefile.am @@ -3,6 +3,7 @@ noinst_LTLIBRARIES += libwebpdsp_sse2.la libwebpdspdecode_sse2.la noinst_LTLIBRARIES += libwebpdsp_sse41.la libwebpdspdecode_sse41.la noinst_LTLIBRARIES += libwebpdsp_neon.la libwebpdspdecode_neon.la noinst_LTLIBRARIES += libwebpdsp_msa.la libwebpdspdecode_msa.la +noinst_LTLIBRARIES += libwebpdspdecode_wasm.la if BUILD_LIBWEBPDECODER noinst_LTLIBRARIES += libwebpdspdecode.la @@ -96,6 +97,10 @@ libwebpdspdecode_msa_la_SOURCES += upsampling_msa.c libwebpdspdecode_msa_la_CPPFLAGS = $(libwebpdsp_msa_la_CPPFLAGS) libwebpdspdecode_msa_la_CFLAGS = $(libwebpdsp_msa_la_CFLAGS) +# WASM is not fully integrated into configure; the addition here keeps source +# extraction by cmake simple. +libwebpdspdecode_wasm_la_SOURCES = dec_wasm.c + libwebpdsp_sse2_la_SOURCES = libwebpdsp_sse2_la_SOURCES += argb_sse2.c libwebpdsp_sse2_la_SOURCES += cost_sse2.c diff --git a/src/dsp/cpu.c b/src/dsp/cpu.c index b5583b6e..11b780d0 100644 --- a/src/dsp/cpu.c +++ b/src/dsp/cpu.c @@ -217,6 +217,12 @@ static int mipsCPUInfo(CPUFeature feature) { } VP8CPUInfo VP8GetCPUInfo = mipsCPUInfo; +#elif defined(WEBP_USE_WASM) +static int wasmCPUInfo(CPUFeature feature) { + if (feature != kWASM) return 0; + return 1; +} +VP8CPUInfo VP8GetCPUInfo = wasmCPUInfo; #else VP8CPUInfo VP8GetCPUInfo = NULL; #endif diff --git a/src/dsp/dec.c b/src/dsp/dec.c index 007e985d..a0ba4ee6 100644 --- a/src/dsp/dec.c +++ b/src/dsp/dec.c @@ -700,6 +700,7 @@ extern void VP8DspInitNEON(void); extern void VP8DspInitMIPS32(void); extern void VP8DspInitMIPSdspR2(void); extern void VP8DspInitMSA(void); +extern void VP8DspInitWASM(void); static volatile VP8CPUInfo dec_last_cpuinfo_used = (VP8CPUInfo)&dec_last_cpuinfo_used; @@ -789,6 +790,11 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8DspInit(void) { if (VP8GetCPUInfo(kMSA)) { VP8DspInitMSA(); } +#endif +#if defined(WEBP_USE_WASM) + if (VP8GetCPUInfo(kWASM)) { + VP8DspInitWASM(); + } #endif } dec_last_cpuinfo_used = VP8GetCPUInfo; diff --git a/src/dsp/dec_wasm.c b/src/dsp/dec_wasm.c new file mode 100644 index 00000000..57879136 --- /dev/null +++ b/src/dsp/dec_wasm.c @@ -0,0 +1,29 @@ +// Copyright 2017 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. +// + +#include "./dsp.h" + +#if defined(WEBP_USE_WASM) + +//------------------------------------------------------------------------------ +// Entry point + +extern void VP8DspInitWASM(void); + +WEBP_TSAN_IGNORE_FUNCTION void VP8DspInitWASM(void) { +} + +#else // !WEBP_USE_WASM + +WEBP_DSP_INIT_STUB(VP8DspInitWASM) + +#endif // WEBP_USE_WASM diff --git a/src/dsp/dsp.h b/src/dsp/dsp.h index ccb9df7b..e2bebf97 100644 --- a/src/dsp/dsp.h +++ b/src/dsp/dsp.h @@ -42,8 +42,9 @@ extern "C" { # define __has_builtin(x) 0 #endif -// for now, none of the optimizations below are available in emscripten -#if !defined(EMSCRIPTEN) +// For now, none of the optimizations below are available in emscripten. +// WebAssembly overrides native optimizations. +#if !(defined(EMSCRIPTEN) || defined(WEBP_USE_WASM)) #if defined(_MSC_VER) && _MSC_VER > 1310 && \ (defined(_M_X64) || defined(_M_IX86)) @@ -144,7 +145,8 @@ typedef enum { kNEON, kMIPS32, kMIPSdspR2, - kMSA + kMSA, + kWASM } CPUFeature; // returns true if the CPU supports the feature. typedef int (*VP8CPUInfo)(CPUFeature feature);