diff --git a/CMake/Config.cmake.in b/CMake/Config.cmake.in new file mode 100644 index 000000000..e6ef25a83 --- /dev/null +++ b/CMake/Config.cmake.in @@ -0,0 +1,6 @@ +@PACKAGE_INIT@ + +# If there are any PUBLIC upstream dependencies, they should be included here. +# STB and tinyexr are private dependencies and don't need to be included here. + +include("${CMAKE_CURRENT_LIST_DIR}/astcencTargets.cmake") diff --git a/CMake/SIMD.cmake b/CMake/SIMD.cmake new file mode 100644 index 000000000..fae92c785 --- /dev/null +++ b/CMake/SIMD.cmake @@ -0,0 +1,270 @@ + +# On CMake 3.25 or older CXX_COMPILER_FRONTEND_VARIANT is not always set +if(CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "") + set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "${CMAKE_CXX_COMPILER_ID}") +endif() + +# Compiler accepts MSVC-style command line options +set(is_msvc_fe "$") +# Compiler accepts GNU-style command line options +set(is_gnu_fe1 "$") +# Compiler accepts AppleClang-style command line options, which is also GNU-style +set(is_gnu_fe2 "$") +# Compiler accepts GNU-style command line options +set(is_gnu_fe "$") + +# Compiler is Visual Studio cl.exe +set(is_msvccl "$>") +# Compiler is Visual Studio clangcl.exe +set(is_clangcl "$>") +# Compiler is upstream clang with the standard frontend +set(is_clang "$>") + +# All the common compiler options for all targets +add_library(common INTERFACE) +target_compile_definitions(common INTERFACE + $<${is_msvc_fe}:_CRT_SECURE_NO_WARNINGS>) + +if(${ASTCENC_DECOMPRESSOR}) + target_compile_definitions(common INTERFACE + ASTCENC_DECOMPRESS_ONLY) +endif() + +if(${ASTCENC_BLOCK_MAX_TEXELS}) + target_compile_definitions(common INTERFACE + ASTCENC_BLOCK_MAX_TEXELS=${ASTCENC_BLOCK_MAX_TEXELS}) +endif() + +if(${ASTCENC_DIAGNOSTICS}) + target_compile_definitions(common INTERFACE + ASTCENC_DIAGNOSTICS) +endif() + +target_compile_options(common + INTERFACE + # Use pthreads on Linux/macOS + $<$:-pthread> + + # MSVC compiler defines + $<${is_msvc_fe}:/EHsc> + $<${is_msvccl}:/wd4324> + + # G++ and Clang++ compiler defines + $<${is_gnu_fe}:-Wall> + $<${is_gnu_fe}:-Wextra> + $<${is_gnu_fe}:-Wpedantic> + $<${is_gnu_fe}:-Werror> + $<${is_gnu_fe}:-Wshadow> + $<${is_gnu_fe}:-Wdouble-promotion> + $<${is_clang}:-Wdocumentation> + + # Hide noise thrown up by Clang 10 and clang-cl + $<${is_gnu_fe}:-Wno-unknown-warning-option> + $<${is_gnu_fe}:-Wno-c++98-compat-pedantic> + $<${is_gnu_fe}:-Wno-c++98-c++11-compat-pedantic> + $<${is_gnu_fe}:-Wno-float-equal> + $<${is_gnu_fe}:-Wno-deprecated-declarations> + $<${is_gnu_fe}:-Wno-atomic-implicit-seq-cst> + + # Clang 10 also throws up warnings we need to investigate (ours) + $<${is_gnu_fe}:-Wno-cast-align> + $<${is_gnu_fe}:-Wno-sign-conversion> + $<${is_gnu_fe}:-Wno-implicit-int-conversion> + $<${is_gnu_fe}:-Wno-shift-sign-overflow> + $<${is_gnu_fe}:-Wno-format-nonliteral> + $<${is_gnu_fe}:-Wno-reserved-identifier> + $<${is_gnu_fe}:-Wno-cast-function-type> + + # Force DWARF4 for Valgrind profiling + $<$,${is_clang}>:-gdwarf-4> + + # Disable non-portable Windows.h warning (fixing it fails builds on MinGW) + $<$,${is_clang}>:-Wno-nonportable-system-include-path>) + +target_link_options(common INTERFACE + # Use pthreads on Linux/macOS + $<$:-pthread>) + +target_compile_options(common INTERFACE $<${is_msvc_fe}:/W4>) + +if(${ASTCENC_ASAN}) + target_compile_options(common INTERFACE + $<${is_clang}:-fsanitize=address>) + + target_link_options(common INTERFACE + $<${is_clang}:-fsanitize=address>) +endif() + +if(NOT ${ASTCENC_INVARIANCE}) + target_compile_definitions(common INTERFACE + ASTCENC_NO_INVARIANCE=1) + + # For Visual Studio prior to 2022 (compiler < 19.30) /fp:precise + # For Visual Studio 2022 (compiler >= 19.30) /fp:precise and /fp:contract + + # For Visual Studio 2022 ClangCL seems to have accidentally enabled contraction by default, + # so behaves differently to CL.exe. Use the -Xclang argument to workaround and allow access + # GNU-style switch to control contraction on the assumption this gets fixed and disabled. + # Note ClangCL does not accept /fp:contract as an argument as of v15.0.7. + target_compile_options(common INTERFACE + $<${is_msvccl}:/fp:precise> + $<${is_clangcl}:/fp:precise> + $<$,19.30>>:/fp:contract> + $<$,14.0.0>>:-Xclang -ffp-contract=fast> + $<$,10.0.0>>:-ffp-model=precise> + $<${is_gnu_fe}:-ffp-contract=fast>) +else() + # For Visual Studio prior to 2022 (compiler < 19.30) /fp:strict + # For Visual Studio 2022 (compiler >= 19.30) /fp:precise + + # For Visual Studio 2022 ClangCL seems to have accidentally enabled contraction by default, + # so behaves differently to CL.exe. Use the -Xclang argument to workaround and allow access + # GNU-style switch to control contraction and force disable. + target_compile_options(common INTERFACE + $<$,19.30>>:/fp:strict> + $<$,19.30>>:/fp:precise> + $<${is_clangcl}:/fp:precise> + $<$,14.0.0>>:-Xclang -ffp-contract=off> + $<$,10.0.0>>:-ffp-model=precise> + $<${is_gnu_fe}:-ffp-contract=off>) +endif() + + +if(${ASTCENC_CLI}) + # Enable LTO on release builds + set_property(TARGET common + PROPERTY + INTERPROCEDURAL_OPTIMIZATION_RELEASE True) +endif() + +add_library(simd-none INTERFACE) +target_link_libraries(simd-none INTERFACE common) +target_compile_definitions(simd-none INTERFACE + ASTCENC_NEON=0 + ASTCENC_SSE=0 + ASTCENC_AVX=0 + ASTCENC_POPCNT=0 + ASTCENC_F16C=0) + +# Force SSE2 on AppleClang (normally SSE4.1 is the default) +target_compile_options(simd-none INTERFACE + $<${is_gnu_fe}:-mno-sse2> + $<${is_gnu_fe}:-mno-sse4.1> + $<${is_gnu_fe}:-Wno-unused-command-line-argument> +) + + +add_library(simd-neon INTERFACE) +target_link_libraries(simd-neon INTERFACE common) +target_compile_definitions(simd-neon INTERFACE + ASTCENC_NEON=1 + ASTCENC_SSE=0 + ASTCENC_AVX=0 + ASTCENC_POPCNT=0 + ASTCENC_F16C=0) + +# target_compile_options(simd-neon INTERFACE +# $<${is_clang}:-mfpu=neon -mfloat-abi=hard> +# $<${is_gnu_fe}:-Wno-unused-command-line-argument>) + + +# Workaround MSVC codegen bug for NEON builds on VS 2022 17.2 or older +# https://developercommunity.visualstudio.com/t/inlining-turns-constant-into-register-operand-for/1394798 +if (MSVC_VERSION LESS 1933) + target_compile_options(simd-neon INTERFACE + $<${is_msvccl}:/d2ssa-cfg-sink->) +endif() + +# SSE 2.0 compiler options +add_library(simd-sse2 INTERFACE) +target_link_libraries(simd-sse2 INTERFACE common) +target_compile_definitions(simd-sse2 INTERFACE + ASTCENC_NEON=0 + ASTCENC_SSE=20 + ASTCENC_AVX=0 + ASTCENC_POPCNT=0 + ASTCENC_F16C=0) + +# Force SSE2 on AppleClang (normally SSE4.1 is the default) +target_compile_options(simd-sse2 INTERFACE + $<${is_clangcl}:-msse2> + $<${is_gnu_fe}:-msse2> + $<${is_gnu_fe}:-mno-sse4.1> + $<${is_gnu_fe}:-Wno-unused-command-line-argument>) + +# SSE 4.1 compiler options +add_library(simd-sse41 INTERFACE) +target_link_libraries(simd-sse41 INTERFACE common) +target_compile_definitions(simd-sse41 INTERFACE + ASTCENC_NEON=0 + ASTCENC_SSE=41 + ASTCENC_AVX=0 + ASTCENC_POPCNT=1 + ASTCENC_F16C=0) + +target_compile_options(simd-sse41 INTERFACE + $<${is_clangcl}:-msse4.1 -mpopcnt> + $<${is_gnu_fe}:-msse4.1 -mpopcnt> + $<${is_gnu_fe}:-Wno-unused-command-line-argument>) + +# AVX2 compiler options +add_library(simd-avx2 INTERFACE) +target_link_libraries(simd-avx2 INTERFACE common) +target_compile_definitions(simd-avx2 INTERFACE + ASTCENC_NEON=0 + ASTCENC_SSE=41 + ASTCENC_AVX=2 + ASTCENC_POPCNT=1 + ASTCENC_F16C=1) + +target_compile_options(simd-avx2 INTERFACE + $<${is_msvc_fe}:/arch:AVX2> + $<${is_clangcl}:-mavx2 -mpopcnt -mf16c> + $<${is_gnu_fe}:-mavx2 -mpopcnt -mf16c> + $<${is_gnu_fe}:-Wno-unused-command-line-argument>) + + +# Non-invariant builds enable us to loosen the compiler constraints on +# floating point, but this is only worth doing on CPUs with AVX2 because +# this implies we can also enable the FMA instruction set extensions +# which significantly improve performance. Note that this DOES reduce +# image quality by up to 0.2 dB (normally much less), but buys an +# average of 10-15% performance improvement ... +if((NOT ${ASTCENC_INVARIANCE}) AND (NOT ${ASTCENC_IS_VENEER})) + target_compile_options(simd-avx2 INTERFACE + $<${is_gnu_fe}:-mfma>) +endif() + +macro(TARGET_SIMD_OPTIONS_BY_ARCH SIMD_TARGET_NAME ARCH_NAME) + if (${ARCH_NAME} STREQUAL "arm64") + target_link_libraries(${SIMD_TARGET_NAME} PRIVATE simd-neon) + elseif (${ARCH_NAME} STREQUAL "x86_64h") + target_link_libraries(${SIMD_TARGET_NAME} PRIVATE simd-avx2) + elseif(${ARCH_NAME} STREQUAL "x86_64") + target_link_libraries(${SIMD_TARGET_NAME} PRIVATE simd-sse41) + endif() +endmacro() + +macro(TARGET_SIMD_OPTIONS_BY_NAME SIMD_TARGET_NAME SIMD_NAME) + if (${SIMD_NAME} STREQUAL "neon") + target_link_libraries(${SIMD_TARGET_NAME} PRIVATE simd-neon) + elseif (${SIMD_NAME} STREQUAL "avx2") + target_link_libraries(${SIMD_TARGET_NAME} PRIVATE simd-avx2) + elseif(${SIMD_NAME} STREQUAL "sse4.1") + target_link_libraries(${SIMD_TARGET_NAME} PRIVATE simd-sse41) + elseif(${SIMD_NAME} STREQUAL "sse2") + target_link_libraries(${SIMD_TARGET_NAME} PRIVATE simd-sse2) + elseif(${SIMD_NAME} STREQUAL "none") + target_link_libraries(${SIMD_TARGET_NAME} PRIVATE common) + endif() + + + if(${ASTCENC_ISA_SIMD} MATCHES "neon") + set_target_properties(${SIMD_TARGET_NAME} PROPERTIES OSX_ARCHITECTURES arm64) + elseif(${ASTCENC_ISA_SIMD} MATCHES "avx2") + set_target_properties(${SIMD_TARGET_NAME} PROPERTIES OSX_ARCHITECTURES x86_64h) + elseif(NOT ${ASTCENC_ISA_SIMD} MATCHES "none") + set_target_properties(${SIMD_TARGET_NAME} PROPERTIES OSX_ARCHITECTURES x86_64) + endif() + +endmacro() diff --git a/CMakeLists.txt b/CMakeLists.txt index 304471530..d6c4794a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,12 +41,13 @@ option(ASTCENC_ISA_NEON "Enable astcenc builds for NEON SIMD") option(ASTCENC_ISA_NONE "Enable astcenc builds for no SIMD") option(ASTCENC_ISA_NATIVE "Enable astcenc builds for native SIMD") option(ASTCENC_DECOMPRESSOR "Enable astcenc builds for decompression only") -option(ASTCENC_SHAREDLIB "Enable astcenc builds with core library shared objects") +option(ASTCENC_SHAREDLIB "Enable astcenc builds with core library shared objects" ${BUILD_SHARED_LIBS}) option(ASTCENC_DIAGNOSTICS "Enable astcenc builds with diagnostic trace") option(ASTCENC_ASAN "Enable astcenc builds with address sanitizer") option(ASTCENC_UNITTEST "Enable astcenc builds with unit tests") option(ASTCENC_INVARIANCE "Enable astcenc floating point invariance" ON) option(ASTCENC_CLI "Enable build of astcenc command line tools" ON) +option(ASTCENC_LEGACY_NAMING "Use old naming scheme for build artifacts (for compatibility)" ON) # Preflight for some macOS-specific build options if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") @@ -125,12 +126,16 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") printopt("Universal bin " ${ASTCENC_UNIVERSAL_BUILD}) endif() printopt("Invariance " ${ASTCENC_INVARIANCE}) -printopt("Shared libs " ${ASTCENC_SHAREDLIB}) +if (NOT ${ASTCENC_UNIVERSAL_BUILD}) + printopt("Shared libs " ${ASTCENC_SHAREDLIB}) +endif() printopt("Decompressor " ${ASTCENC_DECOMPRESSOR}) printopt("Diagnostics " ${ASTCENC_DIAGNOSTICS}) printopt("ASAN " ${ASTCENC_ASAN}) printopt("Unit tests " ${ASTCENC_UNITTEST}) +include(CMake/SIMD.cmake) + # Subcomponents add_subdirectory(Source) diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 4acbc95b5..00f984619 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -27,70 +27,221 @@ else() set(ASTCENC_CODEC enc) endif() -set(ASTCENC_ARTIFACTS native none neon avx2 sse4.1 sse2) -set(ASTCENC_CONFIGS ${ASTCENC_ISA_NATIVE} ${ASTCENC_ISA_NONE} ${ASTCENC_ISA_NEON} ${ASTCENC_ISA_AVX2} ${ASTCENC_ISA_SSE41} ${ASTCENC_ISA_SSE2}) -list(LENGTH ASTCENC_ARTIFACTS ASTCENC_ARTIFACTS_LEN) -math(EXPR ASTCENC_ARTIFACTS_LEN "${ASTCENC_ARTIFACTS_LEN} - 1") - -foreach(INDEX RANGE ${ASTCENC_ARTIFACTS_LEN}) - list(GET ASTCENC_ARTIFACTS ${INDEX} ASTCENC_ARTIFACT) - list(GET ASTCENC_CONFIGS ${INDEX} ASTCENC_CONFIG) - if(${ASTCENC_CONFIG}) - set(ASTCENC_ISA_SIMD ${ASTCENC_ARTIFACT}) - - if(${ASTCENC_ISA_SIMD} MATCHES "neon") - set(CMAKE_OSX_ARCHITECTURES arm64) - elseif(${ASTCENC_ISA_SIMD} MATCHES "avx2") - set(CMAKE_OSX_ARCHITECTURES x86_64h) - elseif(NOT ${ASTCENC_ISA_SIMD} MATCHES "none") - set(CMAKE_OSX_ARCHITECTURES x86_64) +if (${ASTCENC_ISA_NEON}) + set(ASTCENC_ISA_SIMD "neon") +elseif(${ASTCENC_ISA_AVX2}) + set(ASTCENC_ISA_SIMD "avx2") +elseif(${ASTCENC_ISA_SSE41}) + set(ASTCENC_ISA_SIMD "sse4.1") +elseif(${ASTCENC_ISA_SSE2}) + set(ASTCENC_ISA_SIMD "sse2") +elseif(${ASTCENC_ISA_NONE}) + set(ASTCENC_ISA_SIMD "none") +else() + set(ASTCENC_ISA_SIMD "native") +endif() + +set(ASTCENC_SOURCES + astcenc_averages_and_directions.cpp + astcenc_block_sizes.cpp + astcenc_color_quantize.cpp + astcenc_color_unquantize.cpp + astcenc_compress_symbolic.cpp + astcenc_compute_variance.cpp + astcenc_decompress_symbolic.cpp + astcenc_diagnostic_trace.cpp + astcenc_entry.cpp + astcenc_find_best_partitioning.cpp + astcenc_ideal_endpoints_and_weights.cpp + astcenc_image.cpp + astcenc_integer_sequence.cpp + astcenc_mathlib.cpp + astcenc_mathlib_softfloat.cpp + astcenc_partition_tables.cpp + astcenc_percentile_tables.cpp + astcenc_pick_best_endpoint_format.cpp + astcenc_quantization.cpp + astcenc_symbolic_physical.cpp + astcenc_weight_align.cpp + astcenc_weight_quant_xfer_tables.cpp) + +set(ASTCENC_CLI_SOURCES + astcenccli_entry.cpp + astcenccli_error_metrics.cpp + astcenccli_image.cpp + astcenccli_image_external.cpp + astcenccli_image_load_store.cpp + astcenccli_platform_dependents.cpp + astcenccli_toplevel.cpp + astcenccli_toplevel_help.cpp) + + +string(CONCAT EXTERNAL_CXX_FLAGS + " $<${is_gnu_fe}: -fno-strict-aliasing>" + " $<${is_gnu_fe}: -Wno-unused-parameter>" + " $<${is_gnu_fe}: -Wno-old-style-cast>" + " $<${is_gnu_fe}: -Wno-double-promotion>" + " $<${is_gnu_fe}: -Wno-zero-as-null-pointer-constant>" + " $<${is_gnu_fe}: -Wno-disabled-macro-expansion>" + " $<${is_gnu_fe}: -Wno-reserved-id-macro>" + " $<${is_gnu_fe}: -Wno-extra-semi-stmt>" + " $<${is_gnu_fe}: -Wno-implicit-fallthrough>" + " $<${is_gnu_fe}: -Wno-tautological-type-limit-compare>" + " $<${is_gnu_fe}: -Wno-cast-qual>" + " $<${is_gnu_fe}: -Wno-reserved-identifier>" + " $<${is_clang}: -Wno-missing-prototypes>" + " $<${is_gnu_fe}: -Wno-missing-field-initializers>" + " $<${is_gnu_fe}: -Wno-suggest-override>" + " $<${is_gnu_fe}: -Wno-used-but-marked-unused>" + " $<${is_gnu_fe}: -Wno-noexcept-type>" + " $<${is_gnu_fe}: -Wno-comma>" + " $<${is_gnu_fe}: -Wno-c99-extensions>") + +set_source_files_properties(astcenccli_image_external.cpp + PROPERTIES + COMPILE_FLAGS ${EXTERNAL_CXX_FLAGS}) + +string(TIMESTAMP astcencoder_YEAR "%Y") +configure_file( + astcenccli_version.h.in + astcenccli_version.h + ESCAPE_QUOTES @ONLY) + + +# Install the public interface +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Include/ + DESTINATION include + FILES_MATCHING PATTERN "*.h") + +target_include_directories(common INTERFACE + $ + $) + +# For universal builds, we build a static library, a shared library, and a cli (linked against the shared, so the cli is standalone and can be copied around) +if (${ASTCENC_UNIVERSAL_BUILD}) + message(STATUS "Foo") + # For legacy naming compatibility + set(ASTCENC_TARGET astc${ASTCENC_CODEC}) + + set(ASTCENC_ARCHITECTURES arm64 x86_64h x86_64) + # Create all the arch-specific stargets + foreach(ASTCENC_ARCHITECTURE ${ASTCENC_ARCHITECTURES}) + set(CMAKE_OSX_ARCHITECTURES ${ASTCENC_ARCHITECTURE}) + # shared library + set(TARGET_NAME astcenc-${ASTCENC_ARCHITECTURE}) + add_library(${TARGET_NAME} SHARED ${ASTCENC_SOURCES}) + target_simd_options_by_arch(${TARGET_NAME} ${ASTCENC_ARCHITECTURE}) + target_compile_definitions(${TARGET_NAME} PRIVATE ASTCENC_DYNAMIC_LIBRARY=1) + + # static library (for executable) + set(TARGET_NAME astcenc-static-${ASTCENC_ARCHITECTURE}) + add_library(${TARGET_NAME} STATIC ${ASTCENC_SOURCES}) + target_simd_options_by_arch(${TARGET_NAME} ${ASTCENC_ARCHITECTURE}) + + if(${ASTCENC_CLI}) + set(TARGET_NAME cli-${ASTCENC_ARCHITECTURE}) + add_executable(${TARGET_NAME} ${ASTCENC_CLI_SOURCES}) + target_include_directories(${TARGET_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_compile_options(${TARGET_NAME} PRIVATE $<${is_msvc_fe}:/W3>) + target_simd_options_by_arch(${TARGET_NAME} ${ASTCENC_ARCHITECTURE}) + target_link_libraries(${TARGET_NAME} PUBLIC astcenc-static-${ASTCENC_ARCHITECTURE}) + endif() + endforeach() + + + # Create the output binary using lipo + set(ASTCENC_LIBRARY ${CMAKE_CURRENT_BINARY_DIR}/${ASTCENC_TARGET}-shared.dylib) + add_custom_target(astcenc + ALL + COMMAND lipo -create -output ${ASTCENC_LIBRARY} -arch x86_64 $ -arch x86_64h $ -arch arm64 $ + ) + add_dependencies(astcenc + astcenc-x86_64 + astcenc-x86_64h + astcenc-arm64 + ) + install(PROGRAMS ${ASTCENC_LIBRARY} DESTINATION bin) + + # Handle the CLI + if(${ASTCENC_CLI}) + set(CLI_EXEC ${CMAKE_CURRENT_BINARY_DIR}/${ASTCENC_TARGET}) + add_custom_target(cli ALL + COMMAND lipo -create -output ${CLI_EXEC} -arch x86_64 $ -arch x86_64h $ -arch arm64 $ + ) + add_dependencies(cli + astcenc + cli-x86_64 + cli-x86_64h + cli-arm64 + ) + install(PROGRAMS ${CLI_EXEC} DESTINATION bin) + endif() +else() + # For legacy naming compatibility + set(ASTCENC_TARGET astc${ASTCENC_CODEC}-${ASTCENC_ISA_SIMD}) + add_library(astcenc ${ASTCENC_SOURCES}) + target_include_directories(astcenc PUBLIC + $ + $) + + if (${ASTCENC_LEGACY_NAMING}) + if (${BUILD_SHARED_LIBS}) + set_target_properties(astcenc PROPERTIES OUTPUT_NAME ${ASTCENC_TARGET}-shared) + else() + set_target_properties(astcenc PROPERTIES OUTPUT_NAME ${ASTCENC_TARGET}) + endif() + endif() + target_simd_options_by_name(astcenc ${ASTCENC_ISA_SIMD}) + + if(${ASTCENC_CLI}) + add_executable(cli ${ASTCENC_CLI_SOURCES}) + if (${ASTCENC_LEGACY_NAMING}) + set_target_properties(cli PROPERTIES OUTPUT_NAME ${ASTCENC_TARGET}) + else() + set_target_properties(cli PROPERTIES OUTPUT_NAME astcenc) endif() + target_simd_options_by_name(cli ${ASTCENC_ISA_SIMD}) + target_include_directories(cli PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_link_libraries(cli PUBLIC astcenc) + endif() + + include(CMakePackageConfigHelpers) + + # Create an export type "astcencTargets" detailing the targetable artifacts created + # by this project. + # install(TARGETS + # EXPORT simdTargets) + install(TARGETS astcenc common simd-avx2 simd-neon simd-sse2 simd-sse41 simd-none + EXPORT astcencTargets) - include(cmake_core.cmake) + # Install the export targets as a CMake config file in the share/astcenc folder so + # that they can referenced by downstream projects as `astcenc::astcenc` after a + # successful `find_package` call. + install(EXPORT astcencTargets + NAMESPACE astcenc:: + FILE astcencTargets.cmake + DESTINATION share/astcenc/) + + # Generate the config file that includes the exports. + configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/Config.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/astcencConfig.cmake" + INSTALL_DESTINATION "share/astcenc/" + NO_SET_AND_CHECK_MACRO + NO_CHECK_REQUIRED_COMPONENTS_MACRO) + + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/astcencConfig.cmake + DESTINATION "share/astcenc/") + + if(${ASTCENC_CLI}) + install(TARGETS cli) endif() -endforeach() - -if(${ASTCENC_CLI} AND ${ASTCENC_UNIVERSAL_BUILD}) - add_custom_target( - astc${ASTCENC_CODEC} - ALL - COMMAND - lipo -create -output $/astc${ASTCENC_CODEC} -arch x86_64 $ -arch x86_64h $ -arch arm64 $ - VERBATIM) - - add_dependencies( - astc${ASTCENC_CODEC} - astc${ASTCENC_CODEC}-sse4.1 - astc${ASTCENC_CODEC}-avx2 - astc${ASTCENC_CODEC}-neon) - - install(PROGRAMS $/astc${ASTCENC_CODEC} - DESTINATION bin) endif() -if(${ASTCENC_SHAREDLIB} AND ${ASTCENC_UNIVERSAL_BUILD}) - add_custom_target( - astc${ASTCENC_CODEC}-shared - ALL - COMMAND - lipo -create -output $/libastc${ASTCENC_CODEC}-shared.dylib -arch x86_64 $ -arch x86_64h $ -arch arm64 $ - VERBATIM) - - add_dependencies( - astc${ASTCENC_CODEC}-shared - astc${ASTCENC_CODEC}-sse4.1-shared - astc${ASTCENC_CODEC}-avx2-shared - astc${ASTCENC_CODEC}-neon-shared) - - install(PROGRAMS $/libastc${ASTCENC_CODEC}-shared.dylib - DESTINATION lib) -endif() # - - - - - - - - - - - - - - - - - - # Unit testing if(${ASTCENC_UNITTEST}) set(INSTALL_GTEST OFF CACHE BOOL "" FORCE) - set(CMAKE_OSX_ARCHITECTURES x86_64;arm64) add_subdirectory(GoogleTest) enable_testing() add_subdirectory(UnitTest) diff --git a/Source/astcenc.h b/Source/Include/astcenc.h similarity index 99% rename from Source/astcenc.h rename to Source/Include/astcenc.h index 3d04b4ea5..eb69d0534 100644 --- a/Source/astcenc.h +++ b/Source/Include/astcenc.h @@ -177,7 +177,7 @@ #define ASTCENC_PUBLIC extern "C" __attribute__ ((visibility ("default"))) #endif #else - #define ASTCENC_PUBLIC + #define ASTCENC_PUBLIC extern "C" #endif /* ============================================================================ diff --git a/Source/cmake_core.cmake b/Source/cmake_core.cmake deleted file mode 100644 index 3c85acc1f..000000000 --- a/Source/cmake_core.cmake +++ /dev/null @@ -1,442 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -# ---------------------------------------------------------------------------- -# Copyright 2020-2023 Arm Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy -# of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -set(ASTCENC_TARGET astc${ASTCENC_CODEC}-${ASTCENC_ISA_SIMD}) - -project(${ASTCENC_TARGET}) - -# On CMake 3.25 or older CXX_COMPILER_FRONTEND_VARIANT is not always set -if(CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "") - set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "${CMAKE_CXX_COMPILER_ID}") -endif() - -# Compiler accepts MSVC-style command line options -set(is_msvc_fe "$") -# Compiler accepts GNU-style command line options -set(is_gnu_fe1 "$") -# Compiler accepts AppleClang-style command line options, which is also GNU-style -set(is_gnu_fe2 "$") -# Compiler accepts GNU-style command line options -set(is_gnu_fe "$") - -# Compiler is Visual Studio cl.exe -set(is_msvccl "$>") -# Compiler is Visual Studio clangcl.exe -set(is_clangcl "$>") -# Compiler is upstream clang with the standard frontend -set(is_clang "$>") - -add_library(${ASTCENC_TARGET}-static - STATIC - astcenc_averages_and_directions.cpp - astcenc_block_sizes.cpp - astcenc_color_quantize.cpp - astcenc_color_unquantize.cpp - astcenc_compress_symbolic.cpp - astcenc_compute_variance.cpp - astcenc_decompress_symbolic.cpp - astcenc_diagnostic_trace.cpp - astcenc_entry.cpp - astcenc_find_best_partitioning.cpp - astcenc_ideal_endpoints_and_weights.cpp - astcenc_image.cpp - astcenc_integer_sequence.cpp - astcenc_mathlib.cpp - astcenc_mathlib_softfloat.cpp - astcenc_partition_tables.cpp - astcenc_percentile_tables.cpp - astcenc_pick_best_endpoint_format.cpp - astcenc_quantization.cpp - astcenc_symbolic_physical.cpp - astcenc_weight_align.cpp - astcenc_weight_quant_xfer_tables.cpp) - -target_include_directories(${ASTCENC_TARGET}-static - PUBLIC - $ - $) - -if(${ASTCENC_SHAREDLIB}) - add_library(${ASTCENC_TARGET}-shared - SHARED - astcenc_averages_and_directions.cpp - astcenc_block_sizes.cpp - astcenc_color_quantize.cpp - astcenc_color_unquantize.cpp - astcenc_compress_symbolic.cpp - astcenc_compute_variance.cpp - astcenc_decompress_symbolic.cpp - astcenc_diagnostic_trace.cpp - astcenc_entry.cpp - astcenc_find_best_partitioning.cpp - astcenc_ideal_endpoints_and_weights.cpp - astcenc_image.cpp - astcenc_integer_sequence.cpp - astcenc_mathlib.cpp - astcenc_mathlib_softfloat.cpp - astcenc_partition_tables.cpp - astcenc_percentile_tables.cpp - astcenc_pick_best_endpoint_format.cpp - astcenc_quantization.cpp - astcenc_symbolic_physical.cpp - astcenc_weight_align.cpp - astcenc_weight_quant_xfer_tables.cpp) - - target_include_directories(${ASTCENC_TARGET}-shared - PUBLIC - $ - $) -endif() - -if(${ASTCENC_CLI}) - # Veneer is compiled without any extended ISA so we can safely do - # ISA compatability checks without triggering a SIGILL - add_library(${ASTCENC_TARGET}-veneer - astcenccli_entry.cpp) - - add_executable(${ASTCENC_TARGET} - astcenccli_error_metrics.cpp - astcenccli_image.cpp - astcenccli_image_external.cpp - astcenccli_image_load_store.cpp - astcenccli_platform_dependents.cpp - astcenccli_toplevel.cpp - astcenccli_toplevel_help.cpp) - - target_link_libraries(${ASTCENC_TARGET} - PRIVATE - ${ASTCENC_TARGET}-veneer - ${ASTCENC_TARGET}-static) -endif() - -macro(astcenc_set_properties ASTCENC_TARGET_NAME ASTCENC_IS_VENEER) - - target_compile_features(${ASTCENC_TARGET_NAME} - PRIVATE - cxx_std_14) - - target_compile_definitions(${ASTCENC_TARGET_NAME} - PRIVATE - $<${is_msvc_fe}:_CRT_SECURE_NO_WARNINGS>) - - if(${ASTCENC_DECOMPRESSOR}) - target_compile_definitions(${ASTCENC_TARGET_NAME} - PRIVATE - ASTCENC_DECOMPRESS_ONLY) - endif() - - if(${ASTCENC_BLOCK_MAX_TEXELS}) - target_compile_definitions(${ASTCENC_TARGET_NAME} - PRIVATE - ASTCENC_BLOCK_MAX_TEXELS=${ASTCENC_BLOCK_MAX_TEXELS}) - endif() - - if(${ASTCENC_DIAGNOSTICS}) - target_compile_definitions(${ASTCENC_TARGET_NAME} - PUBLIC - ASTCENC_DIAGNOSTICS) - endif() - - target_compile_options(${ASTCENC_TARGET_NAME} - PRIVATE - # Use pthreads on Linux/macOS - $<$:-pthread> - - # MSVC compiler defines - $<${is_msvc_fe}:/EHsc> - $<${is_msvccl}:/wd4324> - - # G++ and Clang++ compiler defines - $<${is_gnu_fe}:-Wall> - $<${is_gnu_fe}:-Wextra> - $<${is_gnu_fe}:-Wpedantic> - $<${is_gnu_fe}:-Werror> - $<${is_gnu_fe}:-Wshadow> - $<${is_gnu_fe}:-Wdouble-promotion> - $<${is_clang}:-Wdocumentation> - - # Hide noise thrown up by Clang 10 and clang-cl - $<${is_gnu_fe}:-Wno-unknown-warning-option> - $<${is_gnu_fe}:-Wno-c++98-compat-pedantic> - $<${is_gnu_fe}:-Wno-c++98-c++11-compat-pedantic> - $<${is_gnu_fe}:-Wno-float-equal> - $<${is_gnu_fe}:-Wno-deprecated-declarations> - $<${is_gnu_fe}:-Wno-atomic-implicit-seq-cst> - - # Clang 10 also throws up warnings we need to investigate (ours) - $<${is_gnu_fe}:-Wno-cast-align> - $<${is_gnu_fe}:-Wno-sign-conversion> - $<${is_gnu_fe}:-Wno-implicit-int-conversion> - $<${is_gnu_fe}:-Wno-shift-sign-overflow> - $<${is_gnu_fe}:-Wno-format-nonliteral> - $<${is_gnu_fe}:-Wno-reserved-identifier> - $<${is_gnu_fe}:-Wno-cast-function-type> - - # Force DWARF4 for Valgrind profiling - $<$,${is_clang}>:-gdwarf-4> - - # Disable non-portable Windows.h warning (fixing it fails builds on MinGW) - $<$,${is_clang}>:-Wno-nonportable-system-include-path>) - - target_link_options(${ASTCENC_TARGET_NAME} - PRIVATE - # Use pthreads on Linux/macOS - $<$:-pthread>) - - if(${ASTCENC_ASAN}) - target_compile_options(${ASTCENC_TARGET_NAME} - PRIVATE - $<${is_clang}:-fsanitize=address>) - - target_link_options(${ASTCENC_TARGET_NAME} - PRIVATE - $<${is_clang}:-fsanitize=address>) - endif() - - if(NOT ${ASTCENC_INVARIANCE}) - target_compile_definitions(${ASTCENC_TARGET_NAME} - PRIVATE - ASTCENC_NO_INVARIANCE=1) - - # For Visual Studio prior to 2022 (compiler < 19.30) /fp:precise - # For Visual Studio 2022 (compiler >= 19.30) /fp:precise and /fp:contract - - # For Visual Studio 2022 ClangCL seems to have accidentally enabled contraction by default, - # so behaves differently to CL.exe. Use the -Xclang argument to workaround and allow access - # GNU-style switch to control contraction on the assumption this gets fixed and disabled. - # Note ClangCL does not accept /fp:contract as an argument as of v15.0.7. - target_compile_options(${ASTCENC_TARGET_NAME} - PRIVATE - $<${is_msvccl}:/fp:precise> - $<${is_clangcl}:/fp:precise> - $<$,19.30>>:/fp:contract> - $<$,14.0.0>>:-Xclang -ffp-contract=fast> - $<$,10.0.0>>:-ffp-model=precise> - $<${is_gnu_fe}:-ffp-contract=fast>) - else() - # For Visual Studio prior to 2022 (compiler < 19.30) /fp:strict - # For Visual Studio 2022 (compiler >= 19.30) /fp:precise - - # For Visual Studio 2022 ClangCL seems to have accidentally enabled contraction by default, - # so behaves differently to CL.exe. Use the -Xclang argument to workaround and allow access - # GNU-style switch to control contraction and force disable. - target_compile_options(${ASTCENC_TARGET_NAME} - PRIVATE - $<$,19.30>>:/fp:strict> - $<$,19.30>>:/fp:precise> - $<${is_clangcl}:/fp:precise> - $<$,14.0.0>>:-Xclang -ffp-contract=off> - $<$,10.0.0>>:-ffp-model=precise> - $<${is_gnu_fe}:-ffp-contract=off>) - endif() - - if(${ASTCENC_CLI}) - # Enable LTO on release builds - set_property(TARGET ${ASTCENC_TARGET_NAME} - PROPERTY - INTERPROCEDURAL_OPTIMIZATION_RELEASE True) - - # Use a static runtime on MSVC builds (ignored on non-MSVC compilers) - set_property(TARGET ${ASTCENC_TARGET_NAME} - PROPERTY - MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") - endif() - - # Set up configuration for SIMD ISA builds - if(${ASTCENC_ISA_SIMD} MATCHES "none") - target_compile_definitions(${ASTCENC_TARGET_NAME} - PRIVATE - ASTCENC_NEON=0 - ASTCENC_SSE=0 - ASTCENC_AVX=0 - ASTCENC_POPCNT=0 - ASTCENC_F16C=0) - - elseif(${ASTCENC_ISA_SIMD} MATCHES "neon") - target_compile_definitions(${ASTCENC_TARGET_NAME} - PRIVATE - ASTCENC_NEON=1 - ASTCENC_SSE=0 - ASTCENC_AVX=0 - ASTCENC_POPCNT=0 - ASTCENC_F16C=0) - - # Workaround MSVC codegen bug for NEON builds on VS 2022 17.2 or older - # https://developercommunity.visualstudio.com/t/inlining-turns-constant-into-register-operand-for/1394798 - if((CMAKE_CXX_COMPILER_ID MATCHES "MSVC") AND (MSVC_VERSION LESS 1933)) - target_compile_options(${ASTCENC_TARGET_NAME} - PRIVATE - $<${is_msvccl}:/d2ssa-cfg-sink->) - endif() - - elseif(${ASTCENC_ISA_SIMD} MATCHES "sse2") - target_compile_definitions(${ASTCENC_TARGET_NAME} - PRIVATE - ASTCENC_NEON=0 - ASTCENC_SSE=20 - ASTCENC_AVX=0 - ASTCENC_POPCNT=0 - ASTCENC_F16C=0) - - # Force SSE2 on AppleClang (normally SSE4.1 is the default) - target_compile_options(${ASTCENC_TARGET_NAME} - PRIVATE - $<${is_clangcl}:-msse2> - $<${is_gnu_fe}:-msse2> - $<${is_gnu_fe}:-mno-sse4.1> - $<${is_gnu_fe}:-Wno-unused-command-line-argument>) - - elseif(${ASTCENC_ISA_SIMD} MATCHES "sse4.1") - target_compile_definitions(${ASTCENC_TARGET_NAME} - PRIVATE - ASTCENC_NEON=0 - ASTCENC_SSE=41 - ASTCENC_AVX=0 - ASTCENC_POPCNT=1 - ASTCENC_F16C=0) - - if (${ASTCENC_IS_VENEER}) - # Force SSE2 on AppleClang (normally SSE4.1 is the default) - target_compile_options(${ASTCENC_TARGET_NAME} - PRIVATE - $<${is_gnu_fe}:-msse2> - $<${is_gnu_fe}:-mno-sse4.1> - $<${is_gnu_fe}:-Wno-unused-command-line-argument>) - else() - target_compile_options(${ASTCENC_TARGET_NAME} - PRIVATE - $<${is_clangcl}:-msse4.1 -mpopcnt> - $<${is_gnu_fe}:-msse4.1 -mpopcnt> - $<${is_gnu_fe}:-Wno-unused-command-line-argument>) - endif() - - elseif(${ASTCENC_ISA_SIMD} MATCHES "avx2") - target_compile_definitions(${ASTCENC_TARGET_NAME} - PRIVATE - ASTCENC_NEON=0 - ASTCENC_SSE=41 - ASTCENC_AVX=2 - ASTCENC_POPCNT=1 - ASTCENC_F16C=1) - - if (${ASTCENC_IS_VENEER}) - # Force SSE2 on AppleClang (normally SSE4.1 is the default) - target_compile_options(${ASTCENC_TARGET_NAME} - PRIVATE - $<${is_gnu_fe}:-msse2> - $<${is_gnu_fe}:-mno-sse4.1> - $<${is_gnu_fe}:-Wno-unused-command-line-argument>) - else() - target_compile_options(${ASTCENC_TARGET_NAME} - PRIVATE - $<${is_msvc_fe}:/arch:AVX2> - $<${is_clangcl}:-mavx2 -mpopcnt -mf16c> - $<${is_gnu_fe}:-mavx2 -mpopcnt -mf16c> - $<${is_gnu_fe}:-Wno-unused-command-line-argument>) - endif() - - # Non-invariant builds enable us to loosen the compiler constraints on - # floating point, but this is only worth doing on CPUs with AVX2 because - # this implies we can also enable the FMA instruction set extensions - # which significantly improve performance. Note that this DOES reduce - # image quality by up to 0.2 dB (normally much less), but buys an - # average of 10-15% performance improvement ... - if((NOT ${ASTCENC_INVARIANCE}) AND (NOT ${ASTCENC_IS_VENEER})) - target_compile_options(${ASTCENC_TARGET_NAME} - PRIVATE - $<${is_gnu_fe}:-mfma>) - endif() - - endif() - -endmacro() - -string(CONCAT EXTERNAL_CXX_FLAGS - " $<${is_gnu_fe}: -fno-strict-aliasing>" - " $<${is_gnu_fe}: -Wno-unused-parameter>" - " $<${is_gnu_fe}: -Wno-old-style-cast>" - " $<${is_gnu_fe}: -Wno-double-promotion>" - " $<${is_gnu_fe}: -Wno-zero-as-null-pointer-constant>" - " $<${is_gnu_fe}: -Wno-disabled-macro-expansion>" - " $<${is_gnu_fe}: -Wno-reserved-id-macro>" - " $<${is_gnu_fe}: -Wno-extra-semi-stmt>" - " $<${is_gnu_fe}: -Wno-implicit-fallthrough>" - " $<${is_gnu_fe}: -Wno-tautological-type-limit-compare>" - " $<${is_gnu_fe}: -Wno-cast-qual>" - " $<${is_gnu_fe}: -Wno-reserved-identifier>" - " $<${is_clang}: -Wno-missing-prototypes>" - " $<${is_gnu_fe}: -Wno-missing-field-initializers>" - " $<${is_gnu_fe}: -Wno-suggest-override>" - " $<${is_gnu_fe}: -Wno-used-but-marked-unused>" - " $<${is_gnu_fe}: -Wno-noexcept-type>" - " $<${is_gnu_fe}: -Wno-comma>" - " $<${is_gnu_fe}: -Wno-c99-extensions>") - -set_source_files_properties(astcenccli_image_external.cpp - PROPERTIES - COMPILE_FLAGS ${EXTERNAL_CXX_FLAGS}) - -astcenc_set_properties(${ASTCENC_TARGET}-static OFF) - -target_compile_options(${ASTCENC_TARGET}-static - PRIVATE - $<${is_msvc_fe}:/W4>) - -if(${ASTCENC_SHAREDLIB}) - astcenc_set_properties(${ASTCENC_TARGET}-shared OFF) - - target_compile_definitions(${ASTCENC_TARGET}-shared - PRIVATE - ASTCENC_DYNAMIC_LIBRARY=1) - - target_compile_options(${ASTCENC_TARGET}-shared - PRIVATE - $<${is_gnu_fe}:-fvisibility=hidden> - $<${is_msvc_fe}:/W4>) - - if(NOT ${ASTCENC_UNIVERSAL_BUILD}) - install(TARGETS ${ASTCENC_TARGET}-shared) - endif() -endif() - -if(${ASTCENC_CLI}) - astcenc_set_properties(${ASTCENC_TARGET}-veneer ON) - astcenc_set_properties(${ASTCENC_TARGET} OFF) - - target_compile_options(${ASTCENC_TARGET} - PRIVATE - $<${is_msvc_fe}:/W3>) - - target_compile_options(${ASTCENC_TARGET}-veneer - PRIVATE - $<${is_msvc_fe}:/W3>) - - string(TIMESTAMP astcencoder_YEAR "%Y") - - configure_file( - astcenccli_version.h.in - astcenccli_version.h - ESCAPE_QUOTES @ONLY) - - target_include_directories(${ASTCENC_TARGET} - PRIVATE - ${CMAKE_CURRENT_BINARY_DIR}) - - if(NOT ${ASTCENC_UNIVERSAL_BUILD}) - install(TARGETS ${ASTCENC_TARGET}) - endif() -endif()