diff --git a/.github/workflows/emcc.yml b/.github/workflows/emcc.yml new file mode 100644 index 00000000..48298f61 --- /dev/null +++ b/.github/workflows/emcc.yml @@ -0,0 +1,47 @@ +name: Build with EMCC + +on: + push: + pull_request: + types: [opened, reopened] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Configure emcc + uses: mymindstorm/setup-emsdk@v14 + with: + actions-cache-folder: 'emsdk-cache' + + - name: Build non-SIMD and Debug + run: | + cd build + 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 .. diff --git a/CMakeLists.txt b/CMakeLists.txt index cfa70ea8..1a629bfb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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. @@ -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) @@ -148,15 +164,10 @@ endif() ################################################################################################ include(GNUInstallDirs) -install(TARGETS openjph - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) -install(DIRECTORY src/core/common/ - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/openjph - FILES_MATCHING - PATTERN "*.h") +install(EXPORT openjph-config + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/openjph +) install(FILES "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc" DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) @@ -179,6 +190,16 @@ configure_file( @ONLY ) +include(CMakePackageConfigHelpers) +write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/openjph-config-version.cmake + COMPATIBILITY SameMinorVersion) + +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/openjph-config-version.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/openjph +) + + ################################################################################################ # Testing (OJPH_BUILD_TESTS) ################################################################################################ diff --git a/src/apps/CMakeLists.txt b/src/apps/CMakeLists.txt index e4f14a3f..b5737f62 100644 --- a/src/apps/CMakeLists.txt +++ b/src/apps/CMakeLists.txt @@ -1,16 +1,15 @@ # Add tiff library ############################################################ -if( OJPH_ENABLE_TIFF_SUPPORT ) +if( OJPH_ENABLE_TIFF_SUPPORT AND (NOT EMSCRIPTEN)) FIND_PACKAGE( TIFF ) if( TIFF_FOUND ) set(USE_TIFF TRUE CACHE BOOL "Add TIFF support") - include_directories( ${TIFF_INCLUDE_DIR} ) add_definitions(-DOJPH_ENABLE_TIFF_SUPPORT) - elseif(MSVC) - message(STATUS "TIFF support has been enabled by no path to the TIFF library " + else() + message(WARNING "TIFF support has been requested but no path to the TIFF library " "has been specified; please configure with -DCMAKE_PREFIX_PATH=, " "or disable TIFF support using -DOJPH_ENABLE_TIFF_SUPPORT=OFF.") endif( TIFF_FOUND ) @@ -18,7 +17,13 @@ if( OJPH_ENABLE_TIFF_SUPPORT ) 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']) +endif() + ## Build executables add_subdirectory(ojph_expand) add_subdirectory(ojph_compress) -add_subdirectory(ojph_stream_expand) +if (OJPH_BUILD_STREAM_EXPAND) + add_subdirectory(ojph_stream_expand) +endif() \ No newline at end of file diff --git a/src/apps/ojph_compress/CMakeLists.txt b/src/apps/ojph_compress/CMakeLists.txt index c99298be..d4c704e4 100644 --- a/src/apps/ojph_compress/CMakeLists.txt +++ b/src/apps/ojph_compress/CMakeLists.txt @@ -1,9 +1,6 @@ ## building ojph_compress ######################### -include_directories(../common) -include_directories(../../core/common) - file(GLOB OJPH_COMPRESS "ojph_compress.cpp") file(GLOB OJPH_IMG_IO "../others/ojph_img_io.cpp") file(GLOB OJPH_IMG_IO_SSE4 "../others/ojph_img_io_sse41.cpp") @@ -17,17 +14,11 @@ source_group("others" FILES ${OJPH_IMG_IO}) source_group("common" FILES ${OJPH_IMG_IO_H}) if(EMSCRIPTEN) - add_compile_options(-std=c++11 -O3 -fexceptions) - add_link_options(-sWASM=1 -sASSERTIONS=1 -sALLOW_MEMORY_GROWTH=1 -sNODERAWFS=1 -sENVIRONMENT=node -sEXIT_RUNTIME=1 -sEXCEPTION_CATCHING_ALLOWED=['fake']) - add_executable(ojph_compress ${SOURCES}) - add_executable(ojph_compress_simd ${SOURCES} ${OJPH_IMG_IO_SSE4}) - target_compile_options(ojph_compress_simd PRIVATE -DOJPH_ENABLE_WASM_SIMD -msimd128 -msse4.1) - source_group("others" FILES ${OJPH_IMG_IO_SSE4}) - - target_link_libraries(ojph_compress PRIVATE openjph) - install(TARGETS ojph_compress DESTINATION bin) - target_link_libraries(ojph_compress_simd PRIVATE openjphsimd) - install(TARGETS ojph_compress_simd DESTINATION bin) + 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")) @@ -48,18 +39,17 @@ else() set_source_files_properties(${OJPH_IMG_IO_AVX2} PROPERTIES COMPILE_FLAGS -mavx2) endif() elseif ("${OJPH_TARGET_ARCH}" MATCHES "OJPH_ARCH_ARM") - + endif() endif() - add_executable(ojph_compress ${SOURCES}) +endif() - if( USE_TIFF ) - target_link_libraries(ojph_compress PUBLIC openjph ${TIFF_LIBRARIES}) - else() - target_link_libraries(ojph_compress PUBLIC openjph) - endif() +add_executable(ojph_compress ${SOURCES}) +target_include_directories(ojph_compress PRIVATE ../common) +target_link_libraries(ojph_compress PRIVATE openjph $) - install(TARGETS ojph_compress DESTINATION bin) -endif() +install(TARGETS ojph_compress + EXPORT openjph-config +) diff --git a/src/apps/ojph_compress/ojph_compress.cpp b/src/apps/ojph_compress/ojph_compress.cpp index d96d93e5..824fa07d 100644 --- a/src/apps/ojph_compress/ojph_compress.cpp +++ b/src/apps/ojph_compress/ojph_compress.cpp @@ -777,33 +777,20 @@ int main(int argc, char * argv[]) { if (num_bit_depths < num_comps) // but if not enough, repeat for (ojph::ui32 c = num_bit_depths; c < num_comps; ++c) bit_depth[c] = bit_depth[num_bit_depths - 1]; - if (is_signed[0] != -1) // one was set - if (num_is_signed < num_comps) // but if not enough, repeat - for (ojph::ui32 c = num_is_signed; c < num_comps; ++c) - is_signed[c] = is_signed[num_is_signed - 1]; bool all_the_same = true; if (num_comps == 3) - { all_the_same = all_the_same && bit_depth[0] == bit_depth[1] && bit_depth[1] == bit_depth[2]; - all_the_same = all_the_same - && is_signed[0] == is_signed[1] - && is_signed[1] == is_signed[2]; - } - pfm.configure(bit_depth); - ojph::point ds(1, 1); for (ojph::ui32 c = 0; c < num_comps; ++c) { - ojph::ui32 bd = 32; - if (bit_depth[c] != 0) - bd = bit_depth[c]; - bool is = true; - if (is_signed[c] != -1) - is = is_signed[c] != 0; - siz.set_component(c, ds, bd, is); + if (bit_depth[c] == 0) + bit_depth[c] = 32; + siz.set_component(c, ojph::point(1,1), bit_depth[c], true); } + pfm.configure(bit_depth); + siz.set_image_offset(image_offset); siz.set_tile_size(tile_size); siz.set_tile_offset(tile_offset); @@ -817,7 +804,7 @@ int main(int argc, char * argv[]) { if (num_comps == 1) { if (employ_color_transform != -1) - OJPH_WARN(0x01000092, + OJPH_WARN(0x01000091, "-colour_trans option is not needed and was not used; " "this is because the image has one component only\n"); } @@ -829,29 +816,30 @@ int main(int argc, char * argv[]) { cod.set_color_transform(employ_color_transform == 1); } cod.set_reversible(reversible); - if (!reversible && quantization_step != -1.0f) + if (!reversible) { + const float min_step = 1.0f / 16384.0f; + if (quantization_step == -1.0f) + quantization_step = min_step; + else + quantization_step = ojph_max(quantization_step, min_step); codestream.access_qcd().set_irrev_quant(quantization_step); + } + // Note: Even if only ALL_COMPS is set to + // OJPH_NLT_BINARY_COMPLEMENT_NLT, the library can decide if + // one ALL_COMPS NLT marker segment is needed, or multiple + // per component NLT marker segments are needed (when the components + // have different bit depths or signedness). + // Of course for .pfm images all components should have the same + // bit depth and signedness. ojph::param_nlt nlt = codestream.access_nlt(); - if (reversible) { - // Note: Even if only ALL_COMPS is set to - // OJPH_NLT_BINARY_COMPLEMENT_NLT, the library can decide if - // one ALL_COMPS NLT marker segment is needed, or multiple - // per component NLT marker segments are needed (when the components - // have different bit depths or signedness). - // Of course for .pfm images all components should have the same - // bit depth and signedness. - if (all_the_same) - nlt.set_nonlinear_transform(ojph::param_nlt::ALL_COMPS, - ojph::param_nlt::OJPH_NLT_BINARY_COMPLEMENT_NLT); - else - for (ojph::ui32 c = 0; c < num_comps; ++c) - nlt.set_nonlinear_transform(c, - ojph::param_nlt::OJPH_NLT_BINARY_COMPLEMENT_NLT); - } + if (all_the_same) + nlt.set_nonlinear_transform(ojph::param_nlt::ALL_COMPS, + ojph::param_nlt::OJPH_NLT_BINARY_COMPLEMENT_NLT); else - OJPH_ERROR(0x01000093, "We currently support lossless only for " - "pfm images; this may change in the future."); + for (ojph::ui32 c = 0; c < num_comps; ++c) + nlt.set_nonlinear_transform(c, + ojph::param_nlt::OJPH_NLT_BINARY_COMPLEMENT_NLT); codestream.set_planar(false); if (profile_string[0] != '\0') @@ -861,13 +849,16 @@ int main(int argc, char * argv[]) { codestream.request_tlm_marker(tlm_marker); if (dims.w != 0 || dims.h != 0) - OJPH_WARN(0x01000094, + OJPH_WARN(0x01000092, "-dims option is not needed and was not used\n"); if (num_components != 0) - OJPH_WARN(0x01000095, + OJPH_WARN(0x01000093, "-num_comps is not needed and was not used\n"); + if (is_signed[0] != -1) + OJPH_WARN(0x01000094, + "-signed is not needed and was not used\n"); if (comp_downsampling[0].x != 0 || comp_downsampling[0].y != 0) - OJPH_WARN(0x01000096, + OJPH_WARN(0x01000095, "-downsamp is not needed and was not used\n"); base = &pfm; diff --git a/src/apps/ojph_expand/CMakeLists.txt b/src/apps/ojph_expand/CMakeLists.txt index dfb22be3..6ca4d6f5 100644 --- a/src/apps/ojph_expand/CMakeLists.txt +++ b/src/apps/ojph_expand/CMakeLists.txt @@ -1,9 +1,6 @@ ## building ojph_expand ####################### -include_directories(../common) -include_directories(../../core/common) - 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") @@ -17,17 +14,11 @@ source_group("others" FILES ${OJPH_IMG_IO}) source_group("common" FILES ${OJPH_IMG_IO_H}) if(EMSCRIPTEN) - add_compile_options(-std=c++11 -O3 -fexceptions) - add_link_options(-sWASM=1 -sASSERTIONS=1 -sALLOW_MEMORY_GROWTH=1 -sNODERAWFS=1 -sENVIRONMENT=node -sEXIT_RUNTIME=1 -sEXCEPTION_CATCHING_ALLOWED=['fake']) - add_executable(ojph_expand ${SOURCES}) - add_executable(ojph_expand_simd ${SOURCES} ${OJPH_IMG_IO_SSE4}) - target_compile_options(ojph_expand_simd PRIVATE -DOJPH_ENABLE_WASM_SIMD -msimd128 -msse4.1) - source_group("others" FILES ${OJPH_IMG_IO_SSE4}) - - target_link_libraries(ojph_expand PRIVATE openjph) - install(TARGETS ojph_expand DESTINATION bin) - target_link_libraries(ojph_expand_simd PRIVATE openjphsimd) - install(TARGETS ojph_expand_simd DESTINATION bin) + 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")) @@ -53,13 +44,12 @@ else() endif() - add_executable(ojph_expand ${SOURCES}) +endif() - if( USE_TIFF ) - target_link_libraries(ojph_expand PUBLIC openjph ${TIFF_LIBRARIES}) - else() - target_link_libraries(ojph_expand PUBLIC openjph) - endif() +add_executable(ojph_expand ${SOURCES}) +target_include_directories(ojph_expand PRIVATE ../common) +target_link_libraries(ojph_expand PRIVATE openjph $) - install(TARGETS ojph_expand DESTINATION bin) -endif() +install(TARGETS ojph_expand + EXPORT openjph-config +) \ No newline at end of file diff --git a/src/apps/ojph_expand/ojph_expand.cpp b/src/apps/ojph_expand/ojph_expand.cpp index 717fa382..1546cf77 100644 --- a/src/apps/ojph_expand/ojph_expand.cpp +++ b/src/apps/ojph_expand/ojph_expand.cpp @@ -269,60 +269,31 @@ int main(int argc, char *argv[]) { } else if (is_matching(".pfm", v)) { - OJPH_INFO(0x02000011, "Note: The .pfm implementation is " - "experimental. It is developed for me the test NLT marker segments. " - "For this reason, I am restricting it to images that employ the " - "NLT marker segment, with the assumption that original values are " + OJPH_INFO(0x02000010, "Note: The .pfm implementation is " + "experimental. Here, we are assuming that the original data is " "floating-point numbers."); codestream.set_planar(false); ojph::param_siz siz = codestream.access_siz(); - ojph::param_cod cod = codestream.access_cod(); - ojph::param_nlt nlt = codestream.access_nlt(); ojph::ui32 num_comps = siz.get_num_components(); if (num_comps != 3 && num_comps != 1) OJPH_ERROR(0x0200000C, "The file has %d color components; this cannot be saved to" - " a .pfm file\n", num_comps); + " a .pfm file", num_comps); bool all_same = true; ojph::point p = siz.get_downsampling(0); - for (ojph::ui32 i = 1; i < siz.get_num_components(); ++i) - { + for (ojph::ui32 i = 1; i < siz.get_num_components(); ++i) { ojph::point p1 = siz.get_downsampling(i); all_same = all_same && (p1.x == p.x) && (p1.y == p.y); } if (!all_same) OJPH_ERROR(0x0200000D, "To save an image to ppm, all the components must have the " - "same downsampling ratio\n"); + "same downsampling ratio"); ojph::ui32 bit_depth[3]; - for (ojph::ui32 c = 0; c < siz.get_num_components(); ++c) { - ojph::ui8 bd = 0; - bool is = true; - ojph::ui8 nl_type; - bool result = nlt.get_nonlinear_transform(c, bd, is, nl_type); - if (result == false || - nl_type != ojph::param_nlt::OJPH_NLT_BINARY_COMPLEMENT_NLT) - OJPH_ERROR(0x0200000E, - "This codestream is not supported; it does not have an " - "NLT segment marker for this component (or no default NLT " - "settings) .\n"); - if (bd != siz.get_bit_depth(c) || is != siz.is_signed(c)) - OJPH_ERROR(0x0200000F, - "There is discrepancy in component %d configuration between " - "SIZ marker segment, which specifies bit_depth = %d and " - "signedness = %s, and NLT marker segment, which specifies " - "bit_depth = %d and signedness = %s.\n", c, - siz.get_bit_depth(c), is != siz.is_signed(c) ? "True" : "False", - bd, is ? "True" : "False"); - bit_depth[c] = bd; - } - if (!cod.is_reversible()) - OJPH_ERROR(0x02000010, - "This codestream is lossy (not reversible), and we currently " - "only support reversible codestreams for .pfm target files. " - "This is only temporary and will be changed at some point.\n"); + for (ojph::ui32 c = 0; c < siz.get_num_components(); ++c) + bit_depth[c] = siz.get_bit_depth(c); pfm.configure(siz.get_recon_width(0), siz.get_recon_height(0), siz.get_num_components(), -1.0f, bit_depth); pfm.open(output_filename); diff --git a/src/apps/ojph_stream_expand/CMakeLists.txt b/src/apps/ojph_stream_expand/CMakeLists.txt index 5aea3421..24bc2d12 100644 --- a/src/apps/ojph_stream_expand/CMakeLists.txt +++ b/src/apps/ojph_stream_expand/CMakeLists.txt @@ -1,31 +1,28 @@ ## building ojph_stream_expand ############################## -if (OJPH_BUILD_STREAM_EXPAND) +set(CMAKE_CXX_STANDARD 14) - include_directories(../common) - include_directories(../../core/common) - set(CMAKE_CXX_STANDARD 14) - - file(GLOB OJPH_STREAM_EXPAND "*.cpp" "*.h") - file(GLOB OJPH_SOCKETS "../others/ojph_sockets.cpp") - file(GLOB OJPH_SOCKETS_H "../common/ojph_sockets.h") - file(GLOB OJPH_THREADS "../others/ojph_threads.cpp") - file(GLOB OJPH_THREADS_H "../common/ojph_threads.h") +file(GLOB OJPH_STREAM_EXPAND "*.cpp" "*.h") +file(GLOB OJPH_SOCKETS "../others/ojph_sockets.cpp") +file(GLOB OJPH_SOCKETS_H "../common/ojph_sockets.h") +file(GLOB OJPH_THREADS "../others/ojph_threads.cpp") +file(GLOB OJPH_THREADS_H "../common/ojph_threads.h") - list(APPEND SOURCES ${OJPH_STREAM_EXPAND} ${OJPH_SOCKETS} ${OJPH_SOCKETS_H} ${OJPH_THREADS} ${OJPH_THREADS_H}) +list(APPEND SOURCES ${OJPH_STREAM_EXPAND} ${OJPH_SOCKETS} ${OJPH_SOCKETS_H} ${OJPH_THREADS} ${OJPH_THREADS_H}) - source_group("main" FILES ${OJPH_STREAM_EXPAND}) - source_group("others" FILES ${OJPH_SOCKETS} ${OJPH_THREADS}) - source_group("common" FILES ${OJPH_SOCKETS_H} ${OJPH_THREADS_H}) +source_group("main" FILES ${OJPH_STREAM_EXPAND}) +source_group("others" FILES ${OJPH_SOCKETS} ${OJPH_THREADS}) +source_group("common" FILES ${OJPH_SOCKETS_H} ${OJPH_THREADS_H}) - add_executable(ojph_stream_expand ${SOURCES}) - if(MSVC) - target_link_libraries(ojph_stream_expand PUBLIC openjph ws2_32) - else() - target_link_libraries(ojph_stream_expand PUBLIC openjph pthread) - endif(MSVC) +add_executable(ojph_stream_expand ${SOURCES}) +target_include_directories(ojph_stream_expand PRIVATE ../common) +if(MSVC) + target_link_libraries(ojph_stream_expand PUBLIC openjph ws2_32) +else() + target_link_libraries(ojph_stream_expand PUBLIC openjph pthread) +endif(MSVC) - install(TARGETS ojph_stream_expand DESTINATION bin) - -endif(OJPH_BUILD_STREAM_EXPAND) +install(TARGETS ojph_stream_expand + EXPORT openjph-config +) diff --git a/src/apps/others/ojph_img_io.cpp b/src/apps/others/ojph_img_io.cpp index fad05544..548f715e 100644 --- a/src/apps/others/ojph_img_io.cpp +++ b/src/apps/others/ojph_img_io.cpp @@ -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; @@ -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 } //////////////////////////////////////////////////////////////////////////// diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 552fd2d9..8aef3e88 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,6 +1,4 @@ -include_directories(common) - file(GLOB CODESTREAM "codestream/*.cpp" "codestream/*.h") file(GLOB CODESTREAM_SSE "codestream/*_sse.cpp") file(GLOB CODESTREAM_SSE2 "codestream/*_sse2.cpp") @@ -34,19 +32,12 @@ source_group("others" FILES ${OTHERS}) source_group("transform" FILES ${TRANSFORM}) if(EMSCRIPTEN) - add_compile_options(-std=c++11 -O3 -fexceptions) - add_library(openjph ${SOURCES}) - add_library(openjphsimd ${SOURCES} ${CODESTREAM_WASM} ${CODING_WASM} ${TRANSFORM_WASM}) - - target_include_directories(openjph PUBLIC $ $) - target_include_directories(openjphsimd PUBLIC $ $) - - target_compile_options(openjphsimd PRIVATE -DOJPH_ENABLE_WASM_SIMD -msimd128) - - 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")) @@ -114,18 +105,19 @@ else() endif() - add_library(openjph ${SOURCES}) endif() +add_library(openjph ${SOURCES}) + ## The option BUILD_SHARED_LIBS if (BUILD_SHARED_LIBS AND WIN32) target_compile_definitions(openjph PRIVATE OJPH_BUILD_SHARED_LIBRARY) endif() ## include library version/name -target_include_directories(openjph PUBLIC $ $) target_compile_definitions(openjph PUBLIC _FILE_OFFSET_BITS=64) +target_include_directories(openjph PUBLIC $ $) if (MSVC) set(OJPH_LIB_NAME_STRING "openjph.${OPENJPH_VERSION_MAJOR}.${OPENJPH_VERSION_MINOR}") @@ -139,3 +131,13 @@ else() SOVERSION "${OPENJPH_VERSION_MAJOR}.${OPENJPH_VERSION_MINOR}" VERSION "${OPENJPH_VERSION}") endif() + +install(TARGETS openjph + EXPORT openjph-config +) + +install(DIRECTORY common/ + DESTINATION include/openjph + FILES_MATCHING + PATTERN "*.h" +) diff --git a/src/core/codestream/ojph_codeblock.cpp b/src/core/codestream/ojph_codeblock.cpp index e5046068..88e20eba 100644 --- a/src/core/codestream/ojph_codeblock.cpp +++ b/src/core/codestream/ojph_codeblock.cpp @@ -74,7 +74,7 @@ namespace ojph { const size& cb_size, coded_cb_header* coded_cb, ui32 K_max, int line_offset, - ui32 precision) + ui32 precision, ui32 comp_idx) { mem_fixed_allocator* allocator = codestream->get_allocator(); @@ -101,10 +101,10 @@ namespace ojph { this->K_max = K_max; for (int i = 0; i < 4; ++i) this->max_val64[i] = 0; - ojph::param_cod cod = codestream->access_cod(); - this->reversible = cod.is_reversible(); + const param_cod* coc = codestream->get_coc(comp_idx); + this->reversible = coc->is_reversible(); this->resilient = codestream->is_resilient(); - this->stripe_causal = cod.get_block_vertical_causality(); + this->stripe_causal = coc->get_block_vertical_causality(); this->zero_block = false; this->coded_cb = coded_cb; diff --git a/src/core/codestream/ojph_codeblock.h b/src/core/codestream/ojph_codeblock.h index 4fa29312..24ee0eef 100644 --- a/src/core/codestream/ojph_codeblock.h +++ b/src/core/codestream/ojph_codeblock.h @@ -75,8 +75,8 @@ namespace ojph { ui32 precision); void finalize_alloc(codestream *codestream, subband* parent, const size& nominal, const size& cb_size, - coded_cb_header* coded_cb, - ui32 K_max, int tbx0, ui32 precision); + coded_cb_header* coded_cb, ui32 K_max, + int tbx0, ui32 precision, ui32 comp_idx); void push(line_buf *line); void encode(mem_elastic_allocator *elastic); void recreate(const size& cb_size, coded_cb_header* coded_cb); diff --git a/src/core/codestream/ojph_codestream_local.cpp b/src/core/codestream/ojph_codestream_local.cpp index 7648b1c4..ed88d0a9 100644 --- a/src/core/codestream/ojph_codestream_local.cpp +++ b/src/core/codestream/ojph_codestream_local.cpp @@ -79,9 +79,6 @@ namespace ojph { precinct_scratch_needed_bytes = 0; - used_coc_fields = 0; - coc = coc_store; - atk = atk_store; atk[0].init_irv97(); atk[0].link(atk_store + 1); @@ -626,6 +623,9 @@ namespace ojph { if (!cod.write(file)) OJPH_ERROR(0x00030025, "Error writing to file"); + if (!cod.write_coc(file, num_comps)) + OJPH_ERROR(0x0003002E, "Error writing to file"); + if (!qcd.write(file)) OJPH_ERROR(0x00030026, "Error writing to file"); @@ -751,7 +751,7 @@ namespace ojph { skip_marker(file, "CPF", NULL, OJPH_MSG_LEVEL::NO_MSG, false); else if (marker_idx == 3) { - cod.read(file, param_cod::COD_MAIN); + cod.read(file); received_markers |= 1; ojph::param_cod c(&cod); int num_qlayers = c.get_num_layers(); @@ -762,12 +762,17 @@ namespace ojph { } else if (marker_idx == 4) { - ui32 num_comps = siz.get_num_components(); - if (coc == coc_store && - num_comps * sizeof(param_cod) > sizeof(coc_store)) - coc = new param_cod[num_comps]; - coc[used_coc_fields++].read( - file, param_cod::COC_MAIN, num_comps, &cod); + param_cod* p = cod.add_coc_object(param_cod::OJPH_COD_UNKNOWN); + p->read_coc(file, siz.get_num_components(), &cod); + if (p->get_comp_idx() >= siz.get_num_components()) + OJPH_INFO(0x00030056, "The codestream carries a COC marker " + "segment for a component indexed by %d, which is more than the " + "allowed index number, since the codestream has %d components", + p->get_comp_idx(), num_comps); + param_cod *q = cod.get_coc(p->get_comp_idx()); + if (p != q && p->get_comp_idx() == q->get_comp_idx()) + OJPH_ERROR(0x00030057, "The codestream has two COC marker " + "segments for one component of index %d", p->get_comp_idx()); } else if (marker_idx == 5) { @@ -779,15 +784,14 @@ namespace ojph { param_qcd* p = qcd.add_qcc_object(param_qcd::OJPH_QCD_UNKNOWN); p->read_qcc(file, siz.get_num_components()); if (p->get_comp_idx() >= siz.get_num_components()) - OJPH_ERROR(0x00030054, "The codestream carries a QCC narker " + OJPH_ERROR(0x00030054, "The codestream carries a QCC marker " "segment for a component indexed by %d, which is more than the " "allowed index number, since the codestream has %d components", p->get_comp_idx(), num_comps); param_qcd *q = qcd.get_qcc(p->get_comp_idx()); if (p != q && p->get_comp_idx() == q->get_comp_idx()) OJPH_ERROR(0x00030055, "The codestream has two QCC marker " - "segments for one component of index %d", - p->get_comp_idx()); + "segments for one component of index %d", p->get_comp_idx()); } else if (marker_idx == 7) skip_marker(file, "RGN", "RGN is not supported yet", @@ -827,12 +831,6 @@ namespace ojph { } cod.update_atk(atk); - for (int i = 0; i < used_coc_fields; ++i) - { - if (i == 0) cod.link_cod(coc); - else coc[i - 1].link_cod(coc + i); - coc[i].update_atk(atk); - } siz.link(&cod); if (dfs.exists()) siz.link(&dfs); diff --git a/src/core/codestream/ojph_codestream_local.h b/src/core/codestream/ojph_codestream_local.h index 8fce85e9..8e7c8b26 100644 --- a/src/core/codestream/ojph_codestream_local.h +++ b/src/core/codestream/ojph_codestream_local.h @@ -159,11 +159,6 @@ namespace ojph { param_tlm tlm; // tile-part lengths param_nlt nlt; // non-linearity point transformation - private: // this is to handle qcc and coc - int used_coc_fields; - param_cod *coc; // coding style component - param_cod coc_store[4]; // we allocate 4, we allocate more if needed - private: // these are from Part 2 of the standard param_dfs dfs; // downsmapling factor styles param_atk* atk; // a pointer to atk diff --git a/src/core/codestream/ojph_params.cpp b/src/core/codestream/ojph_params.cpp index 5883a73c..bf66f689 100644 --- a/src/core/codestream/ojph_params.cpp +++ b/src/core/codestream/ojph_params.cpp @@ -254,6 +254,15 @@ namespace ojph { state->set_reversible(reversible); } + //////////////////////////////////////////////////////////////////////////// + param_coc param_cod::get_coc(ui32 component_idx) + { + local::param_cod *p = state->get_coc(component_idx); + if (p == state) // no COC segment marker for this component + p = state->add_coc_object(component_idx); + return param_coc(p); + } + //////////////////////////////////////////////////////////////////////////// ui32 param_cod::get_num_decompositions() const { @@ -275,12 +284,7 @@ namespace ojph { //////////////////////////////////////////////////////////////////////////// bool param_cod::is_reversible() const { - if (state->SPcod.wavelet_trans <= 1) - return state->get_wavelet_kern() == local::param_cod::DWT_REV53; - else { - assert(state->atk != NULL); - return state->access_atk()->is_reversible(); - } + return state->is_reversible(); } //////////////////////////////////////////////////////////////////////////// @@ -346,9 +350,61 @@ namespace ojph { //////////////////////////////////////////////////////////////////////////// bool param_cod::get_block_vertical_causality() const { - return (state->SPcod.block_style & local::param_cod::VERT_CAUSAL_MODE)!=0; + return state->get_block_vertical_causality(); } + //////////////////////////////////////////////////////////////////////////// + // + // + // + // + // + //////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////// + void param_coc::set_num_decomposition(ui32 num_decompositions) + { ojph::param_cod(state).set_num_decomposition(num_decompositions); } + + //////////////////////////////////////////////////////////////////////////// + void param_coc::set_block_dims(ui32 width, ui32 height) + { ojph::param_cod(state).set_block_dims(width, height); } + + //////////////////////////////////////////////////////////////////////////// + void param_coc::set_precinct_size(int num_levels, size* precinct_size) + { ojph::param_cod(state).set_precinct_size(num_levels, precinct_size); } + + //////////////////////////////////////////////////////////////////////////// + void param_coc::set_reversible(bool reversible) + { ojph::param_cod(state).set_reversible(reversible); } + + //////////////////////////////////////////////////////////////////////////// + ui32 param_coc::get_num_decompositions() const + { return ojph::param_cod(state).get_num_decompositions(); } + + //////////////////////////////////////////////////////////////////////////// + size param_coc::get_block_dims() const + { return ojph::param_cod(state).get_block_dims(); } + + //////////////////////////////////////////////////////////////////////////// + size param_coc::get_log_block_dims() const + { return ojph::param_cod(state).get_log_block_dims(); } + + //////////////////////////////////////////////////////////////////////////// + bool param_coc::is_reversible() const + { return ojph::param_cod(state).is_reversible(); } + + //////////////////////////////////////////////////////////////////////////// + size param_coc::get_precinct_size(ui32 level_num) const + { return ojph::param_cod(state).get_precinct_size(level_num); } + + //////////////////////////////////////////////////////////////////////////// + size param_coc::get_log_precinct_size(ui32 level_num) const + { return ojph::param_cod(state).get_log_precinct_size(level_num); } + + //////////////////////////////////////////////////////////////////////////// + bool param_coc::get_block_vertical_causality() const + { return ojph::param_cod(state).get_block_vertical_causality(); } + //////////////////////////////////////////////////////////////////////////// // @@ -783,6 +839,17 @@ namespace ojph { // ////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////// + bool param_cod::is_reversible() const + { + if (SPcod.wavelet_trans <= 1) + return get_wavelet_kern() == local::param_cod::DWT_REV53; + else { + assert(atk != NULL); + return atk->is_reversible(); + } + } + ////////////////////////////////////////////////////////////////////////// bool param_cod::write(outfile_base *file) { @@ -826,12 +893,71 @@ namespace ojph { } ////////////////////////////////////////////////////////////////////////// - void param_cod::read(infile_base *file, param_cod::cod_type type) + bool param_cod::write_coc(outfile_base *file, ui32 num_comps) + { + assert(type == COD_MAIN); + bool result = true; + param_cod *p = this->next; + while (p) + { + if (p->comp_idx < num_comps) + result &= p->internal_write_coc(file, num_comps); + p = p->next; + } + return result; + } + + ////////////////////////////////////////////////////////////////////////// + bool param_cod::internal_write_coc(outfile_base *file, ui32 num_comps) + { + assert(type == COC_MAIN); + + //marker size excluding header + Lcod = num_comps < 257 ? 9 : 10; + Lcod = (ui16)(Lcod + (Scod & 1 ? 1 + SPcod.num_decomp : 0)); + + ui8 buf[4]; + bool result = true; + + *(ui16*)buf = JP2K_MARKER::COC; + *(ui16*)buf = swap_byte(*(ui16*)buf); + result &= file->write(&buf, 2) == 2; + *(ui16*)buf = swap_byte(Lcod); + result &= file->write(&buf, 2) == 2; + if (num_comps < 257) + { + *(ui8*)buf = (ui8)comp_idx; + result &= file->write(&buf, 1) == 1; + } + else + { + *(ui16*)buf = swap_byte(comp_idx); + result &= file->write(&buf, 2) == 2; + } + *(ui8*)buf = Scod; + result &= file->write(&buf, 1) == 1; + buf[0] = SPcod.num_decomp; + buf[1] = SPcod.block_width; + buf[2] = SPcod.block_height; + buf[3] = SPcod.block_style; + result &= file->write(&buf, 4) == 4; + *(ui8*)buf = SPcod.wavelet_trans; + result &= file->write(&buf, 1) == 1; + if (Scod & 1) + for (int i = 0; i <= SPcod.num_decomp; ++i) + { + *(ui8*)buf = SPcod.precinct_size[i]; + result &= file->write(&buf, 1) == 1; + } + + return result; + } + + ////////////////////////////////////////////////////////////////////////// + void param_cod::read(infile_base *file) { - assert(this->type == UNDEFINED); assert(type == COD_MAIN); - this->type = type; if (file->read(&Lcod, 2) != 2) OJPH_ERROR(0x00050071, "error reading COD segment"); Lcod = swap_byte(Lcod); @@ -864,16 +990,14 @@ namespace ojph { } ////////////////////////////////////////////////////////////////////////// - void param_cod::read(infile_base* file, param_cod::cod_type type, - ui32 num_comps, param_cod *cod) + void param_cod::read_coc(infile_base* file, ui32 num_comps, + param_cod *top_cod) { - assert(this->type == UNDEFINED); assert(type == COC_MAIN); - assert(cod != NULL); + assert(top_cod != NULL); - this->type = type; - this->SGCod = cod->SGCod; - this->parent = cod; + this->SGCod = top_cod->SGCod; + this->top_cod = top_cod; if (file->read(&Lcod, 2) != 2) OJPH_ERROR(0x00050121, "error reading COC segment"); Lcod = swap_byte(Lcod); @@ -881,12 +1005,12 @@ namespace ojph { ui8 t; if (file->read(&t, 1) != 1) OJPH_ERROR(0x00050122, "error reading COC segment"); - comp_num = t; + comp_idx = t; } else { - if (file->read(&comp_num, 2) != 2) + if (file->read(&comp_idx, 2) != 2) OJPH_ERROR(0x00050123, "error reading COC segment"); - comp_num = swap_byte(comp_num); + comp_idx = swap_byte(comp_idx); } if (file->read(&Scod, 1) != 1) OJPH_ERROR(0x00050124, "error reading COC segment"); @@ -917,11 +1041,56 @@ namespace ojph { ////////////////////////////////////////////////////////////////////////// void param_cod::update_atk(const param_atk* atk) { + assert(type == COD_MAIN); this->atk = atk->get_atk(SPcod.wavelet_trans); if (this->atk == NULL) - OJPH_ERROR(0x00050131, "A COD/COC segment employs the DWT kernel " - "atk=%d, but a corresponding ATK segment cannot be found", + OJPH_ERROR(0x00050131, "A COD segment employs the DWT kernel " + "atk = %d, but a corresponding ATK segment cannot be found.", SPcod.wavelet_trans); + param_cod *p = next; + while (p) + { + p->atk = atk->get_atk(p->SPcod.wavelet_trans); + if (p->atk == NULL) + OJPH_ERROR(0x00050132, "A COC segment employs the DWT kernel " + "atk = %d, but a corresponding ATK segment cannot be found", + SPcod.wavelet_trans); + p = p->next; + } + } + + ////////////////////////////////////////////////////////////////////////// + const param_cod* param_cod::get_coc(ui32 comp_idx) const + { + assert(this->type == COD_MAIN || this->top_cod->type == COD_MAIN); + const param_cod *p, *q; + if (this->type == COD_MAIN) + q = p = this; + else + q = p = this->top_cod; + while (p && p->comp_idx != comp_idx) + p = p->next; + return p ? p : q; + } + + //////////////////////////////////////// + param_cod* param_cod::get_coc(ui32 comp_idx) + { + // cast object to constant + const param_cod* const_p = const_cast(this); + // call using the constant object, then cast to non-const + return const_cast(const_p->get_coc(comp_idx)); + } + + //////////////////////////////////////// + param_cod* param_cod::add_coc_object(ui32 comp_idx) + { + assert(type == COD_MAIN); + param_cod *p = this; + while (p->next != NULL) + p = p->next; + p->next = new param_cod(this, (ui16)comp_idx); + return p->next; } ////////////////////////////////////////////////////////////////////////// @@ -1230,7 +1399,7 @@ namespace ojph { ////////////////////////////////////////////////////////////////////////// ui32 param_qcd::propose_precision(const param_cod* cod) const { - ui32 comp_idx = cod->get_comp_num(); + ui32 comp_idx = cod->get_comp_idx(); ui32 precision = 0; const param_cod *main = cod->get_coc(param_cod::OJPH_COD_DEFAULT); @@ -1552,11 +1721,15 @@ namespace ojph { ////////////////////////////////////////////////////////////////////////// const param_qcd* param_qcd::get_qcc(ui32 comp_idx) const { - assert(this->top_qcd->type == QCD_MAIN); - param_qcd* p = this->top_qcd; + assert(this->type == QCD_MAIN || this->top_qcd->type == QCD_MAIN); + const param_qcd *p, *q; + if (this->type == QCD_MAIN) + q = p = this; + else + q = p = this->top_qcd; while (p && p->comp_idx != comp_idx) p = p->next; - return p ? p : this->top_qcd; + return p ? p : q; } ////////////////////////////////////////////////////////////////////////// @@ -1566,14 +1739,8 @@ namespace ojph { param_qcd *p = this; while (p->next != NULL) p = p->next; - p->next = new param_qcd; - p = p->next; - - p->type = QCC_MAIN; - p->next = NULL; - p->top_qcd = this; - p->comp_idx = (ui16)comp_idx; - return p; + p->next = new param_qcd(this, (ui16)comp_idx); + return p->next; } ////////////////////////////////////////////////////////////////////////// diff --git a/src/core/codestream/ojph_params_local.h b/src/core/codestream/ojph_params_local.h index dedaf44a..048705f7 100644 --- a/src/core/codestream/ojph_params_local.h +++ b/src/core/codestream/ojph_params_local.h @@ -100,6 +100,7 @@ namespace ojph { OJPH_TILEPART_RESOLUTIONS = 0x1, OJPH_TILEPART_COMPONENTS = 0x2, OJPH_TILEPART_LAYERS = 0x4, // these are meaningless with HTJ2K + OJPH_TILEPART_MASK = 0x3, // mask used for testing }; namespace local { @@ -369,7 +370,10 @@ namespace ojph { { // serves for both COD and COC markers friend ::ojph::param_cod; - enum default_comp_num : ui16 { OJPH_COD_DEFAULT = 65535 }; + enum default_comp_num : ui16 { + OJPH_COD_UNKNOWN = 65534, + OJPH_COD_DEFAULT = 65535 + }; //////////////////////////////////////// enum BLOCK_CODING_STYLES { @@ -392,22 +396,29 @@ namespace ojph { public: // COD_MAIN and COC_MAIN common functions //////////////////////////////////////// - param_cod() + param_cod(param_cod* top_cod = NULL, ui16 comp_idx = OJPH_COD_DEFAULT) { - type = UNDEFINED; + type = top_cod ? COC_MAIN : COD_MAIN; Lcod = 0; Scod = 0; next = NULL; atk = NULL; - parent = NULL; - comp_num = OJPH_COD_DEFAULT; + this->top_cod = top_cod; + this->comp_idx = comp_idx; + } + + //////////////////////////////////////// + ~param_cod() { + if (next) { + delete next; + next = NULL; + } } //////////////////////////////////////// void set_reversible(bool reversible) { - assert(type == UNDEFINED || type == COD_MAIN); - type = COD_MAIN; + assert(type == UNDEFINED || type == COD_MAIN || type == COC_MAIN); SPcod.wavelet_trans = reversible ? DWT_REV53 : DWT_IRV97; } @@ -416,15 +427,13 @@ namespace ojph { { assert(val == 0 || val == 1); assert(type == UNDEFINED || type == COD_MAIN); - type = COD_MAIN; SGCod.mc_trans = val; } //////////////////////////////////////// void check_validity(const param_siz& siz) { - assert(type == UNDEFINED || type == COD_MAIN); - type = COD_MAIN; + assert(type == COD_MAIN); //check that colour transform and match number of components and // downsampling @@ -490,7 +499,7 @@ namespace ojph { else if (type == COC_MAIN) { if (is_dfs_defined()) - return parent->get_num_decompositions(); + return top_cod->get_num_decompositions(); else return SPcod.num_decomp; } @@ -512,9 +521,17 @@ namespace ojph { ui8 get_wavelet_kern() const { return SPcod.wavelet_trans; } + //////////////////////////////////////// + bool is_reversible() const; + //////////////////////////////////////// bool is_employing_color_transform() const - { return (SGCod.mc_trans == 1); } + { + if (type == COD_MAIN || type == COD_TILE) + return (SGCod.mc_trans == 1); + else + return top_cod->is_employing_color_transform(); + } //////////////////////////////////////// size get_precinct_size(ui32 res_num) const @@ -535,50 +552,46 @@ namespace ojph { //////////////////////////////////////// bool packets_may_use_sop() const { - if (parent) - return (parent->Scod & 2) == 2; - else + if (type == COD_MAIN || type == COD_TILE) return (Scod & 2) == 2; + return false; } //////////////////////////////////////// bool packets_use_eph() const { - if (parent) - return (parent->Scod & 4) == 4; - else + if (type == COD_MAIN || type == COD_TILE) return (Scod & 4) == 4; + return false; } + //////////////////////////////////////// + bool get_block_vertical_causality() const + { return (SPcod.block_style & local::param_cod::VERT_CAUSAL_MODE) != 0; } + //////////////////////////////////////// bool write(outfile_base *file); //////////////////////////////////////// - void read(infile_base *file, cod_type type); + bool write_coc(outfile_base *file, ui32 num_comps); //////////////////////////////////////// - void read(infile_base* file, cod_type type, ui32 num_comps, - param_cod* cod); + void read(infile_base *file); + + //////////////////////////////////////// + void read_coc(infile_base* file, ui32 num_comps, param_cod* top_cod); //////////////////////////////////////// void update_atk(const param_atk* atk); //////////////////////////////////////// - void link_cod(const param_cod* coc) - { this->next = coc; } + const param_cod* get_coc(ui32 comp_idx) const; //////////////////////////////////////// - const param_cod* get_coc(ui32 comp_num) const - { - const param_cod* result = this; - if (result->type != COD_MAIN) - result = result->parent; - assert(result->type == COD_MAIN); - - while (result != NULL && result->get_comp_num() != comp_num) - result = result->next; - return result ? result : this; - } + param_cod* get_coc(ui32 comp_idx); + + //////////////////////////////////////// + param_cod* add_coc_object(ui32 comp_idx); //////////////////////////////////////// const param_atk* access_atk() const { return atk; } @@ -593,25 +606,29 @@ namespace ojph { { return SPcod.num_decomp & 0xF; } //////////////////////////////////////// - ui32 get_comp_num() const + ui32 get_comp_idx() const { - assert((type == COC_MAIN && comp_num != OJPH_COD_DEFAULT) || - (type == COD_MAIN && comp_num == OJPH_COD_DEFAULT)); - return comp_num; + assert((type == COC_MAIN && comp_idx != OJPH_COD_DEFAULT) || + (type == COD_MAIN && comp_idx == OJPH_COD_DEFAULT)); + return comp_idx; } + private: + bool internal_write_coc(outfile_base *file, ui32 num_comps); + + //////////////////////////////////////// private: // Common variables cod_type type; // The type of this cod structure ui16 Lcod; // serves as Lcod and Scod ui8 Scod; // serves as Scod and Scoc cod_SGcod SGCod; // Used in COD and copied to COC cod_SPcod SPcod; // serves as SPcod and SPcoc - const param_cod* next;// to chain coc parameters to cod + param_cod* next; // to chain coc parameters to cod const param_atk* atk; // used to read transform information private: // COC only variables - param_cod* parent; // parent COD structure - ui16 comp_num; // component index of this COC structure + param_cod* top_cod; // parent COD structure + ui16 comp_idx; // component index of this COC structure }; /////////////////////////////////////////////////////////////////////////// @@ -637,11 +654,12 @@ namespace ojph { QCC_MAIN = 2, QCD_TILE = 3, // not implemented QCC_TILE = 4 // not implemented - }; + }; + public: - param_qcd() + param_qcd(param_qcd* top_qcd = NULL, ui16 comp_idx = OJPH_QCD_DEFAULT) { - type = QCD_MAIN; + type = top_qcd ? QCC_MAIN : QCD_MAIN; Lqcd = 0; Sqcd = 0; memset(&SPqcd, 0, sizeof(SPqcd)); @@ -649,8 +667,8 @@ namespace ojph { base_delta = -1.0f; enabled = true; next = NULL; - top_qcd = this; - comp_idx = OJPH_QCD_DEFAULT; + this->top_qcd = top_qcd; + this->comp_idx = comp_idx; } ~param_qcd() { if (next) diff --git a/src/core/codestream/ojph_precinct.cpp b/src/core/codestream/ojph_precinct.cpp index 803790d6..b41b0ba8 100644 --- a/src/core/codestream/ojph_precinct.cpp +++ b/src/core/codestream/ojph_precinct.cpp @@ -274,7 +274,7 @@ namespace ojph { ph_bytes += cur_coded_list->buf_size - cur_coded_list->avail_size; } - return coded ? cb_bytes + ph_bytes : 1; + return coded ? cb_bytes + ph_bytes : 1; // 1 for empty packet } ////////////////////////////////////////////////////////////////////////// @@ -336,15 +336,6 @@ namespace ojph { if (may_use_sop) bb_skip_sop(&bb); - if (bands[0].empty && bands[1].empty && bands[2].empty && bands[3].empty) - { - ui32 bit = 0; - bb_read_bit(&bb, bit); - bb_terminate(&bb, uses_eph); - assert(bit == 0); - return; - } - bool empty_packet = true; for (int s = 0; s < 4; ++s) { @@ -508,12 +499,19 @@ namespace ojph { } } } + if (empty_packet) + { // all subbands are empty + ui32 bit = 0; + bb_read_bit(&bb, bit); + //assert(bit == 0); + } bb_terminate(&bb, uses_eph); //read codeblock data for (int s = 0; s < 4; ++s) { if (bands[s].empty) continue; + ui32 band_width = bands[s].num_blocks.w; ui32 width = cb_idxs[s].siz.w; ui32 height = cb_idxs[s].siz.h; diff --git a/src/core/codestream/ojph_resolution.cpp b/src/core/codestream/ojph_resolution.cpp index 343615f8..59a3dfb6 100644 --- a/src/core/codestream/ojph_resolution.cpp +++ b/src/core/codestream/ojph_resolution.cpp @@ -1039,13 +1039,11 @@ namespace ojph { { if (this->res_num == resolution_num) return get_num_bytes(); - else { - if (child_res) - return child_res->get_num_bytes(resolution_num); - else - return 0; + if (resolution_num < this->res_num) { + assert(child_res); + return child_res->get_num_bytes(resolution_num); } - + return 0; } } } \ No newline at end of file diff --git a/src/core/codestream/ojph_subband.cpp b/src/core/codestream/ojph_subband.cpp index 655a2b8b..b712f200 100644 --- a/src/core/codestream/ojph_subband.cpp +++ b/src/core/codestream/ojph_subband.cpp @@ -200,7 +200,7 @@ namespace ojph { cb_size.w = cbx1 - cbx0; blocks[i].finalize_alloc(codestream, this, nominal, cb_size, coded_cbs + i, K_max, line_offset, - precision); + precision, comp_num); line_offset += cb_size.w; } diff --git a/src/core/codestream/ojph_tile.cpp b/src/core/codestream/ojph_tile.cpp index 7ac60444..7e0f9538 100644 --- a/src/core/codestream/ojph_tile.cpp +++ b/src/core/codestream/ojph_tile.cpp @@ -67,20 +67,38 @@ namespace ojph { allocator->pre_alloc_obj(num_comps); //for line_offsets allocator->pre_alloc_obj(num_comps); //for num_bits allocator->pre_alloc_obj(num_comps); //for is_signed - allocator->pre_alloc_obj(num_comps); //for nlt_type3 + allocator->pre_alloc_obj(num_comps); //for reversible + allocator->pre_alloc_obj(num_comps); //for nlt_type3 allocator->pre_alloc_obj(num_comps); //for cur_line - ui32 tilepart_div = codestream->get_tilepart_div(); - num_tileparts = 1; //for num_rc_bytes - // this code is not ideal, since the number of decompositions can be - // different for different components - if (tilepart_div & OJPH_TILEPART_COMPONENTS) - num_tileparts *= num_comps; - if (tilepart_div & OJPH_TILEPART_RESOLUTIONS) - num_tileparts *= codestream->get_cod()->get_num_decompositions() + 1; - if (num_tileparts > 255) - OJPH_ERROR(0x000300D1, "Trying to create %d tileparts; a tile cannot " - "have more than 255 tile parts.", num_tileparts); + { + ui32 tilepart_div = codestream->get_tilepart_div(); + ui32 t = tilepart_div & OJPH_TILEPART_MASK; + if (t == OJPH_TILEPART_NO_DIVISIONS) + num_tileparts = 1; //for num_rc_bytes + else if (t == OJPH_TILEPART_COMPONENTS) + num_tileparts = num_comps; + else if (t == OJPH_TILEPART_RESOLUTIONS) + { + ui32 max_decs = 0; + for (ui32 c = 0; c < num_comps; ++c) { + ui32 s = codestream->get_coc(c)->get_num_decompositions(); + max_decs = ojph_max(max_decs, s); + } + num_tileparts = 1 + max_decs; + } + else if (t == (OJPH_TILEPART_COMPONENTS | OJPH_TILEPART_RESOLUTIONS)) + { + num_tileparts = 0; + for (ui32 c = 0; c < num_comps; ++c) { + ui32 s = codestream->get_coc(c)->get_num_decompositions(); + num_tileparts += s + 1; + } + } + if (num_tileparts > 255) + OJPH_ERROR(0x000300D1, "Trying to create %d tileparts; a tile " + "cannot have more than 255 tile parts.", num_tileparts); + } ui32 tx0 = tile_rect.org.x; ui32 ty0 = tile_rect.org.y; @@ -125,8 +143,22 @@ namespace ojph { const param_cod* cdp = codestream->get_cod(); if (cdp->is_employing_color_transform()) { + bool reversible[3]; + for (ui32 i = 0; i < 3; ++i) + reversible[i] = codestream->get_coc(i)->is_reversible(); + if (reversible[0] != reversible[1] || reversible[1] != reversible[2]) + OJPH_ERROR(0x000300A2, "When the colour transform is employed. " + "all colour components must undergo either reversible or " + "irreversible wavelet transform; if not, then it is not clear " + "what colour transform should be used (reversible or " + "irreversible). Here we found that the first three colour " + "components uses %s, %s, and %s transforms, respectively.", + reversible[0] ? "reversible" : "irreversible", + reversible[1] ? "reversible" : "irreversible", + reversible[2] ? "reversible" : "irreversible"); + allocator->pre_alloc_obj(3); - if (cdp->access_atk()->is_reversible()) + if (reversible[0]) for (int i = 0; i < 3; ++i) allocator->pre_alloc_data(width, 0); else @@ -159,19 +191,41 @@ namespace ojph { line_offsets = allocator->post_alloc_obj(num_comps); num_bits = allocator->post_alloc_obj(num_comps); is_signed = allocator->post_alloc_obj(num_comps); + reversible = allocator->post_alloc_obj(num_comps); nlt_type3 = allocator->post_alloc_obj(num_comps); cur_line = allocator->post_alloc_obj(num_comps); profile = codestream->get_profile(); tilepart_div = codestream->get_tilepart_div(); need_tlm = codestream->is_tlm_needed(); - num_tileparts = 1; - // this code is not ideal, since the number of decompositions can be - // different for different components - if (tilepart_div & OJPH_TILEPART_COMPONENTS) - num_tileparts *= num_comps; - if (tilepart_div & OJPH_TILEPART_RESOLUTIONS) - num_tileparts *= codestream->get_cod()->get_num_decompositions() + 1; + { + ui32 tilepart_div = codestream->get_tilepart_div(); + ui32 t = tilepart_div & OJPH_TILEPART_MASK; + if (t == OJPH_TILEPART_NO_DIVISIONS) + num_tileparts = 1; //for num_rc_bytes + else if (t == OJPH_TILEPART_COMPONENTS) + num_tileparts = num_comps; + else if (t == OJPH_TILEPART_RESOLUTIONS) + { + ui32 max_decs = 0; + for (ui32 c = 0; c < num_comps; ++c) { + ui32 s = codestream->get_coc(c)->get_num_decompositions(); + max_decs = ojph_max(max_decs, s); + } + num_tileparts = 1 + max_decs; + } + else if (t == (OJPH_TILEPART_COMPONENTS | OJPH_TILEPART_RESOLUTIONS)) + { + num_tileparts = 0; + for (ui32 c = 0; c < num_comps; ++c) { + ui32 s = codestream->get_coc(c)->get_num_decompositions(); + num_tileparts += s + 1; + } + } + if (num_tileparts > 255) + OJPH_ERROR(0x000300D1, "Trying to create %d tileparts; a tile " + "cannot have more than 255 tile parts.", num_tileparts); + } this->resilient = codestream->is_resilient(); this->tile_rect = tile_rect; @@ -223,19 +277,19 @@ namespace ojph { "for component %d", i, num_bits[i], is_signed[i] ? "True" : "False", bd, is ? "True" : "False"); cur_line[i] = 0; + reversible[i] = codestream->get_coc(i)->is_reversible(); } offset += tile_rect.siz.w; //allocate lines const param_cod* cdp = codestream->get_cod(); - this->reversible = cdp->access_atk()->is_reversible(); this->employ_color_transform = cdp->is_employing_color_transform(); if (this->employ_color_transform) { num_lines = 3; lines = allocator->post_alloc_obj(num_lines); - if (reversible) + if (reversible[0]) for (int i = 0; i < 3; ++i) lines[i].wrap( allocator->post_alloc_data(width, 0), width, 0); @@ -270,7 +324,7 @@ namespace ojph { assert(comp_num < num_comps); ui32 comp_width = comp_rects[comp_num].siz.w; line_buf *tc = comps[comp_num].get_line(); - if (reversible) + if (reversible[comp_num]) { si64 shift = (si64)1 << (num_bits[comp_num] - 1); if (is_signed[comp_num] && nlt_type3[comp_num] == type3) @@ -297,7 +351,7 @@ namespace ojph { { si64 shift = (si64)1 << (num_bits[comp_num] - 1); ui32 comp_width = comp_rects[comp_num].siz.w; - if (reversible) + if (reversible[comp_num]) { if (is_signed[comp_num] && nlt_type3[comp_num] == type3) rev_convert_nlt_type3(line, line_offsets[comp_num], @@ -361,7 +415,7 @@ namespace ojph { { line_buf *src_line = comps[comp_num].pull_line(); ui32 comp_width = recon_comp_rects[comp_num].siz.w; - if (reversible) + if (reversible[comp_num]) { si64 shift = (si64)1 << (num_bits[comp_num] - 1); if (is_signed[comp_num] && nlt_type3[comp_num] == type3) @@ -391,7 +445,7 @@ namespace ojph { ui32 comp_width = recon_comp_rects[comp_num].siz.w; if (comp_num == 0) { - if (reversible) + if (reversible[comp_num]) rct_backward(comps[0].pull_line(), comps[1].pull_line(), comps[2].pull_line(), lines + 0, lines + 1, lines + 2, comp_width); @@ -400,7 +454,7 @@ namespace ojph { comps[2].pull_line()->f32, lines[0].f32, lines[1].f32, lines[2].f32, comp_width); } - if (reversible) + if (reversible[comp_num]) { si64 shift = (si64)1 << (num_bits[comp_num] - 1); line_buf* src_line; diff --git a/src/core/codestream/ojph_tile.h b/src/core/codestream/ojph_tile.h index 4398ccd3..03143619 100644 --- a/src/core/codestream/ojph_tile.h +++ b/src/core/codestream/ojph_tile.h @@ -81,7 +81,8 @@ namespace ojph { tile_comp *comps; ui32 num_lines; line_buf* lines; - bool reversible, employ_color_transform, resilient; + bool employ_color_transform, resilient; + bool *reversible; rect *comp_rects, *recon_comp_rects; ui32 *line_offsets; ui32 skipped_res_for_read; diff --git a/src/core/codestream/ojph_tile_comp.cpp b/src/core/codestream/ojph_tile_comp.cpp index ee49d8d9..a807769e 100644 --- a/src/core/codestream/ojph_tile_comp.cpp +++ b/src/core/codestream/ojph_tile_comp.cpp @@ -58,7 +58,8 @@ namespace ojph { mem_fixed_allocator* allocator = codestream->get_allocator(); //allocate a resolution - ui32 num_decomps = codestream->access_cod().get_num_decompositions(); + ui32 num_decomps; + num_decomps = codestream->get_coc(comp_num)->get_num_decompositions(); allocator->pre_alloc_obj(1); resolution::pre_alloc(codestream, comp_rect, recon_comp_rect, comp_num, @@ -130,13 +131,12 @@ namespace ojph { ////////////////////////////////////////////////////////////////////////// bool tile_comp::get_top_left_precinct(ui32 res_num, point &top_left) { - assert(res_num <= num_decomps); - res_num = num_decomps - res_num; + int resolution_num = (int)num_decomps - (int)res_num; resolution *r = res; - while (res_num > 0 && r != NULL) + while (resolution_num > 0 && r != NULL) { r = r->next_resolution(); - --res_num; + --resolution_num; } if (r) //resolution does not exist if r is NULL return r->get_top_left_precinct(top_left); @@ -147,13 +147,12 @@ namespace ojph { ////////////////////////////////////////////////////////////////////////// void tile_comp::write_one_precinct(ui32 res_num, outfile_base *file) { - assert(res_num <= num_decomps); - res_num = num_decomps - res_num; + int resolution_num = (int)num_decomps - (int)res_num; resolution *r = res; - while (res_num > 0 && r != NULL) + while (resolution_num > 0 && r != NULL) { r = r->next_resolution(); - --res_num; + --resolution_num; } if (r) //resolution does not exist if r is NULL r->write_one_precinct(file); diff --git a/src/core/common/ojph_params.h b/src/core/common/ojph_params.h index 688f40c4..c55048db 100644 --- a/src/core/common/ojph_params.h +++ b/src/core/common/ojph_params.h @@ -45,10 +45,21 @@ namespace ojph { /***************************************************************************/ - //prototyping from local + // defined here + class param_siz; + class param_cod; + class param_coc; + class param_qcd; + class param_cap; + class param_nlt; + class codestream; + + /***************************************************************************/ + // prototyping from local namespace local { struct param_siz; struct param_cod; + struct param_coc; struct param_qcd; struct param_cap; struct param_nlt; @@ -100,6 +111,7 @@ namespace ojph { void set_progression_order(const char *name); void set_color_transform(bool color_transform); void set_reversible(bool reversible); + param_coc get_coc(ui32 component_idx); ui32 get_num_decompositions() const; size get_block_dims() const; @@ -119,6 +131,29 @@ namespace ojph { local::param_cod* state; }; + /***************************************************************************/ + class OJPH_EXPORT param_coc + { + public: + param_coc(local::param_cod* p) : state(p) {} + + void set_num_decomposition(ui32 num_decompositions); + void set_block_dims(ui32 width, ui32 height); + void set_precinct_size(int num_levels, size* precinct_size); + void set_reversible(bool reversible); + + ui32 get_num_decompositions() const; + size get_block_dims() const; + size get_log_block_dims() const; + bool is_reversible() const; + size get_precinct_size(ui32 level_num) const; + size get_log_precinct_size(ui32 level_num) const; + bool get_block_vertical_causality() const; + + private: + local::param_cod* state; + }; + /***************************************************************************/ /** * @brief Quantization parameters object diff --git a/src/core/common/ojph_version.h b/src/core/common/ojph_version.h index 4a61fc99..9b3feefd 100644 --- a/src/core/common/ojph_version.h +++ b/src/core/common/ojph_version.h @@ -34,5 +34,5 @@ //***************************************************************************/ #define OPENJPH_VERSION_MAJOR 0 -#define OPENJPH_VERSION_MINOR 19 -#define OPENJPH_VERSION_PATCH 1 +#define OPENJPH_VERSION_MINOR 21 +#define OPENJPH_VERSION_PATCH 0 diff --git a/src/core/transform/ojph_colour_sse2.cpp b/src/core/transform/ojph_colour_sse2.cpp index 63401169..b1d0b325 100644 --- a/src/core/transform/ojph_colour_sse2.cpp +++ b/src/core/transform/ojph_colour_sse2.cpp @@ -82,28 +82,6 @@ namespace ojph { _MM_SET_ROUNDING_MODE(rounding_mode); } - ////////////////////////////////////////////////////////////////////////// - // _mm_max_epi32 requires SSE4.1, so here we implement it in SSE2 - static inline - __m128i ojph_mm_max_epi32(__m128i a, __m128i b) - { - __m128i c = _mm_cmpgt_epi32(a, b); // 0xFFFFFFFF for a > b - __m128i d = _mm_and_si128(c, a); // keep only a, where a > b - __m128i e = _mm_andnot_si128(c, b); // keep only b, where a <= b - return _mm_or_si128(d, e); // combine - } - - ////////////////////////////////////////////////////////////////////////// - // _mm_min_epi32 requires SSE4.1, so here we implement it in SSE2 - static inline - __m128i ojph_mm_min_epi32 (__m128i a, __m128i b) - { - __m128i c = _mm_cmplt_epi32(a, b); // 0xFFFFFFFF for a < b - __m128i d = _mm_and_si128(c, a); // keep only a, where a < b - __m128i e = _mm_andnot_si128(c, b); // keep only b, where a >= b - return _mm_or_si128(d, e); // combine - } - ////////////////////////////////////////////////////////////////////////// static inline __m128i ojph_mm_max_ge_epi32(__m128i a, __m128i b, __m128 x, __m128 y) diff --git a/subprojects/js/CMakeLists.txt b/subprojects/js/CMakeLists.txt index b6a8c581..0dba2baf 100644 --- a/subprojects/js/CMakeLists.txt +++ b/subprojects/js/CMakeLists.txt @@ -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) - diff --git a/subprojects/js/build.sh b/subprojects/js/build.sh index dd292ad5..0a2dd4ad 100755 --- a/subprojects/js/build.sh +++ b/subprojects/js/build.sh @@ -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 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 547f1c5f..0116844c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -69,15 +69,9 @@ else() COMMAND ${CMAKE_COMMAND} -E copy "$" "./" ) if(EMSCRIPTEN) - add_custom_command(TARGET test_executables POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy "$" "./" - COMMAND ${CMAKE_COMMAND} -E copy "$" "./" - ) add_custom_command(TARGET test_executables POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy "$/ojph_expand.wasm" "./" COMMAND ${CMAKE_COMMAND} -E copy "$/ojph_compress.wasm" "./" - COMMAND ${CMAKE_COMMAND} -E copy "$/ojph_expand_simd.wasm" "./" - COMMAND ${CMAKE_COMMAND} -E copy "$/ojph_compress_simd.wasm" "./" ) endif(EMSCRIPTEN) if(MSYS)