|
| 1 | +cmake_minimum_required(VERSION 3.16) |
| 2 | +project(cornerstone-codec-libjxl CXX) |
| 3 | + |
| 4 | +if(NOT EMSCRIPTEN) |
| 5 | + message(FATAL_ERROR "This project must be configured with emcmake (Emscripten).") |
| 6 | +endif() |
| 7 | + |
| 8 | +set(CMAKE_CXX_STANDARD 17) |
| 9 | +set(CMAKE_CXX_STANDARD_REQUIRED ON) |
| 10 | + |
| 11 | +# Where the libjxl submodule lives. |
| 12 | +set(LIBJXL_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/extern/libjxl" |
| 13 | + CACHE PATH "Path to a libjxl source checkout") |
| 14 | + |
| 15 | +if(NOT EXISTS "${LIBJXL_SOURCE_DIR}/lib/include/jxl/decode.h") |
| 16 | + message(FATAL_ERROR |
| 17 | + "libjxl sources not found at ${LIBJXL_SOURCE_DIR}. Update the Git " |
| 18 | + "submodules before configuring.") |
| 19 | +endif() |
| 20 | + |
| 21 | +# Emscripten's ENVIRONMENT. The shipped module targets the browser and the |
| 22 | +# decode web worker only: including `node` makes the glue emit |
| 23 | +# `await import("node:module")`, which rspack/webpack reject as an unhandled |
| 24 | +# scheme. Configure a throwaway build dir with -DJXL_WASM_ENVIRONMENT= |
| 25 | +# web,worker,node to get a module that can be benchmarked or tested under Node. |
| 26 | +set(JXL_WASM_ENVIRONMENT "web,worker" CACHE STRING |
| 27 | + "Value passed to Emscripten's -sENVIRONMENT") |
| 28 | + |
| 29 | +# These apply to libjxl and Highway as well as to the wrapper below, so they |
| 30 | +# have to be set before add_subdirectory. Without -msimd128 Highway compiles |
| 31 | +# only its scalar fallback and decoding is several times slower; SIMD is |
| 32 | +# supported by every browser that can run this module, so it is on by default. |
| 33 | +option(JXL_WASM_SIMD "Compile with WebAssembly SIMD (much faster decode)" ON) |
| 34 | + |
| 35 | +if(JXL_WASM_SIMD) |
| 36 | + add_compile_options(-msimd128) |
| 37 | +endif() |
| 38 | + |
| 39 | +add_compile_options(-O3) |
| 40 | + |
| 41 | +# Static, no tools/tests. Everything the command line tools would pull in is |
| 42 | +# turned off. |
| 43 | +set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) |
| 44 | +set(BUILD_TESTING OFF CACHE BOOL "" FORCE) |
| 45 | +set(JPEGXL_STATIC ON CACHE BOOL "" FORCE) |
| 46 | +set(JPEGXL_ENABLE_TOOLS OFF CACHE BOOL "" FORCE) |
| 47 | +set(JPEGXL_ENABLE_EXAMPLES OFF CACHE BOOL "" FORCE) |
| 48 | +set(JPEGXL_ENABLE_BENCHMARK OFF CACHE BOOL "" FORCE) |
| 49 | +set(JPEGXL_ENABLE_DOXYGEN OFF CACHE BOOL "" FORCE) |
| 50 | +set(JPEGXL_ENABLE_MANPAGES OFF CACHE BOOL "" FORCE) |
| 51 | +set(JPEGXL_ENABLE_JNI OFF CACHE BOOL "" FORCE) |
| 52 | +set(JPEGXL_ENABLE_SJPEG OFF CACHE BOOL "" FORCE) |
| 53 | +set(JPEGXL_ENABLE_OPENEXR OFF CACHE BOOL "" FORCE) |
| 54 | +set(JPEGXL_ENABLE_TCMALLOC OFF CACHE BOOL "" FORCE) |
| 55 | +set(JPEGXL_ENABLE_PLUGINS OFF CACHE BOOL "" FORCE) |
| 56 | +set(JPEGXL_ENABLE_DEVTOOLS OFF CACHE BOOL "" FORCE) |
| 57 | +set(JPEGXL_ENABLE_COVERAGE OFF CACHE BOOL "" FORCE) |
| 58 | +set(JPEGXL_ENABLE_FUZZERS OFF CACHE BOOL "" FORCE) |
| 59 | +set(JPEGXL_BUNDLE_LIBPNG OFF CACHE BOOL "" FORCE) |
| 60 | +set(JPEGXL_ENABLE_SKCMS ON CACHE BOOL "" FORCE) |
| 61 | +set(JPEGXL_FORCE_SYSTEM_BROTLI OFF CACHE BOOL "" FORCE) |
| 62 | +set(JPEGXL_FORCE_SYSTEM_HWY OFF CACHE BOOL "" FORCE) |
| 63 | +# Needed for the JPEG XL JPEG Recompression transfer syntax |
| 64 | +# (1.2.840.10008.1.2.4.111), whose streams carry a jbrd box. |
| 65 | +set(JPEGXL_ENABLE_TRANSCODE_JPEG ON CACHE BOOL "" FORCE) |
| 66 | + |
| 67 | +add_subdirectory("${LIBJXL_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/libjxl" |
| 68 | + EXCLUDE_FROM_ALL) |
| 69 | + |
| 70 | +# Decoder and encoder are separate modules. A viewer only ever decodes, and |
| 71 | +# every decode worker fetches and compiles whatever it loads: linking the |
| 72 | +# encoder in as well takes the module from 1.1 MB to 2.7 MB, which is paid per |
| 73 | +# worker, per session, for code that never runs there. |
| 74 | +# |
| 75 | +# Each module compiles frame_info.cpp for the shared FrameInfo binding - once |
| 76 | +# per module, since embind throws if a value_object name is registered twice. |
| 77 | +function(add_jxl_wasm_module target source export_name) |
| 78 | + add_executable(${target} src/frame_info.cpp "${source}") |
| 79 | + |
| 80 | + # jxl_cms carries JxlGetDefaultCms(), which both halves need. |
| 81 | + target_link_libraries(${target} PRIVATE ${ARGN} jxl_cms) |
| 82 | + |
| 83 | + target_include_directories(${target} PRIVATE |
| 84 | + "${CMAKE_CURRENT_SOURCE_DIR}/src" |
| 85 | + "${LIBJXL_SOURCE_DIR}/lib/include" |
| 86 | + "${CMAKE_CURRENT_BINARY_DIR}/libjxl/lib/include") |
| 87 | + |
| 88 | + target_compile_options(${target} PRIVATE -fexceptions -msimd128 -O3) |
| 89 | + |
| 90 | + set_target_properties(${target} PROPERTIES |
| 91 | + OUTPUT_NAME "${target}" |
| 92 | + SUFFIX ".js" |
| 93 | + LINK_FLAGS "\ |
| 94 | +-O3 \ |
| 95 | +-fexceptions \ |
| 96 | +-lembind \ |
| 97 | +-sWASM=1 \ |
| 98 | +-sMODULARIZE=1 \ |
| 99 | +-sEXPORT_ES6=1 \ |
| 100 | +-sEXPORT_NAME=${export_name} \ |
| 101 | +-sALLOW_MEMORY_GROWTH=1 \ |
| 102 | +-sMALLOC=emmalloc \ |
| 103 | +-sFILESYSTEM=0 \ |
| 104 | +-sENVIRONMENT=${JXL_WASM_ENVIRONMENT} \ |
| 105 | +-sEXPORTED_RUNTIME_METHODS=[getExceptionMessage,decrementExceptionRefcount] \ |
| 106 | +-sDYNAMIC_EXECUTION=0 \ |
| 107 | +-sTEXTDECODER=2 \ |
| 108 | +-sINCOMING_MODULE_JS_API=[locateFile,instantiateWasm,wasmBinary,print,printErr] \ |
| 109 | +") |
| 110 | +endfunction() |
| 111 | + |
| 112 | +# jxl_dec is the decode-only public library, so the decode module carries no |
| 113 | +# encoder code at all; jxl is the full one (see lib/jxl.cmake). |
| 114 | +add_jxl_wasm_module(jpegxlwasm_decode src/jpegxl_decode.cpp |
| 115 | + createJpegXLDecoder jxl_dec) |
| 116 | +add_jxl_wasm_module(jpegxlwasm_encode src/jpegxl_encode.cpp |
| 117 | + createJpegXLEncoder jxl) |
0 commit comments