Skip to content

Commit

Permalink
Merge pull request #174 from aous72/improving_wasm
Browse files Browse the repository at this point in the history
Adding Support for WASM without SIMD.
  • Loading branch information
aous72 authored Feb 2, 2025
2 parents 7cd6186 + 03802f0 commit 2ba1b73
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 76 deletions.
28 changes: 25 additions & 3 deletions .github/workflows/emcc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,30 @@ jobs:
with:
actions-cache-folder: 'emsdk-cache'

- name: Build
- name: Build non-SIMD and Debug
run: |
cd build
emcmake cmake ..
emmake make
emcmake cmake .. --fresh -DOJPH_DISABLE_SIMD=ON -DCMAKE_BUILD_TYPE=Debug
cmake --build . --config Debug --clean-first
cd ..
- name: Build non-SIMD and Release
run: |
cd build
emcmake cmake .. --fresh -DOJPH_DISABLE_SIMD=ON -DCMAKE_BUILD_TYPE=Release
cmake --build . --config Release --clean-first
cd ..
- name: Build SIMD and Debug
run: |
cd build
emcmake cmake .. --fresh -DOJPH_DISABLE_SIMD=OFF -DCMAKE_BUILD_TYPE=Debug
cmake --build . --config Debug --clean-first
cd ..
- name: Build SIMD and Release
run: |
cd build
emcmake cmake .. --fresh -DOJPH_DISABLE_SIMD=OFF -DCMAKE_BUILD_TYPE=Release
cmake --build . --config Release --clean-first
cd ..
28 changes: 22 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,26 @@ if (DEFINED OJPH_ENABLE_INTEL_AVX512)
endif()

## Setting some of the options if EMSCRIPTEN is the compiler
# WebAssembly SIMD is treated differently. The SIMD flags above have no effect on the
# use of WASM SIMD. This is because, for WASM, both non-SIMD and SIMD are required,
# and therefore two sets of binaries are generated. For CPUs, one binary can carry both
# non-SIMD and SIMD, and the program, at run-time, can decide which path to follow,
# depending on what CPU instructions are available.
# In previous releases, the cmake script used to produce both non-SIMD and
# SIMD builds in one go. At the time of this writing, all interpreters and
# compilers of WASM code, such as web-browser and node, support SIMD, therefore
# it is time to make the SIMD build the default. In other words, this cmake
# script builds only WASM SIMD code by default, if desired, a non-SIMD build
# can be generated using the OJPH_DISABLE_SIMD option (in this case, the
# WASM SIMD code is not generated).
# It is worth remembering that the SIMD/non-SIMD issue arose because it is
# NOT possible to have multiple execution paths in the code, one for non-SIMD
# and one for SIMD, as we do for CPUs, letting the program select, at run-time,
# the best path to follow.
if(EMSCRIPTEN)
set(BUILD_SHARED_LIBS OFF)
set(OJPH_ENABLE_TIFF_SUPPORT OFF)
set(OJPH_BUILD_STREAM_EXPAND OFF)
set(OJPH_DISABLE_SIMD ON)
if (OJPH_DISABLE_SIMD)
set(OJPH_ENABLE_WASM_SIMD OFF)
else()
set(OJPH_ENABLE_WASM_SIMD ON)
endif()
endif()

# This is related to how the timestamp is set for URL downloaded files.
Expand Down Expand Up @@ -106,6 +116,12 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
-Wunused-parameter
)
endif()
if (EMSCRIPTEN)
add_compile_options(-fexceptions)
if(OJPH_ENABLE_WASM_SIMD)
add_compile_options(-DOJPH_ENABLE_WASM_SIMD -msimd128)
endif()
endif()

## Enhanced instruction options
if (OJPH_DISABLE_SIMD)
Expand Down
1 change: 0 additions & 1 deletion src/apps/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ endif()

if (EMSCRIPTEN)
add_link_options(-sWASM=1 -sASSERTIONS=1 -sALLOW_MEMORY_GROWTH=1 -sNODERAWFS=1 -sENVIRONMENT=node -sEXIT_RUNTIME=1 -sEXCEPTION_CATCHING_ALLOWED=['fake'])
add_compile_options(-DOJPH_ENABLE_WASM_SIMD -msimd128 -msse4.1 -std=c++11 -O3 -fexceptions)
endif()

## Build executables
Expand Down
6 changes: 5 additions & 1 deletion src/apps/ojph_compress/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ source_group("others" FILES ${OJPH_IMG_IO})
source_group("common" FILES ${OJPH_IMG_IO_H})

if(EMSCRIPTEN)
source_group("others" FILES ${OJPH_IMG_IO_SSE4})
if (OJPH_ENABLE_WASM_SIMD)
list(APPEND SOURCES ${OJPH_IMG_IO_SSE4})
source_group("others" FILES ${OJPH_IMG_IO_SSE4})
set_source_files_properties(${OJPH_IMG_IO_SSE4} PROPERTIES COMPILE_FLAGS -msse4.1)
endif()
else()
if (NOT OJPH_DISABLE_SIMD)
if (("${OJPH_TARGET_ARCH}" MATCHES "OJPH_ARCH_X86_64") OR ("${OJPH_TARGET_ARCH}" MATCHES "OJPH_ARCH_I386"))
Expand Down
7 changes: 5 additions & 2 deletions src/apps/ojph_expand/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
## building ojph_expand
#######################


file(GLOB OJPH_EXPAND "ojph_expand.cpp")
file(GLOB OJPH_IMG_IO "../others/ojph_img_io.cpp")
file(GLOB OJPH_IMG_IO_SSE4 "../others/ojph_img_io_sse41.cpp")
Expand All @@ -15,7 +14,11 @@ source_group("others" FILES ${OJPH_IMG_IO})
source_group("common" FILES ${OJPH_IMG_IO_H})

if(EMSCRIPTEN)
source_group("others" FILES ${OJPH_IMG_IO_SSE4})
if (OJPH_ENABLE_WASM_SIMD)
list(APPEND SOURCES ${OJPH_IMG_IO_SSE4})
source_group("others" FILES ${OJPH_IMG_IO_SSE4})
set_source_files_properties(${OJPH_IMG_IO_SSE4} PROPERTIES COMPILE_FLAGS -msse4.1)
endif()
else()
if (NOT OJPH_DISABLE_SIMD)
if (("${OJPH_TARGET_ARCH}" MATCHES "OJPH_ARCH_X86_64") OR ("${OJPH_TARGET_ARCH}" MATCHES "OJPH_ARCH_I386"))
Expand Down
91 changes: 55 additions & 36 deletions src/apps/others/ojph_img_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,8 @@ namespace ojph {
samples_per_line = num_components * width;
bytes_per_line = bytes_per_sample * samples_per_line;

#if !defined(OJPH_ENABLE_WASM_SIMD) || !defined(OJPH_EMSCRIPTEN)

if (bytes_per_sample == 1) {
if (num_components == 1)
converter = gen_cvrt_32b1c_to_8ub1c;
Expand All @@ -471,49 +473,66 @@ namespace ojph {
converter = gen_cvrt_32b3c_to_16ub3c_be;
}

#ifndef OJPH_DISABLE_SIMD
#ifndef OJPH_DISABLE_SIMD

#if (defined(OJPH_ARCH_X86_64) || defined(OJPH_ARCH_I386))
#if (defined(OJPH_ARCH_X86_64) || defined(OJPH_ARCH_I386))

#ifndef OJPH_DISABLE_SSE4
if (get_cpu_ext_level() >= X86_CPU_EXT_LEVEL_SSE41) {
if (bytes_per_sample == 1) {
if (num_components == 1)
converter = sse41_cvrt_32b1c_to_8ub1c;
else
converter = sse41_cvrt_32b3c_to_8ub3c;
}
else {
if (num_components == 1)
converter = sse41_cvrt_32b1c_to_16ub1c_be;
else
converter = sse41_cvrt_32b3c_to_16ub3c_be;
}
}
#endif // !OJPH_DISABLE_SSE4

#ifndef OJPH_DISABLE_AVX2
if (get_cpu_ext_level() >= X86_CPU_EXT_LEVEL_AVX2) {
if (bytes_per_sample == 1) {
if (num_components == 1)
converter = avx2_cvrt_32b1c_to_8ub1c;
else
converter = avx2_cvrt_32b3c_to_8ub3c;
#ifndef OJPH_DISABLE_SSE4
if (get_cpu_ext_level() >= X86_CPU_EXT_LEVEL_SSE41) {
if (bytes_per_sample == 1) {
if (num_components == 1)
converter = sse41_cvrt_32b1c_to_8ub1c;
else
converter = sse41_cvrt_32b3c_to_8ub3c;
}
else {
if (num_components == 1)
converter = sse41_cvrt_32b1c_to_16ub1c_be;
else
converter = sse41_cvrt_32b3c_to_16ub3c_be;
}
}
else {
if (num_components == 1)
converter = avx2_cvrt_32b1c_to_16ub1c_be;
else
{ } // did not find an implementation better than sse41
#endif // !OJPH_DISABLE_SSE4

#ifndef OJPH_DISABLE_AVX2
if (get_cpu_ext_level() >= X86_CPU_EXT_LEVEL_AVX2) {
if (bytes_per_sample == 1) {
if (num_components == 1)
converter = avx2_cvrt_32b1c_to_8ub1c;
else
converter = avx2_cvrt_32b3c_to_8ub3c;
}
else {
if (num_components == 1)
converter = avx2_cvrt_32b1c_to_16ub1c_be;
else
{ } // did not find an implementation better than sse41
}
}
}
#endif // !OJPH_DISABLE_AVX2
#endif // !OJPH_DISABLE_AVX2

#elif defined(OJPH_ARCH_ARM)

#elif defined(OJPH_ARCH_ARM)
#endif // !(defined(OJPH_ARCH_X86_64) || defined(OJPH_ARCH_I386))

#endif // !(defined(OJPH_ARCH_X86_64) || defined(OJPH_ARCH_I386))
#endif // !OJPH_DISABLE_SIMD

#endif // !OJPH_DISABLE_SIMD
#else // OJPH_ENABLE_WASM_SIMD

if (bytes_per_sample == 1) {
if (num_components == 1)
converter = sse41_cvrt_32b1c_to_8ub1c;
else
converter = sse41_cvrt_32b3c_to_8ub3c;
}
else {
if (num_components == 1)
converter = sse41_cvrt_32b1c_to_16ub1c_be;
else
converter = sse41_cvrt_32b3c_to_16ub3c_be;
}

#endif // !OJPH_ENABLE_WASM_SIMD
}

////////////////////////////////////////////////////////////////////////////
Expand Down
13 changes: 6 additions & 7 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,12 @@ source_group("others" FILES ${OTHERS})
source_group("transform" FILES ${TRANSFORM})

if(EMSCRIPTEN)
add_compile_options(-std=c++11 -O3 -fexceptions -DOJPH_ENABLE_WASM_SIMD -msimd128)
list(APPEND SOURCES ${CODESTREAM_WASM} ${CODING_WASM} ${TRANSFORM_WASM})

source_group("codestream" FILES ${CODESTREAM_WASM})
source_group("coding" FILES ${CODING_WASM})
source_group("transform" FILES ${TRANSFORM_WASM})

if (OJPH_ENABLE_WASM_SIMD)
list(APPEND SOURCES ${CODESTREAM_WASM} ${CODING_WASM} ${TRANSFORM_WASM})
source_group("codestream" FILES ${CODESTREAM_WASM})
source_group("coding" FILES ${CODING_WASM})
source_group("transform" FILES ${TRANSFORM_WASM})
endif()
else()
if (NOT OJPH_DISABLE_SIMD)
if (("${OJPH_TARGET_ARCH}" MATCHES "OJPH_ARCH_X86_64") OR ("${OJPH_TARGET_ARCH}" MATCHES "OJPH_ARCH_I386"))
Expand Down
28 changes: 18 additions & 10 deletions subprojects/js/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,26 @@ cmake_minimum_required(VERSION 3.10.0)

set(CMAKE_SYSTEM_NAME Generic)

project (openjphwasm DESCRIPTION "Open source implementation of JPH" LANGUAGES CXX)

set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../html)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../html)
project (OpenJPH_WASM DESCRIPTION "Open source implementation of JPH" LANGUAGES CXX)

add_subdirectory("../.." openjph EXCLUDE_FROM_ALL)
add_executable(libopenjph "src/ojph_wrapper.cpp")
set_target_properties(libopenjph PROPERTIES SUFFIX ".js" LINK_FLAGS "-O3 -fexceptions -s WASM=1 -s EXPORT_ES6=1 -s MODULARIZE=1 -s ENVIRONMENT=web -s EXPORTED_FUNCTIONS=[_free,_malloc] -s EXPORTED_RUNTIME_METHODS=[ccall,cwrap,writeArrayToMemory] -s NO_EXIT_RUNTIME=1 -s ALLOW_MEMORY_GROWTH=1 -s INITIAL_MEMORY=134217728")
if (OJPH_DISABLE_SIMD)
else()
target_compile_options(libopenjph PRIVATE -DOJPH_ENABLE_WASM_SIMD -msimd128)
endif()
set_target_properties(libopenjph PROPERTIES SUFFIX ".js")
target_link_options(libopenjph PRIVATE
-fexceptions
-sWASM=1
-sEXPORT_ES6=1
-sMODULARIZE=1
-sENVIRONMENT=web
-sEXPORTED_FUNCTIONS=[_free,_malloc]
-sEXPORTED_RUNTIME_METHODS=[ccall,cwrap,writeArrayToMemory]
-sNO_EXIT_RUNTIME=1
-sALLOW_MEMORY_GROWTH=1
-sINITIAL_MEMORY=134217728
)
target_link_libraries(libopenjph PRIVATE openjph)

add_executable(libopenjph_simd "src/ojph_wrapper.cpp" )
target_compile_options(libopenjph_simd PRIVATE -DOJPH_ENABLE_WASM_SIMD -msimd128)
set_target_properties(libopenjph_simd PROPERTIES SUFFIX ".js" LINK_FLAGS "-O3 -fexceptions -s WASM=1 -s EXPORT_ES6=1 -s MODULARIZE=1 -s ENVIRONMENT=web -s EXPORTED_FUNCTIONS=[_free,_malloc] -s EXPORTED_RUNTIME_METHODS=[ccall,cwrap,writeArrayToMemory] -s NO_EXIT_RUNTIME=1 -s ALLOW_MEMORY_GROWTH=1 -s INITIAL_MEMORY=134217728")
target_link_libraries(libopenjph_simd PRIVATE openjphsimd)

12 changes: 8 additions & 4 deletions subprojects/js/build.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#!/bin/sh
#!/bin/bash

mkdir -p build
#(cd build && emcmake cmake -DCMAKE_BUILD_TYPE=Debug ..)
(cd build && emcmake cmake ..)
(cd build && emmake make VERBOSE=1 -j)
cd build
emcmake cmake .. -DCMAKE_BUILD_TYPE=Release -DOJPH_DISABLE_SIMD=ON && emmake make -j8 && mv libopenjph.* ../html/
emcmake cmake .. -DCMAKE_BUILD_TYPE=Release -DOJPH_DISABLE_SIMD=OFF && emmake make -j8 && mv libopenjph.wasm ../html/libopenjph_simd.wasm
cd ..
sed 's/libopenjph.wasm/libopenjph_simd.wasm/g' build/libopenjph.js > html/libopenjph_simd.js
rm build/libopenjph.js
6 changes: 0 additions & 6 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,9 @@ else()
COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE:ojph_compress>" "./"
)
if(EMSCRIPTEN)
add_custom_command(TARGET test_executables POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE:ojph_expand_simd>" "./"
COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE:ojph_compress_simd>" "./"
)
add_custom_command(TARGET test_executables POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE_DIR:ojph_expand>/ojph_expand.wasm" "./"
COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE_DIR:ojph_compress>/ojph_compress.wasm" "./"
COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE_DIR:ojph_expand_simd>/ojph_expand_simd.wasm" "./"
COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE_DIR:ojph_compress_simd>/ojph_compress_simd.wasm" "./"
)
endif(EMSCRIPTEN)
if(MSYS)
Expand Down

0 comments on commit 2ba1b73

Please sign in to comment.