diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..708d57d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build_linux_*/** +lib/** diff --git a/blender-build/build_environment/CMakeLists.txt b/blender-build/build_environment/CMakeLists.txt new file mode 100644 index 0000000..8ad1d86 --- /dev/null +++ b/blender-build/build_environment/CMakeLists.txt @@ -0,0 +1,192 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +################################################################################################## +# +# This is a build system used by platform maintainers to build library dependencies on +# Windows, macOS and Linux. +# +# For users building Blender, we recommend using the precompiled libraries from lib/ on +# Windows and macOS, and install_deps.sh on Linux. +# +# WINDOWS USAGE: +# Don't call this cmake file yourself, use build_deps.cmd +# build_deps 2013 x64 / build_deps 2013 x86 +# build_deps 2015 x64 / build_deps 2015 x86 +# +# MAC OS X USAGE: +# Install with homebrew: brew install autoconf automake bison cmake libtool pkg-config yasm +# Additional requirements for macOS arm64: brew install flex +# Run "make deps" from main Blender directory +# +# LINUX USAGE: +# Install compiler cmake autoconf automake libtool yasm tcl +# Run "make deps" from main Blender directory +# +################################################################################################## + +project("BlenderDependencies") +cmake_minimum_required(VERSION 3.5) +if(POLICY CMP0135) + cmake_policy(SET CMP0135 NEW) # CMake 3.24+ Set the date/time for extracted files to time of extraction +endif() +include(ExternalProject) +include(cmake/check_software.cmake) +include(cmake/options.cmake) +# `versions.cmake` needs to be included after `options.cmake` +# due to the `BLENDER_PLATFORM_ARM` variable being needed. +include(cmake/versions.cmake) +include(cmake/boost_build_options.cmake) +include(cmake/download.cmake) +include(cmake/macros.cmake) + +if(ENABLE_MINGW64) + include(cmake/setup_mingw64.cmake) +else() + set(mingw_LIBDIR ${LIBDIR}) +endif() +include(cmake/ssl.cmake) +include(cmake/zlib.cmake) +include(cmake/zstd.cmake) +include(cmake/openal.cmake) +include(cmake/png.cmake) +include(cmake/jpeg.cmake) +include(cmake/blosc.cmake) +include(cmake/pthreads.cmake) +include(cmake/imath.cmake) +include(cmake/openexr.cmake) +include(cmake/brotli.cmake) +include(cmake/freetype.cmake) +include(cmake/epoxy.cmake) +include(cmake/freeglut.cmake) +include(cmake/alembic.cmake) +include(cmake/opensubdiv.cmake) +include(cmake/sdl.cmake) +include(cmake/opencollada.cmake) +if(APPLE) + include(cmake/openmp.cmake) +endif() +if(UNIX) + include(cmake/nasm.cmake) +endif() +include(cmake/tiff.cmake) +if(WIN32) + include(cmake/flexbison.cmake) +elseif(UNIX AND NOT APPLE) + include(cmake/flex.cmake) +endif() +include(cmake/tbb.cmake) +include(cmake/python.cmake) +include(cmake/llvm.cmake) +include(cmake/osl.cmake) +include(cmake/numpy.cmake) +include(cmake/python_site_packages.cmake) +include(cmake/package_python.cmake) +include(cmake/openimageio.cmake) +include(cmake/usd.cmake) +include(cmake/materialx.cmake) +include(cmake/openvdb.cmake) +include(cmake/potrace.cmake) +include(cmake/haru.cmake) +# Boost needs to be included after `python.cmake` due to the PYTHON_BINARY variable being needed. +include(cmake/boost.cmake) +include(cmake/pugixml.cmake) +include(cmake/fribidi.cmake) +include(cmake/harfbuzz.cmake) +if(NOT APPLE) + include(cmake/xr_openxr.cmake) + if (NOT BLENDER_PLATFORM_ARM) + include(cmake/dpcpp.cmake) + include(cmake/dpcpp_deps.cmake) + endif() + if(NOT WIN32) + if (NOT BLENDER_PLATFORM_ARM) + include(cmake/igc.cmake) + endif() + include(cmake/gmmlib.cmake) + if (NOT BLENDER_PLATFORM_ARM) + include(cmake/ocloc.cmake) + endif() + endif() +endif() +if (NOT BLENDER_PLATFORM_ARM) + include(cmake/ispc.cmake) + include(cmake/openimagedenoise.cmake) +# Embree needs to be included after dpcpp as it uses it for compiling with GPU support + include(cmake/embree.cmake) +endif() +if (NOT BLENDER_PLATFORM_ARM) +include(cmake/openpgl.cmake) +endif() +include(cmake/fmt.cmake) +include(cmake/robinmap.cmake) +include(cmake/xml2.cmake) + +# OpenColorIO and dependencies. +include(cmake/expat.cmake) +include(cmake/pystring.cmake) +include(cmake/yamlcpp.cmake) +include(cmake/minizipng.cmake) +include(cmake/opencolorio.cmake) + +if(BLENDER_PLATFORM_ARM) + include(cmake/sse2neon.cmake) +endif() + +include(cmake/webp.cmake) +if(NOT APPLE) + include(cmake/level-zero.cmake) +endif() + +if(NOT WIN32 OR ENABLE_MINGW64) + include(cmake/gmp.cmake) + include(cmake/openjpeg.cmake) + if(NOT WIN32 OR BUILD_MODE STREQUAL Release) + if(WIN32) + include(cmake/zlib_mingw.cmake) + endif() + include(cmake/lame.cmake) + include(cmake/ogg.cmake) + include(cmake/vorbis.cmake) + include(cmake/theora.cmake) + include(cmake/opus.cmake) + include(cmake/vpx.cmake) + include(cmake/x264.cmake) + include(cmake/xvidcore.cmake) + include(cmake/aom.cmake) + include(cmake/ffmpeg.cmake) + include(cmake/fftw.cmake) + include(cmake/sndfile.cmake) + if(WIN32) + include(cmake/iconv.cmake) + endif() + if(UNIX) + include(cmake/flac.cmake) + if(NOT APPLE) + include(cmake/spnav.cmake) + include(cmake/jemalloc.cmake) + endif() + endif() + endif() +endif() + +if(UNIX) + include(cmake/bzip2.cmake) + include(cmake/ffi.cmake) + include(cmake/lzma.cmake) + include(cmake/sqlite.cmake) +endif() + +if(UNIX AND NOT APPLE) + include(cmake/libglu.cmake) + include(cmake/mesa.cmake) + include(cmake/wayland_protocols.cmake) + # Can be removed when the build-bot upgrades to v1.20.x or newer. + include(cmake/wayland.cmake) + include(cmake/wayland_libdecor.cmake) +endif() +include(cmake/shaderc_deps.cmake) +include(cmake/shaderc.cmake) +include(cmake/vulkan.cmake) +include(cmake/pybind11.cmake) +include(cmake/harvest.cmake) +include(cmake/cve_check.cmake) diff --git a/blender-build/build_environment/cmake/alembic.cmake b/blender-build/build_environment/cmake/alembic.cmake new file mode 100644 index 0000000..7d253ff --- /dev/null +++ b/blender-build/build_environment/cmake/alembic.cmake @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(ALEMBIC_EXTRA_ARGS + -DImath_ROOT=${LIBDIR}/imath + -DUSE_PYALEMBIC=OFF + -DUSE_ARNOLD=OFF + -DUSE_MAYA=OFF + -DUSE_PRMAN=OFF + -DUSE_HDF5=OFF + -DUSE_TESTS=OFF + -DUSE_BINARIES=ON + -DALEMBIC_ILMBASE_LINK_STATIC=OFF + -DALEMBIC_SHARED_LIBS=OFF +) + +ExternalProject_Add(external_alembic + URL file://${PACKAGE_DIR}/${ALEMBIC_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${ALEMBIC_HASH_TYPE}=${ALEMBIC_HASH} + CMAKE_GENERATOR ${PLATFORM_ALT_GENERATOR} + PREFIX ${BUILD_DIR}/alembic + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/alembic -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${ALEMBIC_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/alembic +) + +if(WIN32) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_alembic after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/alembic ${HARVEST_TARGET}/alembic + DEPENDEES install + ) + endif() + if(BUILD_MODE STREQUAL Debug) + ExternalProject_Add_Step(external_alembic after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/alembic/lib/alembic.lib ${HARVEST_TARGET}/alembic/lib/alembic_d.lib + DEPENDEES install + ) + endif() +endif() + + + +add_dependencies( + external_alembic + external_imath +) diff --git a/blender-build/build_environment/cmake/aom.cmake b/blender-build/build_environment/cmake/aom.cmake new file mode 100644 index 0000000..11c81c3 --- /dev/null +++ b/blender-build/build_environment/cmake/aom.cmake @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(WIN32) + # The default generator on windows is msbuild, which we do not + # want to use for this dep, as needs to build with mingw + set(AOM_GENERATOR "Ninja") + # The default flags are full of MSVC options given this will be + # building with mingw, it'll have an unhappy time with that and + # we need to clear them out. + set(AOM_CMAKE_FLAGS ) +else() + set(AOM_GENERATOR "Unix Makefiles") + set(AOM_CMAKE_FLAGS ${DEFAULT_CMAKE_FLAGS}) +endif() + +set(AOM_EXTRA_ARGS + -DENABLE_TESTDATA=OFF + -DENABLE_TESTS=OFF + -DENABLE_TOOLS=OFF + -DENABLE_EXAMPLES=OFF + ${AOM_EXTRA_ARGS_WIN32} +) + +# This is slightly different from all other deps in the way that +# aom uses cmake as a build system, but still needs the environment setup +# to include perl so we manually setup the environment and call +# cmake directly for the configure, build and install commands. + +ExternalProject_Add(external_aom + URL file://${PACKAGE_DIR}/${AOM_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${AOM_HASH_TYPE}=${AOM_HASH} + PREFIX ${BUILD_DIR}/aom + PATCH_COMMAND ${PATCH_CMD} --verbose -p 1 -N -d ${BUILD_DIR}/aom/src/external_aom < ${PATCH_DIR}/aom.diff + CONFIGURE_COMMAND ${CONFIGURE_ENV} && + cd ${BUILD_DIR}/aom/src/external_aom-build/ && + ${CMAKE_COMMAND} -G "${AOM_GENERATOR}" -DCMAKE_INSTALL_PREFIX=${LIBDIR}/aom ${AOM_CMAKE_FLAGS} ${AOM_EXTRA_ARGS} ${BUILD_DIR}/aom/src/external_aom/ + BUILD_COMMAND ${CMAKE_COMMAND} --build . + INSTALL_COMMAND ${CMAKE_COMMAND} --build . --target install + INSTALL_DIR ${LIBDIR}/aom +) diff --git a/blender-build/build_environment/cmake/blosc.cmake b/blender-build/build_environment/cmake/blosc.cmake new file mode 100644 index 0000000..7236880 --- /dev/null +++ b/blender-build/build_environment/cmake/blosc.cmake @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(BLOSC_EXTRA_ARGS + -DZLIB_INCLUDE_DIR=${LIBDIR}/zlib/include/ + -DZLIB_LIBRARY=${LIBDIR}/zlib/lib/${ZLIB_LIBRARY} + -DBUILD_TESTS=OFF + -DBUILD_BENCHMARKS=OFF + -DCMAKE_DEBUG_POSTFIX=_d + -DThreads_FOUND=1 + -DPTHREAD_LIBS=${LIBDIR}/pthreads/lib/pthreadVC3.lib + -DPTHREAD_INCLUDE_DIR=${LIBDIR}/pthreads/inc + -DDEACTIVATE_SNAPPY=ON + -DCMAKE_POSITION_INDEPENDENT_CODE=ON +) + +# Prevent blosc from including its own local copy of zlib in the object file +# and cause linker errors with everybody else. +set(BLOSC_EXTRA_ARGS ${BLOSC_EXTRA_ARGS} + -DPREFER_EXTERNAL_ZLIB=ON +) + +ExternalProject_Add(external_blosc + URL file://${PACKAGE_DIR}/${BLOSC_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${BLOSC_HASH_TYPE}=${BLOSC_HASH} + PREFIX ${BUILD_DIR}/blosc + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/blosc ${DEFAULT_CMAKE_FLAGS} ${BLOSC_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/blosc +) + +add_dependencies( + external_blosc + external_zlib +) +if(WIN32) + add_dependencies( + external_blosc + external_pthreads + ) +endif() diff --git a/blender-build/build_environment/cmake/boost.cmake b/blender-build/build_environment/cmake/boost.cmake new file mode 100644 index 0000000..0daf38f --- /dev/null +++ b/blender-build/build_environment/cmake/boost.cmake @@ -0,0 +1,84 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(WIN32) + set(BOOST_CONFIGURE_COMMAND bootstrap.bat) + set(BOOST_BUILD_COMMAND b2) + set(BOOST_BUILD_OPTIONS runtime-link=shared) + if(BUILD_MODE STREQUAL Debug) + list(APPEND BOOST_BUILD_OPTIONS python-debugging=on variant=debug) + if(WITH_OPTIMIZED_DEBUG) + list(APPEND BOOST_BUILD_OPTIONS debug-symbols=off) + else() + list(APPEND BOOST_BUILD_OPTIONS debug-symbols=on) + endif() + else() + list(APPEND BOOST_BUILD_OPTIONS variant=release) + endif() + set(BOOST_HARVEST_CMD ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/boost/lib/ ${HARVEST_TARGET}/boost/lib/) + if(BUILD_MODE STREQUAL Release) + set(BOOST_HARVEST_CMD ${BOOST_HARVEST_CMD} && ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/boost/include/boost-${BOOST_VERSION_NODOTS_SHORT}/ ${HARVEST_TARGET}/boost/include/) + endif() +elseif(APPLE) + set(BOOST_CONFIGURE_COMMAND ./bootstrap.sh) + set(BOOST_BUILD_COMMAND ./b2) + set(BOOST_BUILD_OPTIONS toolset=clang-darwin cxxflags=${PLATFORM_CXXFLAGS} linkflags=${PLATFORM_LDFLAGS} visibility=global --disable-icu boost.locale.icu=off) + set(BOOST_HARVEST_CMD echo .) +else() + set(BOOST_HARVEST_CMD echo .) + set(BOOST_CONFIGURE_COMMAND ./bootstrap.sh) + set(BOOST_BUILD_COMMAND ./b2) + set(BOOST_BUILD_OPTIONS cxxflags=${PLATFORM_CXXFLAGS} --disable-icu boost.locale.icu=off) +endif() + +set(JAM_FILE ${BUILD_DIR}/boost.user-config.jam) +configure_file(${PATCH_DIR}/boost.user.jam.in ${JAM_FILE}) +set(BOOST_PYTHON_OPTIONS + --with-python + --user-config=${JAM_FILE} +) +if(WIN32 AND BUILD_MODE STREQUAL Debug) + set(BOOST_PYTHON_OPTIONS + ${BOOST_PYTHON_OPTIONS} + define=BOOST_DEBUG_PYTHON + ) +endif() + +set(BOOST_OPTIONS + --with-filesystem + --with-locale + --with-thread + --with-regex + --with-system + --with-date_time + --with-wave + --with-atomic + --with-serialization + --with-program_options + --with-iostreams + -sNO_BZIP2=1 + -sNO_LZMA=1 + -sNO_ZSTD=1 + ${BOOST_TOOLSET} + ${BOOST_PYTHON_OPTIONS} +) + +string(TOLOWER ${BUILD_MODE} BOOST_BUILD_TYPE) + +ExternalProject_Add(external_boost + URL file://${PACKAGE_DIR}/${BOOST_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${BOOST_HASH_TYPE}=${BOOST_HASH} + PREFIX ${BUILD_DIR}/boost + UPDATE_COMMAND "" + PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/boost/src/external_boost < ${PATCH_DIR}/boost.diff + CONFIGURE_COMMAND ${BOOST_CONFIGURE_COMMAND} + BUILD_COMMAND ${BOOST_BUILD_COMMAND} ${BOOST_BUILD_OPTIONS} -j${MAKE_THREADS} architecture=${BOOST_ARCHITECTURE} address-model=${BOOST_ADDRESS_MODEL} link=shared threading=multi ${BOOST_OPTIONS} --prefix=${LIBDIR}/boost install + BUILD_IN_SOURCE 1 + INSTALL_COMMAND "${BOOST_HARVEST_CMD}" +) + +add_dependencies( + external_boost + external_python + external_numpy +) diff --git a/blender-build/build_environment/cmake/boost_build_options.cmake b/blender-build/build_environment/cmake/boost_build_options.cmake new file mode 100644 index 0000000..0965347 --- /dev/null +++ b/blender-build/build_environment/cmake/boost_build_options.cmake @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(BOOST_ADDRESS_MODEL 64) +if(BLENDER_PLATFORM_ARM) + set(BOOST_ARCHITECTURE arm) +else() + set(BOOST_ARCHITECTURE x86) +endif() + +if(WIN32) + if(MSVC_VERSION GREATER_EQUAL 1920) # 2019 + set(BOOST_TOOLSET toolset=msvc-14.2) + set(BOOST_COMPILER_STRING -vc142) + else() # 2017 + set(BOOST_TOOLSET toolset=msvc-14.1) + set(BOOST_COMPILER_STRING -vc141) + endif() +endif() + +set(DEFAULT_BOOST_FLAGS + -DBoost_COMPILER:STRING=${BOOST_COMPILER_STRING} + -DBoost_USE_MULTITHREADED=ON + -DBoost_USE_STATIC_LIBS=OFF + -DBoost_USE_STATIC_RUNTIME=OFF + -DBOOST_ROOT=${LIBDIR}/boost + -DBoost_NO_SYSTEM_PATHS=ON + -DBoost_NO_BOOST_CMAKE=ON + -DBoost_ADDITIONAL_VERSIONS=${BOOST_VERSION_SHORT} + -DBOOST_LIBRARYDIR=${LIBDIR}/boost/lib/ + -DBoost_USE_DEBUG_PYTHON=On +) diff --git a/blender-build/build_environment/cmake/brotli.cmake b/blender-build/build_environment/cmake/brotli.cmake new file mode 100644 index 0000000..5961806 --- /dev/null +++ b/blender-build/build_environment/cmake/brotli.cmake @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(BROTLI_EXTRA_ARGS +) + +ExternalProject_Add(external_brotli + URL file://${PACKAGE_DIR}/${BROTLI_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${BROTLI_HASH_TYPE}=${BROTLI_HASH} + PREFIX ${BUILD_DIR}/brotli + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/brotli ${DEFAULT_CMAKE_FLAGS} ${BROTLI_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/brotli +) + +if(BUILD_MODE STREQUAL Release AND WIN32) + ExternalProject_Add_Step(external_brotli after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/brotli/include ${HARVEST_TARGET}/brotli/include + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/brotli/lib/brotlidec-static${LIBEXT} ${HARVEST_TARGET}/brotli/lib/brotlidec-static${LIBEXT} + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/brotli/lib/brotlicommon-static${LIBEXT} ${HARVEST_TARGET}/brotli/lib/brotlicommon-static${LIBEXT} + DEPENDEES install + ) +endif() diff --git a/blender-build/build_environment/cmake/bzip2.cmake b/blender-build/build_environment/cmake/bzip2.cmake new file mode 100644 index 0000000..4d627bb --- /dev/null +++ b/blender-build/build_environment/cmake/bzip2.cmake @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(BZIP2_PREFIX "${LIBDIR}/bzip2") +set(BZIP2_CONFIGURE_ENV echo .) +set(BZIP2_CONFIGURATION_ARGS) + +if(UNIX AND NOT APPLE) + set(BZIP2_LDFLAGS "-Wl,--as-needed") + set(BZIP2_CFLAGS "-fPIC -Wall -Winline -O2 -g -D_FILE_OFFSET_BITS=64") + set(BZIP2_CONFIGURE_ENV ${BZIP2_CONFIGURE_ENV} && export LDFLAGS=${BZIP2_LDFLAGS} && export CFLAGS=${BZIP2_CFLAGS} + && export PREFIX=${BZIP2_PREFIX}) +else() + set(BZIP2_CONFIGURE_ENV ${CONFIGURE_ENV}) +endif() + +ExternalProject_Add(external_bzip2 + URL file://${PACKAGE_DIR}/${BZIP2_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${BZIP2_HASH_TYPE}=${BZIP2_HASH} + PREFIX ${BUILD_DIR}/bzip2 + CONFIGURE_COMMAND echo . + BUILD_COMMAND ${BZIP2_CONFIGURE_ENV} && cd ${BUILD_DIR}/bzip2/src/external_bzip2/ && make CFLAGS=${BZIP2_CFLAGS} LDFLAGS=${BZIP2_LDFLAGS} -j${MAKE_THREADS} + INSTALL_COMMAND ${BZIP2_CONFIGURE_ENV} && cd ${BUILD_DIR}/bzip2/src/external_bzip2/ && make CFLAGS=${BZIP2_CFLAGS} LDFLAGS=${BZIP2_LDFLAGS} PREFIX=${BZIP2_PREFIX} install + INSTALL_DIR ${LIBDIR}/bzip2 +) diff --git a/blender-build/build_environment/cmake/check_software.cmake b/blender-build/build_environment/cmake/check_software.cmake new file mode 100644 index 0000000..93ea3ff --- /dev/null +++ b/blender-build/build_environment/cmake/check_software.cmake @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(UNIX) + if(APPLE) + set(_libtoolize_name glibtoolize) + else() + set(_libtoolize_name libtoolize) + endif() + + set(_required_software + autoconf + automake + bison + ${_libtoolize_name} + ninja + pkg-config + tclsh + yasm + ) + + if(APPLE) + list(APPEND _required_software dos2unix) + else() + list(APPEND _required_software patchelf) + endif() + + foreach(_software ${_required_software}) + find_program(_software_find NAMES ${_software}) + if(NOT _software_find) + set(_software_missing "${_software_missing}${_software} ") + endif() + unset(_software_find CACHE) + endforeach() + + if(APPLE) + # Homebrew has different default locations for ARM and Intel macOS. + if("${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "arm64") + set(HOMEBREW_LOCATION "/opt/homebrew") + else() + set(HOMEBREW_LOCATION "/usr/local") + endif() + if(NOT EXISTS "${HOMEBREW_LOCATION}/opt/bison/bin/bison") + string(APPEND _software_missing " bison") + endif() + endif() + + if(_software_missing) + message( + "\n" + "Missing software for building Blender dependencies:\n" + " ${_software_missing}\n" + "\n" + "On Debian and Ubuntu:\n" + " apt install autoconf automake bison libtool yasm tcl ninja-build meson python3-mako patchelf\n" + "\n" + "On macOS (with homebrew):\n" + " brew install autoconf automake bison dos2unix flex libtool meson ninja pkg-config yasm\n" + "\n" + "Other platforms:\n" + " Install equivalent packages.\n") + message(FATAL_ERROR "Install missing software before continuing") + endif() +endif() diff --git a/blender-build/build_environment/cmake/cve_check.cmake b/blender-build/build_environment/cmake/cve_check.cmake new file mode 100644 index 0000000..979b5d2 --- /dev/null +++ b/blender-build/build_environment/cmake/cve_check.cmake @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# CVE Check requirements +# +# - A working installation of intels cve-bin-tool [1] has to be available in +# your path +# +# - Not strictly required, but highly recommended is obtaining a NVD key from +# nist since it significantly speeds up downloading/updating the required +# databases one can request a key on the following website: +# https://nvd.nist.gov/developers/request-an-api-key + +# Bill of Materials construction +# +# This constructs a CSV cve-bin-tool [1] can read and process. Sadly +# cve-bin-tool at this point does not take a list of CPE's and output a check +# based on that list. so we need to pick apart the CPE retrieve the vendor, +# product and version tokens and generate a CSV. +# +# [1] https://github.com/intel/cve-bin-tool + +# Because not all deps are downloaded (ie python packages) but can still have a +# xxx_CPE declared loop over all variables and look for variables ending in CPE. + +set(SBOMCONTENTS) +get_cmake_property(_variableNames VARIABLES) +foreach(_variableName ${_variableNames}) + if(_variableName MATCHES "CPE$") + string(REPLACE ":" ";" CPE_LIST ${${_variableName}}) + string(REPLACE "_CPE" "_ID" CPE_DEPNAME ${_variableName}) + list(GET CPE_LIST 3 CPE_VENDOR) + list(GET CPE_LIST 4 CPE_NAME) + list(GET CPE_LIST 5 CPE_VERSION) + set(${CPE_DEPNAME} "${CPE_VENDOR},${CPE_NAME},${CPE_VERSION}") + set(SBOMCONTENTS "${SBOMCONTENTS}${CPE_VENDOR},${CPE_NAME},${CPE_VERSION},,,\n") + endif() +endforeach() +configure_file(${CMAKE_SOURCE_DIR}/cmake/cve_check.csv.in ${CMAKE_CURRENT_BINARY_DIR}/cve_check.csv @ONLY) + +# Custom Targets +# +# This defines two new custom targets one could run in the build folder +# `cve_check` which will output the report to the console, and `cve_check_html` +# which will write out blender_dependencies.html in the build folder that one +# could share with other people or be used to get more information on the +# reported CVE's. +# +# cve-bin-tool takes data from the nist nvd database which rate limits +# unauthenticated requests to 1 requests per 6 seconds making the database +# download take "quite a bit" of time. +# +# When adding -DCVE_CHECK_NVD_KEY=your_api_key_here to your cmake invocation +# this key will be passed on to cve-bin-tool speeding up the process. +# +if(DEFINED CVE_CHECK_NVD_KEY) + set(NVD_ARGS --nvd-api-key ${CVE_CHECK_NVD_KEY}) +endif() + +# This will just report to the console +add_custom_target(cve_check + COMMAND cve-bin-tool + ${NVD_ARGS} + -i ${CMAKE_CURRENT_BINARY_DIR}/cve_check.csv + --affected-versions + SOURCES ${CMAKE_CURRENT_BINARY_DIR}/cve_check.csv +) + +# This will write out blender_dependencies.html +add_custom_target(cve_check_html + COMMAND cve-bin-tool + ${NVD_ARGS} + -i ${CMAKE_CURRENT_BINARY_DIR}/cve_check.csv + -f html + SOURCES ${CMAKE_CURRENT_BINARY_DIR}/cve_check.csv +) diff --git a/blender-build/build_environment/cmake/cve_check.csv.in b/blender-build/build_environment/cmake/cve_check.csv.in new file mode 100644 index 0000000..fd59eb1 --- /dev/null +++ b/blender-build/build_environment/cmake/cve_check.csv.in @@ -0,0 +1,33 @@ +vendor,product,version,cve_number,remarks,comment +@OPENJPEG_ID@,CVE-2016-9675,Ignored,issue in convert command line tool not used by blender +@PYTHON_ID@,CVE-2009-2940,Ignored,issue in pygresql not used by blender +@PYTHON_ID@,CVE-2020-29396,Ignored,issue in odoo not used by blender +@PYTHON_ID@,CVE-2021-32052,Ignored,issue in django not used by blender +@PYTHON_ID@,CVE-2009-3720,Ignored,already fixed in libexpat version used +@PYTHON_ID@,CVE-2023-36632,Ignored,not used in blender and not considered a bug upstream +@PYTHON_ID@,CVE-2023-27043,Ignored,not used in blender +@SSL_ID@,CVE-2009-1390,Ignored,issue in mutt not used by blender +@SSL_ID@,CVE-2009-3765,Ignored,issue in mutt not used by blender +@SSL_ID@,CVE-2009-3766,Ignored,issue in mutt not used by blender +@SSL_ID@,CVE-2009-3767,Ignored,issue in ldap not used by blender +@SSL_ID@,CVE-2019-0190,Ignored,issue in apache not used by blender +@TIFF_ID@,CVE-2022-2056,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-2057,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-2058,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-2519,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-2520,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-2521,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-2953,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-34526,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-3570,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-3597,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-3598,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-3599,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-3626,Ignored,issue in tiff command line tool not used by blender +@TIFF_ID@,CVE-2022-3627,Ignored,issue in tiff command line tool not used by blender +@XML2_ID@,CVE-2016-3709,Ignored,not affecting blender and not considered a security issue upstream +@XML2_ID@,CVE-2023-39615,Ignored,not affecting blender and not considered a security issue upstream +@XML2_ID@,CVE-2020-7595,Ignored,already fixed in the libxml2 version used +@GMP_ID@,CVE-2021-43618,Mitigated,patched using upstream commit 561a9c25298e +@SQLITE_ID@,CVE-2022-35737,Ignored,only affects SQLITE_ENABLE_STAT4 compile option not used by blender or python +@SBOMCONTENTS@ diff --git a/blender-build/build_environment/cmake/download.cmake b/blender-build/build_environment/cmake/download.cmake new file mode 100644 index 0000000..6f24d23 --- /dev/null +++ b/blender-build/build_environment/cmake/download.cmake @@ -0,0 +1,178 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +## Update and uncomment this in the release branch +set(BLENDER_VERSION 3.6) + +function(download_source dep) + set(TARGET_FILE ${${dep}_FILE}) + set(TARGET_HASH_TYPE ${${dep}_HASH_TYPE}) + set(TARGET_HASH ${${dep}_HASH}) + if(PACKAGE_USE_UPSTREAM_SOURCES) + set(TARGET_URI ${${dep}_URI}) + elseif(BLENDER_VERSION) + set(TARGET_URI https://projects.blender.org/blender/lib-source/media/branch/blender-v${BLENDER_VERSION}-release/${TARGET_FILE}) + else() + set(TARGET_URI https://projects.blender.org/blender/lib-source/media/branch/main/${TARGET_FILE}) + endif() + # Validate all required variables are set and give an explicit error message + # rather than CMake erroring out later on with a more ambigious error. + if(NOT DEFINED TARGET_FILE) + message(FATAL_ERROR "${dep}_FILE variable not set") + endif() + if(NOT DEFINED TARGET_HASH) + message(FATAL_ERROR "${dep}_HASH variable not set") + endif() + if(NOT DEFINED TARGET_HASH_TYPE) + message(FATAL_ERROR "${dep}_HASH_TYPE variable not set") + endif() + if(NOT DEFINED TARGET_URI) + message(FATAL_ERROR "${dep}_URI variable not set") + endif() + set(TARGET_FILE ${PACKAGE_DIR}/${TARGET_FILE}) + message("Checking source : ${dep} (${TARGET_FILE})") + if(NOT EXISTS ${TARGET_FILE}) + message("Checking source : ${dep} - source not found downloading from ${TARGET_URI}") + file( + DOWNLOAD ${TARGET_URI} ${TARGET_FILE} + TIMEOUT 1800 # seconds + EXPECTED_HASH ${TARGET_HASH_TYPE}=${TARGET_HASH} + TLS_VERIFY ON + SHOW_PROGRESS + ) + endif() + if(EXISTS ${TARGET_FILE}) + # Sometimes the download fails, but that is not a + # fail condition for "file(DOWNLOAD" it will warn about + # a CRC mismatch and just carry on, we need to explicitly + # catch this and remove the bogus 0 byte file so we can + # retry without having to go find the file and manually + # delete it. + file(SIZE ${TARGET_FILE} TARGET_SIZE) + if(${TARGET_SIZE} EQUAL 0) + file(REMOVE ${TARGET_FILE}) + message(FATAL_ERROR "for ${TARGET_FILE} file size 0, download likely failed, deleted...") + endif() + + # If we are using sources from the blender repo also + # validate that the hashes match, this takes a + # little more time, but protects us when we are + # building a release package and one of the packages + # is missing or incorrect. + # + # For regular platform maintenaince this is not needed + # since the actual build of the dep will notify the + # platform maintainer if there is a problem with the + # source package and refuse to build. + if(NOT PACKAGE_USE_UPSTREAM_SOURCES OR FORCE_CHECK_HASH) + file(${TARGET_HASH_TYPE} ${TARGET_FILE} LOCAL_HASH) + if(NOT ${TARGET_HASH} STREQUAL ${LOCAL_HASH}) + message(FATAL_ERROR "${TARGET_FILE} ${TARGET_HASH_TYPE} mismatch\nExpected\t: ${TARGET_HASH}\nActual\t: ${LOCAL_HASH}") + endif() + endif() + endif() +endfunction(download_source) + +download_source(ZLIB) +download_source(OPENAL) +download_source(PNG) +download_source(JPEG) +download_source(BOOST) +download_source(BLOSC) +download_source(PTHREADS) +download_source(OPENEXR) +download_source(FREETYPE) +download_source(EPOXY) +download_source(FREEGLUT) +download_source(ALEMBIC) +download_source(OPENSUBDIV) +download_source(SDL) +download_source(OPENCOLLADA) +download_source(OPENCOLORIO) +download_source(MINIZIPNG) +download_source(LLVM) +download_source(OPENMP) +download_source(OPENIMAGEIO) +download_source(TIFF) +download_source(OSL) +download_source(PYTHON) +download_source(TBB) +download_source(OPENVDB) +download_source(NUMPY) +download_source(LAME) +download_source(OGG) +download_source(VORBIS) +download_source(THEORA) +download_source(FLAC) +download_source(VPX) +download_source(OPUS) +download_source(X264) +download_source(XVIDCORE) +download_source(OPENJPEG) +download_source(FFMPEG) +download_source(FFTW) +download_source(ICONV) +download_source(SNDFILE) +download_source(WEBP) +download_source(SPNAV) +download_source(JEMALLOC) +download_source(XML2) +download_source(YAMLCPP) +download_source(EXPAT) +download_source(PUGIXML) +download_source(FLEXBISON) +download_source(BZIP2) +download_source(FFI) +download_source(LZMA) +download_source(SSL) +download_source(SQLITE) +download_source(EMBREE) +download_source(USD) +download_source(MATERIALX) +download_source(OIDN) +download_source(LIBGLU) +download_source(MESA) +download_source(NASM) +download_source(XR_OPENXR_SDK) +download_source(WL_PROTOCOLS) +download_source(WAYLAND) +download_source(WAYLAND_LIBDECOR) +download_source(ISPC) +download_source(GMP) +download_source(POTRACE) +download_source(HARU) +download_source(ZSTD) +download_source(SSE2NEON) +download_source(FLEX) +download_source(BROTLI) +download_source(FMT) +download_source(ROBINMAP) +download_source(IMATH) +download_source(PYSTRING) +download_source(OPENPGL) +download_source(LEVEL_ZERO) +download_source(DPCPP) +download_source(VCINTRINSICS) +download_source(OPENCLHEADERS) +download_source(ICDLOADER) +download_source(MP11) +download_source(SPIRV_HEADERS) +download_source(UNIFIED_RUNTIME) +download_source(IGC) +download_source(IGC_LLVM) +download_source(IGC_OPENCL_CLANG) +download_source(IGC_VCINTRINSICS) +download_source(IGC_SPIRV_HEADERS) +download_source(IGC_SPIRV_TOOLS) +download_source(IGC_SPIRV_TRANSLATOR) +download_source(GMMLIB) +download_source(OCLOC) +download_source(AOM) +download_source(FRIBIDI) +download_source(HARFBUZZ) +download_source(SHADERC) +download_source(SHADERC_SPIRV_TOOLS) +download_source(SHADERC_SPIRV_HEADERS) +download_source(SHADERC_GLSLANG) +download_source(VULKAN_HEADERS) +download_source(VULKAN_LOADER) +download_source(PYBIND11) diff --git a/blender-build/build_environment/cmake/dpcpp.cmake b/blender-build/build_environment/cmake/dpcpp.cmake new file mode 100644 index 0000000..58ec46b --- /dev/null +++ b/blender-build/build_environment/cmake/dpcpp.cmake @@ -0,0 +1,127 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# LLVM does not switch over to cpp17 until llvm 16 and building ealier versions with +# MSVC is leading to some crashes in ISPC. Switch back to their default on all platforms +# for now. +string(REPLACE "-DCMAKE_CXX_STANDARD=17" " " DPCPP_CMAKE_FLAGS "${DEFAULT_CMAKE_FLAGS}") + +# DPCPP already generates debug libs, there isn't much point in compiling it in debug mode itself. +string(REPLACE "-DCMAKE_BUILD_TYPE=Debug" "-DCMAKE_BUILD_TYPE=Release" DPCPP_CMAKE_FLAGS "${DPCPP_CMAKE_FLAGS}") + +if(WIN32) + set(LLVM_GENERATOR "Ninja") +else() + set(LLVM_GENERATOR "Unix Makefiles") +endif() + +set(DPCPP_CONFIGURE_ARGS + # When external deps dpcpp needs are not found it will automatically + # download the during the configure stage using FetchContent. Given + # we need to keep an archive of all source used during build for compliance + # reasons it CANNOT download anything we do not know about. By setting + # this property to ON, all downloads are disabled, and we will have to + # provide the missing deps some other way, a build error beats a compliance + # violation + --cmake-opt FETCHCONTENT_FULLY_DISCONNECTED=ON +) +set(DPCPP_SOURCE_ROOT ${BUILD_DIR}/dpcpp/src/external_dpcpp/) +set(DPCPP_EXTRA_ARGS + # When external deps dpcpp needs are not found it will automatically + # download the during the configure stage using FetchContent. Given + # we need to keep an archive of all source used during build for compliance + # reasons it CANNOT download anything we do not know about. By setting + # this property to ON, all downloads are disabled, and we will have to + # provide the missing deps some other way, a build or configure error + # beats a compliance violation + -DFETCHCONTENT_FULLY_DISCONNECTED=ON + -DLLVMGenXIntrinsics_SOURCE_DIR=${BUILD_DIR}/vcintrinsics/src/external_vcintrinsics/ + -DOpenCL_HEADERS=file://${PACKAGE_DIR}/${OPENCLHEADERS_FILE} + -DOpenCL_LIBRARY_SRC=file://${PACKAGE_DIR}/${ICDLOADER_FILE} + -DBOOST_MP11_SOURCE_DIR=${BUILD_DIR}/mp11/src/external_mp11/ + -DLEVEL_ZERO_LIBRARY=${LIBDIR}/level-zero/lib/${LIBPREFIX}ze_loader${SHAREDLIBEXT} + -DLEVEL_ZERO_INCLUDE_DIR=${LIBDIR}/level-zero/include + -DLLVM_EXTERNAL_SPIRV_HEADERS_SOURCE_DIR=${BUILD_DIR}/spirvheaders/src/external_spirvheaders/ + -DUNIFIED_RUNTIME_SOURCE_DIR=${BUILD_DIR}/unifiedruntime/src/external_unifiedruntime/ + # Below here is copied from an invocation of buildbot/config.py + -DLLVM_ENABLE_ASSERTIONS=ON + -DLLVM_TARGETS_TO_BUILD=X86^^AArch64^^ARM + -DLLVM_EXTERNAL_PROJECTS=sycl^^llvm-spirv^^opencl^^libdevice^^xpti^^xptifw^^lld + -DLLVM_EXTERNAL_SYCL_SOURCE_DIR=${DPCPP_SOURCE_ROOT}/sycl + -DLLVM_EXTERNAL_LLVM_SPIRV_SOURCE_DIR=${DPCPP_SOURCE_ROOT}/llvm-spirv + -DLLVM_EXTERNAL_XPTI_SOURCE_DIR=${DPCPP_SOURCE_ROOT}/xpti + -DXPTI_SOURCE_DIR=${DPCPP_SOURCE_ROOT}/xpti + -DLLVM_EXTERNAL_XPTIFW_SOURCE_DIR=${DPCPP_SOURCE_ROOT}/xptifw + -DLLVM_EXTERNAL_LIBDEVICE_SOURCE_DIR=${DPCPP_SOURCE_ROOT}/libdevice + -DLLVM_ENABLE_PROJECTS=clang^^sycl^^llvm-spirv^^opencl^^libdevice^^xpti^^xptifw^^lld + -DLIBCLC_TARGETS_TO_BUILD= + -DLIBCLC_GENERATE_REMANGLED_VARIANTS=OFF + -DSYCL_BUILD_PI_HIP_PLATFORM=AMD + -DLLVM_BUILD_TOOLS=ON + -DSYCL_ENABLE_WERROR=OFF + -DSYCL_INCLUDE_TESTS=ON + -DLLVM_ENABLE_DOXYGEN=OFF + -DLLVM_ENABLE_SPHINX=OFF + -DBUILD_SHARED_LIBS=OFF + -DSYCL_ENABLE_XPTI_TRACING=ON + -DLLVM_ENABLE_LLD=OFF + -DXPTI_ENABLE_WERROR=OFF + -DSYCL_CLANG_EXTRA_FLAGS= + -DSYCL_ENABLE_PLUGINS=level_zero + -DCMAKE_INSTALL_RPATH=\$ORIGIN + -DPython3_ROOT_DIR=${LIBDIR}/python/ + -DPython3_EXECUTABLE=${PYTHON_BINARY} + -DPYTHON_EXECUTABLE=${PYTHON_BINARY} + -DLLDB_ENABLE_CURSES=OFF + -DLLVM_ENABLE_TERMINFO=OFF +) + +if(WIN32) + list(APPEND DPCPP_EXTRA_ARGS -DPython3_FIND_REGISTRY=NEVER) +endif() + +ExternalProject_Add(external_dpcpp + URL file://${PACKAGE_DIR}/${DPCPP_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${DPCPP_HASH_TYPE}=${DPCPP_HASH} + PREFIX ${BUILD_DIR}/dpcpp + CMAKE_GENERATOR ${LLVM_GENERATOR} + SOURCE_SUBDIR llvm + LIST_SEPARATOR ^^ + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/dpcpp ${DPCPP_CMAKE_FLAGS} ${DPCPP_EXTRA_ARGS} + # CONFIGURE_COMMAND + # ${PYTHON_BINARY} + # ${BUILD_DIR}/dpcpp/src/external_dpcpp/buildbot/configure.py ${DPCPP_CONFIGURE_ARGS} + # BUILD_COMMAND + # echo "." # ${PYTHON_BINARY} ${BUILD_DIR}/dpcpp/src/external_dpcpp/buildbot/compile.py + INSTALL_COMMAND ${CMAKE_COMMAND} --build . -- deploy-sycl-toolchain + PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/dpcpp/src/external_dpcpp < ${PATCH_DIR}/dpcpp.diff + INSTALL_DIR ${LIBDIR}/dpcpp +) + +add_dependencies( + external_dpcpp + external_python + external_python_site_packages + external_vcintrinsics + external_openclheaders + external_icdloader + external_mp11 + external_level-zero + external_spirvheaders + external_unifiedruntime +) + +if(BUILD_MODE STREQUAL Release AND WIN32) + ExternalProject_Add_Step(external_dpcpp after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/dpcpp ${HARVEST_TARGET}/dpcpp + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/clang-cl.exe + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/clang-cpp.exe + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/clang.exe + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/ld.lld.exe + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/ld64.lld.exe + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/lld.exe + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/lld-link.exe + COMMAND ${CMAKE_COMMAND} -E rm -f ${HARVEST_TARGET}/dpcpp/bin/wasm-ld.exe + DEPENDEES install + ) +endif() diff --git a/blender-build/build_environment/cmake/dpcpp_deps.cmake b/blender-build/build_environment/cmake/dpcpp_deps.cmake new file mode 100644 index 0000000..662b17f --- /dev/null +++ b/blender-build/build_environment/cmake/dpcpp_deps.cmake @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# These are build time requirements for dpcpp +# We only have to unpack these dpcpp will build +# them. + +ExternalProject_Add(external_vcintrinsics + URL file://${PACKAGE_DIR}/${VCINTRINSICS_FILE} + URL_HASH ${VCINTRINSICS_HASH_TYPE}=${VCINTRINSICS_HASH} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + PREFIX ${BUILD_DIR}/vcintrinsics + CONFIGURE_COMMAND echo . + BUILD_COMMAND echo . + INSTALL_COMMAND echo . +) + +# opencl headers do not have to be unpacked, dpcpp will do it +# but it wouldn't hurt to do it anyway as an opertunity to validate +# the hash is correct. +ExternalProject_Add(external_openclheaders + URL file://${PACKAGE_DIR}/${OPENCLHEADERS_FILE} + URL_HASH ${OPENCLHEADERS_HASH_TYPE}=${OPENCLHEADERS_HASH} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + PREFIX ${BUILD_DIR}/openclheaders + CONFIGURE_COMMAND echo . + BUILD_COMMAND echo . + INSTALL_COMMAND echo . +) + +# icdloader does not have to be unpacked, dpcpp will do it +# but it wouldn't hurt to do it anyway as an opertunity to validate +# the hash is correct. +ExternalProject_Add(external_icdloader + URL file://${PACKAGE_DIR}/${ICDLOADER_FILE} + URL_HASH ${ICDLOADER_HASH_TYPE}=${ICDLOADER_HASH} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + PREFIX ${BUILD_DIR}/icdloader + CONFIGURE_COMMAND echo . + BUILD_COMMAND echo . + INSTALL_COMMAND echo . +) + +ExternalProject_Add(external_mp11 + URL file://${PACKAGE_DIR}/${MP11_FILE} + URL_HASH ${MP11_HASH_TYPE}=${MP11_HASH} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + PREFIX ${BUILD_DIR}/mp11 + CONFIGURE_COMMAND echo . + BUILD_COMMAND echo . + INSTALL_COMMAND echo . +) + +ExternalProject_Add(external_spirvheaders + URL file://${PACKAGE_DIR}/${SPIRV_HEADERS_FILE} + URL_HASH ${SPIRV_HEADERS_HASH_TYPE}=${SPIRV_HEADERS_HASH} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + PREFIX ${BUILD_DIR}/spirvheaders + CONFIGURE_COMMAND echo . + BUILD_COMMAND echo . + INSTALL_COMMAND echo . +) + +ExternalProject_Add(external_unifiedruntime + URL file://${PACKAGE_DIR}/${UNIFIED_RUNTIME_FILE} + URL_HASH ${UNIFIED_RUNTIME_HASH_TYPE}=${UNIFIED_RUNTIME_HASH} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + PREFIX ${BUILD_DIR}/unifiedruntime + CONFIGURE_COMMAND echo . + BUILD_COMMAND echo . + INSTALL_COMMAND echo . +) diff --git a/blender-build/build_environment/cmake/embree.cmake b/blender-build/build_environment/cmake/embree.cmake new file mode 100644 index 0000000..fbf1295 --- /dev/null +++ b/blender-build/build_environment/cmake/embree.cmake @@ -0,0 +1,122 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Note the utility apps may use png/tiff/gif system libraries, but the +# library itself does not depend on them, so should give no problems. + +set(EMBREE_CMAKE_FLAGS ${DEFAULT_CMAKE_FLAGS}) + +set(EMBREE_EXTRA_ARGS + -DEMBREE_ISPC_SUPPORT=OFF + -DEMBREE_TUTORIALS=OFF + -DEMBREE_STATIC_LIB=OFF + -DEMBREE_RAY_MASK=ON + -DEMBREE_FILTER_FUNCTION=ON + -DEMBREE_BACKFACE_CULLING=OFF + -DEMBREE_BACKFACE_CULLING_CURVES=ON + -DEMBREE_BACKFACE_CULLING_SPHERES=ON + -DEMBREE_NO_SPLASH=ON + -DEMBREE_TASKING_SYSTEM=TBB + -DEMBREE_TBB_ROOT=${LIBDIR}/tbb + -DTBB_ROOT=${LIBDIR}/tbb +) + +if(WIN32) + set(EMBREE_EXTRA_ARGS + ${EMBREE_EXTRA_ARGS} + -DCMAKE_DEBUG_POSTFIX=_d + ) +endif() + +if(NOT BLENDER_PLATFORM_ARM) + set(EMBREE_EXTRA_ARGS + ${EMBREE_EXTRA_ARGS} + -DEMBREE_MAX_ISA=AVX2 + ) +endif() + +if(NOT APPLE) + if(WIN32) + # Levels below -O2 don't work well for Embree+SYCL. + string(REGEX REPLACE "-O[A-Za-z0-9]" "" EMBREE_CLANG_CMAKE_CXX_FLAGS_DEBUG ${BLENDER_CLANG_CMAKE_C_FLAGS_DEBUG}) + string(APPEND EMBREE_CLANG_CMAKE_CXX_FLAGS_DEBUG " -O2") + string(REGEX REPLACE "-O[A-Za-z0-9]" "" EMBREE_CLANG_CMAKE_C_FLAGS_DEBUG ${BLENDER_CLANG_CMAKE_C_FLAGS_DEBUG}) + string(APPEND EMBREE_CLANG_CMAKE_C_FLAGS_DEBUG " -O2") + set(EMBREE_CMAKE_FLAGS + -DCMAKE_BUILD_TYPE=${BUILD_MODE} + -DCMAKE_CXX_FLAGS_RELEASE=${BLENDER_CLANG_CMAKE_CXX_FLAGS_RELEASE} + -DCMAKE_CXX_FLAGS_MINSIZEREL=${BLENDER_CLANG_CMAKE_CXX_FLAGS_MINSIZEREL} + -DCMAKE_CXX_FLAGS_RELWITHDEBINFO=${BLENDER_CLANG_CMAKE_CXX_FLAGS_RELWITHDEBINFO} + -DCMAKE_CXX_FLAGS_DEBUG=${EMBREE_CLANG_CMAKE_CXX_FLAGS_DEBUG} + -DCMAKE_C_FLAGS_RELEASE=${BLENDER_CLANG_CMAKE_C_FLAGS_RELEASE} + -DCMAKE_C_FLAGS_MINSIZEREL=${BLENDER_CLANG_CMAKE_C_FLAGS_MINSIZEREL} + -DCMAKE_C_FLAGS_RELWITHDEBINFO=${BLENDER_CLANG_CMAKE_C_FLAGS_RELWITHDEBINFO} + -DCMAKE_C_FLAGS_DEBUG=${EMBREE_CLANG_CMAKE_C_FLAGS_DEBUG} + -DCMAKE_CXX_STANDARD=17 + ) + set(EMBREE_EXTRA_ARGS + -DCMAKE_CXX_COMPILER=${LIBDIR}/dpcpp/bin/clang++.exe + -DCMAKE_C_COMPILER=${LIBDIR}/dpcpp/bin/clang.exe + -DCMAKE_SHARED_LINKER_FLAGS=-L"${LIBDIR}/dpcpp/lib" + -DEMBREE_SYCL_SUPPORT=ON + ${EMBREE_EXTRA_ARGS} + ) + else() + set(EMBREE_EXTRA_ARGS + -DCMAKE_CXX_COMPILER=${LIBDIR}/dpcpp/bin/clang++ + -DCMAKE_C_COMPILER=${LIBDIR}/dpcpp/bin/clang + -DCMAKE_SHARED_LINKER_FLAGS=-L"${LIBDIR}/dpcpp/lib" + -DEMBREE_SYCL_SUPPORT=ON + ${EMBREE_EXTRA_ARGS} + ) + endif() +endif() + +if(TBB_STATIC_LIBRARY) + set(EMBREE_EXTRA_ARGS + ${EMBREE_EXTRA_ARGS} + -DEMBREE_TBB_COMPONENT=tbb_static + ) +endif() + +ExternalProject_Add(external_embree + URL file://${PACKAGE_DIR}/${EMBREE_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${EMBREE_HASH_TYPE}=${EMBREE_HASH} + CMAKE_GENERATOR ${PLATFORM_ALT_GENERATOR} + PREFIX ${BUILD_DIR}/embree + PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/embree/src/external_embree < ${PATCH_DIR}/embree.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/embree ${EMBREE_CMAKE_FLAGS} ${EMBREE_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/embree +) + +if(NOT APPLE) + add_dependencies( + external_embree + external_tbb + external_dpcpp + ) +else() + add_dependencies( + external_embree + external_tbb + ) +endif() + +if(WIN32) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_embree after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/embree/include ${HARVEST_TARGET}/embree/include + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/embree/lib ${HARVEST_TARGET}/embree/lib + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/embree/share ${HARVEST_TARGET}/embree/share + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/bin/embree4.dll ${HARVEST_TARGET}/embree/bin/embree4.dll + DEPENDEES install + ) + else() + ExternalProject_Add_Step(external_embree after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/bin/embree4_d.dll ${HARVEST_TARGET}/embree/bin/embree4_d.dll + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/lib/embree4_d.lib ${HARVEST_TARGET}/embree/lib/embree4_d.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/lib/embree4_sycl_d.lib ${HARVEST_TARGET}/embree/lib/embree4_sycl_d.lib + DEPENDEES install + ) + endif() +endif() diff --git a/blender-build/build_environment/cmake/epoxy.cmake b/blender-build/build_environment/cmake/epoxy.cmake new file mode 100644 index 0000000..28dd8a7 --- /dev/null +++ b/blender-build/build_environment/cmake/epoxy.cmake @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +if(WIN32) + set(EPOXY_LIB_TYPE shared) +else() + set(EPOXY_LIB_TYPE static) +endif() +ExternalProject_Add(external_epoxy + URL file://${PACKAGE_DIR}/${EPOXY_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${EPOXY_HASH_TYPE}=${EPOXY_HASH} + PREFIX ${BUILD_DIR}/epoxy + PATCH_COMMAND ${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/epoxy/src/external_epoxy/ < ${PATCH_DIR}/epoxy.diff + CONFIGURE_COMMAND ${CONFIGURE_ENV} && ${MESON} setup --prefix ${LIBDIR}/epoxy --default-library ${EPOXY_LIB_TYPE} --libdir lib ${BUILD_DIR}/epoxy/src/external_epoxy-build ${BUILD_DIR}/epoxy/src/external_epoxy -Dtests=false ${MESON_BUILD_TYPE} + BUILD_COMMAND ninja + INSTALL_COMMAND ninja install +) + +if(BUILD_MODE STREQUAL Release AND WIN32) + ExternalProject_Add_Step(external_epoxy after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/epoxy/include ${HARVEST_TARGET}/epoxy/include + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/epoxy/bin/epoxy-0.dll ${HARVEST_TARGET}/epoxy/bin/epoxy-0.dll + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/epoxy/lib/epoxy.lib ${HARVEST_TARGET}/epoxy/lib/epoxy.lib + DEPENDEES install + ) +endif() + +add_dependencies( + external_epoxy + # Needed for `MESON`. + external_python_site_packages +) diff --git a/blender-build/build_environment/cmake/expat.cmake b/blender-build/build_environment/cmake/expat.cmake new file mode 100644 index 0000000..3eff949 --- /dev/null +++ b/blender-build/build_environment/cmake/expat.cmake @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(EXPAT_EXTRA_ARGS + -DEXPAT_BUILD_DOCS=OFF + -DEXPAT_BUILD_EXAMPLES=OFF + -DEXPAT_BUILD_TESTS=OFF + -DEXPAT_BUILD_TOOLS=OFF + -DEXPAT_SHARED_LIBS=OFF +) + +ExternalProject_Add(external_expat + URL file://${PACKAGE_DIR}/${EXPAT_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${EXPAT_HASH_TYPE}=${EXPAT_HASH} + PREFIX ${BUILD_DIR}/expat + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/expat ${DEFAULT_CMAKE_FLAGS} ${EXPAT_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/expat + SOURCE_SUBDIR expat +) diff --git a/blender-build/build_environment/cmake/ffi.cmake b/blender-build/build_environment/cmake/ffi.cmake new file mode 100644 index 0000000..b92c503 --- /dev/null +++ b/blender-build/build_environment/cmake/ffi.cmake @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +ExternalProject_Add(external_ffi + URL file://${PACKAGE_DIR}/${FFI_FILE} + URL_HASH ${FFI_HASH_TYPE}=${FFI_HASH} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + PREFIX ${BUILD_DIR}/ffi + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/ffi/src/external_ffi/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/ffi + --enable-shared=no + --enable-static=yes + --with-pic + --libdir=${LIBDIR}/ffi/lib/ + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/ffi/src/external_ffi/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/ffi/src/external_ffi/ && make install + PATCH_COMMAND ${PATCH_CMD} -p 0 -d ${BUILD_DIR}/ffi/src/external_ffi < ${PATCH_DIR}/ffi.diff + INSTALL_DIR ${LIBDIR}/ffi +) + +if(UNIX AND NOT APPLE) + ExternalProject_Add_Step(external_ffi after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/ffi/lib/libffi.a ${LIBDIR}/ffi/lib/libffi_pic.a + DEPENDEES install + ) +endif() diff --git a/blender-build/build_environment/cmake/ffmpeg.cmake b/blender-build/build_environment/cmake/ffmpeg.cmake new file mode 100644 index 0000000..fab6541 --- /dev/null +++ b/blender-build/build_environment/cmake/ffmpeg.cmake @@ -0,0 +1,190 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(WIN32) + set(temp_LIBDIR ${mingw_LIBDIR}) +else() + set(temp_LIBDIR ${LIBDIR}) +endif() + +set(FFMPEG_CFLAGS "\ +-I${temp_LIBDIR}/lame/include \ +-I${temp_LIBDIR}/openjpeg/include/ \ +-I${temp_LIBDIR}/ogg/include \ +-I${temp_LIBDIR}/vorbis/include \ +-I${temp_LIBDIR}/theora/include \ +-I${temp_LIBDIR}/opus/include \ +-I${temp_LIBDIR}/vpx/include \ +-I${temp_LIBDIR}/x264/include \ +-I${temp_LIBDIR}/xvidcore/include \ +-I${temp_LIBDIR}/zlib/include \ +-I${temp_LIBDIR}/aom/include" +) +set(FFMPEG_LDFLAGS "\ +-L${temp_LIBDIR}/lame/lib \ +-L${temp_LIBDIR}/openjpeg/lib \ +-L${temp_LIBDIR}/ogg/lib \ +-L${temp_LIBDIR}/vorbis/lib \ +-L${temp_LIBDIR}/theora/lib \ +-L${temp_LIBDIR}/opus/lib \ +-L${temp_LIBDIR}/vpx/lib \ +-L${temp_LIBDIR}/x264/lib \ +-L${temp_LIBDIR}/xvidcore/lib \ +-L${temp_LIBDIR}/zlib/lib \ +-L${temp_LIBDIR}/aom/lib" +) +set(FFMPEG_EXTRA_FLAGS + --pkg-config-flags=--static + --extra-cflags=${FFMPEG_CFLAGS} + --extra-ldflags=${FFMPEG_LDFLAGS} +) +set(FFMPEG_ENV "PKG_CONFIG_PATH=\ +${temp_LIBDIR}/openjpeg/lib/pkgconfig:\ +${temp_LIBDIR}/x264/lib/pkgconfig:\ +${temp_LIBDIR}/vorbis/lib/pkgconfig:\ +${temp_LIBDIR}/ogg/lib/pkgconfig:\ +${temp_LIBDIR}/vpx/lib/pkgconfig:\ +${temp_LIBDIR}/theora/lib/pkgconfig:\ +${temp_LIBDIR}/openjpeg/lib/pkgconfig:\ +${temp_LIBDIR}/opus/lib/pkgconfig:\ +${temp_LIBDIR}/aom/lib/pkgconfig:" +) + +unset(temp_LIBDIR) + +if(WIN32) + set(FFMPEG_ENV set ${FFMPEG_ENV} &&) + set(FFMPEG_EXTRA_FLAGS + ${FFMPEG_EXTRA_FLAGS} + --disable-static + --enable-shared + --enable-w32threads + --disable-pthreads + --enable-libopenjpeg + --disable-mediafoundation + ) +else() + set(FFMPEG_EXTRA_FLAGS + ${FFMPEG_EXTRA_FLAGS} + --enable-static + --disable-shared + --enable-libopenjpeg + ) +endif() + +if(APPLE) + set(FFMPEG_EXTRA_FLAGS + ${FFMPEG_EXTRA_FLAGS} + --target-os=darwin + --x86asmexe=${LIBDIR}/nasm/bin/nasm + ) +elseif(UNIX) + set(FFMPEG_EXTRA_FLAGS + ${FFMPEG_EXTRA_FLAGS} + --x86asmexe=${LIBDIR}/nasm/bin/nasm + ) +endif() + +ExternalProject_Add(external_ffmpeg + URL file://${PACKAGE_DIR}/${FFMPEG_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${FFMPEG_HASH_TYPE}=${FFMPEG_HASH} + # OpenJpeg is compiled with pthread support on Linux, which is all fine and is what we + # want for maximum runtime performance, but due to static nature of that library we + # need to force ffmpeg to link against pthread, otherwise test program used by autoconf + # will fail. This patch does that in a way that is compatible with multiple distributions. + PATCH_COMMAND ${PATCH_CMD} --verbose -p 1 -N -d ${BUILD_DIR}/ffmpeg/src/external_ffmpeg < ${PATCH_DIR}/ffmpeg.diff + PREFIX ${BUILD_DIR}/ffmpeg + CONFIGURE_COMMAND ${CONFIGURE_ENV_NO_PERL} && + cd ${BUILD_DIR}/ffmpeg/src/external_ffmpeg/ && + ${FFMPEG_ENV} ${CONFIGURE_COMMAND_NO_TARGET} ${FFMPEG_EXTRA_FLAGS} + --disable-lzma + --disable-avfilter + --disable-vdpau + --disable-bzlib + --disable-libgsm + --disable-libspeex + --enable-libvpx + --enable-libopus + --prefix=${LIBDIR}/ffmpeg + --enable-libtheora + --enable-libvorbis + --enable-zlib + --enable-stripping + --enable-runtime-cpudetect + --disable-vaapi + --disable-nonfree + --enable-gpl + --disable-postproc + --enable-libmp3lame + --disable-librtmp + --enable-libx264 + --enable-libxvid + --enable-libaom + --disable-libopencore-amrnb + --disable-libopencore-amrwb + --disable-libdc1394 + --disable-version3 + --disable-debug + --enable-optimizations + --enable-ffplay + --disable-openssl + --disable-securetransport + --disable-indev=avfoundation + --disable-indev=qtkit + --disable-sdl2 + --disable-gnutls + --disable-videotoolbox + --disable-libxcb + --disable-xlib + --disable-audiotoolbox + --disable-cuvid + --disable-nvenc + --disable-indev=jack + --disable-indev=alsa + --disable-outdev=alsa + --disable-crystalhd + --disable-sndio + BUILD_COMMAND ${CONFIGURE_ENV_NO_PERL} && cd ${BUILD_DIR}/ffmpeg/src/external_ffmpeg/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV_NO_PERL} && cd ${BUILD_DIR}/ffmpeg/src/external_ffmpeg/ && make install + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/ffmpeg ${DEFAULT_CMAKE_FLAGS} + INSTALL_DIR ${LIBDIR}/ffmpeg +) + +if(MSVC) + set_target_properties(external_ffmpeg PROPERTIES FOLDER Mingw) +endif() + +add_dependencies( + external_ffmpeg + external_zlib + external_openjpeg + external_xvidcore + external_x264 + external_opus + external_vpx + external_theora + external_vorbis + external_ogg + external_lame + external_aom +) +if(WIN32) + add_dependencies( + external_ffmpeg + external_zlib_mingw + ) +endif() +if(UNIX) + add_dependencies( + external_ffmpeg + external_nasm + ) +endif() + +if(BUILD_MODE STREQUAL Release AND WIN32) + ExternalProject_Add_Step(external_ffmpeg after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/ffmpeg/include ${HARVEST_TARGET}/ffmpeg/include + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/ffmpeg/bin ${HARVEST_TARGET}/ffmpeg/lib + DEPENDEES install + ) +endif() diff --git a/blender-build/build_environment/cmake/fftw.cmake b/blender-build/build_environment/cmake/fftw.cmake new file mode 100644 index 0000000..6f88d78 --- /dev/null +++ b/blender-build/build_environment/cmake/fftw.cmake @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(FFTW_EXTRA_ARGS) + +macro(fftw_build FFTW_POSTFIX) + if(WIN32) + set(FFTW3_PATCH_COMMAND ${PATCH_CMD} --verbose -p 0 -N -d ${BUILD_DIR}/fftw3/src/external_fftw3_${FFTW_POSTFIX} < ${PATCH_DIR}/fftw3.diff) + set(FFTW_EXTRA_ARGS --disable-static --enable-shared) + set(FFTW_INSTALL install-strip) + else() + set(FFTW_EXTRA_ARGS --enable-static) + set(FFTW_INSTALL install) + endif() + ExternalProject_Add(external_fftw3_${FFTW_POSTFIX} + URL file://${PACKAGE_DIR}/${FFTW_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${FFTW_HASH_TYPE}=${FFTW_HASH} + PREFIX ${BUILD_DIR}/fftw3 + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/fftw3/src/external_fftw3_${FFTW_POSTFIX}/ && ${CONFIGURE_COMMAND} ${FFTW_EXTRA_ARGS} ${ARGN} --prefix=${mingw_LIBDIR}/fftw3 + PATCH_COMMAND ${FFTW3_PATCH_COMMAND} + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/fftw3/src/external_fftw3_${FFTW_POSTFIX}/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/fftw3/src/external_fftw3_${FFTW_POSTFIX}/ && make ${FFTW_INSTALL} + INSTALL_DIR ${LIBDIR}/fftw3 + ) +endmacro() + +fftw_build(double) +fftw_build(float --enable-float) + +if(MSVC) + set_target_properties(external_fftw3_double PROPERTIES FOLDER Mingw) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_fftw3_double after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/fftw3/lib/libfftw3.dll.a ${HARVEST_TARGET}/fftw3/lib/libfftw3-3.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/fftw3/bin/libfftw3-3.dll ${HARVEST_TARGET}/fftw3/lib/libfftw3-3.dll + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/fftw3/include/fftw3.h ${HARVEST_TARGET}/fftw3/include/fftw3.h + DEPENDEES install + ) + ExternalProject_Add_Step(external_fftw3_float after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/fftw3/lib/libfftw3f.dll.a ${HARVEST_TARGET}/fftw3/lib/libfftw3f.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/fftw3/bin/libfftw3f-3.dll ${HARVEST_TARGET}/fftw3/lib/libfftw3f-3.dll + DEPENDEES install + ) + endif() + +endif() diff --git a/blender-build/build_environment/cmake/flac.cmake b/blender-build/build_environment/cmake/flac.cmake new file mode 100644 index 0000000..c623fc4 --- /dev/null +++ b/blender-build/build_environment/cmake/flac.cmake @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +ExternalProject_Add(external_flac + URL file://${PACKAGE_DIR}/${FLAC_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${FLAC_HASH_TYPE}=${FLAC_HASH} + PREFIX ${BUILD_DIR}/flac + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/flac/src/external_flac/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/flac --disable-shared --enable-static + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/flac/src/external_flac/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/flac/src/external_flac/ && make install + INSTALL_DIR ${LIBDIR}/flac +) + +if(MSVC) + set_target_properties(external_flac PROPERTIES FOLDER Mingw) +endif() diff --git a/blender-build/build_environment/cmake/flex.cmake b/blender-build/build_environment/cmake/flex.cmake new file mode 100644 index 0000000..2b04c8d --- /dev/null +++ b/blender-build/build_environment/cmake/flex.cmake @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +ExternalProject_Add(external_flex + URL file://${PACKAGE_DIR}/${FLEX_FILE} + URL_HASH ${FLEX_HASH_TYPE}=${FLEX_HASH} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + PREFIX ${BUILD_DIR}/flex + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/flex/src/external_flex/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/flex + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/flex/src/external_flex/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/flex/src/external_flex/ && make install + INSTALL_DIR ${LIBDIR}/flex +) diff --git a/blender-build/build_environment/cmake/flexbison.cmake b/blender-build/build_environment/cmake/flexbison.cmake new file mode 100644 index 0000000..ec03016 --- /dev/null +++ b/blender-build/build_environment/cmake/flexbison.cmake @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(FLEXBISON_EXTRA_ARGS) + +ExternalProject_Add(external_flexbison + URL file://${PACKAGE_DIR}/${FLEXBISON_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${FLEXBISON_HASH_TYPE}=${FLEXBISON_HASH} + PREFIX ${BUILD_DIR}/flexbison + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/flexbison ${DEFAULT_CMAKE_FLAGS} ${FLEXBISON_EXTRA_ARGS} + CONFIGURE_COMMAND echo . + BUILD_COMMAND echo . + INSTALL_COMMAND COMMAND ${CMAKE_COMMAND} -E copy_directory ${BUILD_DIR}/flexbison/src/external_flexbison/ ${LIBDIR}/flexbison/ + INSTALL_DIR ${LIBDIR}/flexbison +) diff --git a/blender-build/build_environment/cmake/fmt.cmake b/blender-build/build_environment/cmake/fmt.cmake new file mode 100644 index 0000000..90982b4 --- /dev/null +++ b/blender-build/build_environment/cmake/fmt.cmake @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(FMT_EXTRA_ARGS + -DFMT_TEST=OFF + -DFMT_DOC=OFF +) + +ExternalProject_Add(external_fmt + URL file://${PACKAGE_DIR}/${FMT_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${FMT_HASH_TYPE}=${FMT_HASH} + PREFIX ${BUILD_DIR}/fmt + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/fmt ${DEFAULT_CMAKE_FLAGS} ${FMT_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/fmt +) diff --git a/blender-build/build_environment/cmake/freeglut.cmake b/blender-build/build_environment/cmake/freeglut.cmake new file mode 100644 index 0000000..9c1dba1 --- /dev/null +++ b/blender-build/build_environment/cmake/freeglut.cmake @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(WIN32) + if(BUILD_MODE STREQUAL Release) + set(FREEGLUT_EXTRA_ARGS + -DFREEGLUT_BUILD_SHARED_LIBS=Off + -DFREEGLUT_BUILD_STATIC_LIBS=On + ) + + ExternalProject_Add(external_freeglut + URL file://${PACKAGE_DIR}/${FREEGLUT_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${FREEGLUT_HASH_TYPE}=${FREEGLUT_HASH} + PREFIX ${BUILD_DIR}/freeglut + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/freeglut ${DEFAULT_C_FLAGS} ${DEFAULT_CXX_FLAGS} ${FREEGLUT_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/freeglut + ) + endif() +endif() diff --git a/blender-build/build_environment/cmake/freetype.cmake b/blender-build/build_environment/cmake/freetype.cmake new file mode 100644 index 0000000..27aace7 --- /dev/null +++ b/blender-build/build_environment/cmake/freetype.cmake @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(FREETYPE_EXTRA_ARGS + -DCMAKE_RELEASE_POSTFIX:STRING=2ST + -DCMAKE_DEBUG_POSTFIX:STRING=2ST_d + -DFT_DISABLE_BZIP2=ON + -DFT_DISABLE_HARFBUZZ=ON + -DFT_DISABLE_PNG=ON + -DFT_REQUIRE_BROTLI=ON + -DFT_REQUIRE_ZLIB=ON + -DPC_BROTLIDEC_INCLUDEDIR=${LIBDIR}/brotli/include + -DPC_BROTLIDEC_LIBDIR=${LIBDIR}/brotli/lib + -DZLIB_LIBRARY=${LIBDIR}/zlib/lib/${ZLIB_LIBRARY} + -DZLIB_INCLUDE_DIR=${LIBDIR}/zlib/include + ) + +ExternalProject_Add(external_freetype + URL file://${PACKAGE_DIR}/${FREETYPE_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${FREETYPE_HASH_TYPE}=${FREETYPE_HASH} + PREFIX ${BUILD_DIR}/freetype + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/freetype ${DEFAULT_CMAKE_FLAGS} ${FREETYPE_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/freetype +) + +add_dependencies( + external_freetype + external_brotli + external_zlib +) + +if(BUILD_MODE STREQUAL Release AND WIN32) + ExternalProject_Add_Step(external_freetype after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/freetype ${HARVEST_TARGET}/freetype + # harfbuzz *NEEDS* to find freetype.lib and will not be conviced to take alternative names so just give it + # what it wants. + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/freetype/lib/freetype2st.lib ${LIBDIR}/freetype/lib/freetype.lib + + DEPENDEES install + ) +endif() diff --git a/blender-build/build_environment/cmake/fribidi.cmake b/blender-build/build_environment/cmake/fribidi.cmake new file mode 100644 index 0000000..e1dd628 --- /dev/null +++ b/blender-build/build_environment/cmake/fribidi.cmake @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(WIN32) + set(CONFIGURE_ENV ${CONFIGURE_ENV_MSVC}) +endif() + +ExternalProject_Add(external_fribidi + URL file://${PACKAGE_DIR}/${FRIBIDI_FILE} + URL_HASH ${FRIBIDI_HASH_TYPE}=${FRIBIDI_HASH} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + PREFIX ${BUILD_DIR}/fribidi + CONFIGURE_COMMAND ${MESON} setup --prefix ${LIBDIR}/fribidi ${MESON_BUILD_TYPE} -Ddocs=false --default-library static --libdir lib ${BUILD_DIR}/fribidi/src/external_fribidi-build ${BUILD_DIR}/fribidi/src/external_fribidi + BUILD_COMMAND ninja + INSTALL_COMMAND ninja install + INSTALL_DIR ${LIBDIR}/fribidi +) + +add_dependencies( + external_fribidi + external_python + # Needed for `MESON`. + external_python_site_packages +) + +if(BUILD_MODE STREQUAL Release AND WIN32) + ExternalProject_Add_Step(external_fribidi after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/fribidi/include ${HARVEST_TARGET}/fribidi/include + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/fribidi/lib/libfribidi.a ${HARVEST_TARGET}/fribidi/lib/libfribidi.lib + DEPENDEES install + ) +endif() diff --git a/blender-build/build_environment/cmake/gmmlib.cmake b/blender-build/build_environment/cmake/gmmlib.cmake new file mode 100644 index 0000000..c46f5c8 --- /dev/null +++ b/blender-build/build_environment/cmake/gmmlib.cmake @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(GMMLIB_EXTRA_ARGS +) + +ExternalProject_Add(external_gmmlib + URL file://${PACKAGE_DIR}/${GMMLIB_FILE} + URL_HASH ${GMMLIB_HASH_TYPE}=${GMMLIB_HASH} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + PREFIX ${BUILD_DIR}/gmmlib + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/gmmlib ${DEFAULT_CMAKE_FLAGS} ${GMMLIB_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/gmmlib +) diff --git a/blender-build/build_environment/cmake/gmp.cmake b/blender-build/build_environment/cmake/gmp.cmake new file mode 100644 index 0000000..cf35b27 --- /dev/null +++ b/blender-build/build_environment/cmake/gmp.cmake @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(GMP_EXTRA_ARGS -enable-cxx) + +if(WIN32) + # Shared for windows because static libs will drag in a libgcc dependency. + set(GMP_OPTIONS --disable-static --enable-shared --enable-fat --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32) +else() + set(GMP_OPTIONS --enable-static --disable-shared ) +endif() + +if(APPLE AND NOT BLENDER_PLATFORM_ARM) + set(GMP_OPTIONS + ${GMP_OPTIONS} + --with-pic + ) +elseif(UNIX AND NOT APPLE) + set(GMP_OPTIONS + ${GMP_OPTIONS} + --with-pic +# --enable-fat + ) +endif() + +# Boolean crashes with Arm assembly, see #103423. +if(BLENDER_PLATFORM_ARM) + set(GMP_OPTIONS + ${GMP_OPTIONS} + --disable-assembly + ) +endif() + +ExternalProject_Add(external_gmp + URL file://${PACKAGE_DIR}/${GMP_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${GMP_HASH_TYPE}=${GMP_HASH} + PREFIX ${BUILD_DIR}/gmp + PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/gmp/src/external_gmp < ${PATCH_DIR}/gmp.diff + CONFIGURE_COMMAND ${CONFIGURE_ENV_NO_PERL} && cd ${BUILD_DIR}/gmp/src/external_gmp/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/gmp ${GMP_OPTIONS} ${GMP_EXTRA_ARGS} + BUILD_COMMAND ${CONFIGURE_ENV_NO_PERL} && cd ${BUILD_DIR}/gmp/src/external_gmp/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV_NO_PERL} && cd ${BUILD_DIR}/gmp/src/external_gmp/ && make install + INSTALL_DIR ${LIBDIR}/gmp +) + +if(MSVC) + set_target_properties(external_gmp PROPERTIES FOLDER Mingw) +endif() + +if(BUILD_MODE STREQUAL Release AND WIN32) + ExternalProject_Add_Step(external_gmp after_install + COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-3.dll.def ${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-10.def + COMMAND lib /def:${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-10.def /machine:x64 /out:${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-10.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/gmp/bin/libgmp-10.dll ${HARVEST_TARGET}/gmp/lib/libgmp-10.dll + COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-10.lib ${HARVEST_TARGET}/gmp/lib/libgmp-10.lib + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/gmp/include ${HARVEST_TARGET}/gmp/include + + DEPENDEES install + ) +endif() + +if(BUILD_MODE STREQUAL Debug AND WIN32) + ExternalProject_Add_Step(external_gmp after_install + COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-3.dll.def ${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-10.def + COMMAND lib /def:${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-10.def /machine:x64 /out:${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-10.lib + + DEPENDEES install + ) +endif() + +if(WIN32) + # gmpxx is somewhat special, it builds on top of the C style gmp library but exposes C++ bindings + # given the C++ ABI between MSVC and mingw is not compatible, we need to build the bindings + # with MSVC, while GMP can only be build with mingw. + ExternalProject_Add(external_gmpxx + URL file://${PACKAGE_DIR}/${GMP_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${GMP_HASH_TYPE}=${GMP_HASH} + PREFIX ${BUILD_DIR}/gmpxx + PATCH_COMMAND COMMAND ${CMAKE_COMMAND} -E copy ${PATCH_DIR}/cmakelists_gmpxx.txt ${BUILD_DIR}/gmpxx/src/external_gmpxx/CMakeLists.txt && + ${CMAKE_COMMAND} -E copy ${PATCH_DIR}/config_gmpxx.h ${BUILD_DIR}/gmpxx/src/external_gmpxx/config.h + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/gmpxx ${DEFAULT_CMAKE_FLAGS} -DGMP_LIBRARY=${BUILD_DIR}/gmp/src/external_gmp/.libs/libgmp-10.lib -DGMP_INCLUDE_DIR=${BUILD_DIR}/gmp/src/external_gmp -DCMAKE_DEBUG_POSTFIX=_d + INSTALL_DIR ${LIBDIR}/gmpxx + ) + set_target_properties(external_gmpxx PROPERTIES FOLDER Mingw) + + add_dependencies( + external_gmpxx + external_gmp + ) + + ExternalProject_Add_Step(external_gmpxx after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/gmpxx/ ${HARVEST_TARGET}/gmp + DEPENDEES install + ) + +endif() diff --git a/blender-build/build_environment/cmake/harfbuzz.cmake b/blender-build/build_environment/cmake/harfbuzz.cmake new file mode 100644 index 0000000..67dccf4 --- /dev/null +++ b/blender-build/build_environment/cmake/harfbuzz.cmake @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(WIN32) + set(HARFBUZZ_CONFIGURE_ENV ${CONFIGURE_ENV_MSVC}) + set(HARFBUZZ_PKG_ENV FREETYPE_DIR=${LIBDIR}/freetype) +else() + set(HARFBUZZ_CONFIGURE_ENV ${CONFIGURE_ENV}) + set(HARFBUZZ_PKG_ENV "PKG_CONFIG_PATH=\ +${LIBDIR}/freetype/lib/pkgconfig:\ +${LIBDIR}/brotli/lib/pkgconfig:\ +${LIBDIR}/lib/python3.10/pkgconfig:\ +$PKG_CONFIG_PATH" + ) +endif() + +set(HARFBUZZ_EXTRA_OPTIONS + -Dtests=disabled + -Dfreetype=enabled + -Dglib=disabled + -Dgobject=disabled + # Only used for command line utilities, + # disable as this would add an addition & unnecessary build-dependency. + -Dcairo=disabled + ${MESON_BUILD_TYPE} +) + +ExternalProject_Add(external_harfbuzz + URL file://${PACKAGE_DIR}/${HARFBUZZ_FILE} + URL_HASH ${HARFBUZZ_HASH_TYPE}=${HARFBUZZ_HASH} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + PREFIX ${BUILD_DIR}/harfbuzz + + CONFIGURE_COMMAND ${HARFBUZZ_CONFIGURE_ENV} && + ${CMAKE_COMMAND} -E env ${HARFBUZZ_PKG_ENV} + ${MESON} setup + --prefix ${LIBDIR}/harfbuzz ${HARFBUZZ_EXTRA_OPTIONS} + --default-library static + --libdir lib + ${BUILD_DIR}/harfbuzz/src/external_harfbuzz-build + ${BUILD_DIR}/harfbuzz/src/external_harfbuzz + + BUILD_COMMAND ninja + INSTALL_COMMAND ninja install + INSTALL_DIR ${LIBDIR}/harfbuzz +) + +add_dependencies( + external_harfbuzz + external_python + external_freetype + # Needed for `MESON`. + external_python_site_packages +) + +if(BUILD_MODE STREQUAL Release AND WIN32) + ExternalProject_Add_Step(external_harfbuzz after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/harfbuzz/include ${HARVEST_TARGET}/harfbuzz/include + # We do not use the subset API currently, so copying only the main library will suffice for now + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/harfbuzz/lib/libharfbuzz.a ${HARVEST_TARGET}/harfbuzz/lib/libharfbuzz.lib + DEPENDEES install + ) +endif() + +if(BUILD_MODE STREQUAL Debug AND WIN32) + ExternalProject_Add_Step(external_harfbuzz after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/harfbuzz/lib/libharfbuzz.a ${HARVEST_TARGET}/harfbuzz/lib/libharfbuzz_d.lib + DEPENDEES install + ) +endif() diff --git a/blender-build/build_environment/cmake/haru.cmake b/blender-build/build_environment/cmake/haru.cmake new file mode 100644 index 0000000..3440be1 --- /dev/null +++ b/blender-build/build_environment/cmake/haru.cmake @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(HARU_EXTRA_ARGS + -DLIBHPDF_SHARED=OFF + -DLIBHPDF_STATIC=ON + -DLIBHPDF_EXAMPLES=OFF + -DLIBHPDF_ENABLE_EXCEPTIONS=ON +) + +ExternalProject_Add(external_haru + URL file://${PACKAGE_DIR}/${HARU_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${HARU_HASH_TYPE}=${HARU_HASH} + PREFIX ${BUILD_DIR}/haru + PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/haru/src/external_haru < ${PATCH_DIR}/haru.diff + CMAKE_ARGS + -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_INSTALL_PREFIX=${LIBDIR}/haru + ${DEFAULT_CMAKE_FLAGS} ${HARU_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/haru +) + +if(WIN32) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_haru after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/haru/include ${HARVEST_TARGET}/haru/include + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/haru/lib/libhpdfs.lib ${HARVEST_TARGET}/haru/lib/libhpdfs.lib + DEPENDEES install + ) + endif() +endif() diff --git a/blender-build/build_environment/cmake/harvest.cmake b/blender-build/build_environment/cmake/harvest.cmake new file mode 100644 index 0000000..26576ab --- /dev/null +++ b/blender-build/build_environment/cmake/harvest.cmake @@ -0,0 +1,316 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +######################################################################## +# Copy all generated files to the proper structure as blender prefers +######################################################################## + +if(NOT DEFINED HARVEST_TARGET) + set(HARVEST_TARGET ${CMAKE_CURRENT_SOURCE_DIR}/Harvest) +endif() +message("HARVEST_TARGET = ${HARVEST_TARGET}") + +if(WIN32) + + if(BUILD_MODE STREQUAL Release) + add_custom_target(Harvest_Release_Results + COMMAND # JPEG rename lib-file + copy include. + ${CMAKE_COMMAND} -E copy ${LIBDIR}/jpeg/lib/jpeg-static.lib ${HARVEST_TARGET}/jpeg/lib/libjpeg.lib && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/jpeg/include/ ${HARVEST_TARGET}/jpeg/include/ && + # PNG. + ${CMAKE_COMMAND} -E copy ${LIBDIR}/png/lib/libpng16_static.lib ${HARVEST_TARGET}/png/lib/libpng.lib && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/png/include/ ${HARVEST_TARGET}/png/include/ && + # FREEGLUT -> OPENGL. + ${CMAKE_COMMAND} -E copy ${LIBDIR}/freeglut/lib/freeglut_static.lib ${HARVEST_TARGET}/opengl/lib/freeglut_static.lib && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/freeglut/include/ ${HARVEST_TARGET}/opengl/include/ && + + DEPENDS + ) + endif() + +else() + + function(harvest from to) + set(pattern "") + foreach(f ${ARGN}) + set(pattern ${f}) + endforeach() + + if(pattern STREQUAL "") + get_filename_component(dirpath ${to} DIRECTORY) + get_filename_component(filename ${to} NAME) + install( + FILES ${LIBDIR}/${from} + DESTINATION ${HARVEST_TARGET}/${dirpath} + RENAME ${filename} + ) + else() + install( + DIRECTORY ${LIBDIR}/${from}/ + DESTINATION ${HARVEST_TARGET}/${to} + USE_SOURCE_PERMISSIONS + FILES_MATCHING PATTERN ${pattern} + PATTERN "pkgconfig" EXCLUDE + PATTERN "cmake" EXCLUDE + PATTERN "__pycache__" EXCLUDE + PATTERN "tests" EXCLUDE + PATTERN "meson*" EXCLUDE + ) + endif() + endfunction() + + # Set rpath on shared libraries to $ORIGIN since all will be installed in the same + # lib folder, and remove any absolute paths. + # + # Ideally this would be done as part of the Blender build since it makes assumptions + # about where the files will be installed. However it would add patchelf as a new + # dependency for building. + # + # Also removes versioned symlinks, which give errors with macOS notarization. + if(APPLE) + set(set_rpath_cmd python3 ${CMAKE_CURRENT_SOURCE_DIR}/darwin/set_rpath.py @loader_path) + else() + set(set_rpath_cmd patchelf --set-rpath $ORIGIN) + endif() + + function(harvest_rpath_lib from to pattern) + harvest(${from} ${to} ${pattern}) + + install(CODE "\ + cmake_policy(SET CMP0009 NEW)\n + file(GLOB_RECURSE shared_libs ${HARVEST_TARGET}/${to}/${pattern}) \n + foreach(f \${shared_libs}) \n + if(IS_SYMLINK \${f})\n + if(APPLE)\n + file(REMOVE_RECURSE \${f}) + endif()\n + else()\n + execute_process(COMMAND ${set_rpath_cmd} \${f}) \n + endif()\n + endforeach()") + endfunction() + + # Set rpath on utility binaries assuming they are run from their install location. + function(harvest_rpath_bin from to pattern) + harvest(${from} ${to} ${pattern}) + + install(CODE "\ + file(GLOB_RECURSE shared_libs ${HARVEST_TARGET}/${to}/${pattern}) \n + foreach(f \${shared_libs}) \n + execute_process(COMMAND ${set_rpath_cmd}/../lib; \${f}) \n + endforeach()") + endfunction() + + # Set rpath on Python module to point to the shared libraries folder in the Blender + # installation. + function(harvest_rpath_python from to pattern) + harvest(${from} ${to} ${pattern}) + + install(CODE "\ + file(GLOB_RECURSE shared_libs ${HARVEST_TARGET}/${to}/${pattern}\.so*) \n + foreach(f \${shared_libs}) \n + if(IS_SYMLINK \${f})\n + if(APPLE)\n + file(REMOVE_RECURSE \${f}) + endif()\n + else()\n + get_filename_component(f_dir \${f} DIRECTORY) \n + file(RELATIVE_PATH relative_dir \${f_dir} ${HARVEST_TARGET}) \n + execute_process(COMMAND ${set_rpath_cmd}/\${relative_dir}../lib \${f}) \n + endif()\n + endforeach()") + endfunction() + + harvest(alembic/include alembic/include "*.h") + harvest(alembic/lib/libAlembic.a alembic/lib/libAlembic.a) + harvest_rpath_bin(alembic/bin alembic/bin "*") + harvest(brotli/include brotli/include "*.h") + harvest(brotli/lib brotli/lib "*.a") + harvest(boost/include boost/include "*") + harvest_rpath_lib(boost/lib boost/lib "*${SHAREDLIBEXT}*") + harvest(imath/include imath/include "*.h") + harvest_rpath_lib(imath/lib imath/lib "*${SHAREDLIBEXT}*") + harvest(ffmpeg/include ffmpeg/include "*.h") + harvest(ffmpeg/lib ffmpeg/lib "*.a") + harvest(fftw3/include fftw3/include "*.h") + harvest(fftw3/lib fftw3/lib "*.a") + harvest(flac/lib sndfile/lib "libFLAC.a") + harvest(freetype/include freetype/include "*.h") + harvest(freetype/lib/libfreetype2ST.a freetype/lib/libfreetype.a) + harvest(fribidi/include fribidi/include "*.h") + harvest(fribidi/lib fribidi/lib "*.a") + harvest(epoxy/include epoxy/include "*.h") + harvest(epoxy/lib epoxy/lib "*.a") + harvest(gmp/include gmp/include "*.h") + harvest(gmp/lib gmp/lib "*.a") + harvest(harfbuzz/include harfbuzz/include "*.h") + harvest(harfbuzz/lib harfbuzz/lib "*.a") + harvest(jemalloc/include jemalloc/include "*.h") + harvest(jemalloc/lib jemalloc/lib "*.a") + harvest(jpeg/include jpeg/include "*.h") + harvest(jpeg/lib jpeg/lib "libjpeg.a") + harvest(lame/lib ffmpeg/lib "*.a") + if(NOT APPLE) + harvest(level-zero/include/level_zero level-zero/include/level_zero "*.h") + harvest(level-zero/lib level-zero/lib "*${SHAREDLIBEXT}*") + endif() + harvest(llvm/bin llvm/bin "clang-format") + if(BUILD_CLANG_TOOLS) + harvest(llvm/bin llvm/bin "clang-tidy") + harvest(llvm/share/clang llvm/share "run-clang-tidy.py") + endif() + harvest(llvm/include llvm/include "*") + harvest(llvm/bin llvm/bin "llvm-config") + harvest(llvm/lib llvm/lib "libLLVM*.a") + harvest(llvm/lib llvm/lib "libclang*.a") + harvest(llvm/lib/clang llvm/lib/clang "*.h") + if(APPLE) + harvest(openmp/lib openmp/lib "libomp.dylib") + harvest(openmp/include openmp/include "*.h") + endif() + if(BLENDER_PLATFORM_ARM) + harvest(sse2neon sse2neon "*.h") + endif() + harvest(ogg/lib ffmpeg/lib "*.a") + harvest(openal/include openal/include "*.h") + if(UNIX AND NOT APPLE) + harvest(openal/lib openal/lib "*.a") + + harvest(zlib/include zlib/include "*.h") + harvest(zlib/lib zlib/lib "*.a") + + harvest(xml2/include xml2/include "*.h") + harvest(xml2/lib xml2/lib "*.a") + + harvest( + wayland-protocols/share/wayland-protocols + wayland-protocols/share/wayland-protocols/ + "*.xml" + ) + harvest(wayland/bin wayland/bin "wayland-scanner") + harvest(wayland/include wayland/include "*.h") + harvest(wayland_libdecor/include wayland_libdecor/include "*.h") + else() + harvest(blosc/lib openvdb/lib "*.a") + harvest(xml2/lib opencollada/lib "*.a") + endif() + harvest(opencollada/include/opencollada opencollada/include "*.h") + harvest(opencollada/lib/opencollada opencollada/lib "*.a") + harvest(opencolorio/include opencolorio/include "*.h") + harvest_rpath_lib(opencolorio/lib opencolorio/lib "*${SHAREDLIBEXT}*") + harvest_rpath_python( + opencolorio/lib/python${PYTHON_SHORT_VERSION} + python/lib/python${PYTHON_SHORT_VERSION} + "*" + ) + harvest(openexr/include openexr/include "*.h") + harvest_rpath_lib(openexr/lib openexr/lib "*${SHAREDLIBEXT}*") + harvest_rpath_bin(openimageio/bin openimageio/bin "idiff") + harvest_rpath_bin(openimageio/bin openimageio/bin "maketx") + harvest_rpath_bin(openimageio/bin openimageio/bin "oiiotool") + harvest(openimageio/include openimageio/include "*") + harvest_rpath_lib(openimageio/lib openimageio/lib "*${SHAREDLIBEXT}*") + harvest_rpath_python( + openimageio/lib/python${PYTHON_SHORT_VERSION} + python/lib/python${PYTHON_SHORT_VERSION} + "*" + ) + if(NOT BLENDER_PLATFORM_ARM) + harvest(openimagedenoise/include openimagedenoise/include "*") + harvest(openimagedenoise/lib openimagedenoise/lib "*.a") + harvest(embree/include embree/include "*.h") + harvest(embree/lib embree/lib "*.a") + harvest_rpath_lib(embree/lib embree/lib "*${SHAREDLIBEXT}*") + harvest(openpgl/include openpgl/include "*.h") + harvest(openpgl/lib openpgl/lib "*.a") + harvest(openpgl/lib/cmake/openpgl-${OPENPGL_SHORT_VERSION} openpgl/lib/cmake/openpgl "*.cmake") + endif() + harvest(openjpeg/include/openjpeg-${OPENJPEG_SHORT_VERSION} openjpeg/include "*.h") + harvest(openjpeg/lib openjpeg/lib "*.a") + harvest(opensubdiv/include opensubdiv/include "*.h") + harvest_rpath_lib(opensubdiv/lib opensubdiv/lib "*${SHAREDLIBEXT}*") + harvest(openvdb/include/openvdb openvdb/include/openvdb "*.h") + harvest(openvdb/include/nanovdb openvdb/include/nanovdb "*.h") + harvest_rpath_lib(openvdb/lib openvdb/lib "*${SHAREDLIBEXT}*") + harvest_rpath_python( + openvdb/lib/python${PYTHON_SHORT_VERSION} + python/lib/python${PYTHON_SHORT_VERSION} + "*pyopenvdb*" + ) + harvest(xr_openxr_sdk/include/openxr xr_openxr_sdk/include/openxr "*.h") + harvest(xr_openxr_sdk/lib xr_openxr_sdk/lib "*.a") + harvest_rpath_bin(osl/bin osl/bin "oslc") + harvest(osl/include osl/include "*.h") + harvest(osl/lib osl/lib "*.a") + harvest(osl/share/OSL/shaders osl/share/OSL/shaders "*.h") + harvest(png/include png/include "*.h") + harvest(png/lib png/lib "*.a") + harvest(pugixml/include pugixml/include "*.hpp") + harvest(pugixml/lib pugixml/lib "*.a") + harvest(python/bin python/bin "python${PYTHON_SHORT_VERSION}") + harvest(python/include python/include "*h") + harvest(python/lib python/lib "*") + harvest(sdl/include/SDL2 sdl/include "*.h") + harvest(sdl/lib sdl/lib "libSDL2.a") + harvest(sndfile/include sndfile/include "*.h") + harvest(sndfile/lib sndfile/lib "*.a") + harvest(spnav/include spnav/include "*.h") + harvest(spnav/lib spnav/lib "*.a") + harvest(tbb/include tbb/include "*.h") + harvest_rpath_lib(tbb/lib tbb/lib "libtbb${SHAREDLIBEXT}*") + harvest(theora/lib ffmpeg/lib "*.a") + harvest(tiff/include tiff/include "*.h") + harvest(tiff/lib tiff/lib "*.a") + harvest(vorbis/lib ffmpeg/lib "*.a") + harvest(opus/lib ffmpeg/lib "*.a") + harvest(vpx/lib ffmpeg/lib "*.a") + harvest(x264/lib ffmpeg/lib "*.a") + harvest(xvidcore/lib ffmpeg/lib "*.a") + harvest(aom/lib ffmpeg/lib "*.a") + harvest(webp/lib webp/lib "*.a") + harvest(webp/include webp/include "*.h") + harvest(usd/include usd/include "*.h") + harvest_rpath_lib(usd/lib usd/lib "libusd_ms${SHAREDLIBEXT}") + harvest(usd/lib/usd usd/lib/usd "*") + harvest_rpath_python( + usd/lib/python/pxr + python/lib/python${PYTHON_SHORT_VERSION}/site-packages/pxr + "*" + ) + harvest(usd/plugin usd/plugin "*") + harvest(materialx/include materialx/include "*.h") + harvest_rpath_lib(materialx/lib materialx/lib "*${SHAREDLIBEXT}*") + harvest(materialx/libraries materialx/libraries "*") + harvest(materialx/lib/cmake/MaterialX materialx/lib/cmake/MaterialX "*.cmake") + harvest_rpath_python( + materialx/python/MaterialX + python/lib/python${PYTHON_SHORT_VERSION}/site-packages/MaterialX + "*" + ) + # We do not need anything from the resources folder, but the MaterialX config + # file will complain if the folder does not exist, so just copy the readme.md + # files to ensure the folder will exist. + harvest(materialx/resources materialx/resources "README.md") + harvest(potrace/include potrace/include "*.h") + harvest(potrace/lib potrace/lib "*.a") + harvest(haru/include haru/include "*.h") + harvest(haru/lib haru/lib "*.a") + harvest(zstd/include zstd/include "*.h") + harvest(zstd/lib zstd/lib "*.a") + harvest(shaderc shaderc "*") + harvest(vulkan_headers vulkan "*") + harvest_rpath_lib(vulkan_loader/lib vulkan/lib "*${SHAREDLIBEXT}*") + if(APPLE) + harvest(vulkan_loader/loader vulkan/loader "*") + endif() + + if(UNIX AND NOT APPLE) + harvest(libglu/lib mesa/lib "*${SHAREDLIBEXT}*") + harvest(mesa/lib64 mesa/lib "*${SHAREDLIBEXT}*") + + if(NOT BLENDER_PLATFORM_ARM) + harvest(dpcpp dpcpp "*") + harvest(igc dpcpp/lib/igc "*") + harvest(ocloc dpcpp/lib/ocloc "*") + endif() + endif() +endif() diff --git a/blender-build/build_environment/cmake/iconv.cmake b/blender-build/build_environment/cmake/iconv.cmake new file mode 100644 index 0000000..34b4718 --- /dev/null +++ b/blender-build/build_environment/cmake/iconv.cmake @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(ICONV_EXTRA_ARGS) + +ExternalProject_Add(external_iconv + URL file://${PACKAGE_DIR}/${ICONV_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${ICONV_HASH_TYPE}=${ICONV_HASH} + PREFIX ${BUILD_DIR}/iconv + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/iconv/src/external_iconv/ && ${CONFIGURE_COMMAND} --enable-static --prefix=${mingw_LIBDIR}/iconv + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/iconv/src/external_iconv/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/iconv/src/external_iconv/ && make install + INSTALL_DIR ${LIBDIR}/iconv +) + +if(MSVC) + set_target_properties(external_iconv PROPERTIES FOLDER Mingw) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_iconv after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/iconv/lib/libiconv.a ${HARVEST_TARGET}/iconv/lib/iconv.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/iconv/include/iconv.h ${HARVEST_TARGET}/iconv/include/iconv.h + DEPENDEES install + ) + endif() +endif() diff --git a/blender-build/build_environment/cmake/igc.cmake b/blender-build/build_environment/cmake/igc.cmake new file mode 100644 index 0000000..28ba727 --- /dev/null +++ b/blender-build/build_environment/cmake/igc.cmake @@ -0,0 +1,128 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +unpack_only(igc_vcintrinsics) +unpack_only(igc_spirv_headers) +unpack_only(igc_spirv_tools) + +# +# igc_opencl_clang contains patches that need to be applied +# to external_igc_llvm and igc_spirv_translator, we unpack +# igc_opencl_clang first, then have the patch stages of +# external_igc_llvm and igc_spirv_translator apply them. +# + +ExternalProject_Add(external_igc_opencl_clang + URL file://${PACKAGE_DIR}/${IGC_OPENCL_CLANG_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${IGC_OPENCL_CLANG_HASH_TYPE}=${IGC_OPENCL_CLANG_HASH} + PREFIX ${BUILD_DIR}/igc_opencl_clang + CONFIGURE_COMMAND echo . + BUILD_COMMAND echo . + INSTALL_COMMAND echo . + PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/igc_opencl_clang/src/external_igc_opencl_clang/ < ${PATCH_DIR}/igc_opencl_clang.diff +) + +set(IGC_OPENCL_CLANG_PATCH_DIR ${BUILD_DIR}/igc_opencl_clang/src/external_igc_opencl_clang/patches) +set(IGC_LLVM_SOURCE_DIR ${BUILD_DIR}/igc_llvm/src/external_igc_llvm) +set(IGC_SPIRV_TRANSLATOR_SOURCE_DIR ${BUILD_DIR}/igc_spirv_translator/src/external_igc_spirv_translator) + +ExternalProject_Add(external_igc_llvm + URL file://${PACKAGE_DIR}/${IGC_LLVM_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${IGC_LLVM_HASH_TYPE}=${IGC_LLVM_HASH} + PREFIX ${BUILD_DIR}/igc_llvm + CONFIGURE_COMMAND echo . + BUILD_COMMAND echo . + INSTALL_COMMAND echo . + PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${IGC_LLVM_SOURCE_DIR} < ${IGC_OPENCL_CLANG_PATCH_DIR}/clang/0001-Remove-__IMAGE_SUPPORT__-macro-for-SPIR.patch && + ${PATCH_CMD} -p 1 -d ${IGC_LLVM_SOURCE_DIR} < ${IGC_OPENCL_CLANG_PATCH_DIR}/clang/0002-Remove-wrong-check-of-__opencl_c_images-feature-macr.patch && + ${PATCH_CMD} -p 1 -d ${IGC_LLVM_SOURCE_DIR} < ${IGC_OPENCL_CLANG_PATCH_DIR}/clang/0003-Fix-checking-mechanism-for-read_write-Image-type.patch && + ${PATCH_CMD} -p 1 -d ${IGC_LLVM_SOURCE_DIR} < ${IGC_OPENCL_CLANG_PATCH_DIR}/clang/0004-OpenCL-Allow-undefining-header-only-macros.patch && + ${PATCH_CMD} -p 1 -d ${IGC_LLVM_SOURCE_DIR} < ${IGC_OPENCL_CLANG_PATCH_DIR}/clang/0005-Enable-use-of-GNU-C-extension.patch && + ${PATCH_CMD} -p 1 -d ${IGC_LLVM_SOURCE_DIR} < ${IGC_OPENCL_CLANG_PATCH_DIR}/clang/0006-Make-globals-used-for-array-initialization-codegen-c.patch +) +add_dependencies( + external_igc_llvm + external_igc_opencl_clang +) + +ExternalProject_Add(external_igc_spirv_translator + URL file://${PACKAGE_DIR}/${IGC_SPIRV_TRANSLATOR_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${IGC_SPIRV_TRANSLATOR_HASH_TYPE}=${IGC_SPIRV_TRANSLATOR_HASH} + PREFIX ${BUILD_DIR}/igc_spirv_translator + CONFIGURE_COMMAND echo . + BUILD_COMMAND echo . + INSTALL_COMMAND echo . +) +add_dependencies( + external_igc_spirv_translator + external_igc_opencl_clang +) + +if(WIN32) + set(IGC_GENERATOR "Ninja") + set(IGC_TARGET Windows64) +else() + set(IGC_GENERATOR "Unix Makefiles") + set(IGC_TARGET Linux64) + if(BLENDER_PLATFORM_ARM) + set(IGC_TARGET LinuxARM) + else() + set(IGC_TARGET Linux64) + endif() + +endif() + +set(IGC_EXTRA_ARGS + -DIGC_OPTION__ARCHITECTURE_TARGET=${IGC_TARGET} + -DIGC_OPTION__ARCHITECTURE_HOST=${IGC_TARGET} +) + +if(UNIX AND NOT APPLE) + list(APPEND IGC_EXTRA_ARGS + -DFLEX_EXECUTABLE=${LIBDIR}/flex/bin/flex + -DFLEX_INCLUDE_DIR=${LIBDIR}/flex/include + ) +endif() + +ExternalProject_Add(external_igc + URL file://${PACKAGE_DIR}/${IGC_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${IGC_HASH_TYPE}=${IGC_HASH} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/igc ${DEFAULT_CMAKE_FLAGS} ${IGC_EXTRA_ARGS} + + # IGC is pretty set in its way where sub projects ought to live, for some it offers + # hooks to supply alternatives folders, other are just hardocded with no way to configure + # we symlink everything here, since it's less work than trying to convince the cmake + # scripts to accept alternative locations. + # + PATCH_COMMAND ${CMAKE_COMMAND} -E create_symlink ${BUILD_DIR}/igc_llvm/src/external_igc_llvm/ ${BUILD_DIR}/igc/src/llvm-project && + ${CMAKE_COMMAND} -E create_symlink ${BUILD_DIR}/igc_opencl_clang/src/external_igc_opencl_clang/ ${BUILD_DIR}/igc/src/llvm-project/llvm/projects/opencl-clang && + ${CMAKE_COMMAND} -E create_symlink ${BUILD_DIR}/igc_spirv_translator/src/external_igc_spirv_translator/ ${BUILD_DIR}/igc/src/llvm-project/llvm/projects/llvm-spirv && + ${CMAKE_COMMAND} -E create_symlink ${BUILD_DIR}/igc_spirv_tools/src/external_igc_spirv_tools/ ${BUILD_DIR}/igc/src/SPIRV-Tools && + ${CMAKE_COMMAND} -E create_symlink ${BUILD_DIR}/igc_spirv_headers/src/external_igc_spirv_headers/ ${BUILD_DIR}/igc/src/SPIRV-Headers && + ${CMAKE_COMMAND} -E create_symlink ${BUILD_DIR}/igc_vcintrinsics/src/external_igc_vcintrinsics/ ${BUILD_DIR}/igc/src/vc-intrinsics + PREFIX ${BUILD_DIR}/igc + INSTALL_DIR ${LIBDIR}/igc + INSTALL_COMMAND ${CMAKE_COMMAND} --install . --strip + CMAKE_GENERATOR ${IGC_GENERATOR} +) + +add_dependencies( + external_igc + external_igc_vcintrinsics + external_igc_llvm + external_igc_opencl_clang + external_igc_vcintrinsics + external_igc_spirv_headers + external_igc_spirv_tools + external_igc_spirv_translator +) + +if(UNIX AND NOT APPLE) + add_dependencies( + external_igc + external_flex + ) +endif() diff --git a/blender-build/build_environment/cmake/imath.cmake b/blender-build/build_environment/cmake/imath.cmake new file mode 100644 index 0000000..1cad822 --- /dev/null +++ b/blender-build/build_environment/cmake/imath.cmake @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(IMATH_EXTRA_ARGS + -DBUILD_SHARED_LIBS=ON + -DBUILD_TESTING=OFF + -DIMATH_LIB_SUFFIX=${OPENEXR_VERSION_BUILD_POSTFIX} +) + +ExternalProject_Add(external_imath + URL file://${PACKAGE_DIR}/${IMATH_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${IMATH_HASH_TYPE}=${IMATH_HASH} + PREFIX ${BUILD_DIR}/imath + CMAKE_GENERATOR ${PLATFORM_ALT_GENERATOR} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/imath ${DEFAULT_CMAKE_FLAGS} ${IMATH_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/imath +) + +if(WIN32) + ExternalProject_Add_Step(external_imath after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/imath/lib ${HARVEST_TARGET}/imath/lib + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/imath/include ${HARVEST_TARGET}/imath/include + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/imath/bin/imath${OPENEXR_VERSION_POSTFIX}.dll ${HARVEST_TARGET}/imath/bin/imath${OPENEXR_VERSION_POSTFIX}.dll + DEPENDEES install + ) +endif() diff --git a/blender-build/build_environment/cmake/ispc.cmake b/blender-build/build_environment/cmake/ispc.cmake new file mode 100644 index 0000000..86e524e --- /dev/null +++ b/blender-build/build_environment/cmake/ispc.cmake @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(WIN32) + set(ISPC_EXTRA_ARGS_WIN + -DFLEX_EXECUTABLE=${LIBDIR}/flexbison/win_flex.exe + -DBISON_EXECUTABLE=${LIBDIR}/flexbison/win_bison.exe + -DM4_EXECUTABLE=${DOWNLOAD_DIR}/mingw/mingw64/msys/1.0/bin/m4.exe + -DARM_ENABLED=Off + -DPython3_FIND_REGISTRY=NEVER + ) +elseif(APPLE) + # Use bison and flex installed via Homebrew. + # The ones that come with Xcode toolset are too old. + if(BLENDER_PLATFORM_ARM) + set(ISPC_EXTRA_ARGS_APPLE + -DBISON_EXECUTABLE=/opt/homebrew/opt/bison/bin/bison + -DFLEX_EXECUTABLE=/opt/homebrew/opt/flex/bin/flex + -DARM_ENABLED=On + ) + else() + set(ISPC_EXTRA_ARGS_APPLE + -DBISON_EXECUTABLE=/usr/local/opt/bison/bin/bison + -DFLEX_EXECUTABLE=/usr/local/opt/flex/bin/flex + -DARM_ENABLED=Off + ) + endif() +elseif(UNIX) + set(ISPC_EXTRA_ARGS_UNIX + -DCMAKE_C_COMPILER=${LIBDIR}/llvm/bin/clang + -DCMAKE_CXX_COMPILER=${LIBDIR}/llvm/bin/clang++ + -DARM_ENABLED=${BLENDER_PLATFORM_ARM} + -DFLEX_EXECUTABLE=${LIBDIR}/flex/bin/flex + ) +endif() + +set(ISPC_EXTRA_ARGS + -DISPC_NO_DUMPS=On + -DISPC_INCLUDE_EXAMPLES=Off + -DISPC_INCLUDE_TESTS=Off + -DLLVM_ROOT=${LIBDIR}/llvm/lib/cmake/llvm + -DLLVM_LIBRARY_DIR=${LIBDIR}/llvm/lib + -DCLANG_EXECUTABLE=${LIBDIR}/llvm/bin/clang + -DCLANGPP_EXECUTABLE=${LIBDIR}/llvm/bin/clang++ + -DISPC_INCLUDE_TESTS=Off + -DCLANG_LIBRARY_DIR=${LIBDIR}/llvm/lib + -DCLANG_INCLUDE_DIRS=${LIBDIR}/llvm/include + -DPython3_ROOT_DIR=${LIBDIR}/python/ + -DPython3_EXECUTABLE=${PYTHON_BINARY} + ${ISPC_EXTRA_ARGS_WIN} + ${ISPC_EXTRA_ARGS_APPLE} + ${ISPC_EXTRA_ARGS_UNIX} +) + +ExternalProject_Add(external_ispc + URL file://${PACKAGE_DIR}/${ISPC_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${ISPC_HASH_TYPE}=${ISPC_HASH} + PREFIX ${BUILD_DIR}/ispc + PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/ispc/src/external_ispc < ${PATCH_DIR}/ispc.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/ispc -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${ISPC_EXTRA_ARGS} ${BUILD_DIR}/ispc/src/external_ispc + INSTALL_DIR ${LIBDIR}/ispc +) + +add_dependencies( + external_ispc + ll + external_python +) + +if(WIN32) + add_dependencies( + external_ispc + external_flexbison + ) +elseif(UNIX AND NOT APPLE) + add_dependencies( + external_ispc + external_flex + ) +endif() diff --git a/blender-build/build_environment/cmake/jemalloc.cmake b/blender-build/build_environment/cmake/jemalloc.cmake new file mode 100644 index 0000000..351fbe4 --- /dev/null +++ b/blender-build/build_environment/cmake/jemalloc.cmake @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +ExternalProject_Add(external_jemalloc + URL file://${PACKAGE_DIR}/${JEMALLOC_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${JEMALLOC_HASH_TYPE}=${JEMALLOC_HASH} + PREFIX ${BUILD_DIR}/jemalloc + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/jemalloc/src/external_jemalloc/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/jemalloc --disable-shared --enable-static --with-pic + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/jemalloc/src/external_jemalloc/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/jemalloc/src/external_jemalloc/ && make install + INSTALL_DIR ${LIBDIR}/jemalloc +) diff --git a/blender-build/build_environment/cmake/jpeg.cmake b/blender-build/build_environment/cmake/jpeg.cmake new file mode 100644 index 0000000..118785d --- /dev/null +++ b/blender-build/build_environment/cmake/jpeg.cmake @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(WIN32) + # CMAKE for MS-Windows. + set(JPEG_EXTRA_ARGS + -DNASM=${NASM_PATH} + -DWITH_JPEG8=ON + -DCMAKE_DEBUG_POSTFIX=d + -DWITH_CRT_DLL=On + -DENABLE_SHARED=OFF + -DENABLE_STATIC=ON + ) + + ExternalProject_Add(external_jpeg + URL file://${PACKAGE_DIR}/${JPEG_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${JPEG_HASH_TYPE}=${JPEG_HASH} + PREFIX ${BUILD_DIR}/jpeg + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/jpeg ${DEFAULT_CMAKE_FLAGS} ${JPEG_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/jpeg + ) + + if(BUILD_MODE STREQUAL Release) + set(JPEG_LIBRARY jpeg-static${LIBEXT}) + else() + set(JPEG_LIBRARY jpeg-staticd${LIBEXT}) + endif() + + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_jpeg after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/jpeg/lib/${JPEG_LIBRARY} ${LIBDIR}/jpeg/lib/jpeg${LIBEXT} + DEPENDEES install + ) + endif() + +else() + # CMAKE for UNIX. + set(JPEG_EXTRA_ARGS + -DWITH_JPEG8=ON + -DENABLE_STATIC=ON + -DENABLE_SHARED=OFF + -DCMAKE_INSTALL_LIBDIR=${LIBDIR}/jpeg/lib) + + ExternalProject_Add(external_jpeg + URL file://${PACKAGE_DIR}/${JPEG_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${JPEG_HASH_TYPE}=${JPEG_HASH} + PREFIX ${BUILD_DIR}/jpeg + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/jpeg ${DEFAULT_CMAKE_FLAGS} ${JPEG_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/jpeg + ) + + set(JPEG_LIBRARY libjpeg${LIBEXT}) +endif() diff --git a/blender-build/build_environment/cmake/lame.cmake b/blender-build/build_environment/cmake/lame.cmake new file mode 100644 index 0000000..3a66153 --- /dev/null +++ b/blender-build/build_environment/cmake/lame.cmake @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(LAME_EXTRA_ARGS) +if(MSVC) + if("${CMAKE_SIZEOF_VOID_P}" EQUAL "4") + set(LAME_EXTRA_ARGS CFLAGS=-msse) + endif() +endif() + +ExternalProject_Add(external_lame + URL file://${PACKAGE_DIR}/${LAME_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${LAME_HASH_TYPE}=${LAME_HASH} + PREFIX ${BUILD_DIR}/lame + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/lame/src/external_lame/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/lame --disable-shared --enable-static ${LAME_EXTRA_ARGS} + --enable-export=full + --with-fileio=sndfile + --without-vorbis + --with-pic + --disable-mp3x + --disable-mp3rtp + --disable-gtktest + --disable-frontend + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/lame/src/external_lame/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/lame/src/external_lame/ && make install + INSTALL_DIR ${LIBDIR}/lame +) + +if(MSVC) + set_target_properties(external_lame PROPERTIES FOLDER Mingw) +endif() diff --git a/blender-build/build_environment/cmake/level-zero.cmake b/blender-build/build_environment/cmake/level-zero.cmake new file mode 100644 index 0000000..4b1ef03 --- /dev/null +++ b/blender-build/build_environment/cmake/level-zero.cmake @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(LEVEL_ZERO_EXTRA_ARGS +) + +ExternalProject_Add(external_level-zero + URL file://${PACKAGE_DIR}/${LEVEL_ZERO_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${LEVEL_ZERO_HASH_TYPE}=${LEVEL_ZERO_HASH} + PREFIX ${BUILD_DIR}/level-zero + PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/level-zero/src/external_level-zero < ${PATCH_DIR}/level-zero.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/level-zero ${DEFAULT_CMAKE_FLAGS} ${LEVEL_ZERO_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/level-zero +) + +if(BUILD_MODE STREQUAL Release AND WIN32) + ExternalProject_Add_Step(external_level-zero after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/level-zero ${HARVEST_TARGET}/level-zero + DEPENDEES install + ) +endif() diff --git a/blender-build/build_environment/cmake/libglu.cmake b/blender-build/build_environment/cmake/libglu.cmake new file mode 100644 index 0000000..d07fbd0 --- /dev/null +++ b/blender-build/build_environment/cmake/libglu.cmake @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(LIBGLU_CFLAGS "-static-libgcc") +set(LIBGLU_CXXFLAGS "-static-libgcc -static-libstdc++ -Bstatic -lstdc++ -Bdynamic -l:libstdc++.a") +set(LIBGLU_LDFLAGS "-pthread -static-libgcc -static-libstdc++ -Bstatic -lstdc++ -Bdynamic -l:libstdc++.a") + +set(LIBGLU_EXTRA_FLAGS + CFLAGS=${LIBGLU_CFLAGS} + CXXFLAGS=${LIBGLU_CXXFLAGS} + LDFLAGS=${LIBGLU_LDFLAGS} +) + +ExternalProject_Add(external_libglu + URL file://${PACKAGE_DIR}/${LIBGLU_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${LIBGLU_HASH_TYPE}=${LIBGLU_HASH} + PREFIX ${BUILD_DIR}/libglu + CONFIGURE_COMMAND ${CONFIGURE_ENV} && + cd ${BUILD_DIR}/libglu/src/external_libglu/ && + ${CONFIGURE_COMMAND_NO_TARGET} --prefix=${LIBDIR}/libglu ${LIBGLU_EXTRA_FLAGS} + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/libglu/src/external_libglu/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/libglu/src/external_libglu/ && make install + INSTALL_DIR ${LIBDIR}/libglu +) diff --git a/blender-build/build_environment/cmake/llvm.cmake b/blender-build/build_environment/cmake/llvm.cmake new file mode 100644 index 0000000..8994d33 --- /dev/null +++ b/blender-build/build_environment/cmake/llvm.cmake @@ -0,0 +1,92 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(BLENDER_PLATFORM_ARM) + set(LLVM_TARGETS AArch64$ARM) +else() + set(LLVM_TARGETS X86) +endif() + +if(APPLE) + set(LLVM_XML2_ARGS + -DLIBXML2_LIBRARY=${LIBDIR}/xml2/lib/libxml2.a + -DLIBXML2_INCLUDE_DIR=${LIBDIR}/xml2/include/libxml2 + ) + set(LLVM_BUILD_CLANG_TOOLS_EXTRA ^^clang-tools-extra) + set(BUILD_CLANG_TOOLS ON) +else() + # NVIDIA PTX for OSL on Windows and Linux. + set(LLVM_TARGETS ${LLVM_TARGETS}$NVPTX) +endif() + +set(LLVM_EXTRA_ARGS + -DLLVM_USE_CRT_RELEASE=MD + -DLLVM_USE_CRT_DEBUG=MDd + -DLLVM_INCLUDE_TESTS=OFF + -DLLVM_TARGETS_TO_BUILD=${LLVM_TARGETS} + -DLLVM_INCLUDE_EXAMPLES=OFF + -DLLVM_ENABLE_TERMINFO=OFF + -DLLVM_BUILD_LLVM_C_DYLIB=OFF + -DLLVM_ENABLE_UNWIND_TABLES=OFF + -DLLVM_ENABLE_PROJECTS=clang${LLVM_BUILD_CLANG_TOOLS_EXTRA} + -DPython3_ROOT_DIR=${LIBDIR}/python/ + -DPython3_EXECUTABLE=${PYTHON_BINARY} + ${LLVM_XML2_ARGS} +) + +if(WIN32) + set(LLVM_GENERATOR "Ninja") + list(APPEND LLVM_EXTRA_ARGS -DPython3_FIND_REGISTRY=NEVER) +else() + set(LLVM_GENERATOR "Unix Makefiles") +endif() + +# LLVM does not switch over to cpp17 until llvm 16 and building ealier versions with +# MSVC is leading to some crashes in ISPC. Switch back to their default on all platforms +# for now. +string(REPLACE "-DCMAKE_CXX_STANDARD=17" " " LLVM_CMAKE_FLAGS "${DEFAULT_CMAKE_FLAGS}") + +# short project name due to long filename issues on windows +ExternalProject_Add(ll + URL file://${PACKAGE_DIR}/${LLVM_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${LLVM_HASH_TYPE}=${LLVM_HASH} + CMAKE_GENERATOR ${LLVM_GENERATOR} + LIST_SEPARATOR ^^ + PREFIX ${BUILD_DIR}/ll + SOURCE_SUBDIR llvm + PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/ll/src/ll < ${PATCH_DIR}/llvm.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/llvm ${LLVM_CMAKE_FLAGS} ${LLVM_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/llvm +) + +if(MSVC) + if(BUILD_MODE STREQUAL Release) + set(LLVM_HARVEST_COMMAND + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/llvm/lib ${HARVEST_TARGET}/llvm/lib && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/llvm/include ${HARVEST_TARGET}/llvm/include && + ${CMAKE_COMMAND} -E copy ${LIBDIR}/llvm/bin/clang-format.exe ${HARVEST_TARGET}/llvm/bin/clang-format.exe + ) + else() + set(LLVM_HARVEST_COMMAND + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/llvm/lib/ ${HARVEST_TARGET}/llvm/debug/lib/ && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/llvm/include/ ${HARVEST_TARGET}/llvm/debug/include/ + ) + endif() + ExternalProject_Add_Step(ll after_install + COMMAND ${LLVM_HARVEST_COMMAND} + DEPENDEES mkdir update patch download configure build install + ) +endif() + +# We currently do not build libxml2 on Windows. +if(APPLE) + add_dependencies( + ll + external_xml2 + ) +endif() + +add_dependencies( + ll + external_python +) diff --git a/blender-build/build_environment/cmake/lzma.cmake b/blender-build/build_environment/cmake/lzma.cmake new file mode 100644 index 0000000..ead975f --- /dev/null +++ b/blender-build/build_environment/cmake/lzma.cmake @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(LZMA_PATCH_CMD echo .) + +ExternalProject_Add(external_lzma + URL file://${PACKAGE_DIR}/${LZMA_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${LZMA_HASH_TYPE}=${LZMA_HASH} + PREFIX ${BUILD_DIR}/lzma + PATCH_COMMAND ${LZMA_PATCH_CMD} + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/lzma/src/external_lzma/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/lzma + --disable-shared + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/lzma/src/external_lzma/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/lzma/src/external_lzma/ && make install + INSTALL_DIR ${LIBDIR}/lzma +) diff --git a/blender-build/build_environment/cmake/macros.cmake b/blender-build/build_environment/cmake/macros.cmake new file mode 100644 index 0000000..82fc151 --- /dev/null +++ b/blender-build/build_environment/cmake/macros.cmake @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# shorthand to only unpack a certain dependency +macro(unpack_only name) + string(TOUPPER ${name} UPPER_NAME) + set(TARGET_FILE ${${UPPER_NAME}_FILE}) + set(TARGET_HASH_TYPE ${${UPPER_NAME}_HASH_TYPE}) + set(TARGET_HASH ${${UPPER_NAME}_HASH}) + ExternalProject_Add(external_${name} + URL file://${PACKAGE_DIR}/${TARGET_FILE} + URL_HASH ${TARGET_HASH_TYPE}=${TARGET_HASH} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + PREFIX ${BUILD_DIR}/${name} + CONFIGURE_COMMAND echo . + BUILD_COMMAND echo . + INSTALL_COMMAND echo . + ) +endmacro() diff --git a/blender-build/build_environment/cmake/materialx.cmake b/blender-build/build_environment/cmake/materialx.cmake new file mode 100644 index 0000000..0b3ce45 --- /dev/null +++ b/blender-build/build_environment/cmake/materialx.cmake @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(MATERIALX_EXTRA_ARGS + -DMATERIALX_BUILD_PYTHON=ON + -DMATERIALX_BUILD_RENDER=ON + -DMATERIALX_INSTALL_PYTHON=OFF + -DMATERIALX_PYTHON_EXECUTABLE=${PYTHON_BINARY} + -DMATERIALX_PYTHON_VERSION=${PYTHON_SHORT_VERSION} + -DMATERIALX_BUILD_SHARED_LIBS=ON + -DMATERIALX_BUILD_TESTS=OFF + -DCMAKE_DEBUG_POSTFIX=_d + -Dpybind11_ROOT=${LIBDIR}/pybind11 + -DPython_EXECUTABLE=${PYTHON_BINARY} +) + +ExternalProject_Add(external_materialx + URL file://${PACKAGE_DIR}/${MATERIALX_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${MATERIALX_HASH_TYPE}=${MATERIALX_HASH} + PREFIX ${BUILD_DIR}/materialx + CMAKE_GENERATOR ${PLATFORM_ALT_GENERATOR} + PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/materialx/src/external_materialx < ${PATCH_DIR}/materialx.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/materialx ${DEFAULT_CMAKE_FLAGS} ${MATERIALX_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/materialx +) + +if(WIN32) + set(MATERIALX_PYTHON_TARGET ${HARVEST_TARGET}/materialx/python/${BUILD_MODE}) + string(REPLACE "/" "\\" MATERIALX_PYTHON_TARGET_DOS "${MATERIALX_PYTHON_TARGET}") + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_materialx after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/materialx/include ${HARVEST_TARGET}/materialx/include + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/materialx/libraries ${HARVEST_TARGET}/materialx/libraries + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/materialx/lib/ ${HARVEST_TARGET}/materialx/lib/ + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/materialx/bin/ ${HARVEST_TARGET}/materialx/bin/ + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/materialx/python/ ${MATERIALX_PYTHON_TARGET} + COMMAND del ${MATERIALX_PYTHON_TARGET_DOS}\\MaterialX\\*.lib + DEPENDEES install + ) + endif() + if(BUILD_MODE STREQUAL Debug) + ExternalProject_Add_Step(external_materialx after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/materialx/lib/ ${HARVEST_TARGET}/materialx/lib/ + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/materialx/bin/ ${HARVEST_TARGET}/materialx/bin/ + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/materialx/python/ ${MATERIALX_PYTHON_TARGET} + COMMAND del ${MATERIALX_PYTHON_TARGET_DOS}\\MaterialX\\*.lib + DEPENDEES install + ) + endif() + unset(MATERIALX_PYTHON_TARGET) + unset(MATERIALX_PYTHON_TARGET_DOS) +endif() + +add_dependencies( + external_materialx + external_python + external_pybind11 +) diff --git a/blender-build/build_environment/cmake/mesa.cmake b/blender-build/build_environment/cmake/mesa.cmake new file mode 100644 index 0000000..c60acaa --- /dev/null +++ b/blender-build/build_environment/cmake/mesa.cmake @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(MESA_CFLAGS "-static-libgcc") +set(MESA_CXXFLAGS "-static-libgcc -static-libstdc++ -Bstatic -lstdc++ -Bdynamic -l:libstdc++.a") +set(MESA_LDFLAGS "-L${LIBDIR}/zlib/lib -pthread -static-libgcc -static-libstdc++ -Bstatic -lstdc++ -Bdynamic -l:libstdc++.a -l:libz_pic.a") + +# The 'native-file', used for overrides with the meson build system. +# meson does not provide a way to do this using command line arguments. +# +# Note that we can't output to "${BUILD_DIR}/mesa/src/external_mesa" as +# it doesn't exist when CMake first executes. +file(WRITE ${BUILD_DIR}/mesa/tmp/native-file.ini "\ +[binaries] +llvm-config = '${LIBDIR}/llvm/bin/llvm-config'" +) + +set(MESA_EXTRA_FLAGS + ${MESON_BUILD_TYPE} + -Dc_args=${MESA_CFLAGS} + -Dcpp_args=${MESA_CXXFLAGS} + -Dc_link_args=${MESA_LDFLAGS} + -Dcpp_link_args=${MESA_LDFLAGS} + -Dglx=gallium-xlib + -Dgallium-drivers=swrast + -Ddri-drivers= + -Dvulkan-drivers= + -Dgbm=disabled + -Degl=disabled + -Dgles1=disabled + -Dgles2=disabled + -Dshared-llvm=disabled + # Without this, the build fails when: `wayland-scanner` is not found. + # At some point we will likely want to support Wayland. + # Disable for now since it's not officially supported. + -Dplatforms=x11 + # Needed to find the local expat. + --pkg-config-path=${LIBDIR}/expat/lib/pkgconfig + --native-file ${BUILD_DIR}/mesa/tmp/native-file.ini +) + +ExternalProject_Add(external_mesa + URL file://${PACKAGE_DIR}/${MESA_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${MESA_HASH_TYPE}=${MESA_HASH} + PREFIX ${BUILD_DIR}/mesa + CONFIGURE_COMMAND ${CONFIGURE_ENV} && + cd ${BUILD_DIR}/mesa/src/external_mesa/ && + ${MESON} ${BUILD_DIR}/mesa/src/external_mesa-build --prefix=${LIBDIR}/mesa ${MESA_EXTRA_FLAGS} + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/mesa/src/external_mesa-build && ninja -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/mesa/src/external_mesa-build && ninja install + INSTALL_DIR ${LIBDIR}/mesa +) + +add_dependencies( + external_mesa + ll + external_zlib + # Run-time dependency. + external_expat + # Needed for `MESON`. + external_python_site_packages +) diff --git a/blender-build/build_environment/cmake/minizipng.cmake b/blender-build/build_environment/cmake/minizipng.cmake new file mode 100644 index 0000000..f9bc7a4 --- /dev/null +++ b/blender-build/build_environment/cmake/minizipng.cmake @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(MINIZIPNG_EXTRA_ARGS + -DMZ_FETCH_LIBS=OFF + -DMZ_LIBCOMP=OFF + -DMZ_PKCRYPT=OFF + -DMZ_WZAES=OFF + -DMZ_OPENSSL=OFF + -DMZ_SIGNING=OFF + -DMZ_LZMA=OFF + -DMZ_ZSTD=OFF + -DZLIB_LIBRARY=${LIBDIR}/zlib/lib/${ZLIB_LIBRARY} + -DZLIB_INCLUDE_DIR=${LIBDIR}/zlib/include/ + -DBZIP2_LIBRARY=${LIBDIR}/bzip2/lib/${LIBPREFIX}bz2${LIBEXT} + -DBZIP2_INCLUDE_DIR=${LIBDIR}/bzip2/include/ + # Because OCIO hardcodes a non standard include path + -DCMAKE_INSTALL_INCLUDEDIR=${LIBDIR}/minizipng/include/minizip-ng +) + +ExternalProject_Add(external_minizipng + URL file://${PACKAGE_DIR}/${MINIZIPNG_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${MINIZIPNG_HASH_TYPE}=${MINIZIPNG_HASH} + PREFIX ${BUILD_DIR}/minizipng + CMAKE_GENERATOR ${PLATFORM_ALT_GENERATOR} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/minizipng ${DEFAULT_CMAKE_FLAGS} ${MINIZIPNG_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/minizipng +) + +add_dependencies( + external_minizipng + external_zlib +) diff --git a/blender-build/build_environment/cmake/nasm.cmake b/blender-build/build_environment/cmake/nasm.cmake new file mode 100644 index 0000000..166f852 --- /dev/null +++ b/blender-build/build_environment/cmake/nasm.cmake @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +ExternalProject_Add(external_nasm + URL file://${PACKAGE_DIR}/${NASM_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${NASM_HASH_TYPE}=${NASM_HASH} + PREFIX ${BUILD_DIR}/nasm + PATCH_COMMAND ${PATCH_CMD} --verbose -p 1 -N -d ${BUILD_DIR}/nasm/src/external_nasm < ${PATCH_DIR}/nasm.diff + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/nasm/src/external_nasm/ && ./autogen.sh && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/nasm + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/nasm/src/external_nasm/ && make -j${MAKE_THREADS} && make manpages + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/nasm/src/external_nasm/ && make install + INSTALL_DIR ${LIBDIR}/nasm +) + +if(UNIX) + # `touch nasm.1 ndisasm.1` helps to create the manual pages files, even when + # local `asciidoc` and `xmlto` packages are not installed. + ExternalProject_Add_Step(external_nasm after_configure + COMMAND ${CMAKE_COMMAND} -E touch ${BUILD_DIR}/nasm/src/external_nasm/nasm.1 ${BUILD_DIR}/nasm/src/external_nasm/ndisasm.1 + DEPENDEES configure + ) +endif() diff --git a/blender-build/build_environment/cmake/numpy.cmake b/blender-build/build_environment/cmake/numpy.cmake new file mode 100644 index 0000000..ea27b0d --- /dev/null +++ b/blender-build/build_environment/cmake/numpy.cmake @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(MSVC) + message("BIN >${PYTHON_BINARY}<") + if(BUILD_MODE STREQUAL Debug) + set(NUMPY_DIR_POSTFIX -pydebug) + set(NUMPY_ARCHIVE_POSTFIX d) + set(NUMPY_BUILD_OPTION --debug) + else() + set(NUMPY_DIR_POSTFIX) + set(NUMPY_ARCHIVE_POSTFIX) + set(NUMPY_BUILD_OPTION) + endif() +endif() + +set(NUMPY_POSTFIX) + +ExternalProject_Add(external_numpy + URL file://${PACKAGE_DIR}/${NUMPY_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${NUMPY_HASH_TYPE}=${NUMPY_HASH} + PREFIX ${BUILD_DIR}/numpy + PATCH_COMMAND ${NUMPY_PATCH} + CONFIGURE_COMMAND "" + LOG_BUILD 1 + BUILD_COMMAND ${PYTHON_BINARY} ${BUILD_DIR}/numpy/src/external_numpy/setup.py build ${NUMPY_BUILD_OPTION} install --old-and-unmanageable + INSTALL_COMMAND "" +) + +add_dependencies( + external_numpy + external_python + external_python_site_packages +) diff --git a/blender-build/build_environment/cmake/ocloc.cmake b/blender-build/build_environment/cmake/ocloc.cmake new file mode 100644 index 0000000..2dbe94e --- /dev/null +++ b/blender-build/build_environment/cmake/ocloc.cmake @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(OCLOC_EXTRA_ARGS + -DNEO_SKIP_UNIT_TESTS=1 + -DNEO_BUILD_WITH_OCL=0 + -DBUILD_WITH_L0=0 + -DIGC_DIR=${LIBDIR}/igc + -DGMM_DIR=${LIBDIR}/gmmlib +) + +ExternalProject_Add(external_ocloc + URL file://${PACKAGE_DIR}/${OCLOC_FILE} + URL_HASH ${OCLOC_HASH_TYPE}=${OCLOC_HASH} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + PREFIX ${BUILD_DIR}/ocloc + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/ocloc ${DEFAULT_CMAKE_FLAGS} ${OCLOC_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/ocloc + PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/ocloc/src/external_ocloc/ < ${PATCH_DIR}/ocloc.diff +) + +add_dependencies( + external_ocloc + external_igc + external_gmmlib +) diff --git a/blender-build/build_environment/cmake/ogg.cmake b/blender-build/build_environment/cmake/ogg.cmake new file mode 100644 index 0000000..feb3171 --- /dev/null +++ b/blender-build/build_environment/cmake/ogg.cmake @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +ExternalProject_Add(external_ogg + URL file://${PACKAGE_DIR}/${OGG_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${OGG_HASH_TYPE}=${OGG_HASH} + PREFIX ${BUILD_DIR}/ogg + PATCH_COMMAND ${PATCH_CMD} --verbose -p 1 -N -d ${BUILD_DIR}/ogg/src/external_ogg < ${PATCH_DIR}/ogg.diff + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/ogg/src/external_ogg/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/ogg --disable-shared --enable-static + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/ogg/src/external_ogg/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/ogg/src/external_ogg/ && make install + INSTALL_DIR ${LIBDIR}/ogg +) + +if(MSVC) + set_target_properties(external_ogg PROPERTIES FOLDER Mingw) +endif() diff --git a/blender-build/build_environment/cmake/openal.cmake b/blender-build/build_environment/cmake/openal.cmake new file mode 100644 index 0000000..379d48e --- /dev/null +++ b/blender-build/build_environment/cmake/openal.cmake @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(BUILD_MODE STREQUAL Release) + set(OPENAL_EXTRA_ARGS + -DALSOFT_UTILS=OFF + -DALSOFT_NO_CONFIG_UTIL=ON + -DALSOFT_EXAMPLES=OFF + -DALSOFT_TESTS=OFF + -DALSOFT_CONFIG=OFF + -DALSOFT_HRTF_DEFS=OFF + -DALSOFT_INSTALL=ON + -DALSOFT_BACKEND_SNDIO=OFF + ) + + if(UNIX) + set(OPENAL_EXTRA_ARGS + ${OPENAL_EXTRA_ARGS} + -DLIBTYPE=STATIC + ) + endif() + + if(UNIX AND NOT APPLE) + # Ensure we have backends for playback. + set(OPENAL_EXTRA_ARGS + ${OPENAL_EXTRA_ARGS} + -DALSOFT_REQUIRE_ALSA=ON + -DALSOFT_REQUIRE_OSS=ON + -DALSOFT_REQUIRE_PULSEAUDIO=ON + ) + endif() + + ExternalProject_Add(external_openal + URL file://${PACKAGE_DIR}/${OPENAL_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${OPENAL_HASH_TYPE}=${OPENAL_HASH} + PREFIX ${BUILD_DIR}/openal + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openal ${DEFAULT_CMAKE_FLAGS} ${OPENAL_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/openal + ) + + if(WIN32) + ExternalProject_Add_Step(external_openal after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openal/lib/openal32.lib ${HARVEST_TARGET}/openal/lib/openal32.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openal/bin/openal32.dll ${HARVEST_TARGET}/openal/lib/openal32.dll + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/openal/include/ ${HARVEST_TARGET}/openal/include/ + DEPENDEES install + ) + endif() + +endif() diff --git a/blender-build/build_environment/cmake/opencollada.cmake b/blender-build/build_environment/cmake/opencollada.cmake new file mode 100644 index 0000000..0042a96 --- /dev/null +++ b/blender-build/build_environment/cmake/opencollada.cmake @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(UNIX) + set(OPENCOLLADA_EXTRA_ARGS + -DLIBXML2_INCLUDE_DIR=${LIBDIR}/xml2/include/libxml2 + -DLIBXML2_LIBRARIES=${LIBDIR}/xml2/lib/libxml2.a) + + # WARNING: the patch contains mixed UNIX and DOS line endings + # as does the OPENCOLLADA package, if this can be corrected upstream that would be better. + # For now use `sed` to force UNIX line endings so the patch applies. + # Needed as neither ignoring white-space or applying as a binary resolve this problem. + if(APPLE) + set(_dos2unix dos2unix) + else() + set(_dos2unix sed -i "s/\\r//") + endif() + set(PATCH_MAYBE_DOS2UNIX_CMD + ${_dos2unix} + ${PATCH_DIR}/opencollada.diff + ${BUILD_DIR}/opencollada/src/external_opencollada/CMakeLists.txt + ${BUILD_DIR}/opencollada/src/external_opencollada/Externals/LibXML/CMakeLists.txt && + ) +else() + set(OPENCOLLADA_EXTRA_ARGS + -DCMAKE_DEBUG_POSTFIX=_d + -DLIBXML2_INCLUDE_DIR=${LIBDIR}/xml2/include/libxml2 + ) + if(BUILD_MODE STREQUAL Release) + list(APPEND OPENCOLLADA_EXTRA_ARGS -DLIBXML2_LIBRARIES=${LIBDIR}/xml2/lib/libxml2s.lib) + else() + list(APPEND OPENCOLLADA_EXTRA_ARGS -DLIBXML2_LIBRARIES=${LIBDIR}/xml2/lib/libxml2sd.lib) + endif() + set(PATCH_MAYBE_DOS2UNIX_CMD) +endif() + +ExternalProject_Add(external_opencollada + URL file://${PACKAGE_DIR}/${OPENCOLLADA_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${OPENCOLLADA_HASH_TYPE}=${OPENCOLLADA_HASH} + PREFIX ${BUILD_DIR}/opencollada + PATCH_COMMAND + ${PATCH_MAYBE_DOS2UNIX_CMD} + ${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/opencollada/src/external_opencollada < ${PATCH_DIR}/opencollada.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/opencollada ${DEFAULT_CMAKE_FLAGS} ${OPENCOLLADA_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/opencollada +) + +unset(PATCH_MAYBE_DOS2UNIX_CMD) + +add_dependencies( + external_opencollada + external_xml2 +) + +if(WIN32) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_opencollada after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/opencollada/ ${HARVEST_TARGET}/opencollada/ + DEPENDEES install + ) + endif() + if(BUILD_MODE STREQUAL Debug) + ExternalProject_Add_Step(external_opencollada after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/opencollada/lib ${HARVEST_TARGET}/opencollada/lib + DEPENDEES install + ) + endif() +endif() diff --git a/blender-build/build_environment/cmake/opencolorio.cmake b/blender-build/build_environment/cmake/opencolorio.cmake new file mode 100644 index 0000000..20683f7 --- /dev/null +++ b/blender-build/build_environment/cmake/opencolorio.cmake @@ -0,0 +1,114 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(OPENCOLORIO_EXTRA_ARGS + -DOCIO_BUILD_APPS=OFF + -DOCIO_BUILD_PYTHON=ON + -DOCIO_BUILD_NUKE=OFF + -DOCIO_BUILD_JAVA=OFF + -DBUILD_SHARED_LIBS=ON + -DOCIO_BUILD_DOCS=OFF + -DOCIO_BUILD_TESTS=OFF + -DOCIO_BUILD_GPU_TESTS=OFF + -DOCIO_USE_SSE=ON + + -DOCIO_INSTALL_EXT_PACKAGES=NONE + + -Dexpat_ROOT=${LIBDIR}/expat + -Dyaml-cpp_ROOT=${LIBDIR}/yamlcpp + -Dyaml-cpp_VERSION=${YAMLCPP_VERSION} + -Dpystring_ROOT=${LIBDIR}/pystring + -DImath_ROOT=${LIBDIR}/imath + -Dminizip-ng_ROOT=${LIBDIR}/minizipng + -Dminizip-ng_INCLUDE_DIR=${LIBDIR}/minizipng/include + -Dminizip-ng_LIBRARY=${LIBDIR}/minizipng/lib/libminizip${LIBEXT} + -DZLIB_LIBRARY=${LIBDIR}/zlib/lib/${ZLIB_LIBRARY} + -DZLIB_INCLUDE_DIR=${LIBDIR}/zlib/include/ + -DPython_EXECUTABLE=${PYTHON_BINARY} + -Dpybind11_ROOT=${LIBDIR}/pybind11 +) + +if(APPLE) + set(OPENCOLORIO_EXTRA_ARGS + ${OPENCOLORIO_EXTRA_ARGS} + "-DCMAKE_SHARED_LINKER_FLAGS=-liconv ${LIBDIR}/bzip2/lib/${LIBPREFIX}bz2${LIBEXT}" + ) +elseif(UNIX) + set(OPENCOLORIO_EXTRA_ARGS + ${OPENCOLORIO_EXTRA_ARGS} + "-DCMAKE_SHARED_LINKER_FLAGS=${LIBDIR}/bzip2/lib/${LIBPREFIX}bz2${LIBEXT}" + ) +endif() + +if(BLENDER_PLATFORM_ARM) + set(OPENCOLORIO_EXTRA_ARGS + ${OPENCOLORIO_EXTRA_ARGS} + -DOCIO_USE_SSE=OFF + ) +endif() + +if(WIN32) + set(OPENCOLORIO_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIMATH_DLL") + if(BUILD_MODE STREQUAL Debug) + set(OPENCOLORIO_CXX_FLAGS "${OPENCOLORIO_CXX_FLAGS} -DPy_DEBUG") + endif() + set(OPENCOLORIO_EXTRA_ARGS + ${OPENCOLORIO_EXTRA_ARGS} + -DCMAKE_DEBUG_POSTFIX=_d + -Dexpat_LIBRARY=${LIBDIR}/expat/lib/libexpat$<$:d>MD${LIBEXT} + -DImath_LIBRARY=${LIBDIR}/imath/lib/imath${OPENEXR_VERSION_POSTFIX}${LIBEXT} + -DCMAKE_CXX_FLAGS=${OPENCOLORIO_CXX_FLAGS} + ) +else() + set(OPENCOLORIO_EXTRA_ARGS + ${OPENCOLORIO_EXTRA_ARGS} + ) +endif() + +ExternalProject_Add(external_opencolorio + URL file://${PACKAGE_DIR}/${OPENCOLORIO_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${OPENCOLORIO_HASH_TYPE}=${OPENCOLORIO_HASH} + CMAKE_GENERATOR ${PLATFORM_ALT_GENERATOR} + PREFIX ${BUILD_DIR}/opencolorio + PATCH_COMMAND ${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/opencolorio/src/external_opencolorio < ${PATCH_DIR}/opencolorio.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/opencolorio ${DEFAULT_CMAKE_FLAGS} ${OPENCOLORIO_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/opencolorio +) + +add_dependencies( + external_opencolorio + external_yamlcpp + external_expat + external_imath + external_pystring + external_zlib + external_minizipng + external_python + external_pybind11 +) + +if(WIN32) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_opencolorio after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/opencolorio/include ${HARVEST_TARGET}/opencolorio/include + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencolorio/bin/OpenColorIO_2_2.dll ${HARVEST_TARGET}/opencolorio/bin/OpenColorIO_2_2.dll + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/opencolorio/lib ${HARVEST_TARGET}/opencolorio/lib + DEPENDEES install + ) + endif() + if(BUILD_MODE STREQUAL Debug) + ExternalProject_Add_Step(external_opencolorio after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencolorio/bin/OpenColorIO_d_2_2.dll ${HARVEST_TARGET}/opencolorio/bin/OpenColorIO_d_2_2.dll + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opencolorio/lib/Opencolorio_d.lib ${HARVEST_TARGET}/opencolorio/lib/OpenColorIO_d.lib + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/opencolorio/lib/site-packages ${HARVEST_TARGET}/opencolorio/lib/site-packages-debug + DEPENDEES install + ) + endif() +else() + ExternalProject_Add_Step(external_opencolorio after_install + COMMAND cp ${LIBDIR}/yamlcpp/lib/libyaml-cpp.a ${LIBDIR}/opencolorio/lib/ + COMMAND cp ${LIBDIR}/expat/lib/libexpat.a ${LIBDIR}/opencolorio/lib/ + COMMAND cp ${LIBDIR}/pystring/lib/libpystring.a ${LIBDIR}/opencolorio/lib/ + DEPENDEES install + ) +endif() diff --git a/blender-build/build_environment/cmake/openexr.cmake b/blender-build/build_environment/cmake/openexr.cmake new file mode 100644 index 0000000..38fa822 --- /dev/null +++ b/blender-build/build_environment/cmake/openexr.cmake @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(WIN32) + set(OPENEXR_CMAKE_CXX_STANDARD_LIBRARIES "kernel32${LIBEXT} user32${LIBEXT} gdi32${LIBEXT} winspool${LIBEXT} shell32${LIBEXT} ole32${LIBEXT} oleaut32${LIBEXT} uuid${LIBEXT} comdlg32${LIBEXT} advapi32${LIBEXT} psapi${LIBEXT}") + set(OPENEXR_EXTRA_ARGS + -DCMAKE_CXX_STANDARD_LIBRARIES=${OPENEXR_CMAKE_CXX_STANDARD_LIBRARIES} + ) +else() + set(OPENEXR_EXTRA_ARGS + ) +endif() + +set(OPENEXR_EXTRA_ARGS + ${OPENEXR_EXTRA_ARGS} + -DZLIB_LIBRARY=${LIBDIR}/zlib/lib/${ZLIB_LIBRARY} + -DZLIB_INCLUDE_DIR=${LIBDIR}/zlib/include/ + -DBUILD_TESTING=OFF + -DOPENEXR_BUILD_BOTH_STATIC_SHARED=OFF + -DBUILD_SHARED_LIBS=ON + -DOPENEXR_INSTALL_TOOLS=OFF + -DOPENEXR_INSTALL_EXAMPLES=OFF + -DImath_DIR=${LIBDIR}/imath/lib/cmake/Imath + -DOPENEXR_LIB_SUFFIX=${OPENEXR_VERSION_BUILD_POSTFIX} +) + +ExternalProject_Add(external_openexr + URL file://${PACKAGE_DIR}/${OPENEXR_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${OPENEXR_HASH_TYPE}=${OPENEXR_HASH} + PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/openexr/src/external_openexr < ${PATCH_DIR}/openexr_b18905772e.diff + CMAKE_GENERATOR ${PLATFORM_ALT_GENERATOR} + PREFIX ${BUILD_DIR}/openexr + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openexr ${DEFAULT_CMAKE_FLAGS} ${OPENEXR_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/openexr +) + +if(WIN32) + ExternalProject_Add_Step(external_openexr after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/openexr/lib ${HARVEST_TARGET}/openexr/lib + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/openexr/include ${HARVEST_TARGET}/openexr/include + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openexr/bin/Iex${OPENEXR_VERSION_POSTFIX}.dll ${HARVEST_TARGET}/openexr/bin/Iex${OPENEXR_VERSION_POSTFIX}.dll + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openexr/bin/IlmThread${OPENEXR_VERSION_POSTFIX}.dll ${HARVEST_TARGET}/openexr/bin/IlmThread${OPENEXR_VERSION_POSTFIX}.dll + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openexr/bin/OpenEXRCore${OPENEXR_VERSION_POSTFIX}.dll ${HARVEST_TARGET}/openexr/bin/OpenEXRCore${OPENEXR_VERSION_POSTFIX}.dll + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openexr/bin/OpenEXRUtil${OPENEXR_VERSION_POSTFIX}.dll ${HARVEST_TARGET}/openexr/bin/OpenEXRUtil${OPENEXR_VERSION_POSTFIX}.dll + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openexr/bin/OpenEXR${OPENEXR_VERSION_POSTFIX}.dll ${HARVEST_TARGET}/openexr/bin/OpenEXR${OPENEXR_VERSION_POSTFIX}.dll + DEPENDEES install + ) +endif() + +add_dependencies( + external_openexr + external_zlib + external_imath +) diff --git a/blender-build/build_environment/cmake/openimagedenoise.cmake b/blender-build/build_environment/cmake/openimagedenoise.cmake new file mode 100644 index 0000000..14a730d --- /dev/null +++ b/blender-build/build_environment/cmake/openimagedenoise.cmake @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + + +set(OIDN_EXTRA_ARGS + -DOIDN_APPS=OFF + -DTBB_ROOT=${LIBDIR}/tbb + -DTBB_STATIC_LIB=${TBB_STATIC_LIBRARY} + -DOIDN_STATIC_LIB=ON + -DOIDN_STATIC_RUNTIME=OFF + -DISPC_EXECUTABLE=${LIBDIR}/ispc/bin/ispc + -DOIDN_FILTER_RTLIGHTMAP=OFF + -DPYTHON_EXECUTABLE=${PYTHON_BINARY} +) + +if(WIN32) + set(OIDN_EXTRA_ARGS + ${OIDN_EXTRA_ARGS} + -DTBB_DEBUG_LIBRARY=${LIBDIR}/tbb/lib/tbb.lib + -DTBB_DEBUG_LIBRARY_MALLOC=${LIBDIR}/tbb/lib/tbbmalloc.lib + ) +else() + set(OIDN_EXTRA_ARGS + ${OIDN_EXTRA_ARGS} + -Dtbb_LIBRARY_RELEASE=${LIBDIR}/tbb/lib/tbb_static.a + -Dtbbmalloc_LIBRARY_RELEASE=${LIBDIR}/tbb/lib/tbbmalloc_static.a + ) +endif() + +ExternalProject_Add(external_openimagedenoise + URL file://${PACKAGE_DIR}/${OIDN_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${OIDN_HASH_TYPE}=${OIDN_HASH} + PREFIX ${BUILD_DIR}/openimagedenoise + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openimagedenoise ${DEFAULT_CMAKE_FLAGS} ${OIDN_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/openimagedenoise +) + +add_dependencies( + external_openimagedenoise + external_tbb + external_ispc + external_python +) + +if(WIN32) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_openimagedenoise after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/openimagedenoise/include ${HARVEST_TARGET}/openimagedenoise/include + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openimagedenoise/lib/openimagedenoise.lib ${HARVEST_TARGET}/openimagedenoise/lib/openimagedenoise.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openimagedenoise/lib/common.lib ${HARVEST_TARGET}/openimagedenoise/lib/common.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openimagedenoise/lib/dnnl.lib ${HARVEST_TARGET}/openimagedenoise/lib/dnnl.lib + DEPENDEES install + ) + endif() + if(BUILD_MODE STREQUAL Debug) + ExternalProject_Add_Step(external_openimagedenoise after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openimagedenoise/lib/openimagedenoise.lib ${HARVEST_TARGET}/openimagedenoise/lib/openimagedenoise_d.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openimagedenoise/lib/common.lib ${HARVEST_TARGET}/openimagedenoise/lib/common_d.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openimagedenoise/lib/dnnl.lib ${HARVEST_TARGET}/openimagedenoise/lib/dnnl_d.lib + DEPENDEES install + ) + endif() +endif() diff --git a/blender-build/build_environment/cmake/openimageio.cmake b/blender-build/build_environment/cmake/openimageio.cmake new file mode 100644 index 0000000..c64f0b1 --- /dev/null +++ b/blender-build/build_environment/cmake/openimageio.cmake @@ -0,0 +1,158 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(BUILD_MODE STREQUAL Release) + set(OIIO_TOOLS ON) +else() + set(OIIO_TOOLS OFF) +endif() + +if(UNIX AND NOT APPLE) + # This causes linking to static pthread libraries which gives link errors. + # Since we manually specify library paths it should static link other libs. + set(OPENIMAGEIO_LINKSTATIC -DLINKSTATIC=OFF) +else() + set(OPENIMAGEIO_LINKSTATIC -DLINKSTATIC=ON) +endif() + +if(WIN32) + set(OIIO_SIMD_FLAGS -DUSE_SIMD=sse2) + set(OPENJPEG_POSTFIX _msvc) + if(BUILD_MODE STREQUAL Debug) + set(TIFF_POSTFIX d) + set(PNG_POSTFIX d) + else() + set(TIFF_POSTFIX) + set(PNG_POSTFIX) + endif() + set(PNG_LIBNAME libpng16_static${PNG_POSTFIX}${LIBEXT}) +else() + set(PNG_LIBNAME libpng${LIBEXT}) + set(OIIO_SIMD_FLAGS) + set(TIFF_POSTFIX) +endif() + +if(MSVC) + set(OPENJPEG_FLAGS + -DOpenJPEG_ROOT=${LIBDIR}/openjpeg_msvc + ) +else() + set(OPENJPEG_FLAGS + -DOpenJPEG_ROOT=${LIBDIR}/openjpeg + ) +endif() + +set(OPENIMAGEIO_EXTRA_ARGS + -DBUILD_SHARED_LIBS=ON + ${OPENIMAGEIO_LINKSTATIC} + ${DEFAULT_BOOST_FLAGS} + -DREQUIRED_DEPS=WebP$JPEGTurbo$TIFF$OpenEXR$PNG$OpenJPEG$fmt$Robinmap$ZLIB$pugixml$Python + -DUSE_LIBSQUISH=OFF + -DUSE_QT5=OFF + -DUSE_NUKE=OFF + -DUSE_OPENVDB=OFF + -DUSE_BZIP2=OFF + -DUSE_FREETYPE=OFF + -DUSE_DCMTK=OFF + -DUSE_LIBHEIF=OFF + -DUSE_OPENGL=OFF + -DUSE_TBB=ON + -DUSE_QT=OFF + -DUSE_PYTHON=ON + -DUSE_GIF=OFF + -DUSE_OPENCV=OFF + -DUSE_OPENJPEG=ON + -DUSE_FFMPEG=OFF + -DUSE_PTEX=OFF + -DUSE_FREETYPE=OFF + -DUSE_LIBRAW=OFF + -DUSE_OPENCOLORIO=OFF + -DUSE_WEBP=ON + -DOIIO_BUILD_TOOLS=${OIIO_TOOLS} + -DOIIO_BUILD_TESTS=OFF + -DBUILD_TESTING=OFF + -DZLIB_LIBRARY=${LIBDIR}/zlib/lib/${ZLIB_LIBRARY} + -DZLIB_INCLUDE_DIR=${LIBDIR}/zlib/include + -DPNG_LIBRARY=${LIBDIR}/png/lib/${PNG_LIBNAME} + -DPNG_PNG_INCLUDE_DIR=${LIBDIR}/png/include + -DTIFF_LIBRARY=${LIBDIR}/tiff/lib/${LIBPREFIX}tiff${TIFF_POSTFIX}${LIBEXT} + -DTIFF_INCLUDE_DIR=${LIBDIR}/tiff/include + -DJPEG_LIBRARY=${LIBDIR}/jpeg/lib/${JPEG_LIBRARY} + -DJPEG_INCLUDE_DIR=${LIBDIR}/jpeg/include + ${OPENJPEG_FLAGS} + -DOPENEXR_ILMTHREAD_LIBRARY=${LIBDIR}/openexr/lib/${LIBPREFIX}IlmThread${OPENEXR_VERSION_POSTFIX}${SHAREDLIBEXT} + -DOPENEXR_IEX_LIBRARY=${LIBDIR}/openexr/lib/${LIBPREFIX}Iex${OPENEXR_VERSION_POSTFIX}${SHAREDLIBEXT} + -DOPENEXR_ILMIMF_LIBRARY=${LIBDIR}/openexr/lib/${LIBPREFIX}IlmImf${OPENEXR_VERSION_POSTFIX}${SHAREDLIBEXT} + -DSTOP_ON_WARNING=OFF + -DUSE_EXTERNAL_PUGIXML=ON + -DPUGIXML_LIBRARY=${LIBDIR}/pugixml/lib/${LIBPREFIX}pugixml${LIBEXT} + -DPUGIXML_INCLUDE_DIR=${LIBDIR}/pugixml/include/ + -Dpugixml_DIR=${LIBDIR}/pugixml/lib/cmake/pugixml + -DBUILD_MISSING_ROBINMAP=OFF + -DBUILD_MISSING_FMT=OFF + -DFMT_INCLUDE_DIR=${LIBDIR}/fmt/include/ + -DRobinmap_ROOT=${LIBDIR}/robinmap + -DWebP_ROOT=${LIBDIR}/webp + ${OIIO_SIMD_FLAGS} + -DOpenEXR_ROOT=${LIBDIR}/openexr + -DImath_ROOT=${LIBDIR}/imath + -Dpybind11_ROOT=${LIBDIR}/pybind11 + -DPython_EXECUTABLE=${PYTHON_BINARY} + -DTBB_ROOT=${LIBDIR}/tbb +) + +ExternalProject_Add(external_openimageio + URL file://${PACKAGE_DIR}/${OPENIMAGEIO_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${OPENIMAGEIO_HASH_TYPE}=${OPENIMAGEIO_HASH} + CMAKE_GENERATOR ${PLATFORM_ALT_GENERATOR} + PREFIX ${BUILD_DIR}/openimageio + PATCH_COMMAND ${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/openimageio.diff && + ${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/oiio_deadlock.diff && + ${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/oiio_3984.diff && + ${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/oiio_3996.diff && + ${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/oiio_webp.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openimageio ${DEFAULT_CMAKE_FLAGS} ${OPENIMAGEIO_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/openimageio +) + +add_dependencies( + external_openimageio + external_png + external_zlib + external_openexr + external_imath + external_jpeg + external_boost + external_tiff + external_pugixml + external_fmt + external_robinmap + external_openjpeg${OPENJPEG_POSTFIX} + external_webp + external_python + external_pybind11 + external_tbb +) + +if(WIN32) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_openimageio after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/OpenImageIO/include ${HARVEST_TARGET}/OpenImageIO/include + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/OpenImageIO/lib ${HARVEST_TARGET}/OpenImageIO/lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/OpenImageIO/bin/idiff.exe ${HARVEST_TARGET}/OpenImageIO/bin/idiff.exe + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/OpenImageIO/bin/OpenImageIO.dll ${HARVEST_TARGET}/OpenImageIO/bin/OpenImageIO.dll + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/OpenImageIO/bin/OpenImageIO_Util.dll ${HARVEST_TARGET}/OpenImageIO/bin/OpenImageIO_Util.dll + DEPENDEES install + ) + endif() + if(BUILD_MODE STREQUAL Debug) + ExternalProject_Add_Step(external_openimageio after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openimageio/lib/OpenImageIO_d.lib ${HARVEST_TARGET}/openimageio/lib/OpenImageIO_d.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openimageio/lib/OpenImageIO_Util_d.lib ${HARVEST_TARGET}/openimageio/lib/OpenImageIO_Util_d.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/OpenImageIO/bin/OpenImageIO_d.dll ${HARVEST_TARGET}/OpenImageIO/bin/OpenImageIO_d.dll + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/OpenImageIO/bin/OpenImageIO_Util_d.dll ${HARVEST_TARGET}/OpenImageIO/bin/OpenImageIO_Util_d.dll + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/OpenImageIO/lib/python${PYTHON_SHORT_VERSION}/ ${HARVEST_TARGET}/OpenImageIO/lib/python${PYTHON_SHORT_VERSION}_debug/ + DEPENDEES install + ) + endif() +endif() diff --git a/blender-build/build_environment/cmake/openjpeg.cmake b/blender-build/build_environment/cmake/openjpeg.cmake new file mode 100644 index 0000000..fc84e56 --- /dev/null +++ b/blender-build/build_environment/cmake/openjpeg.cmake @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Note the encoder/decoder may use png/tiff/lcms system libraries, but the +# library itself does not depend on them, so should give no problems. + +if(WIN32) + set(OPENJPEG_EXTRA_ARGS -G "MSYS Makefiles" -DBUILD_PKGCONFIG_FILES=On) +else() + set(OPENJPEG_EXTRA_ARGS ${DEFAULT_CMAKE_FLAGS}) +endif() + +set(OPENJPEG_EXTRA_ARGS + ${OPENJPEG_EXTRA_ARGS} + -DBUILD_SHARED_LIBS=OFF + -DBUILD_CODEC=OFF +) + +ExternalProject_Add(external_openjpeg + URL file://${PACKAGE_DIR}/${OPENJPEG_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${OPENJPEG_HASH_TYPE}=${OPENJPEG_HASH} + PREFIX ${BUILD_DIR}/openjpeg + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/openjpeg/src/external_openjpeg-build && ${CMAKE_COMMAND} ${OPENJPEG_EXTRA_ARGS} -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openjpeg ${BUILD_DIR}/openjpeg/src/external_openjpeg + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/openjpeg/src/external_openjpeg-build/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/openjpeg/src/external_openjpeg-build/ && make install + INSTALL_DIR ${LIBDIR}/openjpeg +) + +# On windows ffmpeg wants a mingw build, while oiio needs a msvc build. +if(MSVC) + set(OPENJPEG_EXTRA_ARGS ${DEFAULT_CMAKE_FLAGS}) + ExternalProject_Add(external_openjpeg_msvc + URL file://${PACKAGE_DIR}/${OPENJPEG_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${OPENJPEG_HASH_TYPE}=${OPENJPEG_HASH} + PREFIX ${BUILD_DIR}/openjpeg_msvc + CMAKE_ARGS ${OPENJPEG_EXTRA_ARGS} -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openjpeg_msvc -DBUILD_SHARED_LIBS=Off -DBUILD_THIRDPARTY=OFF + INSTALL_DIR ${LIBDIR}/openjpeg_msvc + ) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_openjpeg_msvc after_install + COMMAND + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/openjpeg_msvc/lib ${HARVEST_TARGET}/openjpeg/lib && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/openjpeg_msvc/include ${HARVEST_TARGET}/openjpeg/include + + DEPENDEES install + ) + endif() +endif() + +set(OPENJPEG_LIBRARY libopenjp2${LIBEXT}) +if(MSVC) + set_target_properties(external_openjpeg PROPERTIES FOLDER Mingw) +endif() diff --git a/blender-build/build_environment/cmake/openmp.cmake b/blender-build/build_environment/cmake/openmp.cmake new file mode 100644 index 0000000..6570d58 --- /dev/null +++ b/blender-build/build_environment/cmake/openmp.cmake @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(APPLE) + set(OPENMP_PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/openmp/src/external_openmp < ${PATCH_DIR}/openmp.diff) +else() + set(OPENMP_PATCH_COMMAND) +endif() + +ExternalProject_Add(external_openmp + URL file://${PACKAGE_DIR}/${OPENMP_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${OPENMP_HASH_TYPE}=${OPENMP_HASH} + PREFIX ${BUILD_DIR}/openmp + PATCH_COMMAND ${OPENMP_PATCH_COMMAND} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openmp ${DEFAULT_CMAKE_FLAGS} + INSTALL_COMMAND cd ${BUILD_DIR}/openmp/src/external_openmp-build && install_name_tool -id @rpath/libomp.dylib runtime/src/libomp.dylib && make install + INSTALL_DIR ${LIBDIR}/openmp +) + +add_dependencies( + external_openmp + ll +) diff --git a/blender-build/build_environment/cmake/openpgl.cmake b/blender-build/build_environment/cmake/openpgl.cmake new file mode 100644 index 0000000..081b887 --- /dev/null +++ b/blender-build/build_environment/cmake/openpgl.cmake @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Note the utility apps may use png/tiff/gif system libraries, but the +# library itself does not depend on them, so should give no problems. + +set(OPENPGL_EXTRA_ARGS + -DOPENPGL_BUILD_STATIC=ON + -DOPENPGL_TBB_ROOT=${LIBDIR}/tbb + -DTBB_ROOT=${LIBDIR}/tbb + -DCMAKE_DEBUG_POSTFIX=_d +) + +if(TBB_STATIC_LIBRARY) + set(OPENPGL_EXTRA_ARGS + ${OPENPGL_EXTRA_ARGS} + -DOPENPGL_TBB_COMPONENT=tbb_static + ) +endif() + +ExternalProject_Add(external_openpgl + URL file://${PACKAGE_DIR}/${OPENPGL_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${OPENPGL_HASH_TYPE}=${OPENPGL_HASH} + PREFIX ${BUILD_DIR}/openpgl + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openpgl ${DEFAULT_CMAKE_FLAGS} ${OPENPGL_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/openpgl +) + +add_dependencies( + external_openpgl + external_tbb +) + +if(WIN32) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_openpgl after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/openpgl ${HARVEST_TARGET}/openpgl + DEPENDEES install + ) + else() + ExternalProject_Add_Step(external_openpgl after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openpgl/lib/openpgl_d.lib ${HARVEST_TARGET}/openpgl/lib/openpgl_d.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openpgl/lib/cmake/openpgl-${OPENPGL_SHORT_VERSION}/openpgl_Exports-debug.cmake ${HARVEST_TARGET}/openpgl/lib/cmake/openpgl-${OPENPGL_SHORT_VERSION}/openpgl_Exports-debug.cmake + DEPENDEES install + ) + endif() +endif() diff --git a/blender-build/build_environment/cmake/opensubdiv.cmake b/blender-build/build_environment/cmake/opensubdiv.cmake new file mode 100644 index 0000000..30c86df --- /dev/null +++ b/blender-build/build_environment/cmake/opensubdiv.cmake @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(OPENSUBDIV_EXTRA_ARGS + -DNO_LIB=OFF + -DNO_EXAMPLES=ON + -DNO_TUTORIALS=ON + -DNO_REGRESSION=ON + -DNO_PTEX=ON + -DNO_DOC=ON + -DNO_OMP=ON + -DNO_TBB=OFF + -DNO_CUDA=ON + -DNO_OPENCL=ON + -DNO_CLEW=ON + -DNO_OPENGL=OFF + -DNO_METAL=OFF + -DNO_DX=ON + -DNO_TESTS=ON + -DNO_GLTESTS=ON + -DNO_GLEW=ON + -DNO_GLFW=ON + -DNO_GLFW_X11=ON +) + +if(WIN32) + set(OPENSUBDIV_EXTRA_ARGS + ${OPENSUBDIV_EXTRA_ARGS} + -DTBB_INCLUDE_DIR=${LIBDIR}/tbb/include + -DTBB_LIBRARIES=${LIBDIR}/tbb/lib/tbb.lib + ) +else() + set(OPENSUBDIV_EXTRA_ARGS + ${OPENSUBDIV_EXTRA_ARGS} + -DTBB_LOCATION=${LIBDIR}/tbb + ) +endif() + +ExternalProject_Add(external_opensubdiv + URL file://${PACKAGE_DIR}/${OPENSUBDIV_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${OPENSUBDIV_HASH_TYPE}=${OPENSUBDIV_HASH} + PREFIX ${BUILD_DIR}/opensubdiv + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/opensubdiv -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${OPENSUBDIV_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/opensubdiv +) + +if(WIN32) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_opensubdiv after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/opensubdiv/lib ${HARVEST_TARGET}/opensubdiv/lib + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/opensubdiv/include ${HARVEST_TARGET}/opensubdiv/include + DEPENDEES install + ) + endif() + if(BUILD_MODE STREQUAL Debug) + ExternalProject_Add_Step(external_opensubdiv after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opensubdiv/lib/osdCPU.lib ${HARVEST_TARGET}/opensubdiv/lib/osdCPU_d.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/opensubdiv/lib/osdGPU.lib ${HARVEST_TARGET}/opensubdiv/lib/osdGPU_d.lib + DEPENDEES install + ) + endif() +endif() + +add_dependencies( + external_opensubdiv + external_tbb +) diff --git a/blender-build/build_environment/cmake/openvdb.cmake b/blender-build/build_environment/cmake/openvdb.cmake new file mode 100644 index 0000000..a81c4ce --- /dev/null +++ b/blender-build/build_environment/cmake/openvdb.cmake @@ -0,0 +1,94 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(BUILD_MODE STREQUAL Debug) + set(BLOSC_POST _d) +endif() + +set(OPENVDB_EXTRA_ARGS + ${DEFAULT_BOOST_FLAGS} + -DUSE_STATIC_DEPENDENCIES=OFF # This is the global toggle for static libs + # Once the above switch is off, you can set it + # for each individual library below. + -DBLOSC_USE_STATIC_LIBS=ON + -DTBB_USE_STATIC_LIBS=OFF + -DBoost_USE_STATIC_LIBS=OFF + -DZLIB_LIBRARY=${LIBDIR}/zlib/lib/${ZLIB_LIBRARY} + -DZLIB_INCLUDE_DIR=${LIBDIR}/zlib/include/ + -DBlosc_INCLUDE_DIR=${LIBDIR}/blosc/include/ + -DBlosc_LIBRARY=${LIBDIR}/blosc/lib/libblosc${BLOSC_POST}${LIBEXT} + -DBlosc_LIBRARY_RELEASE=${LIBDIR}/blosc/lib/libblosc${BLOSC_POST}${LIBEXT} + -DBlosc_LIBRARY_DEBUG=${LIBDIR}/blosc/lib/libblosc${BLOSC_POST}${LIBEXT} + -DOPENVDB_BUILD_UNITTESTS=OFF + -DOPENVDB_BUILD_NANOVDB=ON + -DNANOVDB_BUILD_TOOLS=OFF + -DBlosc_ROOT=${LIBDIR}/blosc/ + -DTBB_ROOT=${LIBDIR}/tbb/ + -DTbb_INCLUDE_DIR=${LIBDIR}/tbb/include + -DTbb_LEGACY_INCLUDE_DIR=${LIBDIR}/tbb/include + -DOPENVDB_CORE_SHARED=ON + -DOPENVDB_CORE_STATIC=OFF + -DOPENVDB_BUILD_BINARIES=OFF + -DCMAKE_DEBUG_POSTFIX=_d + -DBLOSC_USE_STATIC_LIBS=ON + -DUSE_NANOVDB=ON + -DOPENVDB_BUILD_PYTHON_MODULE=ON + -DOPENVDB_PYTHON_WRAP_ALL_GRID_TYPES=ON + -DUSE_NUMPY=ON + -DPython_EXECUTABLE=${PYTHON_BINARY} + + # OPENVDB_AX Disabled for now as it adds ~25MB distribution wise + # with no blender code depending on it, seems wasteful. + # -DOPENVDB_BUILD_AX=ON + # -DOPENVDB_AX_SHARED=ON + # -DOPENVDB_AX_STATIC=OFF + # -DLLVM_DIR=${LIBDIR}/llvm/lib/cmake/llvm +) + +set(OPENVDB_PATCH ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/openvdb/src/openvdb < ${PATCH_DIR}/openvdb.diff) +if(APPLE) + set(OPENVDB_PATCH + ${OPENVDB_PATCH} && + ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/openvdb/src/openvdb < ${PATCH_DIR}/openvdb_metal.diff + ) +endif() + +ExternalProject_Add(openvdb + URL file://${PACKAGE_DIR}/${OPENVDB_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${OPENVDB_HASH_TYPE}=${OPENVDB_HASH} + CMAKE_GENERATOR ${PLATFORM_ALT_GENERATOR} + PREFIX ${BUILD_DIR}/openvdb + PATCH_COMMAND ${OPENVDB_PATCH} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openvdb ${DEFAULT_CMAKE_FLAGS} ${OPENVDB_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/openvdb +) + +add_dependencies( + openvdb + external_tbb + external_boost + external_zlib + external_blosc + external_python + external_numpy +) + +if(WIN32) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(openvdb after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/openvdb/include ${HARVEST_TARGET}/openvdb/include + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openvdb/lib/openvdb.lib ${HARVEST_TARGET}/openvdb/lib/openvdb.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openvdb/bin/openvdb.dll ${HARVEST_TARGET}/openvdb/bin/openvdb.dll + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openvdb/lib/python${PYTHON_SHORT_VERSION}/site-packages/pyopenvdb.pyd ${HARVEST_TARGET}openvdb/python/pyopenvdb.pyd + DEPENDEES install + ) + endif() + if(BUILD_MODE STREQUAL Debug) + ExternalProject_Add_Step(openvdb after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openvdb/lib/openvdb_d.lib ${HARVEST_TARGET}/openvdb/lib/openvdb_d.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openvdb/bin/openvdb_d.dll ${HARVEST_TARGET}/openvdb/bin/openvdb_d.dll + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openvdb/lib/python${PYTHON_SHORT_VERSION}/site-packages/pyopenvdb_d.pyd ${HARVEST_TARGET}openvdb/python/pyopenvdb_d.pyd + DEPENDEES install + ) + endif() +endif() diff --git a/blender-build/build_environment/cmake/options.cmake b/blender-build/build_environment/cmake/options.cmake new file mode 100644 index 0000000..ec37d89 --- /dev/null +++ b/blender-build/build_environment/cmake/options.cmake @@ -0,0 +1,247 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(WIN32) + option(ENABLE_MINGW64 "Enable building of ffmpeg/iconv/libsndfile/fftw3 by installing mingw64" ON) +endif() +option(FORCE_CHECK_HASH "Force a check of all hashses during CMake the configure phase" OFF) + +cmake_host_system_information(RESULT NUM_CORES QUERY NUMBER_OF_LOGICAL_CORES) +set(MAKE_THREADS ${NUM_CORES} CACHE STRING "Number of threads to run make with") + +if(NOT BUILD_MODE) + set(BUILD_MODE "Release") + message(STATUS "Build type not specified: defaulting to a release build.") +endif() +message("BuildMode = ${BUILD_MODE}") + +if(BUILD_MODE STREQUAL "Debug") + set(LIBDIR ${CMAKE_CURRENT_BINARY_DIR}/Debug) + set(MESON_BUILD_TYPE -Dbuildtype=debug) +else() + set(LIBDIR ${CMAKE_CURRENT_BINARY_DIR}/Release) + set(MESON_BUILD_TYPE -Dbuildtype=release) +endif() + +set(DOWNLOAD_DIR "${CMAKE_CURRENT_BINARY_DIR}/downloads" CACHE STRING "Path for downloaded files") + +set(PACKAGE_DIR "${CMAKE_CURRENT_BINARY_DIR}/packages" CACHE PATH "default path for downloaded packages") +option(PACKAGE_USE_UPSTREAM_SOURCES "Use sources upstream to download the package sources, when OFF the blender mirror will be used" ON) + +file(TO_CMAKE_PATH ${DOWNLOAD_DIR} DOWNLOAD_DIR) +file(TO_CMAKE_PATH ${PACKAGE_DIR} PACKAGE_DIR) +set(PATCH_DIR ${CMAKE_CURRENT_SOURCE_DIR}/patches) +set(BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/build) + +message("LIBDIR = ${LIBDIR}") +message("DOWNLOAD_DIR = ${DOWNLOAD_DIR}") +message("PACKAGE_DIR = ${PACKAGE_DIR}") +message("PATCH_DIR = ${PATCH_DIR}") +message("BUILD_DIR = ${BUILD_DIR}") + +if(WIN32) + set(PATCH_CMD ${DOWNLOAD_DIR}/mingw/mingw64/msys/1.0/bin/patch.exe) + set(LIBEXT ".lib") + set(SHAREDLIBEXT ".lib") + set(LIBPREFIX "") + set(MESON ${LIBDIR}/python/Scripts/meson) + # For OIIO and OSL + set(COMMON_DEFINES /DPSAPI_VERSION=2 /DTINYFORMAT_ALLOW_WCHAR_STRINGS) + + if(MSVC_VERSION GREATER 1909) + set(COMMON_MSVC_FLAGS "/Wv:18") #some deps with warnings as error aren't quite ready for dealing with the new 2017 warnings. + endif() + string(APPEND COMMON_MSVC_FLAGS " /bigobj") + # To keep MSVC from oversubscribing the CPU, force it to single threaded mode + # msbuild/ninja will queue as many compile units as there are cores, no need for + # msvc to be internally threading as well. + string(APPEND COMMON_MSVC_FLAGS " /cgthreads1 ") + + if(WITH_OPTIMIZED_DEBUG) + set(BLENDER_CMAKE_C_FLAGS_DEBUG "/MDd ${COMMON_MSVC_FLAGS} /O2 /Ob2 /D_DEBUG /DPSAPI_VERSION=2 /DTINYFORMAT_ALLOW_WCHAR_STRINGS") + else() + set(BLENDER_CMAKE_C_FLAGS_DEBUG "/MDd ${COMMON_MSVC_FLAGS} /Zi /Ob0 /Od /RTC1 /D_DEBUG /DPSAPI_VERSION=2 /DTINYFORMAT_ALLOW_WCHAR_STRINGS") + endif() + set(BLENDER_CMAKE_C_FLAGS_MINSIZEREL "/MD ${COMMON_MSVC_FLAGS} /O1 /Ob1 /D NDEBUG /DPSAPI_VERSION=2 /DTINYFORMAT_ALLOW_WCHAR_STRINGS") + set(BLENDER_CMAKE_C_FLAGS_RELEASE "/MD ${COMMON_MSVC_FLAGS} /O2 /Ob2 /DNDEBUG /DPSAPI_VERSION=2 /DTINYFORMAT_ALLOW_WCHAR_STRINGS") + set(BLENDER_CMAKE_C_FLAGS_RELWITHDEBINFO "/MD ${COMMON_MSVC_FLAGS} /Zi /O2 /Ob1 /D NDEBUG /DPSAPI_VERSION=2 /DTINYFORMAT_ALLOW_WCHAR_STRINGS") + + if(WITH_OPTIMIZED_DEBUG) + set(BLENDER_CMAKE_CXX_FLAGS_DEBUG "/MDd ${COMMON_MSVC_FLAGS} /D_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS /O2 /Ob2 /D_DEBUG /D PLATFORM_WINDOWS /DPSAPI_VERSION=2 /DTINYFORMAT_ALLOW_WCHAR_STRINGS /DBOOST_DEBUG_PYTHON /DBOOST_ALL_NO_LIB") + else() + set(BLENDER_CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /D PLATFORM_WINDOWS /D_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS /MTd ${COMMON_MSVC_FLAGS} /Zi /Ob0 /Od /RTC1 /DPSAPI_VERSION=2 /DTINYFORMAT_ALLOW_WCHAR_STRINGS /DBOOST_DEBUG_PYTHON /DBOOST_ALL_NO_LIB") + endif() + set(BLENDER_CMAKE_CXX_FLAGS_MINSIZEREL "/MD /${COMMON_MSVC_FLAGS} /D_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS /O1 /Ob1 /D NDEBUG /D PLATFORM_WINDOWS /DPSAPI_VERSION=2 /DTINYFORMAT_ALLOW_WCHAR_STRINGS") + set(BLENDER_CMAKE_CXX_FLAGS_RELEASE "/MD ${COMMON_MSVC_FLAGS} /D_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS /O2 /Ob2 /D NDEBUG /D PLATFORM_WINDOWS /DPSAPI_VERSION=2 /DTINYFORMAT_ALLOW_WCHAR_STRINGS") + set(BLENDER_CMAKE_CXX_FLAGS_RELWITHDEBINFO "/MD ${COMMON_MSVC_FLAGS} /D_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS /Zi /O2 /Ob1 /D NDEBUG /D PLATFORM_WINDOWS /DPSAPI_VERSION=2 /DTINYFORMAT_ALLOW_WCHAR_STRINGS") + + # Set similar flags for CLANG compilation. + set(COMMON_CLANG_FLAGS "-D_DLL -D_MT") # Equivalent to MSVC /MD + + if(WITH_OPTIMIZED_DEBUG) + set(BLENDER_CLANG_CMAKE_C_FLAGS_DEBUG "${COMMON_CLANG_FLAGS} -Xclang --dependent-lib=msvcrtd -O2 -D_DEBUG -DPSAPI_VERSION=2 -DTINYFORMAT_ALLOW_WCHAR_STRINGS") + else() + set(BLENDER_CLANG_CMAKE_C_FLAGS_DEBUG "${COMMON_CLANG_FLAGS} -Xclang --dependent-lib=msvcrtd -g -D_DEBUG -DPSAPI_VERSION=2 -DTINYFORMAT_ALLOW_WCHAR_STRINGS") + endif() + set(BLENDER_CLANG_CMAKE_C_FLAGS_MINSIZEREL "${COMMON_CLANG_FLAGS} -Xclang --dependent-lib=msvcrt -Os -DNDEBUG -DPSAPI_VERSION=2 -DTINYFORMAT_ALLOW_WCHAR_STRINGS") + set(BLENDER_CLANG_CMAKE_C_FLAGS_RELEASE "${COMMON_CLANG_FLAGS} -Xclang --dependent-lib=msvcrt -O2 -DNDEBUG -DPSAPI_VERSION=2 -DTINYFORMAT_ALLOW_WCHAR_STRINGS") + set(BLENDER_CLANG_CMAKE_C_FLAGS_RELWITHDEBINFO "${COMMON_CLANG_FLAGS} -Xclang --dependent-lib=msvcrt -g -O2 -DNDEBUG -DPSAPI_VERSION=2 -DTINYFORMAT_ALLOW_WCHAR_STRINGS") + + if(WITH_OPTIMIZED_DEBUG) + set(BLENDER_CLANG_CMAKE_CXX_FLAGS_DEBUG "${COMMON_CLANG_FLAGS} -Xclang --dependent-lib=msvcrtd -D_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS -O2 -D_DEBUG -DPLATFORM_WINDOWS -DPSAPI_VERSION=2 -DTINYFORMAT_ALLOW_WCHAR_STRINGS -DBOOST_DEBUG_PYTHON -DBOOST_ALL_NO_LIB") + else() + set(BLENDER_CLANG_CMAKE_CXX_FLAGS_DEBUG "${COMMON_CLANG_FLAG} -Xclang --dependent-lib=msvcrtd -D_DEBUG -DPLATFORM_WINDOWS -D_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS -g -DPSAPI_VERSION=2 -DTINYFORMAT_ALLOW_WCHAR_STRINGS -DBOOST_DEBUG_PYTHON -DBOOST_ALL_NO_LIB") + endif() + set(BLENDER_CLANG_CMAKE_CXX_FLAGS_MINSIZEREL "${COMMON_CLANG_FLAGS} -Xclang --dependent-lib=msvcrt -D_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS -O2 -DNDEBUG -DPLATFORM_WINDOWS -DPSAPI_VERSION=2 -DTINYFORMAT_ALLOW_WCHAR_STRINGS") + set(BLENDER_CLANG_CMAKE_CXX_FLAGS_RELEASE "${COMMON_CLANG_FLAGS} -Xclang --dependent-lib=msvcrt -D_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS -O2 -DNDEBUG -DPLATFORM_WINDOWS -DPSAPI_VERSION=2 -DTINYFORMAT_ALLOW_WCHAR_STRINGS") + set(BLENDER_CLANG_CMAKE_CXX_FLAGS_RELWITHDEBINFO "${COMMON_CLANG_FLAGS} -Xclang --dependent-lib=msvcrt -D_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS -g -O2 -DNDEBUG -DPLATFORM_WINDOWS -DPSAPI_VERSION=2 -DTINYFORMAT_ALLOW_WCHAR_STRINGS") + + set(PLATFORM_FLAGS) + set(PLATFORM_CXX_FLAGS) + set(PLATFORM_CMAKE_FLAGS) + + set(MINGW_PATH ${DOWNLOAD_DIR}/mingw/mingw64) + set(MINGW_SHELL ming64sh.cmd) + set(PERL_SHELL ${DOWNLOAD_DIR}/perl/portableshell.bat) + set(MINGW_HOST x86_64-w64-mingw32) + + # some build systems like meson will respect the *nix like environment vars + # like CFLAGS and LDFlags but will still build with the MSVC compiler, so for + # those we need to empty out the gcc style flags that are normally in there. + set(CONFIGURE_ENV_MSVC + cd ${MINGW_PATH} && + call ${PERL_SHELL} && + call ${MINGW_SHELL} && + set path && + set CFLAGS= && + set LDFLAGS= + ) + + set(CONFIGURE_ENV + cd ${MINGW_PATH} && + call ${PERL_SHELL} && + call ${MINGW_SHELL} && + set path && + set CFLAGS=-g && + set LDFLAGS=-Wl,--as-needed -static-libgcc + ) + + set(CONFIGURE_ENV_NO_PERL + cd ${MINGW_PATH} && + call ${MINGW_SHELL} && + set path && + set CFLAGS=-g && + set LDFLAGS=-Wl,--as-needed -static-libgcc + ) + + set(CONFIGURE_COMMAND sh ./configure) + set(CONFIGURE_COMMAND_NO_TARGET ${CONFIGURE_COMMAND}) +else() + set(PATCH_CMD patch) + set(LIBEXT ".a") + set(LIBPREFIX "lib") + set(MESON ${LIBDIR}/python/bin/meson) + if(APPLE) + set(SHAREDLIBEXT ".dylib") + + # Use same Xcode detection as Blender itself. + include(../cmake/platform/platform_apple_xcode.cmake) + + if("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64") + set(BLENDER_PLATFORM_ARM ON) + endif() + + set(PLATFORM_CFLAGS "-isysroot ${CMAKE_OSX_SYSROOT} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET} -arch ${CMAKE_OSX_ARCHITECTURES}") + set(PLATFORM_CXXFLAGS "-isysroot ${CMAKE_OSX_SYSROOT} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET} -std=c++17 -stdlib=libc++ -arch ${CMAKE_OSX_ARCHITECTURES}") + set(PLATFORM_LDFLAGS "-isysroot ${CMAKE_OSX_SYSROOT} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET} -arch ${CMAKE_OSX_ARCHITECTURES}") + if("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "x86_64") + set(PLATFORM_BUILD_TARGET --build=x86_64-apple-darwin17.0.0) # OS X 10.13 + else() + set(PLATFORM_BUILD_TARGET --build=aarch64-apple-darwin20.0.0) # macOS 11.00 + endif() + set(PLATFORM_CMAKE_FLAGS + -DCMAKE_OSX_ARCHITECTURES:STRING=${CMAKE_OSX_ARCHITECTURES} + -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=${CMAKE_OSX_DEPLOYMENT_TARGET} + -DCMAKE_OSX_SYSROOT:PATH=${CMAKE_OSX_SYSROOT} + ) + else() + set(SHAREDLIBEXT ".so") + + if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "aarch64") + set(BLENDER_PLATFORM_ARM ON) + endif() + + set(PLATFORM_CFLAGS "-fPIC") + set(PLATFORM_CXXFLAGS "-std=c++17 -fPIC") + set(PLATFORM_LDFLAGS) + set(PLATFORM_BUILD_TARGET) + set(PLATFORM_CMAKE_FLAGS -DCMAKE_INSTALL_LIBDIR=lib) + endif() + + if(WITH_OPTIMIZED_DEBUG) + set(BLENDER_CMAKE_C_FLAGS_DEBUG "-O2 -DNDEBUG ${PLATFORM_CFLAGS}") + else() + set(BLENDER_CMAKE_C_FLAGS_DEBUG "-g ${PLATFORM_CFLAGS}") + endif() + set(BLENDER_CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG ${PLATFORM_CFLAGS}") + set(BLENDER_CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG ${PLATFORM_CFLAGS}") + set(BLENDER_CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g -DNDEBUG ${PLATFORM_CFLAGS}") + + if(WITH_OPTIMIZED_DEBUG) + set(BLENDER_CMAKE_CXX_FLAGS_DEBUG "-O2 -DNDEBUG ${PLATFORM_CXXFLAGS}") + else() + set(BLENDER_CMAKE_CXX_FLAGS_DEBUG "-g ${PLATFORM_CXXFLAGS}") + endif() + + set(BLENDER_CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG ${PLATFORM_CXXFLAGS}") + set(BLENDER_CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG ${PLATFORM_CXXFLAGS}") + set(BLENDER_CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DNDEBUG ${PLATFORM_CXXFLAGS}") + + set(CONFIGURE_ENV + export MACOSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET} && + export MACOSX_SDK_VERSION=${CMAKE_OSX_DEPLOYMENT_TARGET} && + export CFLAGS=${PLATFORM_CFLAGS} && + export CXXFLAGS=${PLATFORM_CXXFLAGS} && + export LDFLAGS=${PLATFORM_LDFLAGS} + ) + set(CONFIGURE_ENV_NO_PERL ${CONFIGURE_ENV}) + set(CONFIGURE_COMMAND ./configure ${PLATFORM_BUILD_TARGET}) + set(CONFIGURE_COMMAND_NO_TARGET ./configure) +endif() + +set(DEFAULT_CMAKE_FLAGS + -DCMAKE_BUILD_TYPE=${BUILD_MODE} + -DCMAKE_C_FLAGS_DEBUG=${BLENDER_CMAKE_C_FLAGS_DEBUG} + -DCMAKE_C_FLAGS_MINSIZEREL=${BLENDER_CMAKE_C_FLAGS_MINSIZEREL} + -DCMAKE_C_FLAGS_RELEASE=${BLENDER_CMAKE_C_FLAGS_RELEASE} + -DCMAKE_C_FLAGS_RELWITHDEBINFO=${BLENDER_CMAKE_C_FLAGS_RELWITHDEBINFO} + -DCMAKE_CXX_FLAGS_DEBUG=${BLENDER_CMAKE_CXX_FLAGS_DEBUG} + -DCMAKE_CXX_FLAGS_MINSIZEREL=${BLENDER_CMAKE_CXX_FLAGS_MINSIZEREL} + -DCMAKE_CXX_FLAGS_RELEASE=${BLENDER_CMAKE_CXX_FLAGS_RELEASE} + -DCMAKE_CXX_FLAGS_RELWITHDEBINFO=${CMAKE_CXX_FLAGS_RELWITHDEBINFO} + -DCMAKE_CXX_STANDARD=17 + ${PLATFORM_CMAKE_FLAGS} +) + +if(WIN32) + if(BUILD_MODE STREQUAL Debug) + set(ZLIB_LIBRARY zlibstaticd${LIBEXT}) + else() + set(ZLIB_LIBRARY zlibstatic${LIBEXT}) + endif() +else() + set(ZLIB_LIBRARY libz${LIBEXT}) +endif() + +if(MSVC) + set_property(GLOBAL PROPERTY USE_FOLDERS ON) +endif() + +set(CMAKE_INSTALL_MESSAGE LAZY) + +# On windows we sometimes want to build with ninja, but not all projects quite +# yet, so for select project we pass PLATFORM_ALT_GENERATOR as the generator +if(WIN32) + set(PLATFORM_ALT_GENERATOR "Ninja") +else() + set(PLATFORM_ALT_GENERATOR "Unix Makefiles") +endif() diff --git a/blender-build/build_environment/cmake/opus.cmake b/blender-build/build_environment/cmake/opus.cmake new file mode 100644 index 0000000..c5d1d20 --- /dev/null +++ b/blender-build/build_environment/cmake/opus.cmake @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +ExternalProject_Add(external_opus + URL file://${PACKAGE_DIR}/${OPUS_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${OPUS_HASH_TYPE}=${OPUS_HASH} + PREFIX ${BUILD_DIR}/opus + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/opus/src/external_opus/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/opus + --disable-shared + --enable-static + --with-pic + --disable-maintainer-mode + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/opus/src/external_opus/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/opus/src/external_opus/ && make install + INSTALL_DIR ${LIBDIR}/opus +) + +if(MSVC) + set_target_properties(external_opus PROPERTIES FOLDER Mingw) +endif() diff --git a/blender-build/build_environment/cmake/osl.cmake b/blender-build/build_environment/cmake/osl.cmake new file mode 100644 index 0000000..05b079b --- /dev/null +++ b/blender-build/build_environment/cmake/osl.cmake @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(WIN32) + set(OSL_CMAKE_CXX_STANDARD_LIBRARIES "kernel32${LIBEXT} user32${LIBEXT} gdi32${LIBEXT} winspool${LIBEXT} shell32${LIBEXT} ole32${LIBEXT} oleaut32${LIBEXT} uuid${LIBEXT} comdlg32${LIBEXT} advapi32${LIBEXT} psapi${LIBEXT}") + set(OSL_FLEX_BISON -DFLEX_EXECUTABLE=${LIBDIR}/flexbison/win_flex.exe -DBISON_EXECUTABLE=${LIBDIR}/flexbison/win_bison.exe) +else() + set(OSL_CMAKE_CXX_STANDARD_LIBRARIES) + set(OSL_FLEX_BISON) + set(OSL_OPENIMAGEIO_LIBRARY "${LIBDIR}/openimageio/lib/OpenImageIO${SHAREDLIBEXT};${LIBDIR}/png/lib/${LIBPREFIX}png16${LIBEXT};${LIBDIR}/jpeg/lib/${LIBPREFIX}jpeg${LIBEXT};${LIBDIR}/tiff/lib/${LIBPREFIX}tiff${LIBEXT};${LIBDIR}/openexr/lib/IlmImf${OPENEXR_VERSION_POSTFIX}${SHAREDLIBEXT}") +endif() + +set(OSL_EXTRA_ARGS + ${DEFAULT_BOOST_FLAGS} + -DOpenEXR_ROOT=${LIBDIR}/openexr/ + -DOpenImageIO_ROOT=${LIBDIR}/openimageio/ + -DOSL_BUILD_TESTS=OFF + -DOSL_BUILD_MATERIALX=OFF + -DPNG_ROOT=${LIBDIR}/png + -DZLIB_LIBRARY=${LIBDIR}/zlib/lib/${ZLIB_LIBRARY} + -DZLIB_INCLUDE_DIR=${LIBDIR}/zlib/include/ + ${OSL_FLEX_BISON} + -DCMAKE_CXX_STANDARD_LIBRARIES=${OSL_CMAKE_CXX_STANDARD_LIBRARIES} + -DBUILD_SHARED_LIBS=OFF + -DLINKSTATIC=OFF + -DOSL_BUILD_PLUGINS=OFF + -DSTOP_ON_WARNING=OFF + -DUSE_LLVM_BITCODE=OFF + -DLLVM_ROOT=${LIBDIR}/llvm/ + -DLLVM_DIRECTORY=${LIBDIR}/llvm/ + -DUSE_PARTIO=OFF + -DUSE_QT=OFF + -DUSE_Qt5=OFF + -DINSTALL_DOCS=OFF + -Dpugixml_ROOT=${LIBDIR}/pugixml + -DTIFF_ROOT=${LIBDIR}/tiff + -DJPEG_ROOT=${LIBDIR}/jpeg + -DUSE_PYTHON=OFF + -DImath_ROOT=${LIBDIR}/imath + -DUSE_OIIO_STATIC=OFF +) + +ExternalProject_Add(external_osl + URL file://${PACKAGE_DIR}/${OSL_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + CMAKE_GENERATOR ${PLATFORM_ALT_GENERATOR} + LIST_SEPARATOR ^^ + URL_HASH ${OSL_HASH_TYPE}=${OSL_HASH} + PREFIX ${BUILD_DIR}/osl + PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/osl/src/external_osl < ${PATCH_DIR}/osl.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/osl -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} ${DEFAULT_CMAKE_FLAGS} ${OSL_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/osl +) + +add_dependencies( + external_osl + external_boost + ll + external_openexr + external_zlib + external_openimageio + external_pugixml +) +if(WIN32) + add_dependencies( + external_osl + external_flexbison + ) +elseif(UNIX AND NOT APPLE) + add_dependencies( + external_osl + external_flex + ) +endif() + +if(WIN32) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_osl after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/osl/ ${HARVEST_TARGET}/osl + DEPENDEES install + ) + endif() + if(BUILD_MODE STREQUAL Debug) + ExternalProject_Add_Step(external_osl after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/osl/lib/oslcomp.lib ${HARVEST_TARGET}/osl/lib/oslcomp_d.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/osl/lib/oslexec.lib ${HARVEST_TARGET}/osl/lib/oslexec_d.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/osl/lib/oslquery.lib ${HARVEST_TARGET}/osl/lib/oslquery_d.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/osl/lib/oslnoise.lib ${HARVEST_TARGET}/osl/lib/oslnoise_d.lib + DEPENDEES install + ) + endif() +endif() diff --git a/blender-build/build_environment/cmake/package_python.cmake b/blender-build/build_environment/cmake/package_python.cmake new file mode 100644 index 0000000..8b3bc77 --- /dev/null +++ b/blender-build/build_environment/cmake/package_python.cmake @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(MSVC) + set(PYTARGET ${HARVEST_TARGET}/python/${PYTHON_SHORT_VERSION_NO_DOTS}) + set(PYSRC ${LIBDIR}/python/) + + if(BUILD_MODE STREQUAL Release) + add_custom_command( + OUTPUT ${PYTARGET}/bin/python${PYTHON_POSTFIX}.exe + COMMAND echo packaging python + COMMAND echo this should output at ${PYTARGET}/bin/python${PYTHON_POSTFIX}.exe + COMMAND ${CMAKE_COMMAND} -E make_directory ${PYTARGET}/libs + COMMAND ${CMAKE_COMMAND} -E copy ${PYSRC}/libs/python${PYTHON_SHORT_VERSION_NO_DOTS}.lib ${PYTARGET}/libs/python${PYTHON_SHORT_VERSION_NO_DOTS}.lib + COMMAND ${CMAKE_COMMAND} -E copy ${PYSRC}/python.exe ${PYTARGET}/bin/python.exe + COMMAND ${CMAKE_COMMAND} -E copy ${PYSRC}/python${PYTHON_SHORT_VERSION_NO_DOTS}.dll ${PYTARGET}/bin/python${PYTHON_SHORT_VERSION_NO_DOTS}.dll + COMMAND ${CMAKE_COMMAND} -E copy ${PYSRC}/python3${PYTHON_POSTFIX}.dll ${PYTARGET}/bin/python3${PYTHON_POSTFIX}.dll + COMMAND ${CMAKE_COMMAND} -E copy ${PYSRC}/python${PYTHON_SHORT_VERSION_NO_DOTS}.pdb ${PYTARGET}/libs/python${PYTHON_SHORT_VERSION_NO_DOTS}.pdb + COMMAND ${CMAKE_COMMAND} -E copy_directory ${PYSRC}/include/ ${PYTARGET}/include/ + COMMAND ${CMAKE_COMMAND} -E copy_directory ${PYSRC}/lib/ ${PYTARGET}/lib/ + COMMAND ${CMAKE_COMMAND} -E copy_directory ${PYSRC}/DLLs/ ${PYTARGET}/DLLs/ + COMMAND cd ${PYTARGET}/lib/ && for /d /r . %%d in (__pycache__) do @if exist "%%d" echo "%%d" && rd /s/q "%%d" + ) + add_custom_target(Package_Python ALL DEPENDS external_python external_numpy external_python_site_packages OUTPUT ${HARVEST_TARGET}/python/${PYTHON_SHORT_VERSION_NO_DOTS}/bin/python${PYTHON_POSTFIX}.exe) + endif() + + if(BUILD_MODE STREQUAL Debug) + add_custom_command( + OUTPUT ${PYTARGET}/bin/python${PYTHON_POSTFIX}.exe + COMMAND echo packaging python + COMMAND echo this should output at ${PYTARGET}/bin/python${PYTHON_POSTFIX}.exe + COMMAND ${CMAKE_COMMAND} -E make_directory ${PYTARGET}/libs + COMMAND ${CMAKE_COMMAND} -E copy ${PYSRC}/libs/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.lib ${PYTARGET}/libs/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.lib + COMMAND ${CMAKE_COMMAND} -E copy ${PYSRC}/python${PYTHON_POSTFIX}.exe ${PYTARGET}/bin/python${PYTHON_POSTFIX}.exe + COMMAND ${CMAKE_COMMAND} -E copy ${PYSRC}/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.dll ${PYTARGET}/bin/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.dll + COMMAND ${CMAKE_COMMAND} -E copy ${PYSRC}/python3${PYTHON_POSTFIX}.dll ${PYTARGET}/bin/python3${PYTHON_POSTFIX}.dll + COMMAND ${CMAKE_COMMAND} -E copy ${PYSRC}/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.pdb ${PYTARGET}/libs/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.pdb + COMMAND ${CMAKE_COMMAND} -E copy_directory ${PYSRC}/include/ ${PYTARGET}/include/ + COMMAND ${CMAKE_COMMAND} -E copy_directory ${PYSRC}/lib/ ${PYTARGET}/lib/ + COMMAND ${CMAKE_COMMAND} -E copy_directory ${PYSRC}/DLLs/ ${PYTARGET}/DLLs/ + COMMAND cd ${PYTARGET}/lib/ && for /d /r . %%d in (__pycache__) do @if exist "%%d" echo "%%d" && rd /s/q "%%d" + ) + add_custom_target(Package_Python ALL DEPENDS external_python external_numpy external_python_site_packages OUTPUT ${PYTARGET}/bin/python${PYTHON_POSTFIX}.exe) + endif() +endif() diff --git a/blender-build/build_environment/cmake/png.cmake b/blender-build/build_environment/cmake/png.cmake new file mode 100644 index 0000000..371f260 --- /dev/null +++ b/blender-build/build_environment/cmake/png.cmake @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(PNG_EXTRA_ARGS + -DZLIB_LIBRARY=${LIBDIR}/zlib/lib/${ZLIB_LIBRARY} + -DZLIB_INCLUDE_DIR=${LIBDIR}/zlib/include/ + -DPNG_STATIC=ON +) + +if(BLENDER_PLATFORM_ARM) + set(PNG_EXTRA_ARGS ${PNG_EXTRA_ARGS} -DPNG_HARDWARE_OPTIMIZATIONS=ON -DPNG_ARM_NEON=on -DCMAKE_SYSTEM_PROCESSOR="aarch64") +endif() + +ExternalProject_Add(external_png + URL file://${PACKAGE_DIR}/${PNG_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${PNG_HASH_TYPE}=${PNG_HASH} + PREFIX ${BUILD_DIR}/png + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/png ${DEFAULT_CMAKE_FLAGS} ${PNG_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/png +) + +add_dependencies( + external_png + external_zlib +) + +if(WIN32 AND BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_png after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/png/include/ ${HARVEST_TARGET}/png/include/ + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/png/lib/libpng16_static${LIBEXT} ${HARVEST_TARGET}/png/lib/libpng${LIBEXT} + DEPENDEES install + ) +endif() + +if(WIN32 AND BUILD_MODE STREQUAL Debug) + ExternalProject_Add_Step(external_png after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/png/lib/libpng16_staticd${LIBEXT} ${LIBDIR}/png/lib/libpng16${LIBEXT} + DEPENDEES install + ) +endif() diff --git a/blender-build/build_environment/cmake/potrace.cmake b/blender-build/build_environment/cmake/potrace.cmake new file mode 100644 index 0000000..853594a --- /dev/null +++ b/blender-build/build_environment/cmake/potrace.cmake @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(POTRACE_EXTRA_ARGS +) + +if((WIN32 AND BUILD_MODE STREQUAL Release) OR UNIX) + ExternalProject_Add(external_potrace + URL file://${PACKAGE_DIR}/${POTRACE_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${POTRACE_HASH_TYPE}=${POTRACE_HASH} + PREFIX ${BUILD_DIR}/potrace + PATCH_COMMAND ${CMAKE_COMMAND} -E copy ${PATCH_DIR}/cmakelists_potrace.txt ${BUILD_DIR}/potrace/src/external_potrace/CMakeLists.txt + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/potrace ${DEFAULT_CMAKE_FLAGS} ${POTRACE_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/potrace + ) + if(WIN32) + ExternalProject_Add_Step(external_potrace after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/potrace ${HARVEST_TARGET}/potrace + DEPENDEES install + ) + endif() +endif() diff --git a/blender-build/build_environment/cmake/pthreads.cmake b/blender-build/build_environment/cmake/pthreads.cmake new file mode 100644 index 0000000..59521c7 --- /dev/null +++ b/blender-build/build_environment/cmake/pthreads.cmake @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(WIN32) + + if(MSVC14) # vs2015 has timespec + set(PTHREAD_CPPFLAGS "/I. /DHAVE_CONFIG_H /D_TIMESPEC_DEFINED ") + else() # everything before doesn't + set(PTHREAD_CPPFLAGS "/I. /DHAVE_CONFIG_H ") + endif() + + set(PTHREADS_BUILD cd ${BUILD_DIR}/pthreads/src/external_pthreads/ && cd && nmake VC-static /e CPPFLAGS=${PTHREAD_CPPFLAGS}) + + ExternalProject_Add(external_pthreads + URL file://${PACKAGE_DIR}/${PTHREADS_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${PTHREADS_HASH_TYPE}=${PTHREADS_HASH} + PREFIX ${BUILD_DIR}/pthreads + CONFIGURE_COMMAND echo . + PATCH_COMMAND COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/pthreads/src/external_pthreads < ${PATCH_DIR}/pthreads.diff + BUILD_COMMAND ${PTHREADS_BUILD} + INSTALL_COMMAND COMMAND + ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/pthreads/src/external_pthreads/libpthreadVC3${LIBEXT} ${LIBDIR}/pthreads/lib/pthreadVC3${LIBEXT} && + ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/pthreads/src/external_pthreads/pthread.h ${LIBDIR}/pthreads/inc/pthread.h && + ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/pthreads/src/external_pthreads/sched.h ${LIBDIR}/pthreads/inc/sched.h && + ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/pthreads/src/external_pthreads/semaphore.h ${LIBDIR}/pthreads/inc/semaphore.h && + ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/pthreads/src/external_pthreads/_ptw32.h ${LIBDIR}/pthreads/inc/_ptw32.h + INSTALL_DIR ${LIBDIR}/pthreads + ) + + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_pthreads after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/pthreads/inc/ ${HARVEST_TARGET}/pthreads/include/ + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/pthreads/lib/ ${HARVEST_TARGET}/pthreads/lib + DEPENDEES install + ) + endif() +endif() diff --git a/blender-build/build_environment/cmake/pugixml.cmake b/blender-build/build_environment/cmake/pugixml.cmake new file mode 100644 index 0000000..ddd29bf --- /dev/null +++ b/blender-build/build_environment/cmake/pugixml.cmake @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(PUGIXML_EXTRA_ARGS +) + +ExternalProject_Add(external_pugixml + URL file://${PACKAGE_DIR}/${PUGIXML_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${PUGIXML_HASH_TYPE}=${PUGIXML_HASH} + PREFIX ${BUILD_DIR}/pugixml + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/pugixml ${DEFAULT_CMAKE_FLAGS} ${PUGIXML_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/pugixml +) +if(WIN32) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_pugixml after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/pugixml ${HARVEST_TARGET}/pugixml + DEPENDEES install + ) + endif() + if(BUILD_MODE STREQUAL Debug) + ExternalProject_Add_Step(external_pugixml after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/pugixml/lib/pugixml.lib ${HARVEST_TARGET}/pugixml/lib/pugixml_d.lib + DEPENDEES install + ) + endif() +endif() diff --git a/blender-build/build_environment/cmake/pybind11.cmake b/blender-build/build_environment/cmake/pybind11.cmake new file mode 100644 index 0000000..986da7f --- /dev/null +++ b/blender-build/build_environment/cmake/pybind11.cmake @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(PYBIND11_EXTRA_ARGS + -DPYBIND11_TEST=OFF + -DPYTHON_EXECUTABLE=${PYTHON_BINARY} +) + +ExternalProject_Add(external_pybind11 + URL file://${PACKAGE_DIR}/${PYBIND11_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${PYBIND11_HASH_TYPE}=${PYBIND11_HASH} + PREFIX ${BUILD_DIR}/pybind11 + CMAKE_GENERATOR ${PLATFORM_ALT_GENERATOR} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/pybind11 ${DEFAULT_CMAKE_FLAGS} ${PYBIND11_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/pybind11 +) + +add_dependencies( + external_pybind11 + external_python +) diff --git a/blender-build/build_environment/cmake/pystring.cmake b/blender-build/build_environment/cmake/pystring.cmake new file mode 100644 index 0000000..dd4ea98 --- /dev/null +++ b/blender-build/build_environment/cmake/pystring.cmake @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(PYSTRING_EXTRA_ARGS +) + +ExternalProject_Add(external_pystring + URL file://${PACKAGE_DIR}/${PYSTRING_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${PYSTRING_HASH_TYPE}=${PYSTRING_HASH} + PREFIX ${BUILD_DIR}/pystring + PATCH_COMMAND ${CMAKE_COMMAND} -E copy ${PATCH_DIR}/cmakelists_pystring.txt ${BUILD_DIR}/pystring/src/external_pystring/CMakeLists.txt + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/pystring ${DEFAULT_CMAKE_FLAGS} ${PYSTRING_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/pystring +) + +if(WIN32) + ExternalProject_Add_Step(external_pystring after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/pystring/lib ${HARVEST_TARGET}/pystring/lib + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/pystring/include ${HARVEST_TARGET}/pystring/include + DEPENDEES install + ) +endif() diff --git a/blender-build/build_environment/cmake/python.cmake b/blender-build/build_environment/cmake/python.cmake new file mode 100644 index 0000000..8d8710f --- /dev/null +++ b/blender-build/build_environment/cmake/python.cmake @@ -0,0 +1,143 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(PYTHON_POSTFIX) +if(BUILD_MODE STREQUAL Debug) + set(PYTHON_POSTFIX _d) + set(PYTHON_EXTRA_INSTLAL_FLAGS -d) +endif() + +if(WIN32) + set(PYTHON_BINARY_INTERNAL ${BUILD_DIR}/python/src/external_python/PCBuild/amd64/python${PYTHON_POSTFIX}.exe) + set(PYTHON_BINARY ${LIBDIR}/python/python${PYTHON_POSTFIX}.exe) + set(PYTHON_SRC ${BUILD_DIR}/python/src/external_python/) + macro(cmake_to_dos_path MsysPath ResultingPath) + string(REPLACE "/" "\\" ${ResultingPath} "${MsysPath}") + endmacro() + + set(PYTHON_EXTERNALS_FOLDER ${BUILD_DIR}/python/src/external_python/externals) + set(ZLIB_SOURCE_FOLDER ${BUILD_DIR}/zlib/src/external_zlib) + set(SSL_SOURCE_FOLDER ${BUILD_DIR}/ssl/src/external_ssl) + set(DOWNLOADS_EXTERNALS_FOLDER ${DOWNLOAD_DIR}/externals) + + cmake_to_dos_path(${PYTHON_EXTERNALS_FOLDER} PYTHON_EXTERNALS_FOLDER_DOS) + cmake_to_dos_path(${ZLIB_SOURCE_FOLDER} ZLIB_SOURCE_FOLDER_DOS) + cmake_to_dos_path(${SSL_SOURCE_FOLDER} SSL_SOURCE_FOLDER_DOS) + cmake_to_dos_path(${DOWNLOADS_EXTERNALS_FOLDER} DOWNLOADS_EXTERNALS_FOLDER_DOS) + + ExternalProject_Add(external_python + URL file://${PACKAGE_DIR}/${PYTHON_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${PYTHON_HASH_TYPE}=${PYTHON_HASH} + PREFIX ${BUILD_DIR}/python + # Python will download its own deps and there's very little we can do about + # that beyond placing some code in their externals dir before it tries. + # the foldernames *HAVE* to match the ones inside pythons get_externals.cmd. + # regardless of the version actually in there. + PATCH_COMMAND mkdir ${PYTHON_EXTERNALS_FOLDER_DOS} && + mklink /J ${PYTHON_EXTERNALS_FOLDER_DOS}\\zlib-1.2.13 ${ZLIB_SOURCE_FOLDER_DOS} && + mklink /J ${PYTHON_EXTERNALS_FOLDER_DOS}\\openssl-1.1.1u ${SSL_SOURCE_FOLDER_DOS} && + ${CMAKE_COMMAND} -E copy ${ZLIB_SOURCE_FOLDER}/../external_zlib-build/zconf.h ${PYTHON_EXTERNALS_FOLDER}/zlib-1.2.13/zconf.h && + ${PATCH_CMD} --verbose -p1 -d ${BUILD_DIR}/python/src/external_python < ${PATCH_DIR}/python_windows.diff + CONFIGURE_COMMAND echo "." + BUILD_COMMAND ${CONFIGURE_ENV_MSVC} && cd ${BUILD_DIR}/python/src/external_python/pcbuild/ && set IncludeTkinter=false && set LDFLAGS=/DEBUG && call prepare_ssl.bat && call build.bat -e -p x64 -c ${BUILD_MODE} + INSTALL_COMMAND ${PYTHON_BINARY_INTERNAL} ${PYTHON_SRC}/PC/layout/main.py -b ${PYTHON_SRC}/PCbuild/amd64 -s ${PYTHON_SRC} -t ${PYTHON_SRC}/tmp/ --include-stable --include-pip --include-dev --include-launchers --include-venv --include-symbols ${PYTHON_EXTRA_INSTLAL_FLAGS} --copy ${LIBDIR}/python + ) + add_dependencies( + external_python + external_zlib + ) +else() + if(APPLE) + # Disable functions that can be in 10.13 sdk but aren't available on 10.9 target. + # + # Disable libintl (gettext library) as it might come from Homebrew, which makes + # it so test program compiles, but the Python does not. This is because for Python + # we use isysroot, which seems to forbid using libintl.h. + # The gettext functionality seems to come from CoreFoundation, so should be all fine. + set(PYTHON_FUNC_CONFIGS + export ac_cv_func_futimens=no && + export ac_cv_func_utimensat=no && + export ac_cv_func_basename_r=no && + export ac_cv_func_clock_getres=no && + export ac_cv_func_clock_gettime=no && + export ac_cv_func_clock_settime=no && + export ac_cv_func_dirname_r=no && + export ac_cv_func_getentropy=no && + export ac_cv_func_mkostemp=no && + export ac_cv_func_mkostemps=no && + export ac_cv_func_timingsafe_bcmp=no && + export ac_cv_header_libintl_h=no && + export ac_cv_lib_intl_textdomain=no + ) + if("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64") + set(PYTHON_FUNC_CONFIGS ${PYTHON_FUNC_CONFIGS} && export PYTHON_DECIMAL_WITH_MACHINE=ansi64) + endif() + set(PYTHON_CONFIGURE_ENV ${CONFIGURE_ENV} && ${PYTHON_FUNC_CONFIGS}) + else() + set(PYTHON_CONFIGURE_ENV ${CONFIGURE_ENV}) + endif() + set(PYTHON_BINARY ${LIBDIR}/python/bin/python${PYTHON_SHORT_VERSION}) + # Link against zlib statically (Unix). Avoid rpath issues (macOS). + set(PYTHON_PATCH ${PATCH_CMD} --verbose -p1 -d ${BUILD_DIR}/python/src/external_python < ${PATCH_DIR}/python_unix.diff) + set(PYTHON_CONFIGURE_EXTRA_ARGS "") + set(PYTHON_CFLAGS "-I${LIBDIR}/sqlite/include -I${LIBDIR}/bzip2/include -I${LIBDIR}/lzma/include -I${LIBDIR}/zlib/include ${PLATFORM_CFLAGS}") + set(PYTHON_LDFLAGS "-L${LIBDIR}/ffi/lib -L${LIBDIR}/sqlite/lib -L${LIBDIR}/bzip2/lib -L${LIBDIR}/lzma/lib -L${LIBDIR}/zlib/lib ${PLATFORM_LDFLAGS}") + set(PYTHON_CONFIGURE_EXTRA_ENV + export CFLAGS=${PYTHON_CFLAGS} && + export CPPFLAGS=${PYTHON_CFLAGS} && + export LDFLAGS=${PYTHON_LDFLAGS} && + export PKG_CONFIG_PATH=${LIBDIR}/ffi/lib/pkgconfig:${LIBDIR}/ssl/lib/pkgconfig:${LIBDIR}/ssl/lib64/pkgconfig) + + # NOTE: untested on APPLE so far. + if(NOT APPLE) + set(PYTHON_CONFIGURE_EXTRA_ARGS + ${PYTHON_CONFIGURE_EXTRA_ARGS} + # Used on most release Linux builds (Fedora for e.g.), + # increases build times noticeably with the benefit of a modest speedup at runtime. + --enable-optimizations + # While LTO is OK when building on the same system, it's incompatible across GCC versions, + # making it impractical for developers to build against, so keep it disabled. + # `--with-lto` + ) + endif() + + ExternalProject_Add(external_python + URL file://${PACKAGE_DIR}/${PYTHON_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${PYTHON_HASH_TYPE}=${PYTHON_HASH} + PREFIX ${BUILD_DIR}/python + PATCH_COMMAND ${PYTHON_PATCH} + CONFIGURE_COMMAND ${PYTHON_CONFIGURE_ENV} && ${PYTHON_CONFIGURE_EXTRA_ENV} && cd ${BUILD_DIR}/python/src/external_python/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/python ${PYTHON_CONFIGURE_EXTRA_ARGS} + BUILD_COMMAND ${PYTHON_CONFIGURE_ENV} && cd ${BUILD_DIR}/python/src/external_python/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${PYTHON_CONFIGURE_ENV} && cd ${BUILD_DIR}/python/src/external_python/ && make install + INSTALL_DIR ${LIBDIR}/python) +endif() + +add_dependencies( + external_python + external_ssl + external_zlib +) +if(UNIX) + add_dependencies( + external_python + external_bzip2 + external_ffi + external_lzma + external_sqlite + ) +endif() + +if(WIN32) + if(BUILD_MODE STREQUAL Debug) + ExternalProject_Add_Step(external_python after_install + # Boost can't keep it self from linking release python + # in a debug configuration even if all options are set + # correctly to instruct it to use the debug version + # of python. So just copy the debug imports file over + # and call it a day... + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/python/libs/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.lib ${LIBDIR}/python/libs/python${PYTHON_SHORT_VERSION_NO_DOTS}.lib + DEPENDEES install + ) + endif() +endif() diff --git a/blender-build/build_environment/cmake/python.map b/blender-build/build_environment/cmake/python.map new file mode 100644 index 0000000..1c11c33 --- /dev/null +++ b/blender-build/build_environment/cmake/python.map @@ -0,0 +1,9 @@ +{ +global: + Py*; + _Py*; + _py*; +local: + *; +}; + diff --git a/blender-build/build_environment/cmake/python_site_packages.cmake b/blender-build/build_environment/cmake/python_site_packages.cmake new file mode 100644 index 0000000..93fcd20 --- /dev/null +++ b/blender-build/build_environment/cmake/python_site_packages.cmake @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(WIN32 AND BUILD_MODE STREQUAL Debug) + set(SITE_PACKAGES_EXTRA --global-option build --global-option --debug) + # zstandard is determined to build and link release mode libs in a debug + # configuration, the only way to make it happy is to bend to its will + # and give it a library to link with. + set( + PIP_CONFIGURE_COMMAND ${CMAKE_COMMAND} -E copy + ${LIBDIR}/python/libs/python${PYTHON_SHORT_VERSION_NO_DOTS}_d.lib + ${LIBDIR}/python/libs/python${PYTHON_SHORT_VERSION_NO_DOTS}.lib + ) +else() + set(PIP_CONFIGURE_COMMAND echo ".") +endif() + +ExternalProject_Add(external_python_site_packages + DOWNLOAD_COMMAND "" + CONFIGURE_COMMAND ${PIP_CONFIGURE_COMMAND} + BUILD_COMMAND "" + PREFIX ${BUILD_DIR}/site_packages + + # setuptools is downgraded to 63.2.0 (same as python 3.10.8) since numpy 1.23.x seemingly has + # issues building on windows with the newer versions that ships with python 3.10.9+ + INSTALL_COMMAND ${PYTHON_BINARY} -m pip install --no-cache-dir ${SITE_PACKAGES_EXTRA} + setuptools==63.2.0 + cython==${CYTHON_VERSION} + idna==${IDNA_VERSION} + charset-normalizer==${CHARSET_NORMALIZER_VERSION} + urllib3==${URLLIB3_VERSION} + certifi==${CERTIFI_VERSION} + requests==${REQUESTS_VERSION} + zstandard==${ZSTANDARD_VERSION} + autopep8==${AUTOPEP8_VERSION} + pycodestyle==${PYCODESTYLE_VERSION} + toml==${TOML_VERSION} + meson==${MESON_VERSION} + --no-binary :all: +) + +add_dependencies( + external_python_site_packages + external_python +) diff --git a/blender-build/build_environment/cmake/robinmap.cmake b/blender-build/build_environment/cmake/robinmap.cmake new file mode 100644 index 0000000..6c4ed30 --- /dev/null +++ b/blender-build/build_environment/cmake/robinmap.cmake @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(ROBINMAP_EXTRA_ARGS +) + +ExternalProject_Add(external_robinmap + URL file://${PACKAGE_DIR}/${ROBINMAP_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${ROBINMAP_HASH_TYPE}=${ROBINMAP_HASH} + PREFIX ${BUILD_DIR}/robinmap + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/robinmap ${DEFAULT_CMAKE_FLAGS} ${ROBINMAP_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/robinmap +) diff --git a/blender-build/build_environment/cmake/sdl.cmake b/blender-build/build_environment/cmake/sdl.cmake new file mode 100644 index 0000000..4f68750 --- /dev/null +++ b/blender-build/build_environment/cmake/sdl.cmake @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(WIN32) + set(SDL_EXTRA_ARGS + -DSDL_STATIC=Off + ) +else() + set(SDL_EXTRA_ARGS + -DSDL_STATIC=ON + -DSDL_SHARED=OFF + -DSDL_VIDEO=OFF + -DSNDIO=OFF + ) +endif() + +ExternalProject_Add(external_sdl + URL file://${PACKAGE_DIR}/${SDL_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${SDL_HASH_TYPE}=${SDL_HASH} + PREFIX ${BUILD_DIR}/sdl + PATCH_COMMAND ${PATCH_CMD} -p 0 -N -d ${BUILD_DIR}/sdl/src/external_sdl < ${PATCH_DIR}/sdl.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/sdl ${DEFAULT_CMAKE_FLAGS} ${SDL_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/sdl +) + +if(BUILD_MODE STREQUAL Release AND WIN32) + ExternalProject_Add_Step(external_sdl after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/sdl/include/sdl2 ${HARVEST_TARGET}/sdl/include + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/sdl/lib ${HARVEST_TARGET}/sdl/lib + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/sdl/bin ${HARVEST_TARGET}/sdl/lib + DEPENDEES install + ) +endif() diff --git a/blender-build/build_environment/cmake/setup_mingw64.cmake b/blender-build/build_environment/cmake/setup_mingw64.cmake new file mode 100644 index 0000000..6f53edb --- /dev/null +++ b/blender-build/build_environment/cmake/setup_mingw64.cmake @@ -0,0 +1,219 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +################################################################################################## +# Mingw64 Builds +################################################################################################## +# This installs mingw64+msys to compile ffmpeg/iconv/libsndfile/fftw3 +################################################################################################## + +message("LIBDIR = ${LIBDIR}") +macro(cmake_to_msys_path MsysPath ResultingPath) + string(REPLACE ":" "" TmpPath "${MsysPath}") + string(SUBSTRING ${TmpPath} 0 1 Drive) + string(SUBSTRING ${TmpPath} 1 255 PathPart) + string(TOLOWER ${Drive} LowerDrive) + string(CONCAT ${ResultingPath} "/" ${LowerDrive} ${PathPart}) +endmacro() +cmake_to_msys_path(${LIBDIR} mingw_LIBDIR) +message("mingw_LIBDIR = ${mingw_LIBDIR}") + +message("Checking for mingw64") +# download ming64 +if(NOT EXISTS "${DOWNLOAD_DIR}/x86_64-4.9.4-release-win32-seh-rt_v5-rev0.7z") + message("Downloading mingw64") + file(DOWNLOAD "https://nchc.dl.sourceforge.net/project/mingw-w64/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/4.9.4/threads-win32/seh/x86_64-4.9.4-release-win32-seh-rt_v5-rev0.7z" "${DOWNLOAD_DIR}/x86_64-4.9.4-release-win32-seh-rt_v5-rev0.7z") +endif() + +# make mingw root directory +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw") + execute_process( + COMMAND ${CMAKE_COMMAND} -E make_directory ${DOWNLOAD_DIR}/mingw + WORKING_DIRECTORY ${DOWNLOAD_DIR} + ) +endif() + +# extract mingw64 +if((NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/ming64sh.cmd") AND (EXISTS "${DOWNLOAD_DIR}/x86_64-4.9.4-release-win32-seh-rt_v5-rev0.7z")) + message("Extracting mingw64") + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar jxf ${DOWNLOAD_DIR}/x86_64-4.9.4-release-win32-seh-rt_v5-rev0.7z + WORKING_DIRECTORY ${DOWNLOAD_DIR}/mingw + ) +endif() + +message("Checking for pkg-config") +if(NOT EXISTS "${DOWNLOAD_DIR}/pkg-config-lite-0.28-1_bin-win32.zip") + message("Downloading pkg-config") + file(DOWNLOAD "https://nchc.dl.sourceforge.net/project/pkgconfiglite/0.28-1/pkg-config-lite-0.28-1_bin-win32.zip" "${DOWNLOAD_DIR}/pkg-config-lite-0.28-1_bin-win32.zip") +endif() + +# extract pkgconfig +if((NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/bin/pkg-config.exe") AND (EXISTS "${DOWNLOAD_DIR}/pkg-config-lite-0.28-1_bin-win32.zip")) + message("Extracting pkg-config") + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar jxf "${DOWNLOAD_DIR}/pkg-config-lite-0.28-1_bin-win32.zip" + WORKING_DIRECTORY ${DOWNLOAD_DIR}/ + ) + + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy "${DOWNLOAD_DIR}/pkg-config-lite-0.28-1/bin/pkg-config.exe" "${DOWNLOAD_DIR}/mingw/mingw64/bin/pkg-config.exe" + ) + +endif() + +message("Checking for nasm") +if(NOT EXISTS "${DOWNLOAD_DIR}/nasm-2.13.02-win64.zip") + message("Downloading nasm") + file(DOWNLOAD "http://www.nasm.us/pub/nasm/releasebuilds/2.13.02/win64/nasm-2.13.02-win64.zip" "${DOWNLOAD_DIR}/nasm-2.13.02-win64.zip") +endif() + +# extract nasm +if((NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/bin/nasm.exe") AND (EXISTS "${DOWNLOAD_DIR}/nasm-2.13.02-win64.zip")) + message("Extracting nasm") + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar jxf "${DOWNLOAD_DIR}/nasm-2.13.02-win64.zip" + WORKING_DIRECTORY ${DOWNLOAD_DIR}/ + ) + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy "${DOWNLOAD_DIR}/nasm-2.13.02/nasm.exe" "${DOWNLOAD_DIR}/mingw/mingw64/bin/nasm.exe" + ) + +endif() +SET(NASM_PATH ${DOWNLOAD_DIR}/mingw/mingw64/bin/nasm.exe) + +message("Checking for mingwGet") +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw-get-0.6.2-mingw32-beta-20131004-1-bin.zip") + message("Downloading mingw-get") + file(DOWNLOAD "https://nchc.dl.sourceforge.net/project/mingw/Installer/mingw-get/mingw-get-0.6.2-beta-20131004-1/mingw-get-0.6.2-mingw32-beta-20131004-1-bin.zip" "${DOWNLOAD_DIR}/mingw-get-0.6.2-mingw32-beta-20131004-1-bin.zip") +endif() + +# extract mingw_get +if((NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/bin/mingw-get.exe") AND (EXISTS "${DOWNLOAD_DIR}/mingw-get-0.6.2-mingw32-beta-20131004-1-bin.zip")) + message("Extracting mingw-get") + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar jxf "${DOWNLOAD_DIR}/mingw-get-0.6.2-mingw32-beta-20131004-1-bin.zip" + WORKING_DIRECTORY ${DOWNLOAD_DIR}/mingw/mingw64/ + ) +endif() + +if((EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/bin/mingw-get.exe") AND (NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/msys/1.0/bin/make.exe")) + message("Installing MSYS") + execute_process( + COMMAND ${DOWNLOAD_DIR}/mingw/mingw64/bin/mingw-get install msys msys-patch + WORKING_DIRECTORY ${DOWNLOAD_DIR}/mingw/mingw64/bin/ + ) +endif() + +if((EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/bin/mingw-get.exe") AND (NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/msys/1.0/bin/mktemp.exe")) + message("Installing mktemp") + execute_process( + COMMAND ${DOWNLOAD_DIR}/mingw/mingw64/bin/mingw-get install msys msys-mktemp + WORKING_DIRECTORY ${DOWNLOAD_DIR}/mingw/mingw64/bin/ + ) +endif() + +if((EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/bin/mingw-get.exe") AND (NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/msys/1.0/bin/m4.exe")) + message("Installing m4") + execute_process( + COMMAND ${DOWNLOAD_DIR}/mingw/mingw64/bin/mingw-get install msys msys-m4 + WORKING_DIRECTORY ${DOWNLOAD_DIR}/mingw/mingw64/bin/ + ) +endif() + +message("Checking for CoreUtils") +# download old core_utils for pr.exe (ffmpeg needs it to build) +if(NOT EXISTS "${DOWNLOAD_DIR}/coreutils-5.97-MSYS-1.0.11-snapshot.tar.bz2") + message("Downloading CoreUtils 5.97") + file(DOWNLOAD "https://nchc.dl.sourceforge.net/project/mingw/MSYS/Base/msys-core/_obsolete/coreutils-5.97-MSYS-1.0.11-2/coreutils-5.97-MSYS-1.0.11-snapshot.tar.bz2" "${DOWNLOAD_DIR}/coreutils-5.97-MSYS-1.0.11-snapshot.tar.bz2") +endif() + +if((EXISTS "${DOWNLOAD_DIR}/coreutils-5.97-MSYS-1.0.11-snapshot.tar.bz2") AND (NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/msys/1.0/bin/pr.exe")) + message("Installing pr from CoreUtils 5.97") + execute_process( + COMMAND ${CMAKE_COMMAND} -E make_directory ${DOWNLOAD_DIR}/tmp_coreutils + WORKING_DIRECTORY ${DOWNLOAD_DIR} + ) + + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar jxf ${DOWNLOAD_DIR}/coreutils-5.97-MSYS-1.0.11-snapshot.tar.bz2 + WORKING_DIRECTORY ${DOWNLOAD_DIR}/tmp_coreutils/ + ) + + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy ${DOWNLOAD_DIR}/tmp_coreutils/coreutils-5.97/bin/pr.exe "${DOWNLOAD_DIR}/mingw/mingw64/msys/1.0/bin/pr.exe" + WORKING_DIRECTORY ${DOWNLOAD_DIR}/tmp_coreutils/ + ) +endif() + +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/ming64sh.cmd") + message("Installing ming64sh.cmd") + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy ${PATCH_DIR}/ming64sh.cmd ${DOWNLOAD_DIR}/mingw/mingw64/ming64sh.cmd + ) +endif() + +message("Checking for perl") +# download perl for libvpx +if(NOT EXISTS "${DOWNLOAD_DIR}/strawberry-perl-5.22.1.3-64bit-portable.zip") + message("Downloading perl") + file(DOWNLOAD "http://strawberryperl.com/download/5.22.1.3/strawberry-perl-5.22.1.3-64bit-portable.zip" "${DOWNLOAD_DIR}/strawberry-perl-5.22.1.3-64bit-portable.zip") +endif() + +# make perl root directory +if(NOT EXISTS "${DOWNLOAD_DIR}/perl") + execute_process( + COMMAND ${CMAKE_COMMAND} -E make_directory ${DOWNLOAD_DIR}/perl + WORKING_DIRECTORY ${DOWNLOAD_DIR} + ) +endif() + +# extract perl +if((NOT EXISTS "${DOWNLOAD_DIR}/perl/portable.perl") AND (EXISTS "${DOWNLOAD_DIR}/strawberry-perl-5.22.1.3-64bit-portable.zip")) + message("Extracting perl") + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar jxf ${DOWNLOAD_DIR}/strawberry-perl-5.22.1.3-64bit-portable.zip + WORKING_DIRECTORY ${DOWNLOAD_DIR}/perl + ) +endif() + +# get yasm for vpx +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/bin/yasm.exe") + message("Downloading yasm") + file(DOWNLOAD "http://www.tortall.net/projects/yasm/releases/yasm-1.3.0-win64.exe" "${DOWNLOAD_DIR}/mingw/mingw64/bin/yasm.exe") +endif() + +message("checking x86_64-w64-mingw32-strings.exe") +# copy strings.exe to x86_64-w64-mingw32-strings.exe for x264 +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/bin/x86_64-w64-mingw32-strings.exe") + message("fixing x86_64-w64-mingw32-strings.exe") + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy "${DOWNLOAD_DIR}/mingw/mingw64/bin/strings.exe" "${DOWNLOAD_DIR}/mingw/mingw64/bin/x86_64-w64-mingw32-strings.exe" + ) +endif() + +message("checking x86_64-w64-mingw32-ar.exe") +# copy ar.exe to x86_64-w64-mingw32-ar.exe for x264 +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/bin/x86_64-w64-mingw32-ar.exe") + message("fixing x86_64-w64-mingw32-ar.exe") + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy "${DOWNLOAD_DIR}/mingw/mingw64/bin/ar.exe" "${DOWNLOAD_DIR}/mingw/mingw64/bin/x86_64-w64-mingw32-ar.exe" + ) +endif() + +message("checking x86_64-w64-mingw32-strip.exe") +# copy strip.exe to x86_64-w64-mingw32-strip.exe for x264 +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/bin/x86_64-w64-mingw32-strip.exe") + message("fixing x86_64-w64-mingw32-strip.exe") + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy "${DOWNLOAD_DIR}/mingw/mingw64/bin/strip.exe" "${DOWNLOAD_DIR}/mingw/mingw64/bin/x86_64-w64-mingw32-strip.exe" + ) +endif() + +message("checking x86_64-w64-mingw32-ranlib.exe") +# copy ranlib.exe to x86_64-w64-mingw32-ranlib.exe for x264 +if(NOT EXISTS "${DOWNLOAD_DIR}/mingw/mingw64/bin/x86_64-w64-mingw32-ranlib.exe") + message("fixing x86_64-w64-mingw32-ranlib.exe") + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy "${DOWNLOAD_DIR}/mingw/mingw64/bin/ranlib.exe" "${DOWNLOAD_DIR}/mingw/mingw64/bin/x86_64-w64-mingw32-ranlib.exe" + ) +endif() diff --git a/blender-build/build_environment/cmake/shaderc.cmake b/blender-build/build_environment/cmake/shaderc.cmake new file mode 100644 index 0000000..9831f53 --- /dev/null +++ b/blender-build/build_environment/cmake/shaderc.cmake @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(SHADERC_EXTRA_ARGS + -DSHADERC_SKIP_TESTS=On + -DSHADERC_SPIRV_TOOLS_DIR=${BUILD_DIR}/shaderc_spirv_tools/src/external_shaderc_spirv_tools + -DSHADERC_SPIRV_HEADERS_DIR=${BUILD_DIR}/shaderc_spirv_headers/src/external_shaderc_spirv_headers + -DSHADERC_GLSLANG_DIR=${BUILD_DIR}/shaderc_glslang/src/external_shaderc_glslang + -DCMAKE_DEBUG_POSTFIX=_d + -DPYTHON_EXECUTABLE=${PYTHON_BINARY} +) + +ExternalProject_Add(external_shaderc + URL file://${PACKAGE_DIR}/${SHADERC_FILE} + URL_HASH ${SHADERC_HASH_TYPE}=${SHADERC_HASH} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + PREFIX ${BUILD_DIR}/shaderc + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/shaderc ${DEFAULT_CMAKE_FLAGS} ${SHADERC_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/shaderc +) + +add_dependencies( + external_shaderc + external_shaderc_spirv_tools + external_shaderc_spirv_headers + external_shaderc_glslang + external_python +) + + +if(WIN32) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_shaderc after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/shaderc/include ${HARVEST_TARGET}/shaderc/include + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/shaderc/bin/shaderc_shared.dll ${HARVEST_TARGET}/shaderc/bin/shaderc_shared.dll + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/shaderc/lib/shaderc_shared.lib ${HARVEST_TARGET}/shaderc/lib/shaderc_shared.lib + + DEPENDEES install + ) + endif() + if(BUILD_MODE STREQUAL Debug) + ExternalProject_Add_Step(external_shaderc after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/shaderc/bin/shaderc_shared_d.dll ${HARVEST_TARGET}/shaderc/bin/shaderc_shared_d.dll + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/shaderc/lib/shaderc_shared_d.lib ${HARVEST_TARGET}/shaderc/lib/shaderc_shared_d.lib + DEPENDEES install + ) + endif() +endif() diff --git a/blender-build/build_environment/cmake/shaderc_deps.cmake b/blender-build/build_environment/cmake/shaderc_deps.cmake new file mode 100644 index 0000000..5be13fc --- /dev/null +++ b/blender-build/build_environment/cmake/shaderc_deps.cmake @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# These are build time requirements for shaderc. We only have to unpack these +# shaderc will build them. + +ExternalProject_Add(external_shaderc_glslang + URL file://${PACKAGE_DIR}/${SHADERC_GLSLANG_FILE} + URL_HASH ${SHADERC_GLSLANG_HASH_TYPE}=${SHADERC_GLSLANG_HASH} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + PREFIX ${BUILD_DIR}/shaderc_glslang + CONFIGURE_COMMAND echo . + BUILD_COMMAND echo . + INSTALL_COMMAND echo . +) + +ExternalProject_Add(external_shaderc_spirv_headers + URL file://${PACKAGE_DIR}/${SHADERC_SPIRV_HEADERS_FILE} + URL_HASH ${SHADERC_SPIRV_HEADERS_HASH_TYPE}=${SHADERC_SPIRV_HEADERS_HASH} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + PREFIX ${BUILD_DIR}/shaderc_spirv_headers + CONFIGURE_COMMAND echo . + BUILD_COMMAND echo . + INSTALL_COMMAND echo . +) + +ExternalProject_Add(external_shaderc_spirv_tools + URL file://${PACKAGE_DIR}/${SHADERC_SPIRV_TOOLS_FILE} + URL_HASH ${SHADERC_SPIRV_TOOLS_HASH_TYPE}=${SHADERC_SPIRV_TOOLS_HASH} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + PREFIX ${BUILD_DIR}/shaderc_spirv_tools + CONFIGURE_COMMAND echo . + BUILD_COMMAND echo . + INSTALL_COMMAND echo . +) diff --git a/blender-build/build_environment/cmake/sndfile.cmake b/blender-build/build_environment/cmake/sndfile.cmake new file mode 100644 index 0000000..8fc614c --- /dev/null +++ b/blender-build/build_environment/cmake/sndfile.cmake @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(SNDFILE_EXTRA_ARGS) +set(SNDFILE_ENV) + +if(WIN32) + set(SNDFILE_ENV "PKG_CONFIG_PATH=\ +${mingw_LIBDIR}/ogg/lib/pkgconfig:\ +${mingw_LIBDIR}/vorbis/lib/pkgconfig:\ +${mingw_LIBDIR}/flac/lib/pkgconfig:\ +${mingw_LIBDIR}/opus/lib/pkgconfig" +) + set(SNDFILE_ENV set ${SNDFILE_ENV} &&) + # Shared for windows because static libs will drag in a libgcc dependency. + set(SNDFILE_OPTIONS --disable-static --enable-shared ) +else() + set(SNDFILE_OPTIONS --enable-static --disable-shared ) +endif() + +ExternalProject_Add(external_sndfile + URL file://${PACKAGE_DIR}/${SNDFILE_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${SNDFILE_HASH_TYPE}=${SNDFILE_HASH} + PREFIX ${BUILD_DIR}/sndfile + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sndfile/src/external_sndfile/ && ${SNDFILE_ENV} ${CONFIGURE_COMMAND} ${SNDFILE_OPTIONS} --prefix=${mingw_LIBDIR}/sndfile + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sndfile/src/external_sndfile/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sndfile/src/external_sndfile/ && make install + INSTALL_DIR ${LIBDIR}/sndfile +) + +if(MSVC) + set_target_properties(external_sndfile PROPERTIES FOLDER Mingw) +endif() + +add_dependencies( + external_sndfile + external_ogg + external_vorbis + external_opus +) +if(UNIX) + add_dependencies( + external_sndfile + external_flac + ) +endif() + +if(BUILD_MODE STREQUAL Release AND WIN32) + ExternalProject_Add_Step(external_sndfile after_install + COMMAND lib /def:${BUILD_DIR}/sndfile/src/external_sndfile/src/libsndfile-1.def /machine:x64 /out:${BUILD_DIR}/sndfile/src/external_sndfile/src/libsndfile-1.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/sndfile/bin/libsndfile-1.dll ${HARVEST_TARGET}/sndfile/lib/libsndfile-1.dll + COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/sndfile/src/external_sndfile/src/libsndfile-1.lib ${HARVEST_TARGET}/sndfile/lib/libsndfile-1.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/sndfile/include/sndfile.h ${HARVEST_TARGET}/sndfile/include/sndfile.h + + DEPENDEES install + ) +endif() diff --git a/blender-build/build_environment/cmake/spnav.cmake b/blender-build/build_environment/cmake/spnav.cmake new file mode 100644 index 0000000..12b9048 --- /dev/null +++ b/blender-build/build_environment/cmake/spnav.cmake @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +ExternalProject_Add(external_spnav + URL file://${PACKAGE_DIR}/${SPNAV_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${SPNAV_HASH_TYPE}=${SPNAV_HASH} + PREFIX ${BUILD_DIR}/spnav + + CONFIGURE_COMMAND + ${CONFIGURE_ENV} && + cd ${BUILD_DIR}/spnav/src/external_spnav/ && + ${CONFIGURE_COMMAND} + --prefix=${LIBDIR}/spnav + # X11 is not needed as Blender polls the device as part of the GHOST event loop. + # This is used to support `3dxserv`, however this is no longer supported by 3DCONNEXION. + # Disable so building without X11 is supported (WAYLAND only). + --disable-x11 + --disable-shared + --enable-static + --with-pic + + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/spnav/src/external_spnav/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/spnav/src/external_spnav/ && make install + INSTALL_DIR ${LIBDIR}/spnav +) diff --git a/blender-build/build_environment/cmake/sqlite.cmake b/blender-build/build_environment/cmake/sqlite.cmake new file mode 100644 index 0000000..c151a49 --- /dev/null +++ b/blender-build/build_environment/cmake/sqlite.cmake @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(SQLITE_CONFIGURE_ENV echo .) +set(SQLITE_CONFIGURATION_ARGS) + +if(UNIX) + if(NOT APPLE) + set(SQLITE_LDFLAGS -Wl,--as-needed) + endif() + set(SQLITE_CFLAGS + "-DSQLITE_SECURE_DELETE -DSQLITE_ENABLE_COLUMN_METADATA \ + -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS \ + -DSQLITE_ENABLE_RTREE=1 -DSQLITE_SOUNDEX=1 \ + -DSQLITE_ENABLE_UNLOCK_NOTIFY \ + -DSQLITE_OMIT_LOOKASIDE=1 -DSQLITE_ENABLE_DBSTAT_VTAB \ + -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 \ + -DSQLITE_ENABLE_LOAD_EXTENSION \ + -DSQLITE_ENABLE_JSON1 \ + -DSQLITE_LIKE_DOESNT_MATCH_BLOBS \ + -DSQLITE_THREADSAFE=1 \ + -DSQLITE_ENABLE_FTS3_TOKENIZER=1 \ + -DSQLITE_MAX_SCHEMA_RETRY=25 \ + -DSQLITE_ENABLE_PREUPDATE_HOOK \ + -DSQLITE_ENABLE_SESSION \ + -DSQLITE_ENABLE_STMTVTAB \ + -DSQLITE_MAX_VARIABLE_NUMBER=250000 \ + -fPIC") + set(SQLITE_CONFIGURE_ENV ${SQLITE_CONFIGURE_ENV} && export LDFLAGS=${SQLITE_LDFLAGS} && export CFLAGS=${SQLITE_CFLAGS}) + set(SQLITE_CONFIGURATION_ARGS + ${SQLITE_CONFIGURATION_ARGS} + --enable-threadsafe + --enable-load-extension + --enable-json1 + --enable-fts4 + --enable-fts5 + # While building `tcl` is harmless, it causes problems when the install step + # tries to copy the files into the system path. + # Since this isn't required by Python or Blender this can be disabled. + # Note that Debian (for example), splits this off into a separate package, + # so it's safe to turn off. + --disable-tcl + --enable-shared=no + ) +endif() + +ExternalProject_Add(external_sqlite + URL file://${PACKAGE_DIR}/${SQLITE_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${SQLITE_HASH_TYPE}=${SQLITE_HASH} + PREFIX ${BUILD_DIR}/sqlite + CONFIGURE_COMMAND ${SQLITE_CONFIGURE_ENV} && cd ${BUILD_DIR}/sqlite/src/external_sqlite/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/sqlite ${SQLITE_CONFIGURATION_ARGS} + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sqlite/src/external_sqlite/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/sqlite/src/external_sqlite/ && make install + INSTALL_DIR ${LIBDIR}/sqlite +) diff --git a/blender-build/build_environment/cmake/sse2neon.cmake b/blender-build/build_environment/cmake/sse2neon.cmake new file mode 100644 index 0000000..07fe1ac --- /dev/null +++ b/blender-build/build_environment/cmake/sse2neon.cmake @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +ExternalProject_Add(external_sse2neon + URL file://${PACKAGE_DIR}/${SSE2NEON_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${SSE2NEON_HASH_TYPE}=${SSE2NEON_HASH} + PREFIX ${BUILD_DIR}/sse2neon + CONFIGURE_COMMAND echo sse2neon - Nothing to configure + BUILD_COMMAND echo sse2neon - nothing to build + INSTALL_COMMAND mkdir -p ${LIBDIR}/sse2neon && cp ${BUILD_DIR}/sse2neon/src/external_sse2neon/sse2neon.h ${LIBDIR}/sse2neon + INSTALL_DIR ${LIBDIR}/sse2neon +) diff --git a/blender-build/build_environment/cmake/ssl.cmake b/blender-build/build_environment/cmake/ssl.cmake new file mode 100644 index 0000000..5d02b8e --- /dev/null +++ b/blender-build/build_environment/cmake/ssl.cmake @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(SSL_CONFIGURE_COMMAND ./Configure) + +if(WIN32) + # Python will build this with its preferred build options and patches. We only need to unpack openssl + ExternalProject_Add(external_ssl + URL file://${PACKAGE_DIR}/${SSL_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${SSL_HASH_TYPE}=${SSL_HASH} + PREFIX ${BUILD_DIR}/ssl + CONFIGURE_COMMAND echo "." + BUILD_COMMAND echo "." + INSTALL_COMMAND echo "." + INSTALL_DIR ${LIBDIR}/ssl + ) +else() + if(APPLE) + set(SSL_OS_COMPILER "blender-darwin-${CMAKE_OSX_ARCHITECTURES}") + else() + if(BLENDER_PLATFORM_ARM) + set(SSL_OS_COMPILER "blender-linux-aarch64") + elseif("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") + set(SSL_EXTRA_ARGS enable-ec_nistp_64_gcc_128) + set(SSL_OS_COMPILER "blender-linux-x86_64") + else() + set(SSL_OS_COMPILER "blender-linux-x86") + endif() + endif() + + ExternalProject_Add(external_ssl + URL file://${PACKAGE_DIR}/${SSL_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${SSL_HASH_TYPE}=${SSL_HASH} + PREFIX ${BUILD_DIR}/ssl + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/ssl/src/external_ssl/ && ${SSL_CONFIGURE_COMMAND} --prefix=${LIBDIR}/ssl + --openssldir=${LIBDIR}/ssl + no-shared + no-idea no-mdc2 no-rc5 no-zlib no-ssl3 enable-unit-test no-ssl3-method enable-rfc3779 enable-cms + --config=${CMAKE_CURRENT_SOURCE_DIR}/cmake/ssl.conf + ${SSL_OS_COMPILER} + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/ssl/src/external_ssl/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/ssl/src/external_ssl/ && make install + INSTALL_DIR ${LIBDIR}/ssl + ) +endif() diff --git a/blender-build/build_environment/cmake/ssl.conf b/blender-build/build_environment/cmake/ssl.conf new file mode 100644 index 0000000..fa59bcf --- /dev/null +++ b/blender-build/build_environment/cmake/ssl.conf @@ -0,0 +1,25 @@ +my %targets = ( + + "blender-linux-x86" => { + inherit_from => [ "linux-x86" ], + cflags => add("-fPIC"), + }, + "blender-linux-x86_64" => { + inherit_from => [ "linux-x86_64" ], + cflags => add("-fPIC"), + }, + "blender-linux-aarch64" => { + inherit_from => [ "linux-aarch64" ], + cxxflags => add("-fPIC"), + cflags => add("-fPIC"), + }, + "blender-darwin-x86_64" => { + inherit_from => [ "darwin64-x86_64-cc" ], + cflags => add("-fPIC"), + }, + "blender-darwin-arm64" => { + inherit_from => [ "darwin-common" ], + cxxflags => add("-fPIC -arch arm64"), + cflags => add("-fPIC -arch arm64"), + }, +); diff --git a/blender-build/build_environment/cmake/tbb.cmake b/blender-build/build_environment/cmake/tbb.cmake new file mode 100644 index 0000000..b5db2a3 --- /dev/null +++ b/blender-build/build_environment/cmake/tbb.cmake @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +set(TBB_EXTRA_ARGS + -DTBB_BUILD_SHARED=On + -DTBB_BUILD_TBBMALLOC=On + -DTBB_BUILD_TBBMALLOC_PROXY=On + -DTBB_BUILD_STATIC=Off + -DTBB_BUILD_TESTS=Off + -DCMAKE_DEBUG_POSTFIX=_debug +) +# TBB does not use soversion by default unlike other libs, but it's needed +# to avoid conflicts with incompatible TBB system libs in LD_LIBRARY_PATH +# or the Steam environment. +if(UNIX AND NOT APPLE) + list(APPEND TBB_EXTRA_ARGS -DTBB_SET_SOVERSION=ON) +endif() +set(TBB_LIBRARY tbb) +set(TBB_STATIC_LIBRARY Off) + +# CMake script for TBB from https://github.com/wjakob/tbb/blob/master/CMakeLists.txt +ExternalProject_Add(external_tbb + URL file://${PACKAGE_DIR}/${TBB_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${TBB_HASH_TYPE}=${TBB_HASH} + PREFIX ${BUILD_DIR}/tbb + PATCH_COMMAND COMMAND ${CMAKE_COMMAND} -E copy ${PATCH_DIR}/cmakelists_tbb.txt ${BUILD_DIR}/tbb/src/external_tbb/CMakeLists.txt && + ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/tbb/src/external_tbb/build/vs2013/version_string.ver ${BUILD_DIR}/tbb/src/external_tbb/build/version_string.ver.in && + ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/tbb/src/external_tbb < ${PATCH_DIR}/tbb.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/tbb ${DEFAULT_CMAKE_FLAGS} ${TBB_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/tbb +) + +if(WIN32) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_tbb after_install + # findtbb.cmake in some deps *NEEDS* to find tbb_debug.lib even if they are not going to use it + # to make that test pass, we place a copy with the right name in the lib folder. + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbb.lib ${LIBDIR}/tbb/lib/tbb_debug.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbbmalloc.lib ${LIBDIR}/tbb/lib/tbbmalloc_debug.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/bin/tbb.dll ${LIBDIR}/tbb/bin/tbb_debug.dll + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/bin/tbbmalloc.dll ${LIBDIR}/tbb/bin/tbbmalloc_debug.dll + # Normal collection of build artifacts + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbb.lib ${HARVEST_TARGET}/tbb/lib/tbb.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/bin/tbb.dll ${HARVEST_TARGET}/tbb/bin/tbb.dll + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbbmalloc.lib ${HARVEST_TARGET}/tbb/lib/tbbmalloc.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/bin/tbbmalloc.dll ${HARVEST_TARGET}/tbb/bin/tbbmalloc.dll + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbbmalloc_proxy.lib ${HARVEST_TARGET}/tbb/lib/tbbmalloc_proxy.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/bin/tbbmalloc_proxy.dll ${HARVEST_TARGET}/tbb/bin/tbbmalloc_proxy.dll + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/tbb/include/ ${HARVEST_TARGET}/tbb/include/ + DEPENDEES install + ) + endif() + if(BUILD_MODE STREQUAL Debug) + ExternalProject_Add_Step(external_tbb after_install + # findtbb.cmake in some deps *NEEDS* to find tbb.lib even if they are not going to use it + # to make that test pass, we place a copy with the right name in the lib folder. + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbb_debug.lib ${LIBDIR}/tbb/lib/tbb.lib + # Normal collection of build artifacts + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbb_debug.lib ${HARVEST_TARGET}/tbb/lib/tbb_debug.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/bin/tbb_debug.dll ${HARVEST_TARGET}/tbb/bin/tbb_debug.dll + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbbmalloc_debug.lib ${HARVEST_TARGET}/tbb/lib/tbbmalloc_debug.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/lib/tbbmalloc_proxy_debug.lib ${HARVEST_TARGET}/tbb/lib/tbbmalloc_proxy_debug.lib + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/bin/tbbmalloc_debug.dll ${HARVEST_TARGET}/tbb/bin/tbbmalloc_debug.dll + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tbb/bin/tbbmalloc_proxy_debug.dll ${HARVEST_TARGET}/tbb/bin/tbbmalloc_proxy_debug.dll + DEPENDEES install + ) + endif() +endif() diff --git a/blender-build/build_environment/cmake/theora.cmake b/blender-build/build_environment/cmake/theora.cmake new file mode 100644 index 0000000..3f4fc65 --- /dev/null +++ b/blender-build/build_environment/cmake/theora.cmake @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(UNIX) + set(THEORA_CONFIGURE_ENV ${CONFIGURE_ENV} && export HAVE_PDFLATEX=no) +else() + set(THEORA_CONFIGURE_ENV ${CONFIGURE_ENV}) +endif() + +if(BLENDER_PLATFORM_ARM) + set(THEORA_EXTRA_ARGS --host=aarch64-linux-gnu --build=aarch64-linux-gnu) +else() + set(THEORA_EXTRA_ARGS) +endif() + + +ExternalProject_Add(external_theora + URL file://${PACKAGE_DIR}/${THEORA_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${THEORA_HASH_TYPE}=${THEORA_HASH} + PREFIX ${BUILD_DIR}/theora + PATCH_COMMAND ${PATCH_CMD} -p 0 -d ${BUILD_DIR}/theora/src/external_theora < ${PATCH_DIR}/theora.diff + CONFIGURE_COMMAND ${THEORA_CONFIGURE_ENV} && cd ${BUILD_DIR}/theora/src/external_theora/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/theora + --disable-shared + --enable-static + --with-pic + --with-ogg=${LIBDIR}/ogg + --with-vorbis=${LIBDIR}/vorbis + --disable-examples ${THEORA_EXTRA_ARGS} + BUILD_COMMAND ${THEORA_CONFIGURE_ENV} && cd ${BUILD_DIR}/theora/src/external_theora/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${THEORA_CONFIGURE_ENV} && cd ${BUILD_DIR}/theora/src/external_theora/ && make install + INSTALL_DIR ${LIBDIR}/theora +) + +add_dependencies( + external_theora + external_vorbis + external_ogg +) + +if(MSVC) + set_target_properties(external_theora PROPERTIES FOLDER Mingw) +endif() diff --git a/blender-build/build_environment/cmake/tiff.cmake b/blender-build/build_environment/cmake/tiff.cmake new file mode 100644 index 0000000..a6490f4 --- /dev/null +++ b/blender-build/build_environment/cmake/tiff.cmake @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(TIFF_EXTRA_ARGS + -DZLIB_LIBRARY=${LIBDIR}/zlib/lib/${ZLIB_LIBRARY} + -DZLIB_INCLUDE_DIR=${LIBDIR}/zlib/include + -DJPEG_LIBRARY=${LIBDIR}/jpeg/lib/${JPEG_LIBRARY} + -DJPEG_INCLUDE_DIR=${LIBDIR}/jpeg/include + -DPNG_STATIC=ON + -DBUILD_SHARED_LIBS=OFF + -Dlzma=OFF + -Djbig=OFF + -Dzstd=OFF + -Dwebp=OFF + -Dtiff-tests=OFF +) + +ExternalProject_Add(external_tiff + URL file://${PACKAGE_DIR}/${TIFF_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${TIFF_HASH_TYPE}=${TIFF_HASH} + PREFIX ${BUILD_DIR}/tiff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/tiff ${DEFAULT_CMAKE_FLAGS} ${TIFF_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/tiff +) + +add_dependencies( + external_tiff + external_zlib + external_jpeg +) +if(WIN32) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_tiff after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/tiff/lib/tiff.lib ${HARVEST_TARGET}/tiff/lib/libtiff.lib && + ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/tiff/include/ ${HARVEST_TARGET}/tiff/include/ + DEPENDEES install + ) + endif() +endif() diff --git a/blender-build/build_environment/cmake/usd.cmake b/blender-build/build_environment/cmake/usd.cmake new file mode 100644 index 0000000..955ea62 --- /dev/null +++ b/blender-build/build_environment/cmake/usd.cmake @@ -0,0 +1,158 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(WIN32) + # OIIO and OSL are statically linked for us, but USD doesn't know + set(USD_CXX_FLAGS "${CMAKE_CXX_FLAGS} /DOIIO_STATIC_DEFINE /DOSL_STATIC_DEFINE") + if(BUILD_MODE STREQUAL Debug) + # USD does not look for debug libs, nor does it link them + # when building static, so this is just to keep find_package happy + # if we ever link dynamically on windows util will need to be linked as well. + set(USD_OIIO_CMAKE_DEFINES "-DOIIO_LIBRARIES=${LIBDIR}/openimageio/lib/OpenImageIO_d${LIBEXT}^^${LIBDIR}/openimageio/lib/OpenImageIO_util_d${LIBEXT}") + endif() + set(USD_PLATFORM_FLAGS + ${USD_OIIO_CMAKE_DEFINES} + -DCMAKE_CXX_FLAGS=${USD_CXX_FLAGS} + -D_PXR_CXX_DEFINITIONS=/DBOOST_ALL_NO_LIB + -DCMAKE_SHARED_LINKER_FLAGS_INIT=/LIBPATH:${LIBDIR}/tbb/lib + -DPython_FIND_REGISTRY=NEVER + -DPython3_EXECUTABLE=${PYTHON_BINARY} + ) + if(BUILD_MODE STREQUAL Debug) + list(APPEND USD_PLATFORM_FLAGS -DPXR_USE_DEBUG_PYTHON=ON) + list(APPEND USD_PLATFORM_FLAGS -DOPENVDB_LIBRARY=${LIBDIR}/openvdb/lib/openvdb_d.lib) + endif() +elseif(UNIX) + # Workaround USD not linking correctly with static Python library, where it would embed + # part of the interpret in the USD library. Allow undefined Python symbols and replace + # Python library with TBB so it doesn't complain about missing library. + set(USD_PLATFORM_FLAGS + # NOTE(@ideasman42): Setting the root is needed, without this an older version of Python + # is detected from the system. Referencing the root-directory may remove the need + # to explicitly set the `PYTHON_INCLUDE_DIR` & `PYTHON_LIBRARY`. + # Keep them as it's known these are the libraries to use and it avoids any ambiguity. + -DPython3_ROOT_DIR=${LIBDIR}/python/ + + -DPYTHON_INCLUDE_DIR=${LIBDIR}/python/include/python${PYTHON_SHORT_VERSION}/ + -DPYTHON_LIBRARY=${LIBDIR}/tbb/lib/${LIBPREFIX}${TBB_LIBRARY}${SHAREDLIBEXT} + ) + + if(APPLE) + set(USD_SHARED_LINKER_FLAGS "-Xlinker -undefined -Xlinker dynamic_lookup") + list(APPEND USD_PLATFORM_FLAGS + -DCMAKE_SHARED_LINKER_FLAGS=${USD_SHARED_LINKER_FLAGS} + ) + endif() +endif() + +set(USD_EXTRA_ARGS + ${DEFAULT_BOOST_FLAGS} + ${USD_PLATFORM_FLAGS} + -DOPENSUBDIV_ROOT_DIR=${LIBDIR}/opensubdiv + -DOpenImageIO_ROOT=${LIBDIR}/openimageio + -DMaterialX_ROOT=${LIBDIR}/materialx + -DOPENEXR_LIBRARIES=${LIBDIR}/imath/lib/${LIBPREFIX}Imath${OPENEXR_VERSION_POSTFIX}${SHAREDLIBEXT} + -DOPENEXR_INCLUDE_DIR=${LIBDIR}/imath/include + -DImath_DIR=${LIBDIR}/imath + -DOPENVDB_LOCATION=${LIBDIR}/openvdb + -DPXR_ENABLE_PYTHON_SUPPORT=ON + -DPXR_USE_PYTHON_3=ON + -DPXR_BUILD_IMAGING=ON + -DPXR_BUILD_TESTS=OFF + -DPXR_BUILD_EXAMPLES=OFF + -DPXR_BUILD_TUTORIALS=OFF + -DPXR_BUILD_USDVIEW=OFF + -DPXR_ENABLE_HDF5_SUPPORT=OFF + -DPXR_ENABLE_MATERIALX_SUPPORT=ON + -DPXR_ENABLE_OPENVDB_SUPPORT=ON + -DPYTHON_EXECUTABLE=${PYTHON_BINARY} + -DPython3_EXECUTABLE=${PYTHON_BINARY} + -DPXR_BUILD_MONOLITHIC=ON + # OSL is an optional dependency of the Imaging module. However, since that + # module was included for its support for converting primitive shapes (sphere, + # cube, etc.) to geometry, it's not necessary. Disabling it will make it + # simpler to build Blender; currently only Cycles uses OSL. + -DPXR_ENABLE_OSL_SUPPORT=OFF + # Enable OpenGL for Hydra support. Note that this indirectly also adds an X11 + # dependency on Linux. This would be good to eliminate for headless and Wayland + # only builds, however is not worse than what Blender already links to for + # official releases currently. + -DPXR_ENABLE_GL_SUPPORT=ON + # OIIO is used for loading image textures in Hydra Storm / Embree renderers. + -DPXR_BUILD_OPENIMAGEIO_PLUGIN=ON + # USD 22.03 does not support OCIO 2.x + # Tracking ticket https://github.com/PixarAnimationStudios/USD/issues/1386 + -DPXR_BUILD_OPENCOLORIO_PLUGIN=OFF + -DPXR_ENABLE_PTEX_SUPPORT=OFF + -DPXR_BUILD_USD_TOOLS=OFF + -DCMAKE_DEBUG_POSTFIX=_d + -DBUILD_SHARED_LIBS=ON + -DTBB_INCLUDE_DIRS=${LIBDIR}/tbb/include + -DTBB_LIBRARIES=${LIBDIR}/tbb/lib/${LIBPREFIX}${TBB_LIBRARY}${SHAREDLIBEXT} + -DTbb_TBB_LIBRARY=${LIBDIR}/tbb/lib/${LIBPREFIX}${TBB_LIBRARY}${SHAREDLIBEXT} + -DTBB_tbb_LIBRARY_RELEASE=${LIBDIR}/tbb/lib/${LIBPREFIX}${TBB_LIBRARY}${SHAREDLIBEXT} +) + +# Ray: I'm not sure if the other platforms relied on this or not but this is no longer +# needed for windows. If mac/lin confirm, this can be removed. +if(NOT WIN32) + list(APPEND USD_EXTRA_ARGS + # USD wants the tbb debug lib set even when you are doing a release build + # Otherwise it will error out during the cmake configure phase. + -DTBB_LIBRARIES_DEBUG=${LIBDIR}/tbb/lib/${LIBPREFIX}${TBB_LIBRARY}${SHAREDLIBEXT} + ) +endif() + +ExternalProject_Add(external_usd + URL file://${PACKAGE_DIR}/${USD_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${USD_HASH_TYPE}=${USD_HASH} + CMAKE_GENERATOR ${PLATFORM_ALT_GENERATOR} + PREFIX ${BUILD_DIR}/usd + LIST_SEPARATOR ^^ + # usd_pull_1965.diff https://github.com/PixarAnimationStudios/USD/pull/1965 + # usd_hydra.diff - https://github.com/bnagirniak/RPRHydraRenderBlenderAddon/blob/master/usd.diff + # usd_hydra.diff also included the blender changes and usd_pull_1965 and has been edited to remove those sections. + PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/usd/src/external_usd < ${PATCH_DIR}/usd.diff && + ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/usd/src/external_usd < ${PATCH_DIR}/usd_pull_1965.diff && + ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/usd/src/external_usd < ${PATCH_DIR}/usd_hydra.diff + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/usd -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${USD_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/usd +) + +add_dependencies( + external_usd + external_tbb + external_boost + external_opensubdiv + external_python + external_openimageio + external_materialx + openvdb +) + +# Since USD 21.11 the libraries are prefixed with "usd_", i.e. "libusd_m.a" became "libusd_usd_m.a". +# See https://github.com/PixarAnimationStudios/USD/blob/release/CHANGELOG.md#2111---2021-11-01 +if(NOT WIN32) + if(USD_VERSION VERSION_LESS 21.11) + set(PXR_LIB_PREFIX "") + else() + set(PXR_LIB_PREFIX "usd_") + endif() +endif() + +if(WIN32) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_usd after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/usd ${HARVEST_TARGET}/usd + DEPENDEES install + ) + endif() + if(BUILD_MODE STREQUAL Debug) + ExternalProject_Add_Step(external_usd after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/usd/lib/python ${HARVEST_TARGET}/usd/lib/debug/python + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/usd/lib/usd_ms_d.dll ${HARVEST_TARGET}/usd/lib/usd_ms_d.dll + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/usd/lib/usd_ms_d.lib ${HARVEST_TARGET}/usd/lib/usd_ms_d.lib + DEPENDEES install + ) + endif() +endif() diff --git a/blender-build/build_environment/cmake/versions.cmake b/blender-build/build_environment/cmake/versions.cmake new file mode 100644 index 0000000..d837862 --- /dev/null +++ b/blender-build/build_environment/cmake/versions.cmake @@ -0,0 +1,806 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# CPE's are used to identify dependencies, for more information on what they +# are please see https://nvd.nist.gov/products/cpe +# +# We use them in combination with cve-bin-tool to scan for known security issues. +# +# Not all of our dependencies are currently in the nvd database so not all +# dependencies have one assigned. + +set(ZLIB_VERSION 1.2.13) +set(ZLIB_URI https://github.com/madler/zlib/releases/download/v${ZLIB_VERSION}/zlib-${ZLIB_VERSION}.tar.gz) +set(ZLIB_HASH 9b8aa094c4e5765dabf4da391f00d15c) +set(ZLIB_HASH_TYPE MD5) +set(ZLIB_FILE zlib-${ZLIB_VERSION}.tar.gz) +set(ZLIB_CPE "cpe:2.3:a:zlib:zlib:${ZLIB_VERSION}:*:*:*:*:*:*:*") + +set(OPENAL_VERSION 1.21.1) +set(OPENAL_URI https://github.com/kcat/openal-soft/archive/refs/tags/${OPENAL_VERSION}.tar.gz) +set(OPENAL_HASH a4922a79526c590b6cac0c10f3f1bef8) +set(OPENAL_HASH_TYPE MD5) +set(OPENAL_FILE openal-soft-${OPENAL_VERSION}.tar.gz) + +set(PNG_VERSION 1.6.37) +set(PNG_URI http://prdownloads.sourceforge.net/libpng/libpng-${PNG_VERSION}.tar.xz) +set(PNG_HASH 505e70834d35383537b6491e7ae8641f1a4bed1876dbfe361201fc80868d88ca) +set(PNG_HASH_TYPE SHA256) +set(PNG_FILE libpng-${PNG_VERSION}.tar.xz) +set(PNG_CPE "cpe:2.3:a:libpng:libpng:${PNG_VERSION}:*:*:*:*:*:*:*") + +set(JPEG_VERSION 2.1.3) +set(JPEG_URI https://github.com/libjpeg-turbo/libjpeg-turbo/archive/${JPEG_VERSION}.tar.gz) +set(JPEG_HASH 627b980fad0573e08e4c3b80b290fc91) +set(JPEG_HASH_TYPE MD5) +set(JPEG_FILE libjpeg-turbo-${JPEG_VERSION}.tar.gz) +set(JPEG_CPE "cpe:2.3:a:d.r.commander:libjpeg-turbo:${JPEG_VERSION}:*:*:*:*:*:*:*") + +set(BOOST_VERSION 1.80.0) +set(BOOST_VERSION_SHORT 1.80) +set(BOOST_VERSION_NODOTS 1_80_0) +set(BOOST_VERSION_NODOTS_SHORT 1_80) +set(BOOST_URI https://archives.boost.io/release/${BOOST_VERSION}/source/boost_${BOOST_VERSION_NODOTS}.tar.gz) +set(BOOST_HASH 077f074743ea7b0cb49c6ed43953ae95) +set(BOOST_HASH_TYPE MD5) +set(BOOST_FILE boost_${BOOST_VERSION_NODOTS}.tar.gz) +set(BOOST_CPE "cpe:2.3:a:boost:boost:${BOOST_VERSION}:*:*:*:*:*:*:*") + +set(BLOSC_VERSION 1.21.1) +set(BLOSC_URI https://github.com/Blosc/c-blosc/archive/v${BLOSC_VERSION}.tar.gz) +set(BLOSC_HASH 134b55813b1dca57019d2a2dc1f7a923) +set(BLOSC_HASH_TYPE MD5) +set(BLOSC_FILE blosc-${BLOSC_VERSION}.tar.gz) +set(BLOSC_CPE "cpe:2.3:a:c-blosc2_project:c-blosc2:${BLOSC_VERSION}:*:*:*:*:*:*:*") + +set(PTHREADS_VERSION 3.0.0) +set(PTHREADS_URI http://prdownloads.sourceforge.net/pthreads4w/pthreads4w-code-v${PTHREADS_VERSION}.zip) +set(PTHREADS_HASH f3bf81bb395840b3446197bcf4ecd653) +set(PTHREADS_HASH_TYPE MD5) +set(PTHREADS_FILE pthreads4w-code-${PTHREADS_VERSION}.zip) + +set(OPENEXR_VERSION 3.1.7) +set(OPENEXR_URI https://github.com/AcademySoftwareFoundation/openexr/archive/v${OPENEXR_VERSION}.tar.gz) +set(OPENEXR_HASH ae68f0cb8b30a49c961fa87d31c60394) +set(OPENEXR_HASH_TYPE MD5) +set(OPENEXR_FILE openexr-${OPENEXR_VERSION}.tar.gz) +set(OPENEXR_CPE "cpe:2.3:a:openexr:openexr:${OPENEXR_VERSION}:*:*:*:*:*:*:*") + +set(IMATH_VERSION 3.1.7) +set(IMATH_URI https://github.com/AcademySoftwareFoundation/Imath/archive/v${OPENEXR_VERSION}.tar.gz) +set(IMATH_HASH 5cedab446ab296c080957c3037c6d097) +set(IMATH_HASH_TYPE MD5) +set(IMATH_FILE imath-${IMATH_VERSION}.tar.gz) + + +if(WIN32) + # Openexr started appending _d on its own so now + # we need to tell the build the postfix is _s while + # telling all other deps the postfix is _s_d + if(BUILD_MODE STREQUAL Release) + set(OPENEXR_VERSION_POSTFIX ) + set(OPENEXR_VERSION_BUILD_POSTFIX ) + else() + set(OPENEXR_VERSION_POSTFIX _d) + set(OPENEXR_VERSION_BUILD_POSTFIX ) + endif() +else() + set(OPENEXR_VERSION_BUILD_POSTFIX) + set(OPENEXR_VERSION_POSTFIX) +endif() + +set(FREETYPE_VERSION 2.13.0) +set(FREETYPE_URI http://prdownloads.sourceforge.net/freetype/freetype-${FREETYPE_VERSION}.tar.gz) +set(FREETYPE_HASH 98bc3cf234fe88ef3cf24569251fe0a4) +set(FREETYPE_HASH_TYPE MD5) +set(FREETYPE_FILE freetype-${FREETYPE_VERSION}.tar.gz) +SET(FREETYPE_CPE "cpe:2.3:a:freetype:freetype:${FREETYPE_VERSION}:*:*:*:*:*:*:*") + +set(EPOXY_VERSION 1.5.10) +set(EPOXY_URI https://github.com/anholt/libepoxy/archive/refs/tags/${EPOXY_VERSION}.tar.gz) +set(EPOXY_HASH f0730aad115c952e77591fcc805b1dc1) +set(EPOXY_HASH_TYPE MD5) +set(EPOXY_FILE libepoxy-${EPOXY_VERSION}.tar.gz) + +set(FREEGLUT_VERSION 3.0.0) +set(FREEGLUT_URI http://prdownloads.sourceforge.net/freeglut/freeglut/${FREEGLUT_VERSION}/freeglut-${FREEGLUT_VERSION}.tar.gz) +set(FREEGLUT_HASH 90c3ca4dd9d51cf32276bc5344ec9754) +set(FREEGLUT_HASH_TYPE MD5) +set(FREEGLUT_FILE freeglut-${FREEGLUT_VERSION}.tar.gz) + +set(ALEMBIC_VERSION 1.8.3) +set(ALEMBIC_URI https://github.com/alembic/alembic/archive/${ALEMBIC_VERSION}.tar.gz) +set(ALEMBIC_HASH 2cd8d6e5a3ac4a014e24a4b04f4fadf9) +set(ALEMBIC_HASH_TYPE MD5) +set(ALEMBIC_FILE alembic-${ALEMBIC_VERSION}.tar.gz) + +set(OPENSUBDIV_VERSION v3_5_0) +set(OPENSUBDIV_URI https://github.com/PixarAnimationStudios/OpenSubdiv/archive/${OPENSUBDIV_VERSION}.tar.gz) +set(OPENSUBDIV_HASH 230f5cd2911d6240e58a3773b9c6e5e4) +set(OPENSUBDIV_HASH_TYPE MD5) +set(OPENSUBDIV_FILE opensubdiv-${OPENSUBDIV_VERSION}.tar.gz) + +set(SDL_VERSION 2.0.20) +set(SDL_URI https://www.libsdl.org/release/SDL2-${SDL_VERSION}.tar.gz) +set(SDL_HASH a53acc02e1cca98c4123229069b67c9e) +set(SDL_HASH_TYPE MD5) +set(SDL_FILE SDL2-${SDL_VERSION}.tar.gz) +set(SDL_CPE "cpe:2.3:a:libsdl:sdl:${SDL_VERSION}:*:*:*:*:*:*:*") + +set(OPENCOLLADA_VERSION v1.6.68) +set(OPENCOLLADA_URI https://github.com/KhronosGroup/OpenCOLLADA/archive/${OPENCOLLADA_VERSION}.tar.gz) +set(OPENCOLLADA_HASH ee7dae874019fea7be11613d07567493) +set(OPENCOLLADA_HASH_TYPE MD5) +set(OPENCOLLADA_FILE opencollada-${OPENCOLLADA_VERSION}.tar.gz) + +set(OPENCOLORIO_VERSION 2.2.0) +set(OPENCOLORIO_URI https://github.com/AcademySoftwareFoundation/OpenColorIO/archive/v${OPENCOLORIO_VERSION}.tar.gz) +set(OPENCOLORIO_HASH d58a5980adba2d89a363100a09daa5f3) +set(OPENCOLORIO_HASH_TYPE MD5) +set(OPENCOLORIO_FILE OpenColorIO-${OPENCOLORIO_VERSION}.tar.gz) + +set(MINIZIPNG_VERSION 3.0.7) +set(MINIZIPNG_URI https://github.com/zlib-ng/minizip-ng/archive/${MINIZIPNG_VERSION}.tar.gz) +set(MINIZIPNG_HASH 09dcc8a9def348e1be9659e384c2cd55) +set(MINIZIPNG_HASH_TYPE MD5) +set(MINIZIPNG_FILE minizip-ng-${MINIZIPNG_VERSION}.tar.gz) + +set(LLVM_VERSION 12.0.0) +set(LLVM_URI https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/llvm-project-${LLVM_VERSION}.src.tar.xz) +set(LLVM_HASH 5a4fab4d7fc84aefffb118ac2c8a4fc0) +set(LLVM_HASH_TYPE MD5) +set(LLVM_FILE llvm-project-${LLVM_VERSION}.src.tar.xz) +set(LLVM_CPE "cpe:2.3:a:llvm:compiler:${LLVM_VERSION}:*:*:*:*:*:*:*") + +if(APPLE) + # Cloth physics test is crashing due to this bug: + # https://bugs.llvm.org/show_bug.cgi?id=50579 + set(OPENMP_VERSION 9.0.1) + set(OPENMP_HASH 6eade16057edbdecb3c4eef9daa2bfcf) +else() + set(OPENMP_VERSION ${LLVM_VERSION}) + set(OPENMP_HASH ac48ce3e4582ccb82f81ab59eb3fc9dc) +endif() +set(OPENMP_URI https://github.com/llvm/llvm-project/releases/download/llvmorg-${OPENMP_VERSION}/openmp-${OPENMP_VERSION}.src.tar.xz) +set(OPENMP_HASH_TYPE MD5) +set(OPENMP_FILE openmp-${OPENMP_VERSION}.src.tar.xz) + +set(OPENIMAGEIO_VERSION v2.4.15.0) +set(OPENIMAGEIO_URI https://github.com/OpenImageIO/oiio/archive/refs/tags/${OPENIMAGEIO_VERSION}.tar.gz) +set(OPENIMAGEIO_HASH 784391406ee309075a3f82e60a42f023) +set(OPENIMAGEIO_HASH_TYPE MD5) +set(OPENIMAGEIO_FILE OpenImageIO-${OPENIMAGEIO_VERSION}.tar.gz) + +# 9.1.0 is currently oiio's preferred version although never versions may be available. +# the preferred version can be found in oiio's externalpackages.cmake +set(FMT_VERSION 9.1.0) +set(FMT_URI https://github.com/fmtlib/fmt/archive/refs/tags/${FMT_VERSION}.tar.gz) +set(FMT_HASH 5dea48d1fcddc3ec571ce2058e13910a0d4a6bab4cc09a809d8b1dd1c88ae6f2) +set(FMT_HASH_TYPE SHA256) +set(FMT_FILE fmt-${FMT_VERSION}.tar.gz) +set(FMT_CPE "cpe:2.3:a:fmt:fmt:${FMT_VERSION}:*:*:*:*:*:*:*") + +# 0.6.2 is currently oiio's preferred version although never versions may be available. +# the preferred version can be found in oiio's externalpackages.cmake +set(ROBINMAP_VERSION v0.6.2) +set(ROBINMAP_URI https://github.com/Tessil/robin-map/archive/refs/tags/${ROBINMAP_VERSION}.tar.gz) +set(ROBINMAP_HASH c08ec4b1bf1c85eb0d6432244a6a89862229da1cb834f3f90fba8dc35d8c8ef1) +set(ROBINMAP_HASH_TYPE SHA256) +set(ROBINMAP_FILE robinmap-${ROBINMAP_VERSION}.tar.gz) + +set(TIFF_VERSION 4.5.1) +set(TIFF_URI http://download.osgeo.org/libtiff/tiff-${TIFF_VERSION}.tar.gz) +set(TIFF_HASH d08c5f9eee6350fffc239e5993d92779) +set(TIFF_HASH_TYPE MD5) +set(TIFF_FILE tiff-${TIFF_VERSION}.tar.gz) +set(TIFF_CPE "cpe:2.3:a:libtiff:libtiff:${TIFF_VERSION}:*:*:*:*:*:*:*") + +# Recent commit from 1.13.0.2 under development, which includes string table +# changes that make the Cycles OptiX implementation work. Official 1.12 OSL +# releases should also build but without OptiX support. +set(OSL_VERSION 1a7670600c8b08c2443a78d03c8c27e9a1149140) +set(OSL_URI https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/archive/${OSL_VERSION}.tar.gz) +set(OSL_HASH 7b6d6716b05d1addb92a8f47280bf77f) +set(OSL_HASH_TYPE MD5) +set(OSL_FILE OpenShadingLanguage-${OSL_VERSION}.tar.gz) + +# NOTE: When updating the python version, it's required to check the versions of +# it wants to use in PCbuild/get_externals.bat for the following dependencies: +# BZIP2, FFI, SQLITE and change the versions in this file as well. For compliance +# reasons there can be no exceptions to this. + +set(PYTHON_VERSION 3.10.13) +set(PYTHON_SHORT_VERSION 3.10) +set(PYTHON_SHORT_VERSION_NO_DOTS 310) +set(PYTHON_URI https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tar.xz) +set(PYTHON_HASH 8847dc6458d1431d0ae0f55942deeb89) +set(PYTHON_HASH_TYPE MD5) +set(PYTHON_FILE Python-${PYTHON_VERSION}.tar.xz) +set(PYTHON_CPE "cpe:2.3:a:python:python:${PYTHON_VERSION}:-:*:*:*:*:*:*") + +set(TBB_YEAR 2020) +set(TBB_VERSION ${TBB_YEAR}_U3) +set(TBB_URI https://github.com/oneapi-src/oneTBB/archive/${TBB_VERSION}.tar.gz) +set(TBB_HASH 55ec8df6eae5ed6364a47f0e671e460c) +set(TBB_HASH_TYPE MD5) +set(TBB_FILE oneTBB-${TBB_VERSION}.tar.gz) +set(TBB_CPE "cpe:2.3:a:intel:threading_building_blocks:${TBB_YEAR}:*:*:*:*:*:*:*") + +set(OPENVDB_VERSION 10.0.0) +set(OPENVDB_URI https://github.com/AcademySoftwareFoundation/openvdb/archive/v${OPENVDB_VERSION}.tar.gz) +set(OPENVDB_HASH 64301c737e16b26c8f3085a31e6397e9) +set(OPENVDB_HASH_TYPE MD5) +set(OPENVDB_FILE openvdb-${OPENVDB_VERSION}.tar.gz) + +# ------------------------------------------------------------------------------ +# Python Modules + +# Needed by: `requests` module (so the version doesn't change on rebuild). +set(IDNA_VERSION 3.3) +# Needed by: `requests` module (so the version doesn't change on rebuild). +set(CHARSET_NORMALIZER_VERSION 2.0.10) +# Needed by: `requests` module (so the version doesn't change on rebuild). +set(URLLIB3_VERSION 1.26.8) +set(URLLIB3_CPE "cpe:2.3:a:urllib3:urllib3:${URLLIB3_VERSION}:*:*:*:*:*:*:*") +# Needed by: Python's `requests` module (so add-ons can authenticate against trusted certificates). +set(CERTIFI_VERSION 2021.10.8) +# Needed by: Some of Blender's add-ons (to support convenient interaction with online services). +set(REQUESTS_VERSION 2.27.1) +# Needed by: Python's `numpy` module (used by some add-ons). +set(CYTHON_VERSION 0.29.30) +# Needed by: Python scripts that read `.blend` files, as files may use Z-standard compression. +# The version of the ZSTD library used to build the Python package should match ZSTD_VERSION +# defined below. At this time of writing, 0.17.0 was already released, +# but built against ZSTD 1.5.1, while we use 1.5.0. +set(ZSTANDARD_VERSION 0.16.0) +# Auto-format Python source (developer tool, not used by Blender at run-time). +set(AUTOPEP8_VERSION 1.6.0) +# Needed by: `autopep8` (so the version doesn't change on rebuild). +set(PYCODESTYLE_VERSION 2.8.0) +# Needed by: `autopep8` (so the version doesn't change on rebuild). +set(TOML_VERSION 0.10.2) +# Build system for other packages (not used by Blender at run-time). +set(MESON_VERSION 0.63.0) + +set(NUMPY_VERSION 1.23.5) +set(NUMPY_SHORT_VERSION 1.23) +set(NUMPY_URI https://github.com/numpy/numpy/releases/download/v${NUMPY_VERSION}/numpy-${NUMPY_VERSION}.tar.gz) +set(NUMPY_HASH 8b2692a511a3795f3af8af2cd7566a15) +set(NUMPY_HASH_TYPE MD5) +set(NUMPY_FILE numpy-${NUMPY_VERSION}.tar.gz) +set(NUMPY_CPE "cpe:2.3:a:numpy:numpy:${NUMPY_VERSION}:*:*:*:*:*:*:*") + +set(LAME_VERSION 3.100) +set(LAME_URI http://downloads.sourceforge.net/project/lame/lame/3.100/lame-${LAME_VERSION}.tar.gz) +set(LAME_HASH 83e260acbe4389b54fe08e0bdbf7cddb) +set(LAME_HASH_TYPE MD5) +set(LAME_FILE lame-${LAME_VERSION}.tar.gz) +set(LAME_CPE "cpe:2.3:a:lame_project:lame:${LAME_VERSION}:*:*:*:*:*:*:*") + +set(OGG_VERSION 1.3.5) +set(OGG_URI http://downloads.xiph.org/releases/ogg/libogg-${OGG_VERSION}.tar.gz) +set(OGG_HASH 0eb4b4b9420a0f51db142ba3f9c64b333f826532dc0f48c6410ae51f4799b664) +set(OGG_HASH_TYPE SHA256) +set(OGG_FILE libogg-${OGG_VERSION}.tar.gz) + +set(VORBIS_VERSION 1.3.7) +set(VORBIS_URI http://downloads.xiph.org/releases/vorbis/libvorbis-${VORBIS_VERSION}.tar.gz) +set(VORBIS_HASH 0e982409a9c3fc82ee06e08205b1355e5c6aa4c36bca58146ef399621b0ce5ab) +set(VORBIS_HASH_TYPE SHA256) +set(VORBIS_FILE libvorbis-${VORBIS_VERSION}.tar.gz) +set(VORBIS_CPE "cpe:2.3:a:xiph.org:libvorbis:${VORBIS_VERSION}:*:*:*:*:*:*:*") + +set(THEORA_VERSION 1.1.1) +set(THEORA_URI http://downloads.xiph.org/releases/theora/libtheora-${THEORA_VERSION}.tar.bz2) +set(THEORA_HASH b6ae1ee2fa3d42ac489287d3ec34c5885730b1296f0801ae577a35193d3affbc) +set(THEORA_HASH_TYPE SHA256) +set(THEORA_FILE libtheora-${THEORA_VERSION}.tar.bz2) + +set(FLAC_VERSION 1.4.2) +set(FLAC_URI http://downloads.xiph.org/releases/flac/flac-${FLAC_VERSION}.tar.xz) +set(FLAC_HASH e322d58a1f48d23d9dd38f432672865f6f79e73a6f9cc5a5f57fcaa83eb5a8e4 ) +set(FLAC_HASH_TYPE SHA256) +set(FLAC_FILE flac-${FLAC_VERSION}.tar.xz) +set(FLAC_CPE "cpe:2.3:a:flac_project:flac:${FLAC_VERSION}:*:*:*:*:*:*:*") + +set(VPX_VERSION 1.11.0) +set(VPX_URI https://github.com/webmproject/libvpx/archive/v${VPX_VERSION}/libvpx-v${VPX_VERSION}.tar.gz) +set(VPX_HASH 965e51c91ad9851e2337aebcc0f517440c637c506f3a03948062e3d5ea129a83) +set(VPX_HASH_TYPE SHA256) +set(VPX_FILE libvpx-v${VPX_VERSION}.tar.gz) +set(VPX_CPE "cpe:2.3:a:webmproject:libvpx:${VPX_VERSION}:*:*:*:*:*:*:*") + +set(OPUS_VERSION 1.3.1) +set(OPUS_URI https://archive.mozilla.org/pub/opus/opus-${OPUS_VERSION}.tar.gz) +set(OPUS_HASH 65b58e1e25b2a114157014736a3d9dfeaad8d41be1c8179866f144a2fb44ff9d) +set(OPUS_HASH_TYPE SHA256) +set(OPUS_FILE opus-${OPUS_VERSION}.tar.gz) + +set(X264_VERSION 35fe20d1ba49918ec739a5b068c208ca82f977f7) +set(X264_URI https://code.videolan.org/videolan/x264/-/archive/${X264_VERSION}/x264-${X264_VERSION}.tar.gz) +set(X264_HASH bb4f7da03936b5a030ed5827133b58eb3f701d7e5dce32cca4ba6df93797d42e) +set(X264_HASH_TYPE SHA256) +set(X264_FILE x264-${X264_VERSION}.tar.gz) + +set(XVIDCORE_VERSION 1.3.7) +set(XVIDCORE_URI https://downloads.xvid.com/downloads/xvidcore-${XVIDCORE_VERSION}.tar.gz) +set(XVIDCORE_HASH abbdcbd39555691dd1c9b4d08f0a031376a3b211652c0d8b3b8aa9be1303ce2d) +set(XVIDCORE_HASH_TYPE SHA256) +set(XVIDCORE_FILE xvidcore-${XVIDCORE_VERSION}.tar.gz) + +set(OPENJPEG_VERSION 2.5.0) +set(OPENJPEG_SHORT_VERSION 2.5) +set(OPENJPEG_URI https://github.com/uclouvain/openjpeg/archive/v${OPENJPEG_VERSION}.tar.gz) +set(OPENJPEG_HASH 0333806d6adecc6f7a91243b2b839ff4d2053823634d4f6ed7a59bc87409122a) +set(OPENJPEG_HASH_TYPE SHA256) +set(OPENJPEG_FILE openjpeg-v${OPENJPEG_VERSION}.tar.gz) +set(OPENJPEG_CPE "cpe:2.3:a:uclouvain:openjpeg:${OPENJPEG_VERSION}:*:*:*:*:*:*:*") + +set(FFMPEG_VERSION 6.0) +set(FFMPEG_URI http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.bz2) +set(FFMPEG_HASH 47d062731c9f66a78380e35a19aac77cebceccd1c7cc309b9c82343ffc430c3d) +set(FFMPEG_HASH_TYPE SHA256) +set(FFMPEG_FILE ffmpeg-${FFMPEG_VERSION}.tar.bz2) +set(FFMPEG_CPE "cpe:2.3:a:ffmpeg:ffmpeg:${FFMPEG_VERSION}:*:*:*:*:*:*:*") + +set(FFTW_VERSION 3.3.10) +set(FFTW_URI http://www.fftw.org/fftw-${FFTW_VERSION}.tar.gz) +set(FFTW_HASH 8ccbf6a5ea78a16dbc3e1306e234cc5c) +set(FFTW_HASH_TYPE MD5) +set(FFTW_FILE fftw-${FFTW_VERSION}.tar.gz) + +set(ICONV_VERSION 1.16) +set(ICONV_URI http://ftp.gnu.org/pub/gnu/libiconv/libiconv-${ICONV_VERSION}.tar.gz) +set(ICONV_HASH 7d2a800b952942bb2880efb00cfd524c) +set(ICONV_HASH_TYPE MD5) +set(ICONV_FILE libiconv-${ICONV_VERSION}.tar.gz) + +set(SNDFILE_VERSION 1.2.2) +set(SNDFILE_URI https://github.com/libsndfile/libsndfile/releases/download/1.2.2/libsndfile-${SNDFILE_VERSION}.tar.xz) +set(SNDFILE_HASH 04e2e6f726da7c5dc87f8cf72f250d04) +set(SNDFILE_HASH_TYPE MD5) +set(SNDFILE_FILE libsndfile-${SNDFILE_VERSION}.tar.xz) +set(SNDFILE_CPE "cpe:2.3:a:libsndfile_project:libsndfile:${SNDFILE_VERSION}:*:*:*:*:*:*:*") + +set(WEBP_VERSION 1.3.2) +set(WEBP_URI https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-${WEBP_VERSION}.tar.gz) +set(WEBP_HASH 34869086761c0e2da6361035f7b64771) +set(WEBP_HASH_TYPE MD5) +set(WEBP_FILE libwebp-${WEBP_VERSION}.tar.gz) +set(WEBP_CPE "cpe:2.3:a:webmproject:libwebp:${WEBP_VERSION}:*:*:*:*:*:*:*") + +set(SPNAV_VERSION 1.1) +set(SPNAV_URI https://github.com/FreeSpacenav/libspnav/releases/download/v${SPNAV_VERSION}/libspnav-${SPNAV_VERSION}.tar.gz) +set(SPNAV_HASH 7c0032034672dfba3c4bb9b49a440e70) +set(SPNAV_HASH_TYPE MD5) +set(SPNAV_FILE libspnav-${SPNAV_VERSION}.tar.gz) + +set(JEMALLOC_VERSION 5.2.1) +set(JEMALLOC_URI https://github.com/jemalloc/jemalloc/releases/download/${JEMALLOC_VERSION}/jemalloc-${JEMALLOC_VERSION}.tar.bz2) +set(JEMALLOC_HASH 3d41fbf006e6ebffd489bdb304d009ae) +set(JEMALLOC_HASH_TYPE MD5) +set(JEMALLOC_FILE jemalloc-${JEMALLOC_VERSION}.tar.bz2) + +set(XML2_VERSION 2.10.4) +set(XML2_URI https://download.gnome.org/sources/libxml2/2.10/libxml2-${XML2_VERSION}.tar.xz) +set(XML2_HASH 76808c467a58c31e2dbd511e71d5fd13) +set(XML2_HASH_TYPE MD5) +set(XML2_FILE libxml2-${XML2_VERSION}.tar.xz) +set(XML2_CPE "cpe:2.3:a:xmlsoft:libxml2:${XML2_VERSION}:*:*:*:*:*:*:*") + +set(YAMLCPP_VERSION 0.7.0) +set(YAMLCPP_URI https://codeload.github.com/jbeder/yaml-cpp/tar.gz/yaml-cpp-${YAMLCPP_VERSION}) +set(YAMLCPP_HASH 74d646a3cc1b5d519829441db96744f0) +set(YAMLCPP_HASH_TYPE MD5) +set(YAMLCPP_FILE yaml-cpp-${YAMLCPP_VERSION}.tar.gz) +set(YAMLCPP "cpe:2.3:a:yaml-cpp_project:yaml-cpp:${YAMLCPP_VERSION}:*:*:*:*:*:*:*") + +set(PYSTRING_VERSION v1.1.3) +set(PYSTRING_URI https://codeload.github.com/imageworks/pystring/tar.gz/refs/tags/${PYSTRING_VERSION}) +set(PYSTRING_HASH f2c68786b359f5e4e62bed53bc4fb86d) +set(PYSTRING_HASH_TYPE MD5) +set(PYSTRING_FILE pystring-${PYSTRING_VERSION}.tar.gz) + +set(EXPAT_VERSION 2_5_0) +set(EXPAT_VERSION_DOTS 2.5.0) +set(EXPAT_URI https://github.com/libexpat/libexpat/archive/R_${EXPAT_VERSION}.tar.gz) +set(EXPAT_HASH d375fa3571c0abb945873f5061a8f2e2) +set(EXPAT_HASH_TYPE MD5) +set(EXPAT_FILE libexpat-${EXPAT_VERSION}.tar.gz) +set(EXPAT_CPE "cpe:2.3:a:libexpat_project:libexpat:${EXPAT_VERSION_DOTS}:*:*:*:*:*:*:*") + +set(PUGIXML_VERSION 1.10) +set(PUGIXML_URI https://github.com/zeux/pugixml/archive/v${PUGIXML_VERSION}.tar.gz) +set(PUGIXML_HASH 0c208b0664c7fb822bf1b49ad035e8fd) +set(PUGIXML_HASH_TYPE MD5) +set(PUGIXML_FILE pugixml-${PUGIXML_VERSION}.tar.gz) +set(PUGIXML_CPE "cpe:2.3:a:pugixml_project:pugixml:${PUGIXML_VERSION}:*:*:*:*:*:*:*") + +set(FLEXBISON_VERSION 2.5.24) +set(FLEXBISON_URI http://prdownloads.sourceforge.net/winflexbison/win_flex_bison-${FLEXBISON_VERSION}.zip) +set(FLEXBISON_HASH 6b549d43e34ece0e8ed05af92daa31c4) +set(FLEXBISON_HASH_TYPE MD5) +set(FLEXBISON_FILE win_flex_bison-${FLEXBISON_VERSION}.zip) + +set(FLEX_VERSION 2.6.4) +set(FLEX_URI https://github.com/westes/flex/releases/download/v${FLEX_VERSION}/flex-${FLEX_VERSION}.tar.gz) +set(FLEX_HASH 2882e3179748cc9f9c23ec593d6adc8d) +set(FLEX_HASH_TYPE MD5) +set(FLEX_FILE flex-${FLEX_VERSION}.tar.gz) + +# Libraries to keep Python modules static on Linux. + +# NOTE: bzip.org domain does no longer belong to BZip 2 project, so we download +# sources from Debian packaging. +# +# NOTE 2: This will *HAVE* to match the version python ships on windows which +# is hardcoded in pythons PCbuild/get_externals.bat. For compliance reasons there +# can be no exceptions to this. +set(BZIP2_VERSION 1.0.8) +set(BZIP2_URI http://http.debian.net/debian/pool/main/b/bzip2/bzip2_${BZIP2_VERSION}.orig.tar.gz) +set(BZIP2_HASH ab5a03176ee106d3f0fa90e381da478ddae405918153cca248e682cd0c4a2269) +set(BZIP2_HASH_TYPE SHA256) +set(BZIP2_FILE bzip2_${BZIP2_VERSION}.orig.tar.gz) +set(BZIP2_CPE "cpe:2.3:a:bzip:bzip2:${BZIP2_VERSION}:*:*:*:*:*:*:*") + +# NOTE: This will *HAVE* to match the version python ships on windows which +# is hardcoded in pythons PCbuild/get_externals.bat. For compliance reasons there +# can be no exceptions to this. +set(FFI_VERSION 3.3) +set(FFI_URI https://sourceware.org/pub/libffi/libffi-${FFI_VERSION}.tar.gz) +set(FFI_HASH 72fba7922703ddfa7a028d513ac15a85c8d54c8d67f55fa5a4802885dc652056) +set(FFI_HASH_TYPE SHA256) +set(FFI_FILE libffi-${FFI_VERSION}.tar.gz) +set(FFI_CPE "cpe:2.3:a:libffi_project:libffi:${FFI_VERSION}:*:*:*:*:*:*:*") + +set(LZMA_VERSION 5.2.5) +set(LZMA_URI https://tukaani.org/xz/xz-${LZMA_VERSION}.tar.bz2) +set(LZMA_HASH 5117f930900b341493827d63aa910ff5e011e0b994197c3b71c08a20228a42df) +set(LZMA_HASH_TYPE SHA256) +set(LZMA_FILE xz-${LZMA_VERSION}.tar.bz2) + +# NOTE: Python's build has been modified to use our ssl version. +set(SSL_VERSION 3.1.2) +set(SSL_URI https://www.openssl.org/source/openssl-${SSL_VERSION}.tar.gz) +set(SSL_HASH a0ce69b8b97ea6a35b96875235aa453b966ba3cba8af2de23657d8b6767d6539) +set(SSL_HASH_TYPE SHA256) +set(SSL_FILE openssl-${SSL_VERSION}.tar.gz) +set(SSL_CPE "cpe:2.3:a:openssl:openssl:${SSL_VERSION}:*:*:*:*:*:*:*") + +# Note: This will *HAVE* to match the version python ships on windows which +# is hardcoded in pythons PCbuild/get_externals.bat for compliance reasons there +# can be no exceptions to this. +set(SQLITE_VERSION 3.40.1) +set(SQLLITE_LONG_VERSION 3400100) +set(SQLITE_URI https://www.sqlite.org/2022/sqlite-autoconf-${SQLLITE_LONG_VERSION}.tar.gz) +set(SQLITE_HASH b8c2d4bc0094f5c0ce985dc0e237dfcbaa1f6275) +set(SQLITE_HASH_TYPE SHA1) +set(SQLITE_FILE sqlite-autoconf-${SQLLITE_LONG_VERSION}.tar.gz) +set(SQLITE_CPE "cpe:2.3:a:sqlite:sqlite:${SQLITE_VERSION}:*:*:*:*:*:*:*") + +set(EMBREE_VERSION 4.1.0) +set(EMBREE_URI https://github.com/embree/embree/archive/v${EMBREE_VERSION}.zip) +set(EMBREE_HASH 4b525955b08e1249a700dea5b5ffc8b2) +set(EMBREE_HASH_TYPE MD5) +set(EMBREE_FILE embree-v${EMBREE_VERSION}.zip) + +set(USD_VERSION 23.05) +set(USD_URI https://github.com/PixarAnimationStudios/OpenUSD/archive/v${USD_VERSION}.tar.gz) +set(USD_HASH d4d92ff112bc82a1718bcd129b853a54) +set(USD_HASH_TYPE MD5) +set(USD_FILE usd-v${USD_VERSION}.tar.gz) + +set(MATERIALX_VERSION 1.38.6) +set(MATERIALX_URI https://github.com/AcademySoftwareFoundation/MaterialX/archive/refs/tags/v${MATERIALX_VERSION}.tar.gz) +set(MATERIALX_HASH d49c9fdef34b5702fc60058d3e1864f2) +set(MATERIALX_HASH_TYPE MD5) +set(MATERIALX_FILE materialx-v${MATERIALX_VERSION}.tar.gz) + +set(OIDN_VERSION 1.4.3) +set(OIDN_URI https://github.com/OpenImageDenoise/oidn/releases/download/v${OIDN_VERSION}/oidn-${OIDN_VERSION}.src.tar.gz) +set(OIDN_HASH 027093eaf5e8b4e45835b991137b38e6) +set(OIDN_HASH_TYPE MD5) +set(OIDN_FILE oidn-${OIDN_VERSION}.src.tar.gz) + +set(LIBGLU_VERSION 9.0.1) +set(LIBGLU_URI https://archive.mesa3d.org/glu/glu-${LIBGLU_VERSION}.tar.xz) +set(LIBGLU_HASH 151aef599b8259efe9acd599c96ea2a3) +set(LIBGLU_HASH_TYPE MD5) +set(LIBGLU_FILE glu-${LIBGLU_VERSION}.tar.xz) + +set(MESA_VERSION 21.1.5) +set(MESA_URI https://archive.mesa3d.org/older-versions/21.x/mesa-${MESA_VERSION}.tar.xz) +set(MESA_HASH 022c7293074aeeced2278c872db4fa693147c70f8595b076cf3f1ef81520766d) +set(MESA_HASH_TYPE SHA256) +set(MESA_FILE mesa-${MESA_VERSION}.tar.xz) +set(MESA_CPE "cpe:2.3:a:mesa3d:mesa:${MESA_VERSION}:*:*:*:*:*:*:*") + +set(NASM_VERSION 2.15.02) +set(NASM_URI https://github.com/netwide-assembler/nasm/archive/nasm-${NASM_VERSION}.tar.gz) +set(NASM_HASH aded8b796c996a486a56e0515c83e414116decc3b184d88043480b32eb0a8589) +set(NASM_HASH_TYPE SHA256) +set(NASM_FILE nasm-${NASM_VERSION}.tar.gz) +set(NASM_PCE "cpe:2.3:a:nasm:nasm:${NASM_VERSION}:*:*:*:*:*:*:*") + +set(XR_OPENXR_SDK_VERSION 1.0.22) +set(XR_OPENXR_SDK_URI https://github.com/KhronosGroup/OpenXR-SDK/archive/release-${XR_OPENXR_SDK_VERSION}.tar.gz) +set(XR_OPENXR_SDK_HASH a2623ebab3d0b340bc16311b14f02075) +set(XR_OPENXR_SDK_HASH_TYPE MD5) +set(XR_OPENXR_SDK_FILE OpenXR-SDK-${XR_OPENXR_SDK_VERSION}.tar.gz) + +set(WL_PROTOCOLS_VERSION 1.31) +set(WL_PROTOCOLS_FILE wayland-protocols-${WL_PROTOCOLS_VERSION}.tar.gz) +set(WL_PROTOCOLS_URI https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/${WL_PROTOCOLS_VERSION}/${WL_PROTOCOLS_FILE}) +set(WL_PROTOCOLS_HASH a28ff59a56e2ebb746048b6ef8d931d6) +set(WL_PROTOCOLS_HASH_TYPE MD5) + +set(WAYLAND_VERSION 1.22.0) +set(WAYLAND_FILE wayland-${WAYLAND_VERSION}.tar.xz) +set(WAYLAND_URI https://gitlab.freedesktop.org/wayland/wayland/-/releases/${WAYLAND_VERSION}/downloads/wayland-${WAYLAND_VERSION}.tar.xz) +set(WAYLAND_HASH 7410ab549e3928fce9381455b17b0803) +set(WAYLAND_HASH_TYPE MD5) + +set(WAYLAND_LIBDECOR_VERSION 0.1.0) +set(WAYLAND_LIBDECOR_FILE libdecor-${WAYLAND_LIBDECOR_VERSION}.tar.xz) +set(WAYLAND_LIBDECOR_URI https://gitlab.gnome.org/jadahl/libdecor/uploads/81adf91d27620e20bcc5f6b9b312d768/libdecor-${WAYLAND_LIBDECOR_VERSION}.tar.xz ) +set(WAYLAND_LIBDECOR_HASH 47b59eba76faa3787f0878bf8700e912) +set(WAYLAND_LIBDECOR_HASH_TYPE MD5) + +set(ISPC_VERSION v1.17.0) +set(ISPC_URI https://github.com/ispc/ispc/archive/${ISPC_VERSION}.tar.gz) +set(ISPC_HASH 4f476a3109332a77fe839a9014c60ca9) +set(ISPC_HASH_TYPE MD5) +set(ISPC_FILE ispc-${ISPC_VERSION}.tar.gz) + +set(GMP_VERSION 6.2.1) +set(GMP_URI https://gmplib.org/download/gmp/gmp-${GMP_VERSION}.tar.xz) +set(GMP_HASH 0b82665c4a92fd2ade7440c13fcaa42b) +set(GMP_HASH_TYPE MD5) +set(GMP_FILE gmp-${GMP_VERSION}.tar.xz) +set(GMP_CPE "cpe:2.3:a:gmplib:gmp:${GMP_VERSION}:*:*:*:*:*:*:*") + +set(POTRACE_VERSION 1.16) +set(POTRACE_URI http://potrace.sourceforge.net/download/${POTRACE_VERSION}/potrace-${POTRACE_VERSION}.tar.gz) +set(POTRACE_HASH 5f0bd87ddd9a620b0c4e65652ef93d69) +set(POTRACE_HASH_TYPE MD5) +set(POTRACE_FILE potrace-${POTRACE_VERSION}.tar.gz) +set(POTRACE_CPE "cpe:2.3:a:icoasoft:potrace:${POTRACE_VERSION}:*:*:*:*:*:*:*") + +set(HARU_VERSION 2_3_0) +set(HARU_URI https://github.com/libharu/libharu/archive/RELEASE_${HARU_VERSION}.tar.gz) +set(HARU_HASH 4f916aa49c3069b3a10850013c507460) +set(HARU_HASH_TYPE MD5) +set(HARU_FILE libharu-${HARU_VERSION}.tar.gz) + +set(ZSTD_VERSION 1.5.0) +set(ZSTD_URI https://github.com/facebook/zstd/releases/download/v${ZSTD_VERSION}/zstd-${ZSTD_VERSION}.tar.gz) +set(ZSTD_HASH 5194fbfa781fcf45b98c5e849651aa7b3b0a008c6b72d4a0db760f3002291e94) +set(ZSTD_HASH_TYPE SHA256) +set(ZSTD_FILE zstd-${ZSTD_VERSION}.tar.gz) +set(ZSTD_CPE "cpe:2.3:a:facebook:zstandard:${ZSTD_VERSION}:*:*:*:*:*:*:*") + +set(SSE2NEON_VERSION v1.6.0) +set(SSE2NEON_URI https://github.com/DLTcollab/sse2neon/archive/${SSE2NEON_VERSION}.tar.gz) +set(SSE2NEON_HASH 06f4693219deccb91b457135d836fc514a1c0a57e9fa66b143982901d2d19677) +set(SSE2NEON_HASH_TYPE SHA256) +set(SSE2NEON_FILE sse2neon-${SSE2NEON_VERSION}.tar.gz) + +set(BROTLI_VERSION 1.0.9) +set(BROTLI_URI https://github.com/google/brotli/archive/refs/tags/v${BROTLI_VERSION}.tar.gz) +set(BROTLI_HASH f9e8d81d0405ba66d181529af42a3354f838c939095ff99930da6aa9cdf6fe46) +set(BROTLI_HASH_TYPE SHA256) +set(BROTLI_FILE brotli-v${BROTLI_VERSION}.tar.gz) +set(BROTLI_CPE "cpe:2.3:a:google:brotli:${BROTLI_VERSION}:*:*:*:*:*:*:*") + +set(OPENPGL_VERSION v0.5.0) +set(OPENPGL_SHORT_VERSION 0.5.0) +set(OPENPGL_URI https://github.com/OpenPathGuidingLibrary/openpgl/archive/refs/tags/${OPENPGL_VERSION}.tar.gz) +set(OPENPGL_HASH 1ec806d434d45e43e098f82ee9be0cb74928343898c57490b34ff80584e9805a) +set(OPENPGL_HASH_TYPE SHA256) +set(OPENPGL_FILE openpgl-${OPENPGL_VERSION}.tar.gz) + +set(LEVEL_ZERO_VERSION v1.8.8) +set(LEVEL_ZERO_URI https://github.com/oneapi-src/level-zero/archive/refs/tags/${LEVEL_ZERO_VERSION}.tar.gz) +set(LEVEL_ZERO_HASH 3553ae8fa0d2d69c4210a8f3428bd6612bd8bb8a627faf52c3658a01851e66d2) +set(LEVEL_ZERO_HASH_TYPE SHA256) +set(LEVEL_ZERO_FILE level-zero-${LEVEL_ZERO_VERSION}.tar.gz) + +set(DPCPP_VERSION 2022-12) +set(DPCPP_URI https://github.com/intel/llvm/archive/refs/tags/${DPCPP_VERSION}.tar.gz) +set(DPCPP_HASH 13151d5ae79f7c9c4a9b072a0c486ae7b3c4993e301bb1268c92214451025790) +set(DPCPP_HASH_TYPE SHA256) +set(DPCPP_FILE DPCPP-${DPCPP_VERSION}.tar.gz) + +######################## +### DPCPP DEPS BEGIN ### +######################## +# The following deps are build time requirements for dpcpp, when possible +# the source in the dpcpp source tree for the version chosen is documented +# by each dep, these will only have to be downloaded and unpacked, dpcpp +# will take care of building them, unpack is being done in dpcpp_deps.cmake + +# Source llvm/lib/SYCLLowerIR/CMakeLists.txt +set(VCINTRINSICS_VERSION 782fbf7301dc73acaa049a4324c976ad94f587f7) +set(VCINTRINSICS_URI https://github.com/intel/vc-intrinsics/archive/${VCINTRINSICS_VERSION}.tar.gz) +set(VCINTRINSICS_HASH f4c0ccad8c1f77760364c551c65e8e1cf194d058889fa46d3b1b2d19ec4dc33f) +set(VCINTRINSICS_HASH_TYPE SHA256) +set(VCINTRINSICS_FILE vc-intrinsics-${VCINTRINSICS_VERSION}.tar.gz) + +# Source opencl/CMakeLists.txt +set(OPENCLHEADERS_VERSION dcd5bede6859d26833cd85f0d6bbcee7382dc9b3) +set(OPENCLHEADERS_URI https://github.com/KhronosGroup/OpenCL-Headers/archive/${OPENCLHEADERS_VERSION}.tar.gz) +set(OPENCLHEADERS_HASH ca8090359654e94f2c41e946b7e9d826253d795ae809ce7c83a7d3c859624693) +set(OPENCLHEADERS_HASH_TYPE SHA256) +set(OPENCLHEADERS_FILE opencl_headers-${OPENCLHEADERS_VERSION}.tar.gz) + +# Source opencl/CMakeLists.txt +set(ICDLOADER_VERSION 792682ad3d877ab38573b997808bab3b43902b70) +set(ICDLOADER_URI https://github.com/KhronosGroup/OpenCL-ICD-Loader/archive/${ICDLOADER_VERSION}.tar.gz) +set(ICDLOADER_HASH b33a0320d94bf300efa1da97931ded506d27813bd1148da6858fe79d412d1ea2) +set(ICDLOADER_HASH_TYPE SHA256) +set(ICDLOADER_FILE icdloader-${ICDLOADER_VERSION}.tar.gz) + +# Source sycl/cmake/modules/AddBoostMp11Headers.cmake +# Using external MP11 here, getting AddBoostMp11Headers.cmake to recognize +# our copy in boost directly was more trouble than it was worth. +set(MP11_VERSION 7bc4e1ae9b36ec8ee635c3629b59ec525bbe82b9) +set(MP11_URI https://github.com/boostorg/mp11/archive/${MP11_VERSION}.tar.gz) +set(MP11_HASH 071ee2bd3952ec89882edb3af25dd1816f6b61723f66e42eea32f4d02ceef426) +set(MP11_HASH_TYPE SHA256) +set(MP11_FILE mp11-${MP11_VERSION}.tar.gz) + +# Source llvm-spirv/CMakeLists.txt (repo) +# Source llvm-spirv/spirv-headers-tag.conf (hash) +set(SPIRV_HEADERS_VERSION 5a121866927a16ab9d49bed4788b532c7fcea766) +set(SPIRV_HEADERS_URI https://github.com/KhronosGroup/SPIRV-Headers/archive/${SPIRV_HEADERS_VERSION}.tar.gz) +set(SPIRV_HEADERS_HASH ec8ecb471a62672697846c436501638ab25447ae9d4a6761e0bfe8a9a839502a) +set(SPIRV_HEADERS_HASH_TYPE SHA256) +set(SPIRV_HEADERS_FILE SPIR-V-Headers-${SPIRV_HEADERS_VERSION}.tar.gz) + +# Source llvm/sycl/plugins/unified_runtime/CMakeLists.txt +set(UNIFIED_RUNTIME_VERSION fd711c920acc4434cb52ff18b078c082d9d7f44d) +set(UNIFIED_RUNTIME_URI https://github.com/oneapi-src/unified-runtime/archive/${UNIFIED_RUNTIME_VERSION}.tar.gz) +set(UNIFIED_RUNTIME_HASH 535ca2ee78f68c5e7e62b10f1bbabd909179488885566e6d9b1fc50e8a1be65f) +set(UNIFIED_RUNTIME_HASH_TYPE SHA256) +set(UNIFIED_RUNTIME_FILE unified-runtime-${UNIFIED_RUNTIME_VERSION}.tar.gz) + +###################### +### DPCPP DEPS END ### +###################### + +########################################## +### Intel Graphics Compiler DEPS BEGIN ### +########################################## +# The following deps are build time requirements for the intel graphics +# compiler, the versions used are taken from the following location +# https://github.com/intel/intel-graphics-compiler/releases + +set(IGC_VERSION 1.0.15468.25) +set(IGC_URI https://github.com/intel/intel-graphics-compiler/archive/refs/tags/igc-${IGC_VERSION}.tar.gz) +set(IGC_HASH c2c36af98ead4f4f6975633eaa53f45b84cb96ce48d9bfa879bebfaf12367b79) +set(IGC_HASH_TYPE SHA256) +set(IGC_FILE igc-${IGC_VERSION}.tar.gz) + +set(IGC_LLVM_VERSION llvmorg-14.0.5) +set(IGC_LLVM_URI https://github.com/llvm/llvm-project/archive/refs/tags/${IGC_LLVM_VERSION}.tar.gz) +set(IGC_LLVM_HASH a4a57f029cb81f04618e05853f05fc2d21b64353c760977d8e7799bf7218a23a) +set(IGC_LLVM_HASH_TYPE SHA256) +set(IGC_LLVM_FILE ${IGC_LLVM_VERSION}.tar.gz) + +# WARNING WARNING WARNING +# +# IGC_OPENCL_CLANG contains patches for some of its dependencies. +# +# Whenever IGC_OPENCL_CLANG_VERSION changes, one *MUST* inspect +# IGC_OPENCL_CLANG's patches folder and update igc.cmake to account for +# any added or removed patches. +# +# WARNING WARNING WARNING + +set(IGC_OPENCL_CLANG_VERSION cf95b338d14685e4f3402ab1828bef31d48f1fd6) +set(IGC_OPENCL_CLANG_URI https://github.com/intel/opencl-clang/archive/${IGC_OPENCL_CLANG_VERSION}.tar.gz) +set(IGC_OPENCL_CLANG_HASH e6191148c87ac7fdc2806b04feeb008c217344ee4dd1308b87e4c6cf3112d4bc) +set(IGC_OPENCL_CLANG_HASH_TYPE SHA256) +set(IGC_OPENCL_CLANG_FILE opencl-clang-${IGC_OPENCL_CLANG_VERSION}.tar.gz) + +set(IGC_VCINTRINSICS_VERSION v0.13.0) +set(IGC_VCINTRINSICS_URI https://github.com/intel/vc-intrinsics/archive/refs/tags/${IGC_VCINTRINSICS_VERSION}.tar.gz) +set(IGC_VCINTRINSICS_HASH f98e265b38312cceaa3276b9800e0c5b1f167e5807d50abd9585268c7025e9b7) +set(IGC_VCINTRINSICS_HASH_TYPE SHA256) +set(IGC_VCINTRINSICS_FILE vc-intrinsics-${IGC_VCINTRINSICS_VERSION}.tar.gz) + +set(IGC_SPIRV_HEADERS_VERSION sdk-1.3.239.0) +set(IGC_SPIRV_HEADERS_URI https://github.com/KhronosGroup/SPIRV-Headers/archive/refs/tags/${IGC_SPIRV_HEADERS_VERSION}.tar.gz) +set(IGC_SPIRV_HEADERS_HASH fdaf6670e311cd1c08ae90bf813e89dd31630205bc60030ffd25fb0af39b51fe) +set(IGC_SPIRV_HEADERS_HASH_TYPE SHA256) +set(IGC_SPIRV_HEADERS_FILE SPIR-V-Headers-${IGC_SPIRV_HEADERS_VERSION}.tar.gz) + +set(IGC_SPIRV_TOOLS_VERSION sdk-1.3.239.0) +set(IGC_SPIRV_TOOLS_URI https://github.com/KhronosGroup/SPIRV-Tools/archive/refs/tags/${IGC_SPIRV_TOOLS_VERSION}.tar.gz) +set(IGC_SPIRV_TOOLS_HASH 327b2dba4515646eee28c1a5fe1332891e81c8b6ff289363f52877f3e67c2d81) +set(IGC_SPIRV_TOOLS_HASH_TYPE SHA256) +set(IGC_SPIRV_TOOLS_FILE SPIR-V-Tools-${IGC_SPIRV_TOOLS_VERSION}.tar.gz) + +set(IGC_SPIRV_TRANSLATOR_VERSION 7e332d0acc8ee57462d9fbedefaf411fc193fdd0) +set(IGC_SPIRV_TRANSLATOR_URI https://github.com/KhronosGroup/SPIRV-LLVM-Translator/archive/${IGC_SPIRV_TRANSLATOR_VERSION}.tar.gz) +set(IGC_SPIRV_TRANSLATOR_HASH 29aadf5fd4e64ff1d4f86446eacd6a7439efeb280478988c36314c4441072c36) +set(IGC_SPIRV_TRANSLATOR_HASH_TYPE SHA256) +set(IGC_SPIRV_TRANSLATOR_FILE SPIR-V-Translator-${IGC_SPIRV_TRANSLATOR_VERSION}.tar.gz) + +######################################## +### Intel Graphics Compiler DEPS END ### +######################################## + +set(GMMLIB_VERSION intel-gmmlib-22.3.11) +set(GMMLIB_URI https://github.com/intel/gmmlib/archive/refs/tags/${GMMLIB_VERSION}.tar.gz) +set(GMMLIB_HASH b97f4e501c1e902a559cbd6597c008a700f4ab8c495680bf1968db99c6547afe) +set(GMMLIB_HASH_TYPE SHA256) +set(GMMLIB_FILE ${GMMLIB_VERSION}.tar.gz) + +set(OCLOC_VERSION 23.43.27642.40) +set(OCLOC_URI https://github.com/intel/compute-runtime/archive/refs/tags/${OCLOC_VERSION}.tar.gz) +set(OCLOC_HASH 67d0c6f3103ff12408a628e14f7170da3e0220313e10799693d576cea7821fe2) +set(OCLOC_HASH_TYPE SHA256) +set(OCLOC_FILE ocloc-${OCLOC_VERSION}.tar.gz) + +set(AOM_VERSION 3.4.0) +set(AOM_URI https://storage.googleapis.com/aom-releases/libaom-${AOM_VERSION}.tar.gz) +set(AOM_HASH bd754b58c3fa69f3ffd29da77de591bd9c26970e3b18537951336d6c0252e354) +set(AOM_HASH_TYPE SHA256) +set(AOM_FILE libaom-${AOM_VERSION}.tar.gz) + +set(FRIBIDI_VERSION v1.0.12) +set(FRIBIDI_URI https://github.com/fribidi/fribidi/archive/refs/tags/${FRIBIDI_VERSION}.tar.gz) +set(FRIBIDI_HASH 2e9e859876571f03567ac91e5ed3b5308791f31cda083408c2b60fa1fe00a39d) +set(FRIBIDI_HASH_TYPE SHA256) +set(FRIBIDI_FILE fribidi-${FRIBIDI_VERSION}.tar.gz) + +set(HARFBUZZ_VERSION 5.1.0) +set(HARFBUZZ_URI https://github.com/harfbuzz/harfbuzz/archive/refs/tags/${HARFBUZZ_VERSION}.tar.gz) +set(HARFBUZZ_HASH 5352ff2eec538ea9a63a485cf01ad8332a3f63aa79921c5a2e301cef185caea1) +set(HARFBUZZ_HASH_TYPE SHA256) +set(HARFBUZZ_FILE harfbuzz-${HARFBUZZ_VERSION}.tar.gz) + +set(SHADERC_VERSION v2022.3) +set(SHADERC_URI https://github.com/google/shaderc/archive/${SHADERC_VERSION}.tar.gz) +set(SHADERC_HASH 5cb762af57637caf997d5f46baa4e8a4) +set(SHADERC_HASH_TYPE MD5) +set(SHADERC_FILE shaderc-${SHADERC_VERSION}.tar.gz) + +# The versions of shaderc's dependencies can be found in the root of shaderc's +# source in a file called DEPS. + +set(SHADERC_SPIRV_TOOLS_VERSION eb0a36633d2acf4de82588504f951ad0f2cecacb) +set(SHADERC_SPIRV_TOOLS_URI https://github.com/KhronosGroup/SPIRV-Tools/archive/${SHADERC_SPIRV_TOOLS_VERSION}.tar.gz) +set(SHADERC_SPIRV_TOOLS_HASH a4bdb8161f0e959c75d0d82d367c24f2) +set(SHADERC_SPIRV_TOOLS_HASH_TYPE MD5) +set(SHADERC_SPIRV_TOOLS_FILE SPIRV-Tools-${SHADERC_SPIRV_TOOLS_VERSION}.tar.gz) + +set(SHADERC_SPIRV_HEADERS_VERSION 85a1ed200d50660786c1a88d9166e871123cce39) +set(SHADERC_SPIRV_HEADERS_URI https://github.com/KhronosGroup/SPIRV-Headers/archive/${SHADERC_SPIRV_HEADERS_VERSION}.tar.gz) +set(SHADERC_SPIRV_HEADERS_HASH 10d5e8160f39344a641523810b075568) +set(SHADERC_SPIRV_HEADERS_HASH_TYPE MD5) +set(SHADERC_SPIRV_HEADERS_FILE SPIRV-Headers-${SHADERC_SPIRV_HEADERS_VERSION}.tar.gz) + +set(SHADERC_GLSLANG_VERSION 89db4e1caa273a057ea46deba709c6e50001b314) +set(SHADERC_GLSLANG_URI https://github.com/KhronosGroup/glslang/archive/${SHADERC_GLSLANG_VERSION}.tar.gz) +set(SHADERC_GLSLANG_HASH 3b3c79ad8e9132ffcb8b63cc29c532e2) +set(SHADERC_GLSLANG_HASH_TYPE MD5) +set(SHADERC_GLSLANG_FILE glslang-${SHADERC_GLSLANG_VERSION}.tar.gz) + +set(VULKAN_VERSION v1.2.198) + +set(VULKAN_HEADERS_URI https://github.com/KhronosGroup/Vulkan-Headers/archive/refs/tags/${VULKAN_VERSION}.tar.gz) +set(VULKAN_HEADERS_HASH 64fe73e887c963ad546bfc7f9505fa1d) +set(VULKAN_HEADERS_HASH_TYPE MD5) +set(VULKAN_HEADERS_FILE Vulkan-Headers-${VULKAN_VERSION}.tar.gz) + +set(VULKAN_LOADER_URI https://github.com/KhronosGroup/Vulkan-Loader/archive/refs/tags/${VULKAN_VERSION}.tar.gz) +set(VULKAN_LOADER_HASH 015170a74f648fd2b41e209b6bf1ebc4) +set(VULKAN_LOADER_HASH_TYPE MD5) +set(VULKAN_LOADER_FILE Vulkan-Loader-${VULKAN_VERSION}.tar.gz) + +set(PYBIND11_VERSION 2.10.1) +set(PYBIND11_URI https://github.com/pybind/pybind11/archive/refs/tags/v${PYBIND11_VERSION}.tar.gz) +set(PYBIND11_HASH ce07bfd5089245da7807b3faf6cbc878) +set(PYBIND11_HASH_TYPE MD5) +set(PYBIND11_FILE pybind-v${PYBIND11_VERSION}.tar.gz) diff --git a/blender-build/build_environment/cmake/vorbis.cmake b/blender-build/build_environment/cmake/vorbis.cmake new file mode 100644 index 0000000..2f3f2b3 --- /dev/null +++ b/blender-build/build_environment/cmake/vorbis.cmake @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +ExternalProject_Add(external_vorbis + URL file://${PACKAGE_DIR}/${VORBIS_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${VORBIS_HASH_TYPE}=${VORBIS_HASH} + PREFIX ${BUILD_DIR}/vorbis + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/vorbis/src/external_vorbis/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/vorbis + --disable-shared + --enable-static + --with-pic + --with-ogg=${LIBDIR}/ogg + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/vorbis/src/external_vorbis/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/vorbis/src/external_vorbis/ && make install + INSTALL_DIR ${LIBDIR}/vorbis +) + +add_dependencies( + external_vorbis + external_ogg +) + +if(MSVC) + set_target_properties(external_vorbis PROPERTIES FOLDER Mingw) +endif() diff --git a/blender-build/build_environment/cmake/vpx.cmake b/blender-build/build_environment/cmake/vpx.cmake new file mode 100644 index 0000000..111e93e --- /dev/null +++ b/blender-build/build_environment/cmake/vpx.cmake @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(WIN32) + # VPX is determined to use pthreads which it will tell ffmpeg to dynamically + # link, which is not something we're super into distribution wise. However + # if it cannot find pthread.h it'll happily provide a pthread emulation + # layer using win32 threads. So all this patch does is make it not find + # pthead.h + set(VPX_PATCH ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/vpx/src/external_vpx < ${PATCH_DIR}/vpx_windows.diff) + set(VPX_EXTRA_FLAGS --target=x86_64-win64-gcc ) +else() + if(APPLE) + if("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64") + set(VPX_EXTRA_FLAGS --target=generic-gnu) + else() + set(VPX_EXTRA_FLAGS --target=x86_64-darwin17-gcc) + endif() + else() + set(VPX_EXTRA_FLAGS --target=generic-gnu) + endif() +endif() + +if(NOT BLENDER_PLATFORM_ARM) + list(APPEND VPX_EXTRA_FLAGS + --enable-sse4_1 + --enable-sse3 + --enable-ssse3 + --enable-avx + --enable-avx2 + ) +endif() + +ExternalProject_Add(external_vpx + URL file://${PACKAGE_DIR}/${VPX_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${VPX_HASH_TYPE}=${VPX_HASH} + PREFIX ${BUILD_DIR}/vpx + CONFIGURE_COMMAND ${CONFIGURE_ENV} && + cd ${BUILD_DIR}/vpx/src/external_vpx/ && + ${CONFIGURE_COMMAND_NO_TARGET} --prefix=${LIBDIR}/vpx + --disable-shared + --enable-static + --disable-install-bins + --disable-install-srcs + --disable-unit-tests + --disable-examples + --enable-vp8 + --enable-vp9 + ${VPX_EXTRA_FLAGS} + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/vpx/src/external_vpx/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/vpx/src/external_vpx/ && make install + PATCH_COMMAND ${VPX_PATCH} + INSTALL_DIR ${LIBDIR}/vpx +) + +if(MSVC) + set_target_properties(external_vpx PROPERTIES FOLDER Mingw) +endif() diff --git a/blender-build/build_environment/cmake/vulkan.cmake b/blender-build/build_environment/cmake/vulkan.cmake new file mode 100644 index 0000000..6f194fe --- /dev/null +++ b/blender-build/build_environment/cmake/vulkan.cmake @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(VULKAN_HEADERS_EXTRA_ARGS) + +ExternalProject_Add(external_vulkan_headers + URL file://${PACKAGE_DIR}/${VULKAN_HEADERS_FILE} + URL_HASH ${VULKAN_HEADERS_HASH_TYPE}=${VULKAN_HEADERS_HASH} + PREFIX ${BUILD_DIR}/vulkan_headers + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/vulkan_headers -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${VULKAN_HEADERS_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/vulkan_headers +) + +set(VULKAN_LOADER_EXTRA_ARGS + -DVULKAN_HEADERS_INSTALL_DIR=${LIBDIR}/vulkan_headers +) + +if(UNIX AND NOT APPLE) + # These are used in `cmake/FindWayland.cmake` from `external_vulkan_loader`. + # NOTE: When upgrading to CMAKE 3.22 we it would be cleaner to use: `PKG_CONFIG_ARGN`, + # so `pkgconfig` would find wayland. + set(VULKAN_LOADER_EXTRA_ARGS + ${VULKAN_LOADER_EXTRA_ARGS} + -DPKG_WAYLAND_INCLUDE_DIRS=${LIBDIR}/wayland/include + -DPKG_WAYLAND_LIBRARY_DIRS=${LIBDIR}/wayland/lib64 + ) +endif() + +ExternalProject_Add(external_vulkan_loader + URL file://${PACKAGE_DIR}/${VULKAN_LOADER_FILE} + URL_HASH ${VULKAN_LOADER_HASH_TYPE}=${VULKAN_LOADER_HASH} + PREFIX ${BUILD_DIR}/vulkan_loader + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/vulkan_loader -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${VULKAN_LOADER_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/vulkan_loader +) + +add_dependencies( + external_vulkan_loader + external_vulkan_headers +) + +if(UNIX AND NOT APPLE) + add_dependencies( + external_vulkan_loader + external_wayland + ) +elseif(WIN32) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_vulkan_loader after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/vulkan_loader/ ${HARVEST_TARGET}/vulkan + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/vulkan_headers/ ${HARVEST_TARGET}/vulkan + DEPENDEES install + ) + endif() +endif() diff --git a/blender-build/build_environment/cmake/wayland.cmake b/blender-build/build_environment/cmake/wayland.cmake new file mode 100644 index 0000000..4160de2 --- /dev/null +++ b/blender-build/build_environment/cmake/wayland.cmake @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +ExternalProject_Add(external_wayland + URL file://${PACKAGE_DIR}/${WAYLAND_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${WAYLAND_HASH_TYPE}=${WAYLAND_HASH} + PREFIX ${BUILD_DIR}/wayland + # Use `-E` so the `PKG_CONFIG_PATH` can be defined to link against our own LIBEXPAT & LIBXML2. + # + # NOTE: passing link args "ffi/lib" should not be needed, but + # `pkgconfig` would incorrectly look in "ffi/lib/../lib64" otherwise. + # + # NOTE: `-lm` is needed for `libxml2` which is a static library that uses `libm.so`, + # without this, math symbols such as `floor` aren't found. + CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env PKG_CONFIG_PATH=${LIBDIR}/expat/lib/pkgconfig:${LIBDIR}/xml2/lib/pkgconfig:${LIBDIR}/ffi/lib/pkgconfig:$PKG_CONFIG_PATH + ${MESON} --prefix ${LIBDIR}/wayland ${MESON_BUILD_TYPE} -Ddocumentation=false -Dtests=false -D "c_link_args=-L${LIBDIR}/ffi/lib -lm" . ../external_wayland + BUILD_COMMAND ninja + INSTALL_COMMAND ninja install +) + +add_dependencies( + external_wayland + external_expat + external_xml2 + external_ffi + + # Needed for `MESON`. + external_python_site_packages +) diff --git a/blender-build/build_environment/cmake/wayland_libdecor.cmake b/blender-build/build_environment/cmake/wayland_libdecor.cmake new file mode 100644 index 0000000..f4628fa --- /dev/null +++ b/blender-build/build_environment/cmake/wayland_libdecor.cmake @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# NOTE: currently only the header file is extracted, no compilation is needed +# as the library is dynamically loaded when found on the system. + +ExternalProject_Add(external_wayland_libdecor + URL file://${PACKAGE_DIR}/${WAYLAND_LIBDECOR_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${WAYLAND_LIBDECOR_HASH_TYPE}=${WAYLAND_LIBDECOR_HASH} + PREFIX ${BUILD_DIR}/wayland_libdecor + BUILD_COMMAND echo . + CONFIGURE_COMMAND echo . + INSTALL_COMMAND cp ../external_wayland_libdecor/src/libdecor.h ${LIBDIR}/wayland_libdecor/include/libdecor-0/libdecor.h + INSTALL_DIR ${LIBDIR}/wayland_libdecor/include/libdecor-0 +) diff --git a/blender-build/build_environment/cmake/wayland_protocols.cmake b/blender-build/build_environment/cmake/wayland_protocols.cmake new file mode 100644 index 0000000..b588419 --- /dev/null +++ b/blender-build/build_environment/cmake/wayland_protocols.cmake @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +ExternalProject_Add(external_wayland_protocols + URL file://${PACKAGE_DIR}/${WL_PROTOCOLS_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${WL_PROTOCOLS_HASH_TYPE}=${WL_PROTOCOLS_HASH} + PREFIX ${BUILD_DIR}/wayland-protocols + # Use `-E` so the `PKG_CONFIG_PATH` can be defined to link against our own WAYLAND. + CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env PKG_CONFIG_PATH=${LIBDIR}/wayland/lib64/pkgconfig:$PKG_CONFIG_PATH + ${MESON} --prefix ${LIBDIR}/wayland-protocols ${MESON_BUILD_TYPE} . ../external_wayland_protocols -Dtests=false + BUILD_COMMAND ninja + INSTALL_COMMAND ninja install +) + +add_dependencies( + external_wayland_protocols + external_wayland + # Needed for `MESON`. + external_python_site_packages +) diff --git a/blender-build/build_environment/cmake/webp.cmake b/blender-build/build_environment/cmake/webp.cmake new file mode 100644 index 0000000..285c074 --- /dev/null +++ b/blender-build/build_environment/cmake/webp.cmake @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Note the utility apps may use png/tiff/gif system libraries, but the +# library itself does not depend on them, so should give no problems. + +set(WEBP_EXTRA_ARGS + -DWEBP_BUILD_ANIM_UTILS=OFF + -DWEBP_BUILD_CWEBP=OFF + -DWEBP_BUILD_DWEBP=OFF + -DWEBP_BUILD_GIF2WEBP=OFF + -DWEBP_BUILD_IMG2WEBP=OFF + -DWEBP_BUILD_VWEBP=OFF + -DWEBP_BUILD_WEBPINFO=OFF + -DWEBP_BUILD_WEBPMUX=OFF + -DWEBP_BUILD_EXTRAS=OFF +) + +if(WIN32) + set(WEBP_BUILD_DIR ${BUILD_MODE}/) +else() + set(WEBP_BUILD_DIR) +endif() + +ExternalProject_Add(external_webp + URL file://${PACKAGE_DIR}/${WEBP_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${WEBP_HASH_TYPE}=${WEBP_HASH} + PREFIX ${BUILD_DIR}/webp + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/webp -Wno-dev ${DEFAULT_CMAKE_FLAGS} ${WEBP_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/webp +) + +if(WIN32) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_webp after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/webp ${HARVEST_TARGET}/webp + DEPENDEES install + ) + endif() +endif() diff --git a/blender-build/build_environment/cmake/x264.cmake b/blender-build/build_environment/cmake/x264.cmake new file mode 100644 index 0000000..0165eb2 --- /dev/null +++ b/blender-build/build_environment/cmake/x264.cmake @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(WIN32) + set(X264_EXTRA_ARGS --enable-win32thread --cross-prefix=${MINGW_HOST}- --host=${MINGW_HOST}) +endif() + +if(BLENDER_PLATFORM_ARM) + set(X264_EXTRA_ARGS ${X264_EXTRA_ARGS} "--disable-asm") +endif() + +if((APPLE AND NOT BLENDER_PLATFORM_ARM) OR (UNIX AND NOT APPLE)) + set(X264_CONFIGURE_ENV + export AS=${LIBDIR}/nasm/bin/nasm + ) +else() + set(X264_CONFIGURE_ENV echo .) +endif() + +ExternalProject_Add(external_x264 + URL file://${PACKAGE_DIR}/${X264_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${X264_HASH_TYPE}=${X264_HASH} + PREFIX ${BUILD_DIR}/x264 + CONFIGURE_COMMAND ${CONFIGURE_ENV} && ${X264_CONFIGURE_ENV} && cd ${BUILD_DIR}/x264/src/external_x264/ && + ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/x264 + --enable-static + --enable-pic + --disable-lavf + ${X264_EXTRA_ARGS} + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/x264/src/external_x264/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/x264/src/external_x264/ && make install + INSTALL_DIR ${LIBDIR}/x264 +) + +if(MSVC) + set_target_properties(external_x264 PROPERTIES FOLDER Mingw) +endif() + +if(UNIX) + add_dependencies( + external_x264 + external_nasm + ) +endif() diff --git a/blender-build/build_environment/cmake/xml2.cmake b/blender-build/build_environment/cmake/xml2.cmake new file mode 100644 index 0000000..e403ad4 --- /dev/null +++ b/blender-build/build_environment/cmake/xml2.cmake @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(WIN32) + set(XML2_EXTRA_ARGS + -DLIBXML2_WITH_ZLIB=OFF + -DLIBXML2_WITH_LZMA=OFF + -DLIBXML2_WITH_PYTHON=OFF + -DLIBXML2_WITH_ICONV=OFF + -DLIBXML2_WITH_TESTS=OFF + -DLIBXML2_WITH_PROGRAMS=OFF + -DBUILD_SHARED_LIBS=OFF + ) + ExternalProject_Add(external_xml2 + URL file://${PACKAGE_DIR}/${XML2_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${XML2_HASH_TYPE}=${XML2_HASH} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/xml2 ${DEFAULT_CMAKE_FLAGS} ${XML2_EXTRA_ARGS} + PREFIX ${BUILD_DIR}/xml2 + INSTALL_DIR ${LIBDIR}/xml2 + ) +else() + ExternalProject_Add(external_xml2 + URL file://${PACKAGE_DIR}/${XML2_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${XML2_HASH_TYPE}=${XML2_HASH} + PREFIX ${BUILD_DIR}/xml2 + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && ${CONFIGURE_COMMAND} + --prefix=${LIBDIR}/xml2 + --disable-shared + --enable-static + --with-pic + --with-python=no + --with-lzma=no + --with-zlib=no + --with-iconv=no + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xml2/src/external_xml2/ && make install + INSTALL_DIR ${LIBDIR}/xml2 + ) +endif() + +if(WIN32 AND BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_xml2 after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/xml2/include ${HARVEST_TARGET}/xml2/include + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/xml2/lib/libxml2s.lib ${HARVEST_TARGET}/xml2/lib/libxml2s.lib + DEPENDEES install + ) +endif() diff --git a/blender-build/build_environment/cmake/xr_openxr.cmake b/blender-build/build_environment/cmake/xr_openxr.cmake new file mode 100644 index 0000000..2589e3f --- /dev/null +++ b/blender-build/build_environment/cmake/xr_openxr.cmake @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + + +# Keep flags in sync with install_deps.sh ones in compile_XR_OpenXR_SDK() +set(XR_OPENXR_SDK_EXTRA_ARGS + -DBUILD_FORCE_GENERATION=OFF + -DBUILD_LOADER=ON + -DDYNAMIC_LOADER=OFF +) + +if(UNIX AND NOT APPLE) + list(APPEND XR_OPENXR_SDK_EXTRA_ARGS + -DBUILD_WITH_WAYLAND_HEADERS=OFF + -DBUILD_WITH_XCB_HEADERS=OFF + -DBUILD_WITH_XLIB_HEADERS=ON + -DBUILD_WITH_SYSTEM_JSONCPP=OFF + -DCMAKE_CXX_FLAGS=-DDISABLE_STD_FILESYSTEM=1 + ) +endif() + +ExternalProject_Add(external_xr_openxr_sdk + URL file://${PACKAGE_DIR}/${XR_OPENXR_SDK_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${XR_OPENXR_SDK_HASH_TYPE}=${XR_OPENXR_SDK_HASH} + PREFIX ${BUILD_DIR}/xr_openxr_sdk + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/xr_openxr_sdk ${DEFAULT_CMAKE_FLAGS} ${XR_OPENXR_SDK_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/xr_openxr_sdk +) + +if(WIN32) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_xr_openxr_sdk after_install + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/xr_openxr_sdk/include/openxr ${HARVEST_TARGET}/xr_openxr_sdk/include/openxr + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/xr_openxr_sdk/lib ${HARVEST_TARGET}/xr_openxr_sdk/lib + DEPENDEES install + ) + endif() + if(BUILD_MODE STREQUAL Debug) + ExternalProject_Add_Step(external_xr_openxr_sdk after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/xr_openxr_sdk/lib/openxr_loaderd.lib ${HARVEST_TARGET}/xr_openxr_sdk/lib/openxr_loaderd.lib + DEPENDEES install + ) + endif() +endif() diff --git a/blender-build/build_environment/cmake/xvidcore.cmake b/blender-build/build_environment/cmake/xvidcore.cmake new file mode 100644 index 0000000..e319408 --- /dev/null +++ b/blender-build/build_environment/cmake/xvidcore.cmake @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if(WIN32) + set(XVIDCORE_EXTRA_ARGS --host=${MINGW_HOST}) +endif() + +ExternalProject_Add(external_xvidcore + URL file://${PACKAGE_DIR}/${XVIDCORE_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${XVIDCORE_HASH_TYPE}=${XVIDCORE_HASH} + PREFIX ${BUILD_DIR}/xvidcore + CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xvidcore/src/external_xvidcore/build/generic && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/xvidcore ${XVIDCORE_EXTRA_ARGS} + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/xvidcore/src/external_xvidcore/build/generic && make -j${MAKE_THREADS} + INSTALL_COMMAND ${CONFIGURE_ENV} && + ${CMAKE_COMMAND} -E remove ${LIBDIR}/xvidcore/lib/* && # clean because re-installing fails otherwise + cd ${BUILD_DIR}/xvidcore/src/external_xvidcore/build/generic && make install + INSTALL_DIR ${LIBDIR}/xvidcore +) + +if(WIN32) + ExternalProject_Add_Step(external_xvidcore after_install + COMMAND ${CMAKE_COMMAND} -E rename ${LIBDIR}/xvidcore/lib/xvidcore.a ${LIBDIR}/xvidcore/lib/libxvidcore.a || true + COMMAND ${CMAKE_COMMAND} -E remove ${LIBDIR}/xvidcore/lib/xvidcore.dll.a + DEPENDEES install + ) +endif() + +if(MSVC) + set_target_properties(external_xvidcore PROPERTIES FOLDER Mingw) +endif() diff --git a/blender-build/build_environment/cmake/yamlcpp.cmake b/blender-build/build_environment/cmake/yamlcpp.cmake new file mode 100644 index 0000000..4463db0 --- /dev/null +++ b/blender-build/build_environment/cmake/yamlcpp.cmake @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(YAMLCPP_EXTRA_ARGS + -DYAML_CPP_BUILD_TESTS=OFF + -DYAML_CPP_BUILD_TOOLS=OFF + -DYAML_CPP_BUILD_CONTRIB=OFF +) + +if(WIN32) + set(YAMLCPP_EXTRA_ARGS + ${YAMLCPP_EXTRA_ARGS} + -DBUILD_GMOCK=OFF + -DYAML_MSVC_SHARED_RT=ON + ) +endif() + +ExternalProject_Add(external_yamlcpp + URL file://${PACKAGE_DIR}/${YAMLCPP_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${YAMLCPP_HASH_TYPE}=${YAMLCPP_HASH} + PREFIX ${BUILD_DIR}/yamlcpp + CMAKE_GENERATOR ${PLATFORM_ALT_GENERATOR} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/yamlcpp ${DEFAULT_CMAKE_FLAGS} ${YAMLCPP_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/yamlcpp +) diff --git a/blender-build/build_environment/cmake/zlib.cmake b/blender-build/build_environment/cmake/zlib.cmake new file mode 100644 index 0000000..9adb1dc --- /dev/null +++ b/blender-build/build_environment/cmake/zlib.cmake @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +ExternalProject_Add(external_zlib + URL file://${PACKAGE_DIR}/${ZLIB_FILE} + URL_HASH ${ZLIB_HASH_TYPE}=${ZLIB_HASH} + PREFIX ${BUILD_DIR}/zlib + CMAKE_ARGS -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_INSTALL_PREFIX=${LIBDIR}/zlib ${DEFAULT_CMAKE_FLAGS} + INSTALL_DIR ${LIBDIR}/zlib +) + +if(WIN32) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_zlib after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/zlib/lib/zlibstatic${LIBEXT} ${HARVEST_TARGET}/zlib/lib/libz_st${LIBEXT} + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/zlib/include/ ${HARVEST_TARGET}/zlib/include/ + DEPENDEES install + ) + endif() + if(BUILD_MODE STREQUAL Debug) + ExternalProject_Add_Step(external_zlib after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/zlib/lib/zlibstaticd${LIBEXT} ${HARVEST_TARGET}/zlib/lib/libz_st_d${LIBEXT} + DEPENDEES install + ) + endif() +else() + ExternalProject_Add_Step(external_zlib after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/zlib/lib/libz.a ${LIBDIR}/zlib/lib/libz_pic.a + DEPENDEES install + ) +endif() diff --git a/blender-build/build_environment/cmake/zlib_mingw.cmake b/blender-build/build_environment/cmake/zlib_mingw.cmake new file mode 100644 index 0000000..9858557 --- /dev/null +++ b/blender-build/build_environment/cmake/zlib_mingw.cmake @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +ExternalProject_Add(external_zlib_mingw + URL file://${PACKAGE_DIR}/${ZLIB_FILE} + URL_HASH ${ZLIB_HASH_TYPE}=${ZLIB_HASH} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + PREFIX ${BUILD_DIR}/zlib_mingw + CONFIGURE_COMMAND echo . + BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/zlib_mingw/src/external_zlib_mingw/ && make -f win32/makefile.gcc -j${MAKE_THREADS} + INSTALL_COMMAND echo . + INSTALL_DIR ${LIBDIR}/zlib_mingw +) + +if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_zlib_mingw after_install + COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/zlib_mingw/src/external_zlib_mingw/libz.a ${LIBDIR}/zlib/lib/z.lib + DEPENDEES install + ) +endif() + +if(MSVC) + set_target_properties(external_zlib_mingw PROPERTIES FOLDER Mingw) +endif() diff --git a/blender-build/build_environment/cmake/zstd.cmake b/blender-build/build_environment/cmake/zstd.cmake new file mode 100644 index 0000000..85db89d --- /dev/null +++ b/blender-build/build_environment/cmake/zstd.cmake @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(ZSTD_EXTRA_ARGS + -DZSTD_BUILD_PROGRAMS=OFF + -DZSTD_BUILD_SHARED=OFF + -DZSTD_BUILD_STATIC=ON + -DZSTD_BUILD_TESTS=OFF + -DZSTD_LEGACY_SUPPORT=OFF + -DZSTD_LZ4_SUPPORT=OFF + -DZSTD_LZMA_SUPPORT=OFF + -DZSTD_MULTITHREAD_SUPPORT=ON + -DZSTD_PROGRAMS_LINK_SHARED=OFF + -DZSTD_USE_STATIC_RUNTIME=OFF + -DZSTD_ZLIB_SUPPORT=OFF +) + +ExternalProject_Add(external_zstd + URL file://${PACKAGE_DIR}/${ZSTD_FILE} + DOWNLOAD_DIR ${DOWNLOAD_DIR} + URL_HASH ${ZSTD_HASH_TYPE}=${ZSTD_HASH} + PREFIX ${BUILD_DIR}/zstd + SOURCE_SUBDIR build/cmake + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/zstd ${DEFAULT_CMAKE_FLAGS} ${ZSTD_EXTRA_ARGS} + INSTALL_DIR ${LIBDIR}/zstd +) + +if(WIN32) + if(BUILD_MODE STREQUAL Release) + ExternalProject_Add_Step(external_zstd after_install + COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/zstd/lib/zstd_static${LIBEXT} ${HARVEST_TARGET}/zstd/lib/zstd_static${LIBEXT} + COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/zstd/include/ ${HARVEST_TARGET}/zstd/include/ + DEPENDEES install + ) + endif() +endif() diff --git a/blender-build/build_environment/darwin/set_rpath.py b/blender-build/build_environment/darwin/set_rpath.py new file mode 100644 index 0000000..fec1abc --- /dev/null +++ b/blender-build/build_environment/darwin/set_rpath.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-or-later + +# macOS utility to remove all `rpaths` and add a new one. + +import os +import re +import subprocess +import sys + + +# Strip version numbers from dependenciesm macOS notarizatiom fails +# with version symlinks. +def strip_lib_version(name): + name = re.sub(r'(\.[0-9]+)+.dylib', '.dylib', name) + name = re.sub(r'(\.[0-9]+)+.so', '.so', name) + name = re.sub(r'(\.[0-9]+)+.cpython', '.cpython', name) + return name + + +rpath = sys.argv[1] +file = sys.argv[2] + +# Find existing rpaths and delete them one by one. +p = subprocess.run(['otool', '-l', file], capture_output=True) +tokens = p.stdout.split() + +for i, token in enumerate(tokens): + if token == b'LC_RPATH': + old_rpath = tokens[i + 4] + subprocess.run(['install_name_tool', '-delete_rpath', old_rpath, file]) + +subprocess.run(['install_name_tool', '-add_rpath', rpath, file]) + +# Strip version from dependencies. +p = subprocess.run(['otool', '-L', file], capture_output=True) +tokens = p.stdout.split() +for i, token in enumerate(tokens): + token = token.decode("utf-8") + if token.startswith("@rpath"): + new_token = strip_lib_version(token) + subprocess.run(['install_name_tool', '-change', token, new_token, file]) + +# Strip version from library itself. +new_file = strip_lib_version(file) +new_id = '@rpath/' + os.path.basename(new_file) +os.rename(file, new_file) +subprocess.run(['install_name_tool', '-id', new_id, new_file]) diff --git a/blender-build/build_environment/dependencies.dot b/blender-build/build_environment/dependencies.dot new file mode 100644 index 0000000..b0de929 --- /dev/null +++ b/blender-build/build_environment/dependencies.dot @@ -0,0 +1,115 @@ +strict graph { +graph[autosize = false, size = "25.7,8.3!", resolution = 300]; + external_alembic -- external_openexr; + external_alembic -- external_imath; + external_blosc -- external_zlib; + external_blosc -- external_pthreads; + external_boost -- external_python; + external_boost -- external_numpy; + external_dpcpp -- external_python; + external_dpcpp -- external_python_site_packages; + external_dpcpp -- external_vcintrinsics; + external_dpcpp -- external_openclheaders; + external_dpcpp -- external_icdloader; + external_dpcpp -- external_mp11; + external_dpcpp -- external_level_zero; + external_dpcpp -- external_spirvheaders; + external_dpcpp -- external_unifiedruntime; + external_embree -- external_tbb; + external_ffmpeg -- external_zlib; + external_ffmpeg -- external_openjpeg; + external_ffmpeg -- external_xvidcore; + external_ffmpeg -- external_x264; + external_ffmpeg -- external_opus; + external_ffmpeg -- external_vpx; + external_ffmpeg -- external_theora; + external_ffmpeg -- external_vorbis; + external_ffmpeg -- external_ogg; + external_ffmpeg -- external_lame; + external_ffmpeg -- external_aom; + external_ffmpeg -- external_zlib_mingw; + external_ffmpeg -- external_nasm; + external_freetype -- external_brotli; + external_freetype -- external_zlib; + external_gmpxx -- external_gmp; + external_igc_llvm -- external_igc_opencl_clang; + external_igc_spirv_translator -- external_igc_opencl_clang; + external_igc -- external_igc_vcintrinsics; + external_igc -- external_igc_llvm; + external_igc -- external_igc_opencl_clang; + external_igc -- external_igc_vcintrinsics; + external_igc -- external_igc_spirv_headers; + external_igc -- external_igc_spirv_tools; + external_igc -- external_igc_spirv_translator; + external_igc -- external_flex; + external_ispc -- ll; + external_ispc -- external_python; + external_ispc -- external_flexbison; + external_ispc -- external_flex; + ll -- external_xml2; + ll -- external_python; + external_mesa -- ll; + external_numpy -- external_python; + external_numpy -- external_python_site_packages; + external_ocloc -- external_igc; + external_ocloc -- external_gmmlib; + external_opencollada -- external_xml2; + external_opencolorio -- external_yamlcpp; + external_opencolorio -- external_expat; + external_opencolorio -- external_imath; + external_opencolorio -- external_pystring; + external_openexr -- external_zlib; + external_openimagedenoise -- external_tbb; + external_openimagedenoise -- external_ispc; + external_openimagedenoise -- external_python; + external_openimageio -- external_png; + external_openimageio -- external_zlib; + external_openimageio -- external_openexr; + external_openimageio -- external_imath; + external_openimageio -- external_jpeg; + external_openimageio -- external_boost; + external_openimageio -- external_tiff; + external_openimageio -- external_pugixml; + external_openimageio -- external_fmt; + external_openimageio -- external_robinmap; + external_openimageio -- external_openjpeg; + external_openimageio -- external_webp; + external_openmp -- ll; + external_openpgl -- external_tbb; + external_opensubdiv -- external_tbb; + openvdb -- external_tbb; + openvdb -- external_boost; + openvdb -- external_zlib; + openvdb -- external_blosc; + external_osl -- external_boost; + external_osl -- ll; + external_osl -- external_openexr; + external_osl -- external_zlib; + external_osl -- external_openimageio; + external_osl -- external_pugixml; + external_osl -- external_flexbison; + external_osl -- external_flex; + external_png -- external_zlib; + external_python -- external_bzip2; + external_python -- external_ffi; + external_python -- external_lzma; + external_python -- external_ssl; + external_python -- external_sqlite; + external_python -- external_zlib; + external_python_site_packages -- external_python; + external_sndfile -- external_ogg; + external_sndfile -- external_vorbis; + external_sndfile -- external_flac; + external_theora -- external_vorbis; + external_theora -- external_ogg; + external_tiff -- external_zlib; + external_usd -- external_tbb; + external_usd -- external_boost; + external_usd -- external_opensubdiv; + external_vorbis -- external_ogg; + external_wayland -- external_expat; + external_wayland -- external_xml2; + external_wayland -- external_ffi; + external_wayland_protocols -- external_wayland; + external_x264 -- external_nasm; +} diff --git a/blender-build/build_environment/install_linux_packages.py b/blender-build/build_environment/install_linux_packages.py new file mode 100755 index 0000000..badb6f9 --- /dev/null +++ b/blender-build/build_environment/install_linux_packages.py @@ -0,0 +1,1780 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-or-later + +import logging +import os +import re +import subprocess +import sys +import time + + +DISTRO_ID_DEBIAN = "debian" +DISTRO_ID_FEDORA = "fedora" +DISTRO_ID_SUSE = "suse" +DISTRO_ID_ARCH = "arch" + + +class LoggingColoredFormatter(logging.Formatter): + """ + Logging colored formatter,. + Based on https://alexandra-zaharia.github.io/posts/make-your-own-custom-color-formatter-with-python-logging/ + """ + GREY = '\x1b[38;21m' + BLUE = '\x1b[38;5;39m' + YELLOW = '\x1b[38;5;226m' + RED = '\x1b[38;5;196m' + BOLD_RED = '\x1b[31;1m' + RESET = '\x1b[0m' + + def __init__(self, fmt=None): + super().__init__(fmt=fmt) + self.FORMATS = { + logging.DEBUG: self.GREY + "DEBUG: " + self.RESET + self._fmt, + logging.INFO: self.BLUE + "INFO: " + self.RESET + self._fmt, + logging.WARNING: self.YELLOW + "WARNING: " + self.RESET + self._fmt, + logging.ERROR: self.RED + "ERROR: " + self.RESET + self._fmt, + logging.CRITICAL: self.BOLD_RED + "CRITICAL: " + self.RESET + self._fmt, + } + + def format(self, record): + log_fmt = self.FORMATS.get(record.levelno) + formatter = logging.Formatter(log_fmt) + return formatter.format(record) + + +class Package: + __slots__ = ( + # User-friendly name for the package. + "name", + # This is a fake package used to bulk-install a group of packages. + # There is no version check performed here, and a single missing package will fail the whole thing. + # Used for the basic sets of build packages and dependencies that can be assumed always available, + # with stable enough API that the version does not matter (to some extent, it is expected to work with + # any recent distro version at least). + "is_group", + # Whether Blender can build without this package or not. + # Note: In case of group packages, all sub-packages inherit from the value of the root group package. + "is_mandatory", + # Exact version currently used for pre-built libraries and buildbot builds. + "version", + # Ideal version of the package (if possible, prioritize a package of that version), `version` shoudl match it. + "version_short", + # Minimal (included)/maximal (excluded) assumed supported version range. + # Package outside of that range won't be installed. + "version_min", "version_mex", + # Actual installed package version. + "version_installed", + # Other Packages that depend/are only installed if the 'parent' one is valid. + "sub_packages", + # A mapping from distro name key to distro package name value. + # Value may either be: + # - A package name string. + # - A callback taking the Package and an iterable of its parents as parameters, and returning a string. + # - None to indicate that there is no known package for that distribution. + # - ... to indicate that this package can be skipped for that distribution + # (typically, because it is included in a parent package already). + "distro_package_names", + ) + + def __init__(self, name, is_group=False, is_mandatory=False, + version=None, version_short=None, version_min=None, version_mex=None, + sub_packages=(), distro_package_names={}): + self.name = name + self.is_group = is_group + self.is_mandatory = is_mandatory + self.version = version + self.version_short = version_short + self.version_min = version_min + self.version_mex = version_mex + self.version_installed = ... + self.sub_packages = sub_packages + self.distro_package_names = distro_package_names + + +# Absolute minimal required tools to build Blender. +BUILD_MANDATORY_SUBPACKAGES = ( + Package(name="Build Essentials", is_group=True, + sub_packages=( + Package(name="GCC", + distro_package_names={DISTRO_ID_DEBIAN: ..., + DISTRO_ID_FEDORA: "gcc", + DISTRO_ID_SUSE: "gcc", + DISTRO_ID_ARCH: ..., + }, + ), + Package(name="GCC-C++", + distro_package_names={DISTRO_ID_DEBIAN: ..., + DISTRO_ID_FEDORA: "gcc-c++", + DISTRO_ID_SUSE: "gcc-c++", + DISTRO_ID_ARCH: ..., + }, + ), + Package(name="make", + distro_package_names={DISTRO_ID_DEBIAN: ..., + DISTRO_ID_FEDORA: "make", + DISTRO_ID_SUSE: "make", + DISTRO_ID_ARCH: ..., + }, + ), + Package(name="glibc", + distro_package_names={DISTRO_ID_DEBIAN: ..., + DISTRO_ID_FEDORA: "glibc-devel", + DISTRO_ID_SUSE: "glibc-devel", + DISTRO_ID_ARCH: ..., + }, + ), + ), + distro_package_names={DISTRO_ID_DEBIAN: "build-essential", + DISTRO_ID_FEDORA: ..., + DISTRO_ID_SUSE: ..., + DISTRO_ID_ARCH: "base-devel", + }, + ), + Package(name="Git", is_group=True, + sub_packages=( + Package(name="Git LFS", + distro_package_names={DISTRO_ID_DEBIAN: "git-lfs", + DISTRO_ID_FEDORA: "git-lfs", + DISTRO_ID_SUSE: "git-lfs", + DISTRO_ID_ARCH: "git-lfs", + }, + ), + ), + distro_package_names={DISTRO_ID_DEBIAN: "git", + DISTRO_ID_FEDORA: "git", + DISTRO_ID_SUSE: "git", + DISTRO_ID_ARCH: "git", + }, + ), + Package(name="Subversion (aka svn)", + distro_package_names={DISTRO_ID_DEBIAN: "subversion", + DISTRO_ID_FEDORA: "subversion", + DISTRO_ID_SUSE: "subversion", + DISTRO_ID_ARCH: "subversion", + }, + ), + Package(name="CMake", + distro_package_names={DISTRO_ID_DEBIAN: "cmake", + DISTRO_ID_FEDORA: "cmake", + DISTRO_ID_SUSE: "cmake", + DISTRO_ID_ARCH: "cmake", + }, + ), +) + + +# Fairly common additional tools useful to build Blender. +BUILD_OPTIONAL_SUBPACKAGES = ( + Package(name="Ninja Builder", + distro_package_names={DISTRO_ID_DEBIAN: "ninja-build", + DISTRO_ID_FEDORA: "ninja-build", + DISTRO_ID_SUSE: "ninja", + DISTRO_ID_ARCH: "ninja", + }, + ), + Package(name="CMake commandline GUI", + distro_package_names={DISTRO_ID_DEBIAN: "cmake-curses-gui", + DISTRO_ID_FEDORA: None, + DISTRO_ID_SUSE: None, + DISTRO_ID_ARCH: None, + }, + ), + Package(name="CMake GUI", + distro_package_names={DISTRO_ID_DEBIAN: "cmake-gui", + DISTRO_ID_FEDORA: "cmake-gui", + DISTRO_ID_SUSE: "cmake-gui", + DISTRO_ID_ARCH: None, + }, + ), + Package(name="Patch", + distro_package_names={DISTRO_ID_DEBIAN: "patch", + DISTRO_ID_FEDORA: "patch", + DISTRO_ID_SUSE: "patch", + DISTRO_ID_ARCH: "patch", + }, + ), +) + + +# Library dependencies that are not provided by precompiled libraries. +DEPS_CRITICAL_SUBPACKAGES = ( + Package(name="X11 library", + distro_package_names={DISTRO_ID_DEBIAN: "libx11-dev", + DISTRO_ID_FEDORA: "libX11-devel", + DISTRO_ID_SUSE: "libX11-devel", + DISTRO_ID_ARCH: "libx11", + }, + ), + Package(name="Xxf86vm Library", + distro_package_names={DISTRO_ID_DEBIAN: "libxxf86vm-dev", + DISTRO_ID_FEDORA: "libXxf86vm-devel", + DISTRO_ID_SUSE: "libXxf86vm-devel", + DISTRO_ID_ARCH: "libxxf86vm", + }, + ), + Package(name="XCursor Library", + distro_package_names={DISTRO_ID_DEBIAN: "libxcursor-dev", + DISTRO_ID_FEDORA: "libXcursor-devel", + DISTRO_ID_SUSE: "libXcursor-devel", + DISTRO_ID_ARCH: "libxcursor", + }, + ), + Package(name="Xi Library", + distro_package_names={DISTRO_ID_DEBIAN: "libxi-dev", + DISTRO_ID_FEDORA: "libXi-devel", + DISTRO_ID_SUSE: "libXi-devel", + DISTRO_ID_ARCH: "libxi", + }, + ), + Package(name="XRandr Library", + distro_package_names={DISTRO_ID_DEBIAN: "libxrandr-dev", + DISTRO_ID_FEDORA: "libXrandr-devel", + DISTRO_ID_SUSE: "libXrandr-devel", + DISTRO_ID_ARCH: "libxrandr", + }, + ), + Package(name="Xinerama Library", + distro_package_names={DISTRO_ID_DEBIAN: "libxinerama-dev", + DISTRO_ID_FEDORA: "libXinerama-devel", + DISTRO_ID_SUSE: "libXinerama-devel", + DISTRO_ID_ARCH: "libxinerama", + }, + ), + Package(name="XKbCommon Library", + distro_package_names={DISTRO_ID_DEBIAN: "libxkbcommon-dev", + DISTRO_ID_FEDORA: "libxkbcommon-devel", + DISTRO_ID_SUSE: "libxkbcommon-devel", + DISTRO_ID_ARCH: "libxkbcommon", + }, + ), + Package(name="Wayland Library", + distro_package_names={DISTRO_ID_DEBIAN: "libwayland-dev", + DISTRO_ID_FEDORA: "wayland-devel", + DISTRO_ID_SUSE: "wayland-devel", + DISTRO_ID_ARCH: "wayland", + }, + ), + Package(name="Decor Library", + distro_package_names={DISTRO_ID_DEBIAN: "libdecor-0-dev", + DISTRO_ID_FEDORA: "libdecor-devel", + DISTRO_ID_SUSE: "libdecor-devel", + DISTRO_ID_ARCH: "libdecor", + }, + ), + Package(name="Wayland Protocols", + distro_package_names={DISTRO_ID_DEBIAN: "wayland-protocols", + DISTRO_ID_FEDORA: "wayland-protocols-devel", + DISTRO_ID_SUSE: "wayland-protocols-devel", + DISTRO_ID_ARCH: "wayland-protocols", + }, + ), + Package(name="DBus Library", + distro_package_names={DISTRO_ID_DEBIAN: "libdbus-1-dev", + DISTRO_ID_FEDORA: "dbus-devel", + DISTRO_ID_SUSE: "dbus-1-devel", + DISTRO_ID_ARCH: "dbus", + }, + ), + Package(name="OpenGL Library", + distro_package_names={DISTRO_ID_DEBIAN: "libgl-dev", + DISTRO_ID_FEDORA: "mesa-libGL-devel", + DISTRO_ID_SUSE: "Mesa-libGL-devel", + DISTRO_ID_ARCH: "libglvnd", + }, + ), + Package(name="EGL Library", + distro_package_names={DISTRO_ID_DEBIAN: "libegl-dev", + DISTRO_ID_FEDORA: "mesa-libEGL-devel", + DISTRO_ID_SUSE: "Mesa-libEGL-devel", + DISTRO_ID_ARCH: None, # Included in libglvnd. + }, + ), +) + + +# Basic mandatory set of common libraries to build Blender, which are also available as pre-conmpiled libraries. +DEPS_MANDATORY_SUBPACKAGES = ( + Package(name="JPEG Library", + distro_package_names={DISTRO_ID_DEBIAN: "libjpeg-dev", + DISTRO_ID_FEDORA: "libjpeg-turbo-devel", + DISTRO_ID_SUSE: "libjpeg8-devel", + DISTRO_ID_ARCH: "libjpeg-turbo", + }, + ), + Package(name="PNG Library", + distro_package_names={DISTRO_ID_DEBIAN: "libpng-dev", + DISTRO_ID_FEDORA: "libpng-devel", + DISTRO_ID_SUSE: "libpng16-compat-devel", + DISTRO_ID_ARCH: "libpng", + }, + ), + Package(name="FreeType Library", + distro_package_names={DISTRO_ID_DEBIAN: "libfreetype6-dev", + DISTRO_ID_FEDORA: "freetype-devel", + DISTRO_ID_SUSE: "freetype2-devel", + DISTRO_ID_ARCH: "freetype2", + }, + ), + Package(name="FontConfig Library", + distro_package_names={DISTRO_ID_DEBIAN: "libfontconfig-dev", + DISTRO_ID_FEDORA: "fontconfig", + DISTRO_ID_SUSE: "fontconfig", + DISTRO_ID_ARCH: "fontconfig", + }, + ), + Package(name="ZStandard Library", + distro_package_names={DISTRO_ID_DEBIAN: "libzstd-dev", + DISTRO_ID_FEDORA: "libzstd-devel", + DISTRO_ID_SUSE: "libzstd-devel", + DISTRO_ID_ARCH: "zstd", + }, + ), + Package(name="BZ2 Library", + distro_package_names={DISTRO_ID_DEBIAN: "libbz2-dev", + DISTRO_ID_FEDORA: "bzip2-devel", + DISTRO_ID_SUSE: "libbz2-devel", + DISTRO_ID_ARCH: "bzip2", + }, + ), + Package(name="LZMA Library", + distro_package_names={DISTRO_ID_DEBIAN: "liblzma-dev", + DISTRO_ID_FEDORA: "lzma-sdk-devel", # ??? + DISTRO_ID_SUSE: "lzma-sdk-devel", # ??? + DISTRO_ID_ARCH: "xz", # ??? + }, + ), + Package(name="SDL2 Library", + distro_package_names={DISTRO_ID_DEBIAN: "libsdl2-dev", + DISTRO_ID_FEDORA: "SDL2-devel", + DISTRO_ID_SUSE: "SDL2-devel", + DISTRO_ID_ARCH: "sdl2", + }, + ), + Package(name="ShaderC Library", + distro_package_names={DISTRO_ID_DEBIAN: "libshaderc-dev", + DISTRO_ID_FEDORA: "libshaderc-devel", + DISTRO_ID_SUSE: "shaderc-devel", + DISTRO_ID_ARCH: "shaderc", + }, + ), + Package(name="Epoxy Library", + distro_package_names={DISTRO_ID_DEBIAN: "libepoxy-dev", + DISTRO_ID_FEDORA: "libepoxy-devel", + DISTRO_ID_SUSE: "libepoxy-devel", + DISTRO_ID_ARCH: "libepoxy", + }, + ), + Package(name="XML2 Library", + distro_package_names={DISTRO_ID_DEBIAN: "libxml2-dev", + DISTRO_ID_FEDORA: "libxml2-devel", + DISTRO_ID_SUSE: "libxml2-devel", + DISTRO_ID_ARCH: "libxml2", + }, + ), + Package(name="Haru Library", + distro_package_names={DISTRO_ID_DEBIAN: "libhpdf-dev", + DISTRO_ID_FEDORA: "libharu-devel", + DISTRO_ID_SUSE: "libharu-devel", + DISTRO_ID_ARCH: "libharu", + }, + ), + Package(name="PyString Library", + distro_package_names={DISTRO_ID_DEBIAN: "libpystring-dev", + DISTRO_ID_FEDORA: "pystring-devel", + DISTRO_ID_SUSE: "pystring-devel", + DISTRO_ID_ARCH: "pystring", + }, + ), +) + + +# Basic optional set of common libraries to build Blender, which are also available as pre-conmpiled libraries. +DEPS_OPTIONAL_SUBPACKAGES = ( + Package(name="OpenJPG Library", + distro_package_names={DISTRO_ID_DEBIAN: "libopenjp2-7-dev", + DISTRO_ID_FEDORA: "openjpeg2-devel", + DISTRO_ID_SUSE: "openjpeg2-devel", + DISTRO_ID_ARCH: "openjpeg2", + }, + ), + Package(name="TIFF Library", + distro_package_names={DISTRO_ID_DEBIAN: "libtiff-dev", + DISTRO_ID_FEDORA: "libtiff-devel", + DISTRO_ID_SUSE: "libtiff-devel", + DISTRO_ID_ARCH: "libtiff", + }, + ), + Package(name="Jack2 Library", + distro_package_names={DISTRO_ID_DEBIAN: "libjack-jackd2-dev", + DISTRO_ID_FEDORA: "jack-audio-connection-kit-devel", + DISTRO_ID_SUSE: None, + DISTRO_ID_ARCH: "jack2", + }, + ), + Package(name="Pulse Library", + distro_package_names={DISTRO_ID_DEBIAN: "libpulse-dev", + DISTRO_ID_FEDORA: "pulseaudio-libs-devel", + DISTRO_ID_SUSE: "libpulse-devel", + DISTRO_ID_ARCH: "libpulse", + }, + ), + Package(name="OpenAL Library", + distro_package_names={DISTRO_ID_DEBIAN: "libopenal-dev", + DISTRO_ID_FEDORA: "openal-soft-devel", + DISTRO_ID_SUSE: None, + DISTRO_ID_ARCH: "openal", + }, + ), + Package(name="SndFile Library", + distro_package_names={DISTRO_ID_DEBIAN: "libsndfile1-dev", + DISTRO_ID_FEDORA: "libsndfile-devel", + DISTRO_ID_SUSE: None, + DISTRO_ID_ARCH: "libsndfile", + }, + ), + Package(name="JEMalloc Library", + distro_package_names={DISTRO_ID_DEBIAN: "libjemalloc-dev", + DISTRO_ID_FEDORA: "jemalloc-devel", + DISTRO_ID_SUSE: "jemalloc-devel", + DISTRO_ID_ARCH: "jemalloc", + }, + ), + Package(name="Vulkan Library", + distro_package_names={DISTRO_ID_DEBIAN: "libvulkan-dev", + DISTRO_ID_FEDORA: ..., + DISTRO_ID_SUSE: ..., + DISTRO_ID_ARCH: ..., + }, + ), + Package(name="Vulkan Headers", + distro_package_names={DISTRO_ID_DEBIAN: ..., + DISTRO_ID_FEDORA: "vulkan-headers", + DISTRO_ID_SUSE: "vulkan-headers", + DISTRO_ID_ARCH: "vulkan-headers", + }, + ), + Package(name="Vulkan ICD Loader", + distro_package_names={DISTRO_ID_DEBIAN: ..., + DISTRO_ID_FEDORA: "vulkan-loader-devel", + DISTRO_ID_SUSE: ..., + DISTRO_ID_ARCH: "vulkan-icd-loader", + }, + ), + Package(name="GMP Library", + distro_package_names={DISTRO_ID_DEBIAN: "libgmp-dev", + DISTRO_ID_FEDORA: "gmp-devel", + DISTRO_ID_SUSE: "gmp-devel", + DISTRO_ID_ARCH: "gmp", + }, + ), + Package(name="PugiXML Library", + distro_package_names={DISTRO_ID_DEBIAN: "libpugixml-dev", + DISTRO_ID_FEDORA: "pugixml-devel", + DISTRO_ID_SUSE: "pugixml-devel", + DISTRO_ID_ARCH: "pugixml", + }, + ), + Package(name="FFTW3 Library", + distro_package_names={DISTRO_ID_DEBIAN: "libfftw3-dev", + DISTRO_ID_FEDORA: "fftw-devel", + DISTRO_ID_SUSE: "fftw-devel", + DISTRO_ID_ARCH: "fftw", + }, + ), + Package(name="POTrace Library", + distro_package_names={DISTRO_ID_DEBIAN: "libpotrace-dev", + DISTRO_ID_FEDORA: "potrace-devel", + DISTRO_ID_SUSE: "potrace-devel", + DISTRO_ID_ARCH: "potrace", + }, + ), + Package(name="Yaml CPP Library", + distro_package_names={DISTRO_ID_DEBIAN: "libyaml-cpp-dev", + DISTRO_ID_FEDORA: "yaml-cpp-devel", + DISTRO_ID_SUSE: "yaml-cpp-devel", + DISTRO_ID_ARCH: "yaml-cpp", + }, + ), + Package(name="Pcre Library Devel", + sub_packages=( + Package(name="Pcre Library", is_mandatory=False, + distro_package_names={DISTRO_ID_DEBIAN: ..., + DISTRO_ID_FEDORA: ..., + DISTRO_ID_SUSE: "libpcre1", # this is... a dependency joke? + DISTRO_ID_ARCH: ..., + }, + ), + ), + distro_package_names={DISTRO_ID_DEBIAN: ..., + DISTRO_ID_FEDORA: "pcre-devel", # Missing dependency of collada package? + DISTRO_ID_SUSE: "pcre-devel", # Missing dependency of collada package? + DISTRO_ID_ARCH: ..., + }, + ), +) + + +# Python packages that should be available for Blender pyscripts. +# Suse uses names like `python310-Cython` for its python module packages... +def suse_pypackages_name_gen(name): + def _gen(package, parent_packages): + pp = parent_packages[-1] + if pp is not None and pp.version_installed is not ...: + v = "".join(str(i) for i in PackageInstaller.version_tokenize(pp.version_installed)[0][:2]) + return "python" + v + "-" + name + return _gen + + +PYTHON_SUBPACKAGES = ( + Package(name="Cython", version="0.29", version_short="0.29", version_min="0.20", version_mex="1.0", + distro_package_names={DISTRO_ID_DEBIAN: "cython3", + DISTRO_ID_FEDORA: "python3-Cython", + DISTRO_ID_SUSE: suse_pypackages_name_gen("Cython"), + DISTRO_ID_ARCH: "cython", + }, + ), + Package(name="IDNA", version="3.3", version_short="3.3", version_min="2.0", version_mex="4.0", + distro_package_names={DISTRO_ID_DEBIAN: "python3-idna", + DISTRO_ID_FEDORA: "python3-idna", + DISTRO_ID_SUSE: suse_pypackages_name_gen("idna"), + DISTRO_ID_ARCH: "python-idna", + }, + ), + Package(name="Charset Normalizer", version="2.0.10", version_short="2.0", version_min="2.0.6", version_mex="4.0.0", + distro_package_names={DISTRO_ID_DEBIAN: "python3-charset-normalizer", + DISTRO_ID_FEDORA: "python3-charset-normalizer", + DISTRO_ID_SUSE: suse_pypackages_name_gen("charset-normalizer"), + DISTRO_ID_ARCH: "python-charset-normalizer", + }, + ), + Package(name="URLLib", version="1.26.8", version_short="1.26", version_min="1.0", version_mex="2.0", + distro_package_names={DISTRO_ID_DEBIAN: "python3-urllib3", + DISTRO_ID_FEDORA: "python3-urllib3", + DISTRO_ID_SUSE: suse_pypackages_name_gen("urllib3"), + DISTRO_ID_ARCH: "python-urllib3", + }, + ), + Package(name="Certifi", version="2021.10.08", version_short="2021.10", version_min="2021.0", version_mex="2023.0", + distro_package_names={DISTRO_ID_DEBIAN: "python3-certifi", + DISTRO_ID_FEDORA: "python3-certifi", + DISTRO_ID_SUSE: suse_pypackages_name_gen("certifi"), + DISTRO_ID_ARCH: "python-certifi", + }, + ), + Package(name="Requests", version="2.27.1", version_short="2.27", version_min="2.0", version_mex="3.0", + distro_package_names={DISTRO_ID_DEBIAN: "python3-requests", + DISTRO_ID_FEDORA: "python3-requests", + DISTRO_ID_SUSE: suse_pypackages_name_gen("requests"), + DISTRO_ID_ARCH: "python-requests", + }, + ), + Package(name="ZStandard", version="0.16.0", version_short="0.16", version_min="0.15.2", version_mex="1.0.0", + distro_package_names={DISTRO_ID_DEBIAN: "python3-zstandard", + DISTRO_ID_FEDORA: "python3-zstandard", + DISTRO_ID_SUSE: suse_pypackages_name_gen("zstandard"), + DISTRO_ID_ARCH: "python-zstandard", + }, + ), + Package(name="NumPy", version="1.23.5", version_short="1.23", version_min="1.14", version_mex="2.0", + distro_package_names={DISTRO_ID_DEBIAN: "python3-numpy", + DISTRO_ID_FEDORA: "python3-numpy", + DISTRO_ID_SUSE: suse_pypackages_name_gen("numpy"), + DISTRO_ID_ARCH: "python-numpy", + }, + ), + Package(name="NumPy Devel", version="1.23.5", version_short="1.23", version_min="1.14", version_mex="2.0", + distro_package_names={DISTRO_ID_DEBIAN: ..., + DISTRO_ID_FEDORA: ..., + DISTRO_ID_SUSE: suse_pypackages_name_gen("numpy-devel"), + DISTRO_ID_ARCH: ..., + }, + ), +) + + +# List of boost individual libraries, some distro do not install everything anymore with the generic boost package. +BOOST_SUBPACKAGES = ( + Package(name="LibBoost FileSystem", is_mandatory=True, + distro_package_names={DISTRO_ID_DEBIAN: "libboost-filesystem-dev", + DISTRO_ID_FEDORA: ..., + DISTRO_ID_SUSE: "libboost_filesystem-devel", + DISTRO_ID_ARCH: ..., + }, + ), + Package(name="LibBoost Locale", is_mandatory=True, + distro_package_names={DISTRO_ID_DEBIAN: "libboost-locale-dev", + DISTRO_ID_FEDORA: ..., + DISTRO_ID_SUSE: "libboost_locale-devel", + DISTRO_ID_ARCH: ..., + }, + ), + Package(name="LibBoost Thread", is_mandatory=True, + distro_package_names={DISTRO_ID_DEBIAN: "libboost-thread-dev", + DISTRO_ID_FEDORA: ..., + DISTRO_ID_SUSE: "libboost_thread-devel", + DISTRO_ID_ARCH: ..., + }, + ), + Package(name="LibBoost Regex", is_mandatory=True, + distro_package_names={DISTRO_ID_DEBIAN: "libboost-regex-dev", + DISTRO_ID_FEDORA: ..., + DISTRO_ID_SUSE: "libboost_regex-devel", + DISTRO_ID_ARCH: ..., + }, + ), + Package(name="LibBoost System", is_mandatory=True, + distro_package_names={DISTRO_ID_DEBIAN: "libboost-system-dev", + DISTRO_ID_FEDORA: ..., + DISTRO_ID_SUSE: "libboost_system-devel", + DISTRO_ID_ARCH: ..., + }, + ), + Package(name="LibBoost Date/Time", is_mandatory=True, + distro_package_names={DISTRO_ID_DEBIAN: "libboost-date-time-dev", + DISTRO_ID_FEDORA: ..., + DISTRO_ID_SUSE: "libboost_date_time-devel", + DISTRO_ID_ARCH: ..., + }, + ), + Package(name="LibBoost Wave", is_mandatory=True, + distro_package_names={DISTRO_ID_DEBIAN: "libboost-wave-dev", + DISTRO_ID_FEDORA: ..., + DISTRO_ID_SUSE: "libboost_wave-devel", + DISTRO_ID_ARCH: ..., + }, + ), + Package(name="LibBoost Atomic", is_mandatory=True, + distro_package_names={DISTRO_ID_DEBIAN: "libboost-atomic-dev", + DISTRO_ID_FEDORA: ..., + DISTRO_ID_SUSE: "libboost_atomic-devel", + DISTRO_ID_ARCH: ..., + }, + ), + Package(name="LibBoost Serialization", is_mandatory=True, + distro_package_names={DISTRO_ID_DEBIAN: "libboost-serialization-dev", + DISTRO_ID_FEDORA: ..., + DISTRO_ID_SUSE: "libboost_serialization-devel", + DISTRO_ID_ARCH: ..., + }, + ), + Package(name="LibBoost ProgramOptions", is_mandatory=True, + distro_package_names={DISTRO_ID_DEBIAN: "libboost-program-options-dev", + DISTRO_ID_FEDORA: ..., + DISTRO_ID_SUSE: "libboost_program_options-devel", + DISTRO_ID_ARCH: ..., + }, + ), + Package(name="LibBoost IOStreams", is_mandatory=True, + distro_package_names={DISTRO_ID_DEBIAN: "libboost-iostreams-dev", + DISTRO_ID_FEDORA: ..., + DISTRO_ID_SUSE: "libboost_iostreams-devel", + DISTRO_ID_ARCH: ..., + }, + ), + Package(name="LibBoost Python", is_mandatory=True, + distro_package_names={DISTRO_ID_DEBIAN: "libboost-python-dev", + DISTRO_ID_FEDORA: ..., + DISTRO_ID_SUSE: "libboost_python3-devel", + DISTRO_ID_ARCH: ..., + }, + ), + Package(name="LibBoost Numpy", is_mandatory=True, + distro_package_names={DISTRO_ID_DEBIAN: "libboost-numpy-dev", + DISTRO_ID_FEDORA: ..., + DISTRO_ID_SUSE: "libboost_numpy3-devel", + DISTRO_ID_ARCH: ..., + }, + ), +) + + +# Packages required to build Blender, which are not included in the precompiled libraries. +PACKAGES_BASICS_BUILD = ( + Package(name="Basics Mandatory Build", is_group=True, is_mandatory=True, sub_packages=BUILD_MANDATORY_SUBPACKAGES), + Package(name="Basics Optional Build", is_group=True, is_mandatory=False, sub_packages=BUILD_OPTIONAL_SUBPACKAGES), + Package(name="Basic Critical Deps", is_group=True, is_mandatory=True, sub_packages=DEPS_CRITICAL_SUBPACKAGES), +) + + +# All packages, required or 'nice to have', to build Blender. +# Also covers (as best as possible) the dependencies provided by the precompiled libraries. +PACKAGES_ALL = ( + Package(name="Basics Mandatory Build", is_group=True, is_mandatory=True, sub_packages=BUILD_MANDATORY_SUBPACKAGES), + Package(name="Basics Optional Build", is_group=True, is_mandatory=False, sub_packages=BUILD_OPTIONAL_SUBPACKAGES), + Package(name="Basic Critical Deps", is_group=True, is_mandatory=True, sub_packages=DEPS_CRITICAL_SUBPACKAGES), + Package(name="Basic Mandatory Deps", is_group=True, is_mandatory=True, sub_packages=DEPS_MANDATORY_SUBPACKAGES), + Package(name="Basic Optional Deps", is_group=True, is_mandatory=False, sub_packages=DEPS_OPTIONAL_SUBPACKAGES), + + Package(name="Clang Format", version="10.0", version_short="10.0", version_min="6.0", version_mex="15.0", + distro_package_names={DISTRO_ID_DEBIAN: "clang-format", + DISTRO_ID_FEDORA: "clang", # clang-format is part of the main clang package. + DISTRO_ID_SUSE: "clang", # clang-format is part of the main clang package. + DISTRO_ID_ARCH: "clang", # clang-format is part of the main clang package. + }, + ), + Package(name="Python", is_mandatory=True, version="3.10.12", version_short="3.10", version_min="3.10", version_mex="3.12", + sub_packages=PYTHON_SUBPACKAGES, + distro_package_names={DISTRO_ID_DEBIAN: "python3-dev", + DISTRO_ID_FEDORA: "python3-devel", + DISTRO_ID_SUSE: "python3-devel", + DISTRO_ID_ARCH: "python", + }, + ), + Package(name="Boost Libraries", is_mandatory=True, version="1.80.0", version_short="1.80", version_min="1.49", version_mex="2.0", + sub_packages=BOOST_SUBPACKAGES, + distro_package_names={DISTRO_ID_DEBIAN: "libboost-dev", + DISTRO_ID_FEDORA: "boost-devel", + DISTRO_ID_SUSE: "boost-devel", + DISTRO_ID_ARCH: "boost", + }, + ), + Package(name="TBB Library", is_mandatory=True, version="2020", version_short="2020", version_min="2018", version_mex="2022", + sub_packages=(), + distro_package_names={DISTRO_ID_DEBIAN: "libtbb-dev", + DISTRO_ID_FEDORA: "tbb-devel", + DISTRO_ID_SUSE: "tbb-devel", + DISTRO_ID_ARCH: "intel-oneapi-tbb", + }, + ), + Package(name="OpenColorIO Library", is_mandatory=False, version="2.2.0", version_short="2.2", version_min="2.0", version_mex="3.0", + sub_packages=(), + distro_package_names={DISTRO_ID_DEBIAN: "libopencolorio-dev", + DISTRO_ID_FEDORA: "OpenColorIO-devel", + DISTRO_ID_SUSE: "OpenColorIO-devel", + DISTRO_ID_ARCH: "opencolorio", + }, + ), + Package(name="IMath Library", is_mandatory=False, version="3.1.7", version_short="3.1", version_min="3.0", version_mex="4.0", + sub_packages=(), + distro_package_names={DISTRO_ID_DEBIAN: "libimath-dev", + DISTRO_ID_FEDORA: "imath-devel", + DISTRO_ID_SUSE: "Imath-devel", + DISTRO_ID_ARCH: "imath", + }, + ), + Package(name="OpenEXR Library", is_mandatory=False, version="3.1.7", version_short="3.1", version_min="3.0", version_mex="4.0", + sub_packages=(), + distro_package_names={DISTRO_ID_DEBIAN: "libopenexr-dev", + DISTRO_ID_FEDORA: "openexr-devel", + DISTRO_ID_SUSE: "openexr-devel", + DISTRO_ID_ARCH: "openexr", + }, + ), + Package(name="OpenImageIO Library", is_mandatory=True, version="2.4.11.0", version_short="2.4", version_min="2.2.0", version_mex="2.5.0", + sub_packages=( + Package(name="OpenImageIO Tools", is_mandatory=False, + distro_package_names={DISTRO_ID_DEBIAN: "openimageio-tools", + DISTRO_ID_FEDORA: "OpenImageIO-utils", + DISTRO_ID_SUSE: "OpenImageIO", # ??? + DISTRO_ID_ARCH: ..., + }, + ), + ), + distro_package_names={DISTRO_ID_DEBIAN: "libopenimageio-dev", + DISTRO_ID_FEDORA: "OpenImageIO-devel", + DISTRO_ID_SUSE: "OpenImageIO-devel", + DISTRO_ID_ARCH: "openimageio", + }, + ), + Package(name="LLVM Library", is_mandatory=False, version="12.0.0", version_short="12.0", version_min="11.0", version_mex="16.0", + sub_packages=( + Package(name="Clang Compiler", is_mandatory=False, + distro_package_names={DISTRO_ID_DEBIAN: "clang", + DISTRO_ID_FEDORA: "clang-devel", + DISTRO_ID_SUSE: "clang-devel", + DISTRO_ID_ARCH: "clang", + }, + ), + Package(name="Clang Library", is_mandatory=False, + distro_package_names={DISTRO_ID_DEBIAN: "libclang-dev", + DISTRO_ID_FEDORA: ..., + DISTRO_ID_SUSE: ..., + DISTRO_ID_ARCH: ..., + }, + ), + ), + distro_package_names={DISTRO_ID_DEBIAN: "llvm-dev", + DISTRO_ID_FEDORA: "llvm-devel", + DISTRO_ID_SUSE: "llvm-devel", + DISTRO_ID_ARCH: "llvm", + }, + ), + Package(name="OpenShadingLanguage Library", is_mandatory=False, version="1.13.0.2", version_short="1.13", version_min="1.11", version_mex="2.0", + sub_packages=(), + distro_package_names={DISTRO_ID_DEBIAN: None, # No package currently. + DISTRO_ID_FEDORA: "openshadinglanguage-devel", + DISTRO_ID_SUSE: "OpenShadingLanguage-devel", + DISTRO_ID_ARCH: "openshadinglanguage", + }, + ), + Package(name="OpenSubDiv Library", is_mandatory=False, version="3.5.0", version_short="3.5", version_min="3.5", version_mex="4.0", + sub_packages=(), + distro_package_names={DISTRO_ID_DEBIAN: "libosd-dev", + DISTRO_ID_FEDORA: "opensubdiv-devel", + DISTRO_ID_SUSE: None, + DISTRO_ID_ARCH: "opensubdiv", + }, + ), + Package(name="OpenVDB Library", is_mandatory=False, version="10.0.0", version_short="10.0", version_min="10.0", version_mex="11.0", + sub_packages=( + # Assume packaged versions of the dependencies are compatible with OpenVDB package. + Package(name="OpenVDB Dependencies", is_mandatory=False, is_group=True, + sub_packages=( + Package(name="Blosc Library", is_mandatory=False, + distro_package_names={DISTRO_ID_DEBIAN: "libblosc-dev", + DISTRO_ID_FEDORA: "blosc-devel", + DISTRO_ID_SUSE: "blosc-devel", + DISTRO_ID_ARCH: "blosc", + }, + ), + Package(name="NanoVDB Library", is_mandatory=False, + distro_package_names={DISTRO_ID_DEBIAN: "libnanovdb-dev", + DISTRO_ID_FEDORA: ..., # Part of openvdb package. + DISTRO_ID_SUSE: None, + DISTRO_ID_ARCH: ..., # Part of openvdb package. + }, + ), + ), + ), + ), + distro_package_names={DISTRO_ID_DEBIAN: "libopenvdb-dev", + DISTRO_ID_FEDORA: "openvdb-devel", + DISTRO_ID_SUSE: None, # No known package yet. + DISTRO_ID_ARCH: "openvdb", + }, + ), + Package(name="Alembic Library", is_mandatory=False, version="1.8.3", version_short="1.8", version_min="1.7", version_mex="2.0", + sub_packages=(), + distro_package_names={DISTRO_ID_DEBIAN: None, + DISTRO_ID_FEDORA: "alembic-devel", + DISTRO_ID_SUSE: "alembic-devel", + DISTRO_ID_ARCH: "alembic", + }, + ), + Package(name="MaterialX Library", is_mandatory=False, version="1.38.6", version_short="1.38", version_min="1.38", version_mex="1.40", + sub_packages=(), + distro_package_names={DISTRO_ID_DEBIAN: None, + DISTRO_ID_FEDORA: None, + DISTRO_ID_SUSE: None, + DISTRO_ID_ARCH: "materialx-git", + }, + ), + Package(name="USD Library", is_mandatory=False, version="23.05", version_short="23.05", version_min="20.05", version_mex="24.00", + sub_packages=(), + distro_package_names={DISTRO_ID_DEBIAN: None, + DISTRO_ID_FEDORA: "usd-devel", + DISTRO_ID_SUSE: None, + DISTRO_ID_ARCH: "usd", # No official package, in AUR only currently. + }, + ), + Package(name="OpenCollada Library", is_mandatory=False, version="1.6.68", version_short="1.6", version_min="1.6.68", version_mex="1.7", + distro_package_names={DISTRO_ID_DEBIAN: "opencollada-dev", # Useless, very old! + DISTRO_ID_FEDORA: "openCOLLADA-devel", + DISTRO_ID_SUSE: "libopenCOLLADA-devel", + DISTRO_ID_ARCH: "opencollada", + }, + ), + Package(name="Embree Library", is_mandatory=False, version="4.1.0", version_short="4.1", version_min="3.13", version_mex="5.0", + sub_packages=(), + distro_package_names={DISTRO_ID_DEBIAN: "libembree-dev", + DISTRO_ID_FEDORA: "embree-devel", + DISTRO_ID_SUSE: "embree-devel", + DISTRO_ID_ARCH: "embree", + }, + ), + Package(name="OpenImageDenoiser Library", is_mandatory=False, version="1.4.3", version_short="1.4", version_min="1.4.0", version_mex="1.5", + sub_packages=(), + distro_package_names={DISTRO_ID_DEBIAN: None, + DISTRO_ID_FEDORA: "oidn-devel", + DISTRO_ID_SUSE: "OpenImageDenoise-devel", + DISTRO_ID_ARCH: "openimagedenoise", + }, + ), + Package(name="Level Zero Library", is_mandatory=False, version="1.8.8", version_short="1.8", version_min="1.7", version_mex="2.0", + sub_packages=(), + distro_package_names={DISTRO_ID_DEBIAN: None, + DISTRO_ID_FEDORA: "oneapi-level-zero-devel", + DISTRO_ID_SUSE: None, + DISTRO_ID_ARCH: "level-zero-headers", # ??? + }, + ), + Package(name="OpenPGL Library", is_mandatory=False, version="0.5.0", version_short="0.5", version_min="0.5.0", version_mex="0.6", + sub_packages=(), + distro_package_names={DISTRO_ID_DEBIAN: None, + DISTRO_ID_FEDORA: "openpgl-devel", + DISTRO_ID_SUSE: None, + DISTRO_ID_ARCH: "openpgl", + }, + ), + Package(name="XROpenXR Library", is_mandatory=False, version="1.0.22", version_short="1.0", version_min="1.0.8", version_mex="2.0", + sub_packages=(), + distro_package_names={DISTRO_ID_DEBIAN: "libopenxr-dev", + DISTRO_ID_FEDORA: None, + DISTRO_ID_SUSE: None, + DISTRO_ID_ARCH: "openxr", + }, + ), + Package(name="FFMPEG Library", is_mandatory=False, version="6.0", version_short="6.0", version_min="4.0", version_mex="7.0", + sub_packages=( + Package(name="AVDevice FFMPEG Library", is_mandatory=False, + distro_package_names={DISTRO_ID_DEBIAN: "libavdevice-dev", + DISTRO_ID_FEDORA: ..., + DISTRO_ID_SUSE: ..., + DISTRO_ID_ARCH: ..., + }, + ), + ), + distro_package_names={DISTRO_ID_DEBIAN: "ffmpeg", + DISTRO_ID_FEDORA: "ffmpeg-free-devel", + DISTRO_ID_SUSE: "ffmpeg-devel", + DISTRO_ID_ARCH: "ffmpeg", + }, + ), +) + + +class ProgressBar: + """Very basic progress bar printing in the console.""" + + def __init__(self, min_value=0, max_value=100, print_len=80, is_known_limit=True): + self.value = 0 + self.min_value = min_value + self.max_value = max_value + self.print_len = print_len + self.is_known_limit = is_known_limit + self.print_stdout() + + def update(self, steps=1): + self.value += steps + self.print_stdout() + + def finish(self): + print("\033[2K\r", end="") + + def print_stdout(self): + print("\r", self, end="") + + def __repr__(self): + value_print_len = self.print_len - 2 + range_value = self.max_value - self.min_value + diff_to_min = self.value - self.min_value + value = (self.value % range_value) / range_value * value_print_len + if (diff_to_min // range_value) % 2 == 0: + value_str = "*" * int(value) + " " * (value_print_len - int(value)) + else: + value_str = " " * int(value) + "*" * (value_print_len - int(value)) + if self.is_known_limit: + return f"[{value_str}]" + return f">{value_str}<" + + +class PackageInstaller: + """Parent class of all package installers, does nothing but printing list of packages and defining the 'interface'. + """ + _instance = None + + def __new__(cls, settings): + if cls._instance is None: + cls._instance = super(PackageInstaller, cls).__new__(cls) + cls._instance.settings = settings + return cls._instance + + def run_command(self, command): + """Basic wrapper around `subprocess.Popen`, mimicking `subprocess.run` with a basic progress bar.""" + # First dummy call to get user password for sudo. Otherwise the progress bar on actuall commands + # makes it impossible for users to enter their password. + if not self.settings.no_sudo: + subprocess.run(["sudo", "echo"], capture_output=True) + + p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + pbar = ProgressBar(is_known_limit=False) + while p.poll() is None: + pbar.update(steps=2) + time.sleep(0.05) + pbar.finish() + return subprocess.CompletedProcess( + args=command, + returncode=p.returncode, + stdout=p.stdout.read(), + stderr=p.stderr.read()) + + @property + def can_install(self): + return not self.settings.no_sudo and self.__class__ != PackageInstaller + + # Version utils, should not need to be redefined in each sub-class. + # ---------- + _re_version_sanitize = re.compile(r"(?P([0-9]+\.?)+([0-9]+)).*") + + @classmethod + def version_sanitize(cls, version): + """ + Sanitize a version string by removing 'extras' like `_RC2` in `1.2_RC2`. + Note that the version string is expected to start with at least two numbers + separated by a dot. + """ + version = cls._re_version_sanitize.search(version) + return version["version"] if version is not None else version + + @classmethod + def version_tokenize(cls, *args): + """ + Tokenize an iterable of sanitized version strings into tuples of integers of a same length, + filling missing items with zero values. + """ + versions = tuple(tuple(int(i) for i in cls.version_sanitize(v).split(".")) for v in args) + maxlen = max(len(v) for v in versions) + return tuple(v + (0,) * (maxlen - len(v)) for v in versions) + + @classmethod + def version_match(cls, version, ref_version): + """ + Return True if the `version` string falls into the version range covered by the `ref_version` string. + `version` should be at least as long as `ref_version` (in term of version number items). + E.g. 3.3.2: + - matches 3.3 + - matches 3.3.2 + - does not match 3.4 + - does not match 3.3.0 + - does not match 3.3.2.5 + """ + version = cls.version_tokenize(version)[0] + ref_version = cls.version_tokenize(ref_version)[0] + len_ref_version = len(ref_version) + return (len(version) >= len_ref_version) and version[:len_ref_version] == ref_version + + @classmethod + def versions_range_gen(cls, package, versions_set): + def do_yield(version, versions_set): + if version not in versions_set: + versions_set.add(version) + yield version + MEX_RANGE_DIFF = 5 + VERSION_FACTOR_MAX = 100 + VERSION_FACTOR_MINRANGE_MULTIPLIER = 2 + VERSION_FACTOR_STEP_DIVIDER = 10 + + version = cls.version_tokenize(package.version)[0][:2] + version_min = cls.version_tokenize(package.version_min)[0][:2] + version_mex = cls.version_tokenize(package.version_mex)[0][:2] + + version_major = version[0] + version_major_min = version_min[0] + version_major_mex = version_mex[0] + if version_major_mex - version_major_min > 1: + yield from do_yield(str(version_major), versions_set) + for i in range(1, MEX_RANGE_DIFF): + if version_major + i < version_major_mex: + yield from do_yield(str(version_major + i), versions_set) + for i in range(1, MEX_RANGE_DIFF): + if version_major - i >= version_major_min: + yield from do_yield(str(version_major - i), versions_set) + return + if len(version) < 2: + yield from do_yield(str(version_major), versions_set) + return + + version_minor = version[1] + version_minor_min = 0 if len(version_min) < 2 else version_min[1] + version_minor_mex = 0 if len(version_mex) < 2 else version_mex[1] + version_minor_fac = 1 + vfac = VERSION_FACTOR_MAX + while vfac > 1: + version_minor_minrange = vfac * VERSION_FACTOR_MINRANGE_MULTIPLIER + is_vfac_in_range = (version_minor >= vfac or version_minor_min >= vfac or version_minor_mex >= vfac) + is_version_range_big_enough = (version_major_min != version_major_mex or + version_minor_mex - version_minor_min >= version_minor_minrange) + if (is_vfac_in_range and is_version_range_big_enough and version_minor % vfac == 0): + version_minor_fac = vfac + break + vfac = vfac // VERSION_FACTOR_STEP_DIVIDER + yield from do_yield(str(version_major) + "." + str(version_minor), versions_set) + yield from do_yield(str(version_major) + str(version_minor), versions_set) + for i in range(1, MEX_RANGE_DIFF): + i *= version_minor_fac + if version_minor + i < version_minor_mex or version_major_mex > version_major: + yield from do_yield(str(version_major) + "." + str(version_minor + i), versions_set) + yield from do_yield(str(version_major) + str(version_minor + i), versions_set) + for i in range(1, MEX_RANGE_DIFF): + i *= version_minor_fac + if version_minor - i >= version_minor_min or (version_minor - i >= 0 and version_major_min < version_major): + yield from do_yield(str(version_major) + "." + str(version_minor - i), versions_set) + yield from do_yield(str(version_major) + str(version_minor - i), versions_set) + return + + # Generic package handling, should not need to be redefined in each sub-class. + # Note that they may depend on some non-generic functions defined below though. + # ---------- + + def package_query_version_get(self, package_distro_name): + """Return the available, potentially cached if already looked-up, version of the given package.""" + if not hasattr(self, "_package_versions_cache"): + self._package_versions_cache = {} + return self._package_versions_cache.setdefault(package_distro_name, + self.package_query_version_get_impl(package_distro_name)) + + def package_query_version_match(self, package_distro_name, ref_version): + """Check if given package name matches given reference version.""" + version = self.package_query_version_get(package_distro_name) + if version is None: + return False + if version is ...: + # Only from PackageInstaller base class. + assert self.__class__ is PackageInstaller + return True + return self.version_match(version, ref_version) + + def package_query_version_ge_lt(self, package_distro_name, ref_version_min, ref_version_mex): + """Check if given package name fits inbetween given minimal and maximal excluded versions.""" + version = self.package_query_version_get(package_distro_name) + if version is None: + return False + if version is ...: + # Only from PackageInstaller base class. + assert self.__class__ is PackageInstaller + return True + version, ref_version_min, ref_version_mex = self.version_tokenize(version, ref_version_min, ref_version_mex) + return ref_version_min <= version < ref_version_mex + + def packages_database_update(self): + """Ensure that data-base of available packages is up-to-date.""" + if self._update_command is ...: + # Only from PackageInstaller base class. + assert self.__class__ is PackageInstaller + return True + + if self.settings.no_sudo: + self.settings.logger.debug("\t--no-sudo enabled, no update of packages info.") + return True + + self.settings.logger.info("Trying to update packages info.") + result = self.run_command(self._update_command) + if result.returncode != 0: + self.settings.logger.critical(f"\tFailed to update packages info:\n\t{repr(result)}\n") + exit(1) + self.settings.logger.info("Done.\n") + self.settings.logger.debug(repr(result)) + return result.returncode == 0 + + def package_find(self, package, package_distro_name): + """ + Generic euristics to try and find 'best macthing version' for a given package. + For most packages it just ensures given package name version matches the exact version from the `package`, + or at least fits within the [version_min, version_mex[ range. + But some, like e.g. python, llvm or boost, can have packages available for several versions, + with complex naming (like 'python3.10', 'llvm-9-dev', etc.). + This code attempts to find the best matching one possible, based on a set of 'possible names' + generated by the distro-specific `package_name_version_gen` generator. + """ + # Check 'exact' version match on given name. + if self.package_query_version_match(package_distro_name, package.version_short): + return package_distro_name + # Check exact version match on special 'versioned' names (like `python3.10-dev' e.g.). + for pn in self.package_name_version_gen(package, package_distro_name): + if self.package_query_version_match(pn, package.version_short): + return pn + # Check version in supported range. + if self.package_query_version_ge_lt(package_distro_name, package.version_min, package.version_mex): + return package_distro_name + # Check version in supported range on special 'versioned' names (like `llvm-11-dev' e.g.). + for pn in self.package_name_version_gen(package, package_distro_name, do_range_version_names=True): + if self.package_query_version_ge_lt(pn, package.version_min, package.version_mex): + return pn + return None + + def package_distro_name(self, package, parent_packages): + """ + Generate a collection of distro-specific package names from given package. + Typically only one name, unless given package is a group one, in which case all its + sub-packages' distro-specific names are returned in the list. + """ + distro_id = self.settings.distro_id + + packages_distro_names = [] + if package.is_group: + for p in package.sub_packages: + p.is_mandatory = package.is_mandatory + if distro_id is ...: + packages_distro_names.append(p.name) + else: + package_name = p.distro_package_names[distro_id] + if callable(package_name): + package_name = package_name(p, parent_packages) + if package_name not in {None, ...}: + packages_distro_names.append(package_name) + if p.is_group: + packages_distro_names += self.package_distro_name(p, parent_packages + (package,)) + return packages_distro_names + + if distro_id is ...: + package_name = package.name + else: + package_name = package.distro_package_names[distro_id] + if callable(package_name): + package_name = package_name(package, parent_packages) + return [package_name] + + def packages_install(self, packages, parent_packages=()): + """ + Install all given packages and their sub-packages. + This call is recursive, parent_packages is a tuple of the ancestors of current `package`, in calling order + (grand-parent, parent). + """ + def package_info_name(package, parent_packages): + packages = parent_packages + (package,) + return " ".join(p.name for p in packages) + + distro_id = self.settings.distro_id + for package in packages: + if not package.name: + continue + info_name = package_info_name(package, parent_packages) + + if package.is_group: + if self.can_install: + self.settings.logger.info(f"Trying to install group of packages {info_name}.") + if not package.sub_packages: + self.settings.logger.critical(f"Invalid group of packages {info_name}") + exit(1) + success = self.group_package_install(package, parent_packages) + if self.can_install: + if not success: + self.settings.logger.info("Failed.\n") + else: + self.settings.logger.info("Done.\n") + continue + + package_distro_name = self.package_distro_name(package, parent_packages)[0] + if package_distro_name is None: + if package.is_mandatory: + self.settings.logger.warning( + f"Mandatory package {info_name} is not defined for {distro_id} distribution, " + "Blender will likely not build at all without it.\n") + else: + self.settings.logger.info(f"Package {info_name} is not defined for {distro_id} distribution.\n") + continue + if package_distro_name is ...: + self.settings.logger.debug(f"Package {info_name} is not required for {distro_id} distribution.\n") + continue + + # Inherit parent version info if needed and possible. + if package.version is None: + if not parent_packages: + self.settings.logger.critical( + f"Package {info_name} ({package_distro_name}) has no version information.") + exit(1) + package.version = parent_packages[-1].version + package.version_short = parent_packages[-1].version_short + package.version_min = parent_packages[-1].version_min + package.version_mex = parent_packages[-1].version_mex + + if self.can_install: + self.settings.logger.info(f"Trying to install package {info_name} ({package_distro_name}).") + success = self.single_package_install(package, parent_packages) + if not success: + if self.can_install: + self.settings.logger.info("Failed.\n") + continue + + if self.can_install: + self.settings.logger.info("Done.\n") + if package.sub_packages: + self.packages_install(package.sub_packages, parent_packages + (package,)) + + def single_package_install(self, package, parent_packages=()): + """Install a normal, single package.""" + package_distro_name = self.package_distro_name(package, parent_packages)[0] + package_name = self.package_find(package, package_distro_name) + if package_name is None: + if package.is_mandatory: + self.settings.logger.critical( + f"\tFailed to find a matching mandatory {package_distro_name} " + f"(withing versions range [{package.version_min}, {package.version_mex}[).") + exit(1) + self.settings.logger.warning(f"\tFailed to find a matching {package_distro_name} " + f"(withing versions range [{package.version_min}, {package.version_mex}[).") + return False + + if self._install_command is ...: + # Only from PackageInstaller base class. + assert self.__class__ is PackageInstaller + self.settings.logger.info(f"\tWould install {package_distro_name}.") + return True + + if self.settings.no_sudo: + self.settings.logger.warning(f"\t--no-sudo enabled, impossible to run apt-get install for {package_name}.") + return True + + package_version = self.package_query_version_get(package_name) + self.settings.logger.info(f"\tInstalling package {package_name} ({package_version}).") + cmd = self._install_command + [package_name] + result = self.run_command(cmd) + if result.returncode != 0: + self.settings.logger.critical(f"\tFailed to install {package_name}:\n\t{repr(result)}") + exit(1) + + package_version_installed = self.package_installed_version_get(package_name) + if package_version_installed != package_version: + self.settings.logger.critical(f"\tInstalled version of {package_name} does not match expected value " + f"({package_version_installed} vs {package_version})") + exit(1) + self.settings.logger.debug(repr(result)) + package.version_installed = package_version_installed + return result.returncode == 0 + + def group_package_install(self, package, parent_packages=()): + """Install a group package and all of its sub-packages.""" + packages_distro_names = self.package_distro_name(package, parent_packages) + if self._install_command is ...: + # Only from PackageInstaller base class. + assert self.__class__ is PackageInstaller + packages_info_names = ',\n\t\t\t'.join(packages_distro_names) + self.settings.logger.info( + f"\tWould install group of packages {package.name}:\n\t\t\t{packages_info_names}.") + return True + + if self.settings.no_sudo: + self.settings.logger.warning( + f"\t--no-sudo enabled, impossible to run apt-get install for {packages_distro_names}.") + return True + + if not packages_distro_names: + return True + + self.settings.logger.info(f"\tInstalling packages {', '.join(packages_distro_names)}.") + cmd = self._install_command + [*packages_distro_names] + result = self.run_command(cmd) + if result.returncode != 0: + if package.is_mandatory: + self.settings.logger.critical(f"\tFailed to install packages:\n\t{repr(result)}") + exit(1) + else: + self.settings.logger.warning( + f"\tFailed to find install all of {packages_distro_names}:\n\t{repr(result)}") + self.settings.logger.debug(repr(result)) + return result.returncode == 0 + + # Implementation-specific, will most likely need to be re-defined in sub-classes. + # ---------- + + # Command and options to pass to install packages in specific distro (as a list, for `subprocess.run`). + # Will be appended with package or list of packages to install. + _install_command = ... + + # Command and options to pass to update packages data-base in specific distro (as a list, for `subprocess.run`). + _update_command = ... + + def package_installed_version_get(self, package_distro_name): + """Return the installed version of the given package.""" + return ... + + def package_query_version_get_impl(self, package_distro_name): + """Return the available version of the given package.""" + return ... + + def package_name_version_gen(self, package, package_distro_name, version, suffix="", do_range_version_names=False): + """Generator for all potential names for a given package 'base name'.""" + yield package_distro_name + + +class PackageInstallerDebian(PackageInstaller): + """Debian-like package installer, using apt and dpkg-query.""" + _instance = None + + def __new__(cls, settings): + if cls._instance is None: + cls._instance = super(PackageInstallerDebian, cls).__new__(cls, settings) + return cls._instance + + _version_regex_base_pattern = r"(?:[0-9]+:)?(?P([0-9]+\.?)+([0-9]+)).*" + _re_version = re.compile(_version_regex_base_pattern) + _re_version_candidate = re.compile(r"Candidate:\s*" + _version_regex_base_pattern) + + _install_command = ["sudo", "apt", "install", "-y"] + _update_command = ["sudo", "apt", "update"] + + def package_installed_version_get(self, package_distro_name): + cmd = ["dpkg-query", "-W", "-f", "${Version}", package_distro_name] + result = self.run_command(cmd) + version = self._re_version.search(str(result.stdout)) + return version["version"] if version is not None else None + + def package_query_version_get_impl(self, package_distro_name): + cmd = ["apt-cache", "policy", package_distro_name] + result = self.run_command(cmd) + version = self._re_version_candidate.search(str(result.stdout)) + return version["version"] if version is not None else None + + def package_name_version_gen( + self, + package, + package_distro_name, + version=..., + suffix="", + do_range_version_names=False): + if version is ...: + version = package.version_short + # Generate versions variants with version between main name and '-dev' suffix, if any. + tmp_package_name = package_distro_name.removesuffix("-dev") + if tmp_package_name != package_distro_name: + for pn in self.package_name_version_gen( + package, + tmp_package_name, + version, + suffix="-dev" + suffix, + do_range_version_names=do_range_version_names): + yield pn + # Strip any 'version-like' numbers at the end of the package name (already stripped of '-dev' suffix) + # and generate versions variants out of it. + tmp_package_name = tmp_package_name.rstrip("0123456789.-") + if tmp_package_name != package_distro_name: + for pn in self.package_name_version_gen( + package, + tmp_package_name, + version, + suffix=suffix, + do_range_version_names=do_range_version_names): + yield pn + # Generate version variants from given package name. + versions = [version] + if do_range_version_names: + # Also search for major version numbers around the target one, within to allowed range. + # Necessary for packages like llvm e.g. + versions += [*self.versions_range_gen(package, set(versions))] + for v in versions: + yield package_distro_name + v + suffix + yield package_distro_name + "-" + v + suffix + + +class PackageInstallerFedora(PackageInstaller): + """Fedora-like package installer, using dnf.""" + _instance = None + + def __new__(cls, settings): + if cls._instance is None: + cls._instance = super(PackageInstallerFedora, cls).__new__(cls, settings) + return cls._instance + + _re_version = re.compile(r"Version\s*:\s*(?:[0-9]+:)?(?P([0-9]+\.?)+([0-9]+)).*") + + _install_command = ["sudo", "dnf", "install", "-y"] + _update_command = ["sudo", "dnf", "check-update"] + + def package_version_get(self, command): + result = self.run_command(command) + version = self._re_version.search(str(result.stdout)) + return version["version"] if version is not None else None + + def package_installed_version_get(self, package_distro_name): + return self.package_version_get(["sudo", "dnf", "info", "--installed", package_distro_name]) + + def package_query_version_get_impl(self, package_distro_name): + return self.package_version_get(["sudo", "dnf", "info", "--all", package_distro_name]) + + def package_name_version_gen( + self, + package, + package_distro_name, + version=..., + suffix="", + do_range_version_names=False): + if version is ...: + version = package.version_short + # Generate versions variants with version between main name and '-devel' suffix, if any. + tmp_package_name = package_distro_name.removesuffix("-devel") + if tmp_package_name != package_distro_name: + for pn in self.package_name_version_gen( + package, + tmp_package_name, + version, + suffix="-devel" + suffix, + do_range_version_names=do_range_version_names): + yield pn + # Strip any 'version-like' numbers at the end of the package name (already stripped of '-devel' suffix) + # and generate versions variants out of it. + tmp_package_name = tmp_package_name.rstrip("0123456789.-") + if tmp_package_name != package_distro_name: + for pn in self.package_name_version_gen( + package, + tmp_package_name, + version, + suffix=suffix, + do_range_version_names=do_range_version_names): + yield pn + # Generate version variants from given package name. + versions = [version] + if do_range_version_names: + # Also search for major version numbers around the target one, within to allowed range. + # Necessary for packages like llvm e.g. + versions += [*self.versions_range_gen(package, set(versions))] + for v in versions: + yield package_distro_name + v + suffix + yield package_distro_name + "-" + v + suffix + + +class PackageInstallerSuse(PackageInstaller): + """Suse-like package installer, using zypper.""" + _instance = None + + def __new__(cls, settings): + if cls._instance is None: + cls._instance = super(PackageInstallerSuse, cls).__new__(cls, settings) + return cls._instance + + _re_version = re.compile(r"Version\s*:\s*(?:[0-9]+:)?(?P([0-9]+\.?)+([0-9]+)).*") + _re_installed = re.compile(r"Installed\s*:\s*Yes") + + _install_command = ["sudo", "zypper", "--non-interactive", "install"] + _update_command = ["sudo", "zypper", "refresh"] + + def package_version_get(self, command_result): + version = self._re_version.search(str(command_result.stdout)) + return version["version"] if version is not None else None + + def package_installed_version_get(self, package_distro_name): + result = self.run_command(["sudo", "zypper", "info", package_distro_name]) + is_installed = self._re_installed.search(str(result.stdout)) + return self.package_version_get(result) if is_installed is not None else None + + def package_query_version_get_impl(self, package_distro_name): + result = self.run_command(["sudo", "zypper", "info", package_distro_name]) + return self.package_version_get(result) + + def package_name_version_gen( + self, + package, + package_distro_name, + version=..., + suffix="", + do_range_version_names=False): + if version is ...: + version = package.version_short + # Generate versions variants with version between main name and '-devel' suffix, if any. + tmp_package_name = package_distro_name.removesuffix("-devel") + if tmp_package_name != package_distro_name: + for pn in self.package_name_version_gen( + package, + tmp_package_name, + version, + suffix="-devel" + suffix, + do_range_version_names=do_range_version_names): + yield pn + # Strip any 'version-like' numbers at the end of the package name (already stripped of '-devel' suffix) + # and generate versions variants out of it. + tmp_package_name = tmp_package_name.rstrip("0123456789.-") + if tmp_package_name != package_distro_name: + for pn in self.package_name_version_gen( + package, + tmp_package_name, + version, + suffix=suffix, + do_range_version_names=do_range_version_names): + yield pn + # Generate version variants from given package name. + versions = [version] + if do_range_version_names: + # Also search for major version numbers around the target one, within to allowed range. + # Necessary for packages like llvm e.g. + versions += [*self.versions_range_gen(package, set(versions))] + for v in versions: + yield package_distro_name + v + suffix + yield package_distro_name + "-" + v + suffix + + +class PackageInstallerArch(PackageInstaller): + """Arch-like package installer, using pacman.""" + _instance = None + + def __new__(cls, settings): + if cls._instance is None: + cls._instance = super(PackageInstallerArch, cls).__new__(cls, settings) + return cls._instance + + _re_version = re.compile(r"Version\s*:\s*(?:[0-9]+:)?(?P([0-9]+\.?)+([0-9]+)).*") + + _install_command = ["sudo", "pacman", "-S", "--needed", "--noconfirm"] + _update_command = ["sudo", "pacman", "-Sy"] + + def package_version_get(self, command): + result = self.run_command(command) + version = self._re_version.search(str(result.stdout)) + return version["version"] if version is not None else None + + def package_installed_version_get(self, package_distro_name): + return self.package_version_get(["pacman", "-Qi", package_distro_name]) + + def package_query_version_get_impl(self, package_distro_name): + return self.package_version_get(["pacman", "-Si", package_distro_name]) + + def package_name_version_gen( + self, + package, + package_distro_name, + version=..., + suffix="", + do_range_version_names=False): + if version is ...: + version = package.version_short + # Generate versions variants with version after the main name. + tmp_package_name = package_distro_name + # Strip any 'version-like' numbers at the end of the package name (already stripped of '-dev' suffix) + # and generate versions variants out of it. + tmp_package_name = tmp_package_name.rstrip("0123456789.-") + if tmp_package_name != package_distro_name: + for pn in self.package_name_version_gen( + package, + tmp_package_name, + version, + suffix=suffix, + do_range_version_names=do_range_version_names): + yield pn + # Generate version variants from given package name. + versions = [version] + if do_range_version_names: + # Also search for major version numbers around the target one, within to allowed range. + # Necessary for packages like llvm e.g. + versions += [*self.versions_range_gen(package, set(versions))] + for v in versions: + yield package_distro_name + v + suffix + yield package_distro_name + "-" + v + suffix + + +DISTRO_IDS_INSTALLERS = { + ...: PackageInstaller, + DISTRO_ID_DEBIAN: PackageInstallerDebian, + DISTRO_ID_FEDORA: PackageInstallerFedora, + DISTRO_ID_SUSE: PackageInstallerSuse, + DISTRO_ID_ARCH: PackageInstallerArch, +} + + +def get_distro(settings): + if settings.distro_id is not ...: + settings.logger.info(f"Distribution identifier forced by user to {settings.distro_id}.") + return settings.distro_id + import platform + if hasattr(platform, "freedesktop_os_release"): + info = platform.freedesktop_os_release() + ids = [info["ID"]] + if "ID_LIKE" in info: + # ids are space separated and ordered by precedence. + ids.extend(info["ID_LIKE"].split()) + for distro_id in ids: + if distro_id in DISTRO_IDS_INSTALLERS: + settings.distro_id = distro_id + return distro_id + settings.logger.warning(f"Distribution IDs do not match any supported one by this script ({ids})") + + settings.logger.warning("A valid distribution ID could not be found using `platform.freedesktop_os_release`, " + "now trying a lower-level check for specific files") + if os.path.exists("/etc/debian_version"): + distro_id = DISTRO_ID_DEBIAN + elif os.path.exists("/etc/redhat-release"): + distro_id = DISTRO_ID_FEDORA + elif os.path.exists("/etc/SuSE-release"): + distro_id = DISTRO_ID_SUSE + elif os.path.exists("/etc/arch-release"): + distro_id = DISTRO_ID_ARCH + if distro_id in DISTRO_IDS_INSTALLERS: + settings.distro_id = distro_id + return distro_id + + settings.distro_id = ... + return ... + + +def get_distro_package_installer(settings): + distro_id = get_distro(settings) + if distro_id is ...: + settings.logger.warning("No valid distribution ID found, please try to set it using the `--distro-id` option") + else: + settings.logger.info(f"Distribution identified as '{distro_id}'") + return DISTRO_IDS_INSTALLERS[distro_id](settings) + + +def argparse_create(): + import argparse + + # When --help or no args are given, print this help + usage_text = ( + "Attempt to install dependencies to build Blender from current linux distribution's packages only.\n" + "\n" + "By default, only installs critical tools and dependencies to build Blender, excluding any library provided\n" + "by the precompiled SVN repository.\n" + "`make update` should then be ran after this script to download all precompiled libraries.\n" + "\n" + "When ran with the `--all` option, this tool will try to install all mandatory and optional dependencies\n" + "from the distribution packages.\n" + "\n" + "NOTE: Many distributions do not provide packages for all libraries used by Blender, or have no\n" + "version-compatible packages. In some cases, mandatory dependencies cannot be satisfied, and Blender\n" + "won't be able to build at all.\n" + "\n" + "NOTE: To build with system package libraries instead of the precompiled ones when both are available,\n" + "the `WITH_LIBS_PRECOMPILED` option must be disabled in CMake.\n" + "\n" + "See https://wiki.blender.org/wiki/Building_Blender for more details.\n" + "\n" + ) + + parser = argparse.ArgumentParser(description=usage_text, formatter_class=argparse.RawDescriptionHelpFormatter) + + parser.add_argument( + "--show-deps", + dest="show_deps", + action='store_true', + help="Show main dependencies of Blender (including officially supported versions) and exit.", + ) + parser.add_argument( + "--no-sudo", + dest="no_sudo", + action='store_true', + help="Disable use of sudo (this script won't be able to do much then, will just print needed packages).", + ) + parser.add_argument( + "--all", + dest="all", + action='store_true', + help="Install all dependencies from the distribution packages, including these also provided as " + "precompiled libraries.", + ) + parser.add_argument( + "--distro-id", + dest="distro_id", + default=..., + choices=set(DISTRO_IDS_INSTALLERS.keys()) - set((...,)), + help="Force the linux distribution identifier to a specific value instead of relying on automatic detection.", + ) + parser.add_argument( + "--debug", + dest="debug", + action='store_true', + help="Enable all debug info messages.", + ) + + return parser + + +def main(): + settings = argparse_create().parse_args() + + logger = logging.getLogger(__name__) + logger.setLevel(logging.DEBUG if settings.debug else logging.INFO) + stdout_handler = logging.StreamHandler(stream=sys.stdout) + stdout_handler.setFormatter(LoggingColoredFormatter()) + logger.addHandler(stdout_handler) + settings.logger = logger + + distro_package_installer = (PackageInstaller(settings) if settings.show_deps + else get_distro_package_installer(settings)) + distro_package_installer.packages_database_update() + + if settings.all: + distro_package_installer.packages_install(PACKAGES_ALL) + else: + distro_package_installer.packages_install(PACKAGES_BASICS_BUILD) + + +if __name__ == "__main__": + main() diff --git a/blender-build/build_environment/linux/linux_rocky8_setup.sh b/blender-build/build_environment/linux/linux_rocky8_setup.sh new file mode 100644 index 0000000..993d4fe --- /dev/null +++ b/blender-build/build_environment/linux/linux_rocky8_setup.sh @@ -0,0 +1,135 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0-or-later + +# This script is part of the official build environment, see wiki page for details. +# https://wiki.blender.org/wiki/Building_Blender/Other/Rocky8ReleaseEnvironment + +set -e + +if [ `id -u` -ne 0 ]; then + echo "This script must be run as root" + exit 1 +fi + +# Required by: config manager command below to enable powertools. +dnf install 'dnf-command(config-manager)' + +# Packages `ninja-build` and `meson` are not available unless CBR or PowerTools repositories are enabled. +# See: https://wiki.rockylinux.org/rocky/repo/#notes-on-unlisted-repositories +dnf config-manager --set-enabled powertools + +# Required by: epel-release has the patchelf and rubygem-asciidoctor packages +dnf install epel-release + +# `yum-config-manager` does not come in the default minimal install, +# so make sure it is installed and available. +yum -y update +yum -y install yum-utils + +# Install all the packages needed for a new tool-chain. +# +# NOTE: Keep this separate from the packages install, since otherwise +# older tool-chain will be installed. +yum -y update +yum -y install scl-utils +yum -y install scl-utils-build + +# Currently this is defined by the VFX platform (CY2023), see: https://vfxplatform.com +yum -y install gcc-toolset-11 + +# Install packages needed for Blender's dependencies. +PACKAGES_FOR_LIBS=( + # Used to checkout Blender's code. + git + git-lfs + # Used to checkout Blender's `../lib/` directory. + subversion + # Used to extract packages. + bzip2 + # Used to extract packages. + tar + # Blender and some dependencies use `cmake`. + cmake3 + # Apply patches from Blender's: `./build_files/build_environment/patches` + patch + # Use by `cmake` and `autoconf`. + make + + # Required by: `external_nasm` which uses an `autoconf` build-system. + autoconf + automake + libtool + + # Used to set rpath on shared libraries + patchelf + + # Builds generated by meson use Ninja for the actual build. + ninja-build + + # Required by Blender build option: `WITH_GHOST_WAYLAND`. + mesa-libEGL-devel + # Required by: Blender & `external_opensubdiv` (probably others). + mesa-libGL-devel + mesa-libGLU-devel + + # Required by: `external_ispc`. + zlib-devel + # TODO: dependencies build without this, consider removal. + rubygem-asciidoctor + # TODO: dependencies build without this, consider removal. + wget + # Required by: `external_sqlite` as a build-time dependency (needed for the `tclsh` command). + tcl + # Required by: `external_aom`. + # TODO: Blender is already building `external_nasm` which is listed as an alternative to `yasm`. + # Why are both needed? + yasm + + # NOTE(@campbellbarton): while `python39` is available, the default Python version is 3.6. + # This is used for the `python3-mako` package for e.g. + # So use the "default" system Python since it means it's most compatible with other packages. + python3 + # Required by: `external_mesa`. + python3-mako + + # Required by: `external_mesa`. + expat-devel + + # Required by: `external_igc` & `external_osl` as a build-time dependency. + bison + # Required by: `external_osl` as a build-time dependency. + flex + + # Required by: `external_ispc`. + ncurses-devel + # Required by: `external_ispc` (when building with CLANG). + libstdc++-static + + # Required by: `external_ssl` (build dependencies). + perl-IPC-Cmd + perl-Pod-Html +) + +# Additional packages needed for building Blender. +PACKAGES_FOR_BLENDER=( + # Required by Blender build option: `WITH_GHOST_WAYLAND`. + libxkbcommon-devel + + # Required by Blender build option: `WITH_GHOST_X11`. + libX11-devel + libXcursor-devel + libXi-devel + libXinerama-devel + libXrandr-devel + libXt-devel + libXxf86vm-devel +) + +yum -y install -y ${PACKAGES_FOR_LIBS[@]} ${PACKAGES_FOR_BLENDER[@]} + +# Dependencies for pip (needed for `buildbot-worker`), uses Python3.6. +yum -y install python3 python3-pip python3-devel + +# Dependencies for asound. +yum -y install -y \ + alsa-lib-devel pulseaudio-libs-devel diff --git a/blender-build/build_environment/linux/make_deps_wrapper.sh b/blender-build/build_environment/linux/make_deps_wrapper.sh new file mode 100755 index 0000000..2e2d00a --- /dev/null +++ b/blender-build/build_environment/linux/make_deps_wrapper.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0-or-later + +# This script ensures: +# - One dependency is built at a time. +# - That dependency uses all available cores. +# +# Without this, simply calling `make -j$(nproc)` from the `${CMAKE_BUILD_DIR}/deps/` +# directory will build many projects at once. +# +# This is undesirable for the following reasons: +# +# - The output from projects is mixed together, +# making it difficult to track down the cause of a build failure. +# +# - Larger dependencies such as LLVM can bottleneck the build process, +# making it necessary to cancel the build and manually run build commands in each directory. +# +# - Building many projects at once means canceling (Control-C) can lead to the build being in an undefined state. +# It's possible canceling happens as a patch is being applied or files are being copied. +# (steps that aren't part of the compilation process where it's typically safe to cancel). + +if [[ -z "$MY_MAKE_CALL_LEVEL" ]]; then + export MY_MAKE_CALL_LEVEL=0 + export MY_MAKEFLAGS=$MAKEFLAGS + + # Extract the jobs argument (`-jN`, `-j N`, `--jobs=N`). + add_next=0 + for i in "$@"; do + case $i in + -j*) + export MY_JOBS_ARG=$i + if [ "$MY_JOBS_ARG" = "-j" ]; then + add_next=1 + fi + ;; + --jobs=*) + shift # past argument=value + MY_JOBS_ARG=$i + ;; + *) + if (( add_next == 1 )); then + MY_JOBS_ARG="$MY_JOBS_ARG $i" + add_next=0 + fi + ;; + esac + done + unset i add_next + + if [[ -z "$MY_JOBS_ARG" ]]; then + MY_JOBS_ARG="-j$(nproc)" + fi + export MY_JOBS_ARG + # Support user defined `MAKEFLAGS`. + export MAKEFLAGS="$MY_MAKEFLAGS -j1" +else + export MY_MAKE_CALL_LEVEL=$(( MY_MAKE_CALL_LEVEL + 1 )) + if (( MY_MAKE_CALL_LEVEL == 1 )); then + # Important to set jobs to 1, otherwise user defined jobs argument is used. + export MAKEFLAGS="$MY_MAKEFLAGS -j1" + elif (( MY_MAKE_CALL_LEVEL == 2 )); then + # This is the level used by each sub-project. + export MAKEFLAGS="$MY_MAKEFLAGS $MY_JOBS_ARG" + fi + # Else leave `MY_MAKEFLAGS` flags as-is, avoids setting a high number of jobs on recursive + # calls (which may easily run out of memory). Let the job-server handle the rest. +fi + +# Useful for troubleshooting the wrapper. +# echo "Call level: $MY_MAKE_CALL_LEVEL, args=$@". + +# Call actual make but ensure recursive calls run via this script. +exec make MAKE="$0" "$@" diff --git a/blender-build/build_environment/patches/.gitattributes b/blender-build/build_environment/patches/.gitattributes new file mode 100644 index 0000000..beb2d80 --- /dev/null +++ b/blender-build/build_environment/patches/.gitattributes @@ -0,0 +1,2 @@ +# Files contains mixed line endings, patch needs to preserve them to apply. +opencollada.diff binary diff --git a/blender-build/build_environment/patches/aom.diff b/blender-build/build_environment/patches/aom.diff new file mode 100644 index 0000000..1611cff --- /dev/null +++ b/blender-build/build_environment/patches/aom.diff @@ -0,0 +1,18 @@ +diff -Naur libaom-3.4.0/build/cmake/aom_configure.cmake external_aom/build/cmake/aom_configure.cmake +--- libaom-3.4.0/build/cmake/aom_configure.cmake 2022-06-17 11:46:18 -0600 ++++ external_aom/build/cmake/aom_configure.cmake 2022-10-16 15:35:54 -0600 +@@ -15,8 +15,12 @@ + + include(FindGit) + include(FindPerl) +-include(FindThreads) +- ++# Blender: This will drag in a dep on libwinpthreads which we prefer ++# not to have, aom will fallback on a native win32 thread wrapper ++# if pthreads are not found. ++if(NOT WIN32) ++ include(FindThreads) ++endif() + include("${AOM_ROOT}/build/cmake/aom_config_defaults.cmake") + include("${AOM_ROOT}/build/cmake/aom_experiment_deps.cmake") + include("${AOM_ROOT}/build/cmake/aom_optimization.cmake") diff --git a/blender-build/build_environment/patches/blosc.diff b/blender-build/build_environment/patches/blosc.diff new file mode 100644 index 0000000..0080694 --- /dev/null +++ b/blender-build/build_environment/patches/blosc.diff @@ -0,0 +1,131 @@ +diff -Naur src/blosc/CMakeLists.txt external_blosc/blosc/CMakeLists.txt +--- src/blosc/CMakeLists.txt 2016-02-03 10:26:28 -0700 ++++ external_blosc/blosc/CMakeLists.txt 2017-03-03 09:03:31 -0700 +@@ -61,6 +61,8 @@ + set(SOURCES ${SOURCES} win32/pthread.c) + else(NOT Threads_FOUND) + set(LIBS ${LIBS} ${CMAKE_THREAD_LIBS_INIT}) ++ set(LIBS ${LIBS} ${PTHREAD_LIBS}) ++ include_directories( ${PTHREAD_INCLUDE_DIR} ) + endif(NOT Threads_FOUND) + else(WIN32) + find_package(Threads REQUIRED) +diff -Naur src/CMakeLists.txt external_blosc/CMakeLists.txt +--- src/CMakeLists.txt 2016-02-03 10:26:28 -0700 ++++ external_blosc/CMakeLists.txt 2017-03-03 09:03:31 -0700 +@@ -17,8 +17,8 @@ + # do not include support for the Snappy library + # DEACTIVATE_ZLIB: default OFF + # do not include support for the Zlib library +-# PREFER_EXTERNAL_COMPLIBS: default ON +-# when found, use the installed compression libs instead of included sources ++# PREFER_EXTERNAL_ZLIB: default ON ++# when found, use the installed zlib instead of included sources + # TEST_INCLUDE_BENCH_SINGLE_1: default ON + # add a test that runs the benchmark program passing "single" with 1 thread + # as first parameter +@@ -80,29 +80,23 @@ + "Do not include support for the SNAPPY library." OFF) + option(DEACTIVATE_ZLIB + "Do not include support for the ZLIB library." OFF) +-option(PREFER_EXTERNAL_COMPLIBS +- "When found, use the installed compression libs instead of included sources." ON) ++option(PREFER_EXTERNAL_ZLIB ++ "When found, use the installed zlib instead of included sources." ON) + + set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") + +-if(NOT PREFER_EXTERNAL_COMPLIBS) ++if(NOT PREFER_EXTERNAL_ZLIB) + message(STATUS "Finding external libraries disabled. Using internal sources.") +-endif(NOT PREFER_EXTERNAL_COMPLIBS) ++endif(NOT PREFER_EXTERNAL_ZLIB) + + + if(NOT DEACTIVATE_LZ4) +- if(PREFER_EXTERNAL_COMPLIBS) +- find_package(LZ4) +- endif(PREFER_EXTERNAL_COMPLIBS) + # HAVE_LZ4 will be set to true because even if the library is + # not found, we will use the included sources for it + set(HAVE_LZ4 TRUE) + endif(NOT DEACTIVATE_LZ4) + + if(NOT DEACTIVATE_SNAPPY) +- if(PREFER_EXTERNAL_COMPLIBS) +- find_package(Snappy) +- endif(PREFER_EXTERNAL_COMPLIBS) + # HAVE_SNAPPY will be set to true because even if the library is not found, + # we will use the included sources for it + set(HAVE_SNAPPY TRUE) +@@ -110,13 +104,13 @@ + + if(NOT DEACTIVATE_ZLIB) + # import the ZLIB_ROOT environment variable to help finding the zlib library +- if(PREFER_EXTERNAL_COMPLIBS) ++ if(PREFER_EXTERNAL_ZLIB) + set(ZLIB_ROOT $ENV{ZLIB_ROOT}) + find_package( ZLIB ) + if (NOT ZLIB_FOUND ) + message(STATUS "No zlib found. Using internal sources.") + endif (NOT ZLIB_FOUND ) +- endif(PREFER_EXTERNAL_COMPLIBS) ++ endif(PREFER_EXTERNAL_ZLIB) + # HAVE_ZLIB will be set to true because even if the library is not found, + # we will use the included sources for it + set(HAVE_ZLIB TRUE) +diff -Naur external_blosc.orig/blosc/blosc.c external_blosc/blosc/blosc.c +--- external_blosc.orig/blosc/blosc.c 2018-07-30 04:56:38 -0600 ++++ external_blosc/blosc/blosc.c 2018-08-11 15:27:26 -0600 +@@ -41,12 +41,7 @@ + #include + #endif /* _WIN32 */ + +-#if defined(_WIN32) +- #include "win32/pthread.h" +- #include "win32/pthread.c" +-#else +- #include +-#endif ++#include + + + /* Some useful units */ + diff --git a/blosc/shuffle.c b/blosc/shuffle.c + index 84b5095..23053b4 100644 + --- a/blosc/shuffle.c + +++ b/blosc/shuffle.c + @@ -490,12 +490,12 @@ void unshuffle(size_t bytesoftype, size_t blocksize, + #else /* no __SSE2__ available */ + + void shuffle(size_t bytesoftype, size_t blocksize, + - uint8_t* _src, uint8_t* _dest) { + + const uint8_t* _src, uint8_t* _dest) { + _shuffle(bytesoftype, blocksize, _src, _dest); + } + + void unshuffle(size_t bytesoftype, size_t blocksize, + - uint8_t* _src, uint8_t* _dest) { + + const uint8_t* _src, uint8_t* _dest) { + _unshuffle(bytesoftype, blocksize, _src, _dest); + } + --- a/cmake/FindSSE.cmake + +++ b/cmake/FindSSE.cmake + @@ -49,6 +49,17 @@ + set(AVX_FOUND false CACHE BOOL "AVX available on host") + ENDIF (AVX_TRUE) + ELSEIF(CMAKE_SYSTEM_NAME MATCHES "Darwin") + + execute_process(COMMAND uname -m OUTPUT_VARIABLE ARCHITECTURE OUTPUT_STRIP_TRAILING_WHITESPACE) + + message(STATUS "Detected architecture ${ARCHITECTURE}") + + IF("${ARCHITECTURE}" STREQUAL "arm64") + + set(SSE2_FOUND false CACHE BOOL "SSE2 available on host") + + set(SSE3_FOUND false CACHE BOOL "SSE3 available on host") + + set(SSSE3_FOUND false CACHE BOOL "SSSE3 available on host") + + set(SSE4_1_FOUND false CACHE BOOL "SSE4.1 available on host") + + set(AVX_FOUND false CACHE BOOL "AVX available on host") + + return() + + ENDIF() + + + EXEC_PROGRAM("/usr/sbin/sysctl -n machdep.cpu.features" OUTPUT_VARIABLE + CPUINFO) + \ No newline at end of file diff --git a/blender-build/build_environment/patches/boost.diff b/blender-build/build_environment/patches/boost.diff new file mode 100644 index 0000000..b415865 --- /dev/null +++ b/blender-build/build_environment/patches/boost.diff @@ -0,0 +1,28 @@ +--- a/boost/python//detail/wrap_python.hpp 2022-12-09 19:16:17 ++++ b/boost/python//detail/wrap_python.hpp 2022-12-09 19:18:08 +@@ -206,7 +206,8 @@ + + #ifdef DEBUG_UNDEFINED_FROM_WRAP_PYTHON_H + # undef DEBUG_UNDEFINED_FROM_WRAP_PYTHON_H +-# define _DEBUG ++// BLENDER: TBB expects this to have a value. ++# define _DEBUG 1 + # ifdef _CRT_NOFORCE_MANIFEST_DEFINED_FROM_WRAP_PYTHON_H + # undef _CRT_NOFORCE_MANIFEST_DEFINED_FROM_WRAP_PYTHON_H + # undef _CRT_NOFORCE_MANIFEST +--- a/boost/config/stdlib/libcpp.hpp 2022-08-03 22:47:07.000000000 -0400 ++++ b/boost/config/stdlib/libcpp.hpp 2022-09-16 22:16:17.044119011 -0400 +@@ -168,4 +168,13 @@ + # define BOOST_NO_CXX14_HDR_SHARED_MUTEX + #endif + ++#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION >= 15000 ++// ++// Unary function is now deprecated in C++11 and later: ++// ++#if __cplusplus >= 201103L ++#define BOOST_NO_CXX98_FUNCTION_BASE ++#endif ++#endif ++ + // --- end --- diff --git a/blender-build/build_environment/patches/boost.user.jam.in b/blender-build/build_environment/patches/boost.user.jam.in new file mode 100644 index 0000000..b20a90d --- /dev/null +++ b/blender-build/build_environment/patches/boost.user.jam.in @@ -0,0 +1,4 @@ +using python : @PYTHON_SHORT_VERSION@ : @PYTHON_BINARY@ + : @LIBDIR@/python/include @LIBDIR@/python/include/python@PYTHON_SHORT_VERSION@/ + : @LIBDIR@/python/libs +; \ No newline at end of file diff --git a/blender-build/build_environment/patches/cmake/modules/FindBlosc.cmake b/blender-build/build_environment/patches/cmake/modules/FindBlosc.cmake new file mode 100644 index 0000000..8c4e65c --- /dev/null +++ b/blender-build/build_environment/patches/cmake/modules/FindBlosc.cmake @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2016 Blender Foundation. + +# - Find BLOSC library +# Find the native BLOSC includes and library +# This module defines +# BLOSC_INCLUDE_DIRS, where to find blosc.h, Set when +# BLOSC is found. +# BLOSC_LIBRARIES, libraries to link against to use BLOSC. +# BLOSC_ROOT_DIR, The base directory to search for BLOSC. +# This can also be an environment variable. +# BLOSC_FOUND, If false, do not try to use BLOSC. +# +# also defined, but not for general use are +# BLOSC_LIBRARY, where to find the BLOSC library. + +# If BLOSC_ROOT_DIR was defined in the environment, use it. +IF(NOT BLOSC_ROOT_DIR AND NOT $ENV{BLOSC_ROOT_DIR} STREQUAL "") + SET(BLOSC_ROOT_DIR $ENV{BLOSC_ROOT_DIR}) +ENDIF() + +SET(_blosc_SEARCH_DIRS + ${BLOSC_ROOT_DIR} + /opt/lib/blosc +) + +FIND_PATH(BLOSC_INCLUDE_DIR + NAMES + blosc.h + HINTS + ${_blosc_SEARCH_DIRS} + PATH_SUFFIXES + include +) + +FIND_LIBRARY(BLOSC_LIBRARY + NAMES + blosc + HINTS + ${_blosc_SEARCH_DIRS} + PATH_SUFFIXES + lib64 lib +) + +# handle the QUIETLY and REQUIRED arguments and set BLOSC_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(BLOSC DEFAULT_MSG + BLOSC_LIBRARY BLOSC_INCLUDE_DIR) + +IF(BLOSC_FOUND) + SET(BLOSC_LIBRARIES ${BLOSC_LIBRARY}) + SET(BLOSC_INCLUDE_DIRS ${BLOSC_INCLUDE_DIR}) +ELSE() + SET(BLOSC_FOUND FALSE) +ENDIF() + +MARK_AS_ADVANCED( + BLOSC_INCLUDE_DIR + BLOSC_LIBRARY +) diff --git a/blender-build/build_environment/patches/cmake/modules/FindCppUnit.cmake b/blender-build/build_environment/patches/cmake/modules/FindCppUnit.cmake new file mode 100644 index 0000000..a27e071 --- /dev/null +++ b/blender-build/build_environment/patches/cmake/modules/FindCppUnit.cmake @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2016 Blender Foundation. + +# - Find CPPUNIT library +# Find the native CPPUNIT includes and library +# This module defines +# CPPUNIT_INCLUDE_DIRS, where to find cppunit.h, Set when +# CPPUNIT is found. +# CPPUNIT_LIBRARIES, libraries to link against to use CPPUNIT. +# CPPUNIT_ROOT_DIR, The base directory to search for CPPUNIT. +# This can also be an environment variable. +# CPPUNIT_FOUND, If false, do not try to use CPPUNIT. +# +# also defined, but not for general use are +# CPPUNIT_LIBRARY, where to find the CPPUNIT library. + +# If CPPUNIT_ROOT_DIR was defined in the environment, use it. +IF(NOT CPPUNIT_ROOT_DIR AND NOT $ENV{CPPUNIT_ROOT_DIR} STREQUAL "") + SET(CPPUNIT_ROOT_DIR $ENV{CPPUNIT_ROOT_DIR}) +ENDIF() + +SET(_cppunit_SEARCH_DIRS + ${CPPUNIT_ROOT_DIR} + /opt/lib/cppunit +) + +FIND_PATH(CPPUNIT_INCLUDE_DIR + NAMES + cppunit/Test.h + HINTS + ${_cppunit_SEARCH_DIRS} + PATH_SUFFIXES + include +) + +FIND_LIBRARY(CPPUNIT_LIBRARY + NAMES + cppunit + HINTS + ${_cppunit_SEARCH_DIRS} + PATH_SUFFIXES + lib64 lib +) + +# handle the QUIETLY and REQUIRED arguments and set CPPUNIT_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(CPPUNIT DEFAULT_MSG + CPPUNIT_LIBRARY CPPUNIT_INCLUDE_DIR) + +IF(CPPUNIT_FOUND) + SET(CPPUNIT_LIBRARIES ${CPPUNIT_LIBRARY}) + SET(CPPUNIT_INCLUDE_DIRS ${CPPUNIT_INCLUDE_DIR}) +ELSE() + SET(CPPUNIT_FOUND FALSE) +ENDIF() + +MARK_AS_ADVANCED( + CPPUNIT_INCLUDE_DIR + CPPUNIT_LIBRARY +) diff --git a/blender-build/build_environment/patches/cmake/modules/FindIlmBase.cmake b/blender-build/build_environment/patches/cmake/modules/FindIlmBase.cmake new file mode 100644 index 0000000..4e86d4a --- /dev/null +++ b/blender-build/build_environment/patches/cmake/modules/FindIlmBase.cmake @@ -0,0 +1,270 @@ +# SPDX-License-Identifier: BSD-3-Clause + +# Module to find IlmBase +# +# This module will first look into the directories defined by the variables: +# - ILMBASE_HOME, ILMBASE_VERSION, ILMBASE_LIB_AREA +# +# It also supports non-standard names for the library components. +# +# To use a custom IlmBase: +# - Set the variable ILMBASE_CUSTOM to TRUE +# - Set the variable ILMBASE_CUSTOM_LIBRARIES to a list of the libraries to +# use, e.g. "SpiImath SpiHalf SpiIlmThread SpiIex" +# - Optionally set the variable ILMBASE_CUSTOM_INCLUDE_DIR to any +# particularly weird place that the OpenEXR/*.h files may be found +# - Optionally set the variable ILMBASE_CUSTOM_LIB_DIR to any +# particularly weird place that the libraries files may be found +# +# This module defines the following variables: +# +# ILMBASE_INCLUDE_DIR - where to find half.h, IlmBaseConfig.h, etc. +# ILMBASE_LIBRARIES - list of libraries to link against when using IlmBase. +# ILMBASE_FOUND - TRUE if IlmBase was found. + +# Other standard issue macros +include(FindPackageHandleStandardArgs) +include(FindPackageMessage) +include(SelectLibraryConfigurations) + + +if(ILMBASE_USE_STATIC_LIBS) + set(_ilmbase_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) + if(WIN32) + set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) + else() + set(CMAKE_FIND_LIBRARY_SUFFIXES .a ) + endif() +endif() + +# Macro to assemble a helper state variable +macro(SET_STATE_VAR varname) + set(tmp_ilmbaselibs ${ILMBASE_CUSTOM_LIBRARIES}) + separate_arguments(tmp_ilmbaselibs) + set(tmp_lst + ${ILMBASE_CUSTOM} | ${tmp_ilmbaselibs} | + ${ILMBASE_HOME} | ${ILMBASE_VERSION} | ${ILMBASE_LIB_AREA} + ) + set(${varname} "${tmp_lst}") + unset(tmp_ilmbaselibs) + unset(tmp_lst) +endmacro() + +# To enforce that find_* functions do not use inadvertently existing versions +if(ILMBASE_CUSTOM) + set(ILMBASE_FIND_OPTIONS "NO_DEFAULT_PATH") +endif() + +# Macro to search for an include directory +macro(PREFIX_FIND_INCLUDE_DIR prefix includefile libpath_var) + string(TOUPPER ${prefix}_INCLUDE_DIR tmp_varname) + find_path(${tmp_varname} ${includefile} + HINTS ${${libpath_var}} + PATH_SUFFIXES include + ${ILMBASE_FIND_OPTIONS} + ) + if(${tmp_varname}) + mark_as_advanced(${tmp_varname}) + endif() + unset(tmp_varname) +endmacro() + + +# Macro to search for the given library and adds the cached +# variable names to the specified list +macro(PREFIX_FIND_LIB prefix libname libpath_var liblist_var cachelist_var) + string(TOUPPER ${prefix}_${libname} tmp_prefix) + # Handle new library names for OpenEXR 2.1 build via cmake + string(REPLACE "." "_" _ILMBASE_VERSION ${ILMBASE_VERSION}) + string(SUBSTRING ${_ILMBASE_VERSION} 0 3 _ILMBASE_VERSION ) + + find_library(${tmp_prefix}_LIBRARY_RELEASE + NAMES ${libname} ${libname}-${_ILMBASE_VERSION} + HINTS ${${libpath_var}} + PATH_SUFFIXES lib + ${ILMBASE_FIND_OPTIONS} + ) + find_library(${tmp_prefix}_LIBRARY_DEBUG + NAMES ${libname}d ${libname}_d ${libname}debug ${libname}_debug + HINTS ${${libpath_var}} + PATH_SUFFIXES lib + ${ILMBASE_FIND_OPTIONS} + ) + # Properly define ${tmp_prefix}_LIBRARY (cached) and ${tmp_prefix}_LIBRARIES + select_library_configurations(${tmp_prefix}) + list(APPEND ${liblist_var} ${tmp_prefix}_LIBRARIES) + + # Add to the list of variables which should be reset + list(APPEND ${cachelist_var} + ${tmp_prefix}_LIBRARY + ${tmp_prefix}_LIBRARY_RELEASE + ${tmp_prefix}_LIBRARY_DEBUG) + mark_as_advanced( + ${tmp_prefix}_LIBRARY + ${tmp_prefix}_LIBRARY_RELEASE + ${tmp_prefix}_LIBRARY_DEBUG) + unset(tmp_prefix) +endmacro() + + +# Encode the current state of the external variables into a string +SET_STATE_VAR(ILMBASE_CURRENT_STATE) + +# If the state has changed, clear the cached variables +if(ILMBASE_CACHED_STATE AND + NOT ILMBASE_CACHED_STATE STREQUAL ILMBASE_CURRENT_STATE) + + foreach(libvar ${ILMBASE_CACHED_VARS}) + unset(${libvar} CACHE) + endforeach() +endif() + + +# Generic search paths +set(IlmBase_generic_include_paths + ${ILMBASE_CUSTOM_INCLUDE_DIR} + /usr/include + /usr/include/${CMAKE_LIBRARY_ARCHITECTURE} + /usr/local/include + /opt/local/include +) +set(IlmBase_generic_library_paths + ${ILMBASE_CUSTOM_LIB_DIR} + /usr/lib + /usr/lib/${CMAKE_LIBRARY_ARCHITECTURE} + /usr/local/lib + /usr/local/lib/${CMAKE_LIBRARY_ARCHITECTURE} + /opt/local/lib +) + +# Search paths for the IlmBase files +if(ILMBASE_HOME) + if(ILMBASE_VERSION) + set(IlmBase_include_paths + ${ILMBASE_HOME}/ilmbase-${ILMBASE_VERSION}/include + ${ILMBASE_HOME}/include/ilmbase-${ILMBASE_VERSION} + ) + set(IlmBase_library_paths + ${ILMBASE_HOME}/ilmbase-${ILMBASE_VERSION}/lib + ${ILMBASE_HOME}/lib/ilmbase-${ILMBASE_VERSION} + ) + endif() + list(APPEND IlmBase_include_paths ${ILMBASE_HOME}/include) + set(IlmBase_library_paths + ${ILMBASE_HOME}/lib + ${ILMBASE_HOME}/lib64 + ${ILMBASE_LIB_AREA} + ${IlmBase_library_paths}) +endif() +list(APPEND IlmBase_include_paths ${IlmBase_generic_include_paths}) +list(APPEND IlmBase_library_paths ${IlmBase_generic_library_paths}) + +# Locate the header files +PREFIX_FIND_INCLUDE_DIR(IlmBase + OpenEXR/IlmBaseConfig.h IlmBase_include_paths) + +if(ILMBASE_INCLUDE_DIR) + # Get the version from config file, if not already set. + if(NOT ILMBASE_VERSION) + FILE(STRINGS "${ILMBASE_INCLUDE_DIR}/OpenEXR/IlmBaseConfig.h" ILMBASE_BUILD_SPECIFICATION + REGEX "^[ \t]*#define[ \t]+ILMBASE_VERSION_STRING[ \t]+\"[.0-9]+\".*$") + + if(ILMBASE_BUILD_SPECIFICATION) + if(NOT IlmBase_FIND_QUIETLY) + message(STATUS "${ILMBASE_BUILD_SPECIFICATION}") + endif() + string(REGEX REPLACE ".*#define[ \t]+ILMBASE_VERSION_STRING[ \t]+\"([.0-9]+)\".*" + "\\1" XYZ ${ILMBASE_BUILD_SPECIFICATION}) + set("ILMBASE_VERSION" ${XYZ} CACHE STRING "Version of ILMBase lib") + else() + # Old versions (before 2.0?) do not have any version string, + # just assuming 2.0 should be fine though. + message(WARNING "Could not determine ILMBase library version, assuming 2.0.") + set("ILMBASE_VERSION" "2.0" CACHE STRING "Version of ILMBase lib") + endif() + endif() +endif() + + +if(ILMBASE_CUSTOM) + if(NOT ILMBASE_CUSTOM_LIBRARIES) + message(FATAL_ERROR "Custom IlmBase libraries requested but ILMBASE_CUSTOM_LIBRARIES is not set.") + endif() + set(IlmBase_Libraries ${ILMBASE_CUSTOM_LIBRARIES}) + separate_arguments(IlmBase_Libraries) +else() +# elseif(${ILMBASE_VERSION} VERSION_LESS "2.1") + set(IlmBase_Libraries Half Iex Imath IlmThread) +# else() + # string(REGEX REPLACE "([0-9]+)[.]([0-9]+).*" "\\1_\\2" _ilmbase_libs_ver ${ILMBASE_VERSION}) + # set(IlmBase_Libraries + # Half + # Iex-${_ilmbase_libs_ver} + # Imath-${_ilmbase_libs_ver} + # IlmThread-${_ilmbase_libs_ver} + # ) +endif() + + +# Locate the IlmBase libraries +set(IlmBase_libvars "") +set(IlmBase_cachevars "") +foreach(ilmbase_lib ${IlmBase_Libraries}) + PREFIX_FIND_LIB(IlmBase ${ilmbase_lib} + IlmBase_library_paths IlmBase_libvars IlmBase_cachevars) +endforeach() +# Create the list of variables that might need to be cleared +set(ILMBASE_CACHED_VARS + ILMBASE_INCLUDE_DIR ${IlmBase_cachevars} + CACHE INTERNAL "Variables set by FindIlmBase.cmake" FORCE) + +# Store the current state so that variables might be cleared if required +set(ILMBASE_CACHED_STATE ${ILMBASE_CURRENT_STATE} + CACHE INTERNAL "State last seen by FindIlmBase.cmake" FORCE) + +# Link with pthreads if required +if(NOT WIN32 AND EXISTS ${ILMBASE_INCLUDE_DIR}/OpenEXR/IlmBaseConfig.h) + file(STRINGS ${ILMBASE_INCLUDE_DIR}/OpenEXR/IlmBaseConfig.h + ILMBASE_HAVE_PTHREAD + REGEX "^[ \\t]*#define[ \\t]+HAVE_PTHREAD[ \\t]1[ \\t]*\$" + ) + if(ILMBASE_HAVE_PTHREAD) + find_package(Threads) + if(CMAKE_USE_PTHREADS_INIT) + set(ILMBASE_PTHREADS ${CMAKE_THREAD_LIBS_INIT}) + endif() + endif() +endif() + +# Use the standard function to handle ILMBASE_FOUND +FIND_PACKAGE_HANDLE_STANDARD_ARGS(IlmBase DEFAULT_MSG + ILMBASE_INCLUDE_DIR ${IlmBase_libvars}) + +if(ILMBASE_FOUND) + set(ILMBASE_LIBRARIES "") + foreach(tmplib ${IlmBase_libvars}) + list(APPEND ILMBASE_LIBRARIES ${${tmplib}}) + endforeach() + list(APPEND ILMBASE_LIBRARIES ${ILMBASE_PTHREADS}) + if(NOT IlmBase_FIND_QUIETLY) + FIND_PACKAGE_MESSAGE(ILMBASE + "Found IlmBase: ${ILMBASE_LIBRARIES}" + "[${ILMBASE_INCLUDE_DIR}][${ILMBASE_LIBRARIES}][${ILMBASE_CURRENT_STATE}]" + ) + endif() +endif() + +# Restore the original find library ordering +if(ILMBASE_USE_STATIC_LIBS ) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${_ilmbase_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) +endif() + +# Unset the helper variables to avoid pollution +unset(ILMBASE_CURRENT_STATE) +unset(IlmBase_include_paths) +unset(IlmBase_library_paths) +unset(IlmBase_generic_include_paths) +unset(IlmBase_generic_library_paths) +unset(IlmBase_libvars) +unset(IlmBase_cachevars) +unset(ILMBASE_PTHREADS) diff --git a/blender-build/build_environment/patches/cmake/modules/FindLogC4Plus.cmake b/blender-build/build_environment/patches/cmake/modules/FindLogC4Plus.cmake new file mode 100644 index 0000000..fe08c74 --- /dev/null +++ b/blender-build/build_environment/patches/cmake/modules/FindLogC4Plus.cmake @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2016 Blender Foundation. + +# - Find LOGC4PLUS library +# Find the native LOGC4PLUS includes and library +# This module defines +# LOGC4PLUS_INCLUDE_DIRS, where to find logc4plus.h, Set when +# LOGC4PLUS is found. +# LOGC4PLUS_LIBRARIES, libraries to link against to use LOGC4PLUS. +# LOGC4PLUS_ROOT_DIR, The base directory to search for LOGC4PLUS. +# This can also be an environment variable. +# LOGC4PLUS_FOUND, If false, do not try to use LOGC4PLUS. +# +# also defined, but not for general use are +# LOGC4PLUS_LIBRARY, where to find the LOGC4PLUS library. + +# If LOGC4PLUS_ROOT_DIR was defined in the environment, use it. +IF(NOT LOGC4PLUS_ROOT_DIR AND NOT $ENV{LOGC4PLUS_ROOT_DIR} STREQUAL "") + SET(LOGC4PLUS_ROOT_DIR $ENV{LOGC4PLUS_ROOT_DIR}) +ENDIF() + +SET(_logc4plus_SEARCH_DIRS + ${LOGC4PLUS_ROOT_DIR} + /opt/lib/logc4plus +) + +FIND_PATH(LOGC4PLUS_INCLUDE_DIR + NAMES + logc4plus.h + HINTS + ${_logc4plus_SEARCH_DIRS} + PATH_SUFFIXES + include +) + +FIND_LIBRARY(LOGC4PLUS_LIBRARY + NAMES + logc4plus + HINTS + ${_logc4plus_SEARCH_DIRS} + PATH_SUFFIXES + lib64 lib + ) + +# handle the QUIETLY and REQUIRED arguments and set LOGC4PLUS_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(LOGC4PLUS DEFAULT_MSG + LOGC4PLUS_LIBRARY LOGC4PLUS_INCLUDE_DIR) + +IF(LOGC4PLUS_FOUND) + SET(LOGC4PLUS_LIBRARIES ${LOGC4PLUS_LIBRARY}) + SET(LOGC4PLUS_INCLUDE_DIRS ${LOGC4PLUS_INCLUDE_DIR}) +ELSE() + SET(LOGC4PLUS_LOGC4PLUS_FOUND FALSE) +ENDIF() + +MARK_AS_ADVANCED( + LOGC4PLUS_INCLUDE_DIR + LOGC4PLUS_LIBRARY +) diff --git a/blender-build/build_environment/patches/cmake/modules/FindOpenEXR.cmake b/blender-build/build_environment/patches/cmake/modules/FindOpenEXR.cmake new file mode 100644 index 0000000..1fd44d4 --- /dev/null +++ b/blender-build/build_environment/patches/cmake/modules/FindOpenEXR.cmake @@ -0,0 +1,247 @@ +# SPDX-License-Identifier: BSD-3-Clause + +# Module to find OpenEXR. +# +# This module will first look into the directories defined by the variables: +# - OPENEXR_HOME, OPENEXR_VERSION, OPENEXR_LIB_AREA +# +# It also supports non-standard names for the library components. +# +# To use a custom OpenEXR +# - Set the variable OPENEXR_CUSTOM to TRUE +# - Set the variable OPENEXR_CUSTOM_LIBRARY to the name of the library to +# use, e.g. "SpiIlmImf" +# - Optionally set the variable OPENEXR_CUSTOM_INCLUDE_DIR to any +# particularly weird place that the OpenEXR/*.h files may be found +# - Optionally set the variable OPENEXR_CUSTOM_LIB_DIR to any +# particularly weird place that the libraries files may be found +# +# This module defines the following variables: +# +# OPENEXR_INCLUDE_DIR - where to find ImfRgbaFile.h, OpenEXRConfig, etc. +# OPENEXR_LIBRARIES - list of libraries to link against when using OpenEXR. +# This list does NOT include the IlmBase libraries. +# These are defined by the FindIlmBase module. +# OPENEXR_FOUND - TRUE if OpenEXR was found. + +# Other standard issue macros +include(SelectLibraryConfigurations) +include(FindPackageHandleStandardArgs) +include(FindPackageMessage) + +if(OPENEXR_USE_STATIC_LIBS) + set(_openexr_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) + if(WIN32) + set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) + else() + set(CMAKE_FIND_LIBRARY_SUFFIXES .a ) + endif() +endif() + +# Macro to assemble a helper state variable +macro(SET_STATE_VAR varname) + set(tmp_lst + ${OPENEXR_CUSTOM} | ${OPENEXR_CUSTOM_LIBRARY} | + ${OPENEXR_HOME} | ${OPENEXR_VERSION} | ${OPENEXR_LIB_AREA} + ) + set(${varname} "${tmp_lst}") + unset(tmp_lst) +endmacro() + +# To enforce that find_* functions do not use inadvertently existing versions +if(OPENEXR_CUSTOM) + set(OPENEXR_FIND_OPTIONS "NO_DEFAULT_PATH") +endif() + +# Macro to search for an include directory +macro(PREFIX_FIND_INCLUDE_DIR prefix includefile libpath_var) + string(TOUPPER ${prefix}_INCLUDE_DIR tmp_varname) + find_path(${tmp_varname} ${includefile} + HINTS ${${libpath_var}} + PATH_SUFFIXES include + ${OPENEXR_FIND_OPTIONS} + ) + if(${tmp_varname}) + mark_as_advanced(${tmp_varname}) + endif() + unset(tmp_varname) +endmacro() + + +# Macro to search for the given library and adds the cached +# variable names to the specified list +macro(PREFIX_FIND_LIB prefix libname libpath_var liblist_var cachelist_var) + string(TOUPPER ${prefix}_${libname} tmp_prefix) + # Handle new library names for OpenEXR 2.1 build via cmake + string(REPLACE "." "_" _ILMBASE_VERSION ${ILMBASE_VERSION}) + string(SUBSTRING ${_ILMBASE_VERSION} 0 3 _ILMBASE_VERSION ) + find_library(${tmp_prefix}_LIBRARY_RELEASE + NAMES ${libname} ${libname}-${_ILMBASE_VERSION} + HINTS ${${libpath_var}} + PATH_SUFFIXES lib + ${OPENEXR_FIND_OPTIONS} + ) + find_library(${tmp_prefix}_LIBRARY_DEBUG + NAMES ${libname}d ${libname}_d ${libname}debug ${libname}_debug + HINTS ${${libpath_var}} + PATH_SUFFIXES lib + ${OPENEXR_FIND_OPTIONS} + ) + # Properly define ${tmp_prefix}_LIBRARY (cached) and ${tmp_prefix}_LIBRARIES + select_library_configurations(${tmp_prefix}) + list(APPEND ${liblist_var} ${tmp_prefix}_LIBRARIES) + + # Add to the list of variables which should be reset + list(APPEND ${cachelist_var} + ${tmp_prefix}_LIBRARY + ${tmp_prefix}_LIBRARY_RELEASE + ${tmp_prefix}_LIBRARY_DEBUG) + mark_as_advanced( + ${tmp_prefix}_LIBRARY + ${tmp_prefix}_LIBRARY_RELEASE + ${tmp_prefix}_LIBRARY_DEBUG) + unset(tmp_prefix) +endmacro() + + +# Encode the current state of the external variables into a string +SET_STATE_VAR(OPENEXR_CURRENT_STATE) + +# If the state has changed, clear the cached variables +if(OPENEXR_CACHED_STATE AND + NOT OPENEXR_CACHED_STATE STREQUAL OPENEXR_CURRENT_STATE) + foreach(libvar ${OPENEXR_CACHED_VARS}) + unset(${libvar} CACHE) + endforeach() +endif() + +# Generic search paths +set(OpenEXR_generic_include_paths + ${OPENEXR_CUSTOM_INCLUDE_DIR} + /usr/include + /usr/include/${CMAKE_LIBRARY_ARCHITECTURE} + /usr/local/include + /opt/local/include +) +set(OpenEXR_generic_library_paths + ${OPENEXR_CUSTOM_LIB_DIR} + /usr/lib + /usr/lib/${CMAKE_LIBRARY_ARCHITECTURE} + /usr/local/lib + /usr/local/lib/${CMAKE_LIBRARY_ARCHITECTURE} + /opt/local/lib +) + +# Search paths for the OpenEXR files +if(OPENEXR_HOME) + set(OpenEXR_library_paths + ${OPENEXR_HOME}/lib + ${OPENEXR_HOME}/lib64) + if(OPENEXR_VERSION) + set(OpenEXR_include_paths + ${OPENEXR_HOME}/openexr-${OPENEXR_VERSION}/include + ${OPENEXR_HOME}/include/openexr-${OPENEXR_VERSION}) + list(APPEND OpenEXR_library_paths + ${OPENEXR_HOME}/openexr-${OPENEXR_VERSION}/lib + ${OPENEXR_HOME}/lib/openexr-${OPENEXR_VERSION}) + endif() + list(APPEND OpenEXR_include_paths ${OPENEXR_HOME}/include) + if(OPENEXR_LIB_AREA) + list(INSERT OpenEXR_library_paths 2 ${OPENEXR_LIB_AREA}) + endif() +endif() +if(ILMBASE_HOME AND OPENEXR_VERSION) + list(APPEND OpenEXR_include_paths + ${ILMBASE_HOME}/include/openexr-${OPENEXR_VERSION}) +endif() +list(APPEND OpenEXR_include_paths ${OpenEXR_generic_include_paths}) +list(APPEND OpenEXR_library_paths ${OpenEXR_generic_library_paths}) + +# Locate the header files +PREFIX_FIND_INCLUDE_DIR(OpenEXR + OpenEXR/ImfArray.h OpenEXR_include_paths) + +if(OPENEXR_INCLUDE_DIR) + # Get the version from config file, if not already set. + if(NOT OPENEXR_VERSION) + FILE(STRINGS "${OPENEXR_INCLUDE_DIR}/OpenEXR/OpenEXRConfig.h" OPENEXR_BUILD_SPECIFICATION + REGEX "^[ \t]*#define[ \t]+OPENEXR_VERSION_STRING[ \t]+\"[.0-9]+\".*$") + + if(OPENEXR_BUILD_SPECIFICATION) + if(NOT OpenEXR_FIND_QUIETLY) + message(STATUS "${OPENEXR_BUILD_SPECIFICATION}") + endif() + string(REGEX REPLACE ".*#define[ \t]+OPENEXR_VERSION_STRING[ \t]+\"([.0-9]+)\".*" + "\\1" XYZ ${OPENEXR_BUILD_SPECIFICATION}) + set("OPENEXR_VERSION" ${XYZ} CACHE STRING "Version of OpenEXR lib") + else() + # Old versions (before 2.0?) do not have any version string, + # just assuming 2.0 should be fine though. + message(WARNING "Could not determine ILMBase library version, assuming 2.0.") + set("OPENEXR_VERSION" "2.0" CACHE STRING "Version of OpenEXR lib") + endif() + endif() +endif() + +if(OPENEXR_CUSTOM) + if(NOT OPENEXR_CUSTOM_LIBRARY) + message(FATAL_ERROR "Custom OpenEXR library requested but OPENEXR_CUSTOM_LIBRARY is not set.") + endif() + set(OpenEXR_Library ${OPENEXR_CUSTOM_LIBRARY}) +else() +# elseif(${OPENEXR_VERSION} VERSION_LESS "2.1") + set(OpenEXR_Library IlmImf) +# else() +# string(REGEX REPLACE "([0-9]+)[.]([0-9]+).*" "\\1_\\2" _openexr_libs_ver ${OPENEXR_VERSION}) +# set(OpenEXR_Library IlmImf-${_openexr_libs_ver}) +endif() + +# Locate the OpenEXR library +set(OpenEXR_libvars "") +set(OpenEXR_cachevars "") +PREFIX_FIND_LIB(OpenEXR ${OpenEXR_Library} + OpenEXR_library_paths OpenEXR_libvars OpenEXR_cachevars) + +# Create the list of variables that might need to be cleared +set(OPENEXR_CACHED_VARS + OPENEXR_INCLUDE_DIR ${OpenEXR_cachevars} + CACHE INTERNAL "Variables set by FindOpenEXR.cmake" FORCE) + +# Store the current state so that variables might be cleared if required +set(OPENEXR_CACHED_STATE ${OPENEXR_CURRENT_STATE} + CACHE INTERNAL "State last seen by FindOpenEXR.cmake" FORCE) + +# Always link explicitly with zlib +set(OPENEXR_ZLIB ${ZLIB_LIBRARIES}) + +# Use the standard function to handle OPENEXR_FOUND +FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenEXR DEFAULT_MSG + OPENEXR_INCLUDE_DIR ${OpenEXR_libvars}) + +if(OPENEXR_FOUND) + set(OPENEXR_LIBRARIES "") + foreach(tmplib ${OpenEXR_libvars}) + list(APPEND OPENEXR_LIBRARIES ${${tmplib}}) + endforeach() + list(APPEND OPENEXR_LIBRARIES ${ZLIB_LIBRARIES}) + if(NOT OpenEXR_FIND_QUIETLY) + FIND_PACKAGE_MESSAGE(OPENEXR + "Found OpenEXR: ${OPENEXR_LIBRARIES}" + "[${OPENEXR_INCLUDE_DIR}][${OPENEXR_LIBRARIES}][${OPENEXR_CURRENT_STATE}]" + ) + endif() +endif() + +# Restore the original find library ordering +if(OPENEXR_USE_STATIC_LIBS ) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${_openexr_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) +endif() + +# Unset the helper variables to avoid pollution +unset(OPENEXR_CURRENT_STATE) +unset(OpenEXR_include_paths) +unset(OpenEXR_library_paths) +unset(OpenEXR_generic_include_paths) +unset(OpenEXR_generic_library_paths) +unset(OpenEXR_libvars) +unset(OpenEXR_cachevars) diff --git a/blender-build/build_environment/patches/cmake/modules/FindTBB.cmake b/blender-build/build_environment/patches/cmake/modules/FindTBB.cmake new file mode 100644 index 0000000..ad7a1a2 --- /dev/null +++ b/blender-build/build_environment/patches/cmake/modules/FindTBB.cmake @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2016 Blender Foundation. + +# - Find TBB library +# Find the native TBB includes and library +# This module defines +# TBB_INCLUDE_DIRS, where to find tbb.h, Set when +# TBB is found. +# TBB_LIBRARIES, libraries to link against to use TBB. +# TBB_ROOT_DIR, The base directory to search for TBB. +# This can also be an environment variable. +# TBB_FOUND, If false, do not try to use TBB. +# +# also defined, but not for general use are +# TBB_LIBRARY, where to find the TBB library. + +# If TBB_ROOT_DIR was defined in the environment, use it. +IF(NOT TBB_ROOT_DIR AND NOT $ENV{TBB_ROOT_DIR} STREQUAL "") + SET(TBB_ROOT_DIR $ENV{TBB_ROOT_DIR}) +ENDIF() + +SET(_tbb_SEARCH_DIRS + ${TBB_ROOT_DIR} + /opt/lib/tbb +) + +FIND_PATH(TBB_INCLUDE_DIR + NAMES + tbb/tbb.h + HINTS + ${_tbb_SEARCH_DIRS} + PATH_SUFFIXES + include +) + +FIND_LIBRARY(TBB_LIBRARY + NAMES + tbb + HINTS + ${_tbb_SEARCH_DIRS} + PATH_SUFFIXES + lib64 lib + ) + +# handle the QUIETLY and REQUIRED arguments and set TBB_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(TBB DEFAULT_MSG + TBB_LIBRARY TBB_INCLUDE_DIR) + +IF(TBB_FOUND) + SET(TBB_LIBRARIES ${TBB_LIBRARY}) + SET(TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIR}) +ELSE() + SET(TBB_TBB_FOUND FALSE) +ENDIF() + +MARK_AS_ADVANCED( + TBB_INCLUDE_DIR + TBB_LIBRARY +) diff --git a/blender-build/build_environment/patches/cmake/modules/SelectLibraryConfigurations.cmake b/blender-build/build_environment/patches/cmake/modules/SelectLibraryConfigurations.cmake new file mode 100644 index 0000000..010e7e3 --- /dev/null +++ b/blender-build/build_environment/patches/cmake/modules/SelectLibraryConfigurations.cmake @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2009 Kitware, Inc. +# 2009 Will Dicharry +# 2005-2009 Kitware, Inc. + +# select_library_configurations( basename ) +# +# This macro takes a library base name as an argument, and will choose good +# values for basename_LIBRARY, basename_LIBRARIES, basename_LIBRARY_DEBUG, and +# basename_LIBRARY_RELEASE depending on what has been found and set. If only +# basename_LIBRARY_RELEASE is defined, basename_LIBRARY, basename_LIBRARY_DEBUG, +# and basename_LIBRARY_RELEASE will be set to the release value. If only +# basename_LIBRARY_DEBUG is defined, then basename_LIBRARY, +# basename_LIBRARY_DEBUG and basename_LIBRARY_RELEASE will take the debug value. +# +# If the generator supports configuration types, then basename_LIBRARY and +# basename_LIBRARIES will be set with debug and optimized flags specifying the +# library to be used for the given configuration. If no build type has been set +# or the generator in use does not support configuration types, then +# basename_LIBRARY and basename_LIBRARIES will take only the release values. + +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +# This macro was adapted from the FindQt4 CMake module and is maintained by Will +# Dicharry . + +# Utility macro to check if one variable exists while another doesn't, and set +# one that doesn't exist to the one that exists. +macro( _set_library_name basename GOOD BAD ) + if( ${basename}_LIBRARY_${GOOD} AND NOT ${basename}_LIBRARY_${BAD} ) + set( ${basename}_LIBRARY_${BAD} ${${basename}_LIBRARY_${GOOD}} ) + set( ${basename}_LIBRARY ${${basename}_LIBRARY_${GOOD}} ) + set( ${basename}_LIBRARIES ${${basename}_LIBRARY_${GOOD}} ) + endif( ${basename}_LIBRARY_${GOOD} AND NOT ${basename}_LIBRARY_${BAD} ) +endmacro( _set_library_name ) + +macro( select_library_configurations basename ) + # if only the release version was found, set the debug to be the release + # version. + _set_library_name( ${basename} RELEASE DEBUG ) + # if only the debug version was found, set the release value to be the + # debug value. + _set_library_name( ${basename} DEBUG RELEASE ) + if( ${basename}_LIBRARY_DEBUG AND ${basename}_LIBRARY_RELEASE ) + # if the generator supports configuration types or CMAKE_BUILD_TYPE + # is set, then set optimized and debug options. + if( CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE ) + set( ${basename}_LIBRARY + optimized ${${basename}_LIBRARY_RELEASE} + debug ${${basename}_LIBRARY_DEBUG} ) + set( ${basename}_LIBRARIES + optimized ${${basename}_LIBRARY_RELEASE} + debug ${${basename}_LIBRARY_DEBUG} ) + else( CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE ) + # If there are no configuration types or build type, just use + # the release version + set( ${basename}_LIBRARY ${${basename}_LIBRARY_RELEASE} ) + set( ${basename}_LIBRARIES ${${basename}_LIBRARY_RELEASE} ) + endif( CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE ) + endif( ${basename}_LIBRARY_DEBUG AND ${basename}_LIBRARY_RELEASE ) + + set( ${basename}_LIBRARY ${${basename}_LIBRARY} CACHE FILEPATH + "The ${basename} library" ) + + if( ${basename}_LIBRARY ) + set( ${basename}_FOUND TRUE ) + endif( ${basename}_LIBRARY ) + + mark_as_advanced( ${basename}_LIBRARY + ${basename}_LIBRARY_RELEASE + ${basename}_LIBRARY_DEBUG + ) +endmacro( select_library_configurations ) diff --git a/blender-build/build_environment/patches/cmakelists_gmpxx.txt b/blender-build/build_environment/patches/cmakelists_gmpxx.txt new file mode 100644 index 0000000..5aa6c40 --- /dev/null +++ b/blender-build/build_environment/patches/cmakelists_gmpxx.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.1) +project(libgmpxx) + +include_directories(. cxx ${GMP_INCLUDE_DIR}) +add_definitions(-D__GMP_WITHIN_GMPXX) +add_library(libgmpxx SHARED + cxx/dummy.cc + cxx/isfuns.cc + cxx/ismpf.cc + cxx/ismpq.cc + cxx/ismpz.cc + cxx/ismpznw.cc + cxx/limits.cc + cxx/osdoprnti.cc + cxx/osfuns.cc + cxx/osmpf.cc + cxx/osmpq.cc + cxx/osmpz.cc +) + +target_link_libraries(libgmpxx ${GMP_LIBRARY}) +install(TARGETS libgmpxx DESTINATION lib) diff --git a/blender-build/build_environment/patches/cmakelists_lcms.txt b/blender-build/build_environment/patches/cmakelists_lcms.txt new file mode 100644 index 0000000..cd7b456 --- /dev/null +++ b/blender-build/build_environment/patches/cmakelists_lcms.txt @@ -0,0 +1,51 @@ +project(lcms2) + +cmake_minimum_required(VERSION 2.8) + +include_directories(include) + +set(HEADERS + include/lcms2.h + include/lcms2_plugin.h +) +set(SOURCES + src/cmscam02.c + src/cmscgats.c + src/cmscnvrt.c + src/cmserr.c + src/cmsgamma.c + src/cmsgmt.c + src/cmsintrp.c + src/cmsio0.c + src/cmsio1.c + src/cmslut.c + src/cmsmd5.c + src/cmsmtrx.c + src/cmsnamed.c + src/cmsopt.c + src/cmspack.c + src/cmspcs.c + src/cmsplugin.c + src/cmsps2.c + src/cmssamp.c + src/cmssm.c + src/cmstypes.c + src/cmsvirt.c + src/cmswtpnt.c + src/cmsxform.c + src/lcms2_internal.h +) + +add_library(${PROJECT_NAME} STATIC ${HEADERS} ${SOURCES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES + LIBRARY_OUTPUT_NAME "${PROJECT_NAME}" + PUBLIC_HEADER "${HEADERS}" +) + +install(TARGETS ${PROJECT_NAME} + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + PUBLIC_HEADER DESTINATION include +) diff --git a/blender-build/build_environment/patches/cmakelists_potrace.txt b/blender-build/build_environment/patches/cmakelists_potrace.txt new file mode 100644 index 0000000..c214ff7 --- /dev/null +++ b/blender-build/build_environment/patches/cmakelists_potrace.txt @@ -0,0 +1,54 @@ +project(potrace) +cmake_minimum_required(VERSION 2.8) + +include_directories(src/include) + +set(SOURCES + src/backend_dxf.c + src/backend_eps.c + src/backend_geojson.c + src/backend_pdf.c + src/backend_pgm.c + src/backend_svg.c + src/backend_xfig.c + src/bbox.c + src/bitmap_io.c + src/curve.c + src/decompose.c + src/flate.c + src/greymap.c + src/lzw.c + src/potracelib.c + src/progress_bar.c + src/render.c + src/trace.c + src/trans.c +) + +set(HEADERS + src/potracelib.h +) + +if(WIN32) + add_definitions(/D_USE_MATH_DEFINES) +endif() + +add_definitions(/DPOTRACE="POTrace") +add_definitions(/DVERSION="Blender") +add_definitions(/DHAVE_INTTYPES_H) + + +add_library(${PROJECT_NAME} STATIC ${HEADERS} ${SOURCES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES + LIBRARY_OUTPUT_NAME "${PROJECT_NAME}" + PUBLIC_HEADER "${HEADERS}" +) + +install(TARGETS ${PROJECT_NAME} + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + PUBLIC_HEADER DESTINATION include +) + diff --git a/blender-build/build_environment/patches/cmakelists_pystring.txt b/blender-build/build_environment/patches/cmakelists_pystring.txt new file mode 100644 index 0000000..0a6dee7 --- /dev/null +++ b/blender-build/build_environment/patches/cmakelists_pystring.txt @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright Contributors to the OpenColorIO Project. + +project(pystring) + +cmake_minimum_required(VERSION 3.10) + +set(HEADERS + pystring.h +) + +set(SOURCES + pystring.cpp +) + +add_library(${PROJECT_NAME} STATIC ${HEADERS} ${SOURCES}) + +if(UNIX) + set(pystring_CXX_FLAGS "${pystring_CXX_FLAGS} -fPIC") +endif() + +set_target_properties(${PROJECT_NAME} PROPERTIES + COMPILE_FLAGS "${PLATFORM_COMPILE_FLAGS} ${pystring_CXX_FLAGS}" + PUBLIC_HEADER "${HEADERS}" +) + +install(TARGETS ${PROJECT_NAME} + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + PUBLIC_HEADER DESTINATION include/pystring +) diff --git a/blender-build/build_environment/patches/cmakelists_tbb.txt b/blender-build/build_environment/patches/cmakelists_tbb.txt new file mode 100644 index 0000000..e05f27a --- /dev/null +++ b/blender-build/build_environment/patches/cmakelists_tbb.txt @@ -0,0 +1,688 @@ +cmake_minimum_required(VERSION 3.1 FATAL_ERROR) + +if (POLICY CMP0048) + # cmake warns if loaded from a min-3.0-required parent dir, so silence the warning: + cmake_policy(SET CMP0048 NEW) +endif() + +project (tbb CXX) + +include(CheckCXXCompilerFlag) +include(CheckCXXSourceRuns) + +if(POLICY CMP0058) + cmake_policy(SET CMP0058 NEW) +endif() + +if(POLICY CMP0068) + cmake_policy(SET CMP0068 NEW) +endif() + +if (POLICY CMP0078) + # swig standard target names + cmake_policy(SET CMP0078 NEW) +endif () + +if (POLICY CMP0086) + # UseSWIG honors SWIG_MODULE_NAME via -module flag + cmake_policy(SET CMP0086 NEW) +endif () + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to 'Release' as none was specified.") + set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" + "MinSizeRel" "RelWithDebInfo") +endif() + +if(NOT TBB_INSTALL_RUNTIME_DIR) + set(TBB_INSTALL_RUNTIME_DIR bin) +endif() +if(NOT TBB_INSTALL_LIBRARY_DIR) + set(TBB_INSTALL_LIBRARY_DIR lib) +endif() +if(NOT TBB_INSTALL_ARCHIVE_DIR) + set(TBB_INSTALL_ARCHIVE_DIR lib) +endif() +if(NOT TBB_INSTALL_INCLUDE_DIR) + set(TBB_INSTALL_INCLUDE_DIR include) +endif() +if(NOT TBB_CMAKE_PACKAGE_INSTALL_DIR) + set(TBB_CMAKE_PACKAGE_INSTALL_DIR lib/cmake/tbb) +endif() + +include_directories(include src src/rml/include ${CMAKE_CURRENT_BINARY_DIR}) + +option(TBB_BUILD_SHARED "Build TBB shared library" ON) +option(TBB_BUILD_STATIC "Build TBB static library" ON) +option(TBB_BUILD_TBBMALLOC "Build TBB malloc library" ON) +option(TBB_BUILD_TBBMALLOC_PROXY "Build TBB malloc proxy library" ON) +option(TBB_BUILD_TESTS "Build TBB tests and enable testing infrastructure" ON) +option(TBB_NO_DATE "Do not save the configure date in the version string" OFF) +option(TBB_BUILD_PYTHON "Build TBB Python bindings" OFF) +option(TBB_SET_SOVERSION "Set the SOVERSION (shared library build version suffix)?" OFF) + +# When this repository is part of a larger build system of a parent project +# we may not want TBB to set up default installation targets +option(TBB_INSTALL_TARGETS "Include build targets for 'make install'" ON) + +if(APPLE) + set(CMAKE_MACOSX_RPATH ON) +endif() + +file(GLOB tbb_src "${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/old/*.cpp") +list(REMOVE_ITEM tbb_src ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/tbb_bind.cpp) +list(APPEND tbb_src ${CMAKE_CURRENT_SOURCE_DIR}/src/rml/client/rml_tbb.cpp) +file(GLOB to_remove "${CMAKE_CURRENT_SOURCE_DIR}/src/old/test*.cpp") +list(REMOVE_ITEM tbb_src ${to_remove}) + +set(tbbmalloc_static_src + src/tbbmalloc/backend.cpp + src/tbbmalloc/large_objects.cpp + src/tbbmalloc/backref.cpp + src/tbbmalloc/tbbmalloc.cpp + src/tbbmalloc/frontend.cpp + src/tbb/itt_notify.cpp) + +set(tbbmalloc_src ${tbbmalloc_static_src}) + +set(tbbmalloc_proxy_src + src/tbbmalloc/proxy.cpp + src/tbbmalloc/tbb_function_replacement.cpp) + +add_library (tbb_interface INTERFACE) +add_definitions(-DTBB_SUPPRESS_DEPRECATED_MESSAGES=1) + +if (CMAKE_SYSTEM_PROCESSOR MATCHES "(i386|x86_64)") + if (NOT APPLE AND NOT MINGW) + target_compile_definitions(tbb_interface INTERFACE DO_ITT_NOTIFY) + endif() +endif() + +if (APPLE) + # Disable annoying "has no symbols" warnings + set(CMAKE_C_ARCHIVE_CREATE " Scr ") + set(CMAKE_CXX_ARCHIVE_CREATE " Scr ") + set(CMAKE_C_ARCHIVE_FINISH " -no_warning_for_no_symbols -c ") + set(CMAKE_CXX_ARCHIVE_FINISH " -no_warning_for_no_symbols -c ") +endif() + +macro(CHECK_CXX_COMPILER_AND_LINKER_FLAGS _RESULT _CXX_FLAGS _LINKER_FLAGS) + set(CMAKE_REQUIRED_FLAGS ${_CXX_FLAGS}) + set(CMAKE_REQUIRED_LIBRARIES ${_LINKER_FLAGS}) + set(CMAKE_REQUIRED_QUIET TRUE) + check_cxx_source_runs("#include \nint main(int argc, char **argv) { std::cout << \"test\"; return 0; }" ${_RESULT}) + set(CMAKE_REQUIRED_FLAGS "") + set(CMAKE_REQUIRED_LIBRARIES "") +endmacro() + +# Prefer libc++ in conjunction with Clang +if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + if (CMAKE_CXX_FLAGS MATCHES "-stdlib=libc\\+\\+") + message(STATUS "TBB: using libc++.") + else() + CHECK_CXX_COMPILER_AND_LINKER_FLAGS(HAS_LIBCPP "-stdlib=libc++" "-stdlib=libc++") + if (HAS_LIBCPP) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -D_LIBCPP_VERSION") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -stdlib=libc++") + message(STATUS "TBB: using libc++.") + else() + message(STATUS "TBB: NOT using libc++.") + endif() + endif() +endif() + +set (CMAKE_CXX_STANDARD 11) + +if (UNIX) + target_compile_definitions(tbb_interface INTERFACE USE_PTHREAD) + + check_cxx_compiler_flag ("-mrtm -Werror" SUPPORTS_MRTM) + if (SUPPORTS_MRTM) + target_compile_options(tbb_interface INTERFACE "-mrtm") + endif () + +elseif(WIN32) + target_compile_definitions(tbb_interface INTERFACE USE_WINTHREAD _WIN32_WINNT=0x0600) + if (MSVC) + enable_language(ASM_MASM) + target_compile_options(tbb_interface INTERFACE /GS- /Zc:wchar_t /Zc:forScope) + check_cxx_compiler_flag ("/volatile:iso" SUPPORTS_VOLATILE_FLAG) + if (SUPPORTS_VOLATILE_FLAG) + target_compile_options(tbb_interface INTERFACE /volatile:iso) + endif () + target_compile_options(tbb_interface INTERFACE $<$:/wd4267 /wd4800 /wd4146 /wd4244 /wd4577 /wd4018>) + if (NOT CMAKE_SIZEOF_VOID_P) + message(FATAL_ERROR "'CMAKE_SIZEOF_VOID_P' is undefined. Please delete your build directory and rerun CMake again!") + endif() + + if (CMAKE_SIZEOF_VOID_P EQUAL 8) + list(APPEND tbb_src src/tbb/intel64-masm/atomic_support.asm + src/tbb/intel64-masm/itsx.asm src/tbb/intel64-masm/intel64_misc.asm) + list(APPEND tbbmalloc_src src/tbb/intel64-masm/atomic_support.asm) + set(CMAKE_ASM_MASM_FLAGS "/DEM64T=1 ${CMAKE_ASM_MASM_FLAGS}") + else() + list(APPEND tbb_src src/tbb/ia32-masm/atomic_support.asm + src/tbb/ia32-masm/itsx.asm src/tbb/ia32-masm/lock_byte.asm) + # Enable SAFESEH feature for assembly (x86 builds only). + set(CMAKE_ASM_MASM_FLAGS "/safeseh ${CMAKE_ASM_MASM_FLAGS}") + endif() + elseif (MINGW) + target_compile_options(tbb_interface INTERFACE "-mthreads") + endif () +endif() + +if (MSVC) + set(ENABLE_RTTI "/EHsc /GR ") + set(DISABLE_RTTI "/EHs- /GR- ") +elseif (UNIX) + set(ENABLE_RTTI "-frtti -fexceptions ") + set(DISABLE_RTTI "-fno-rtti -fno-exceptions ") +endif () + +##-------- +# - Added TBB_USE_GLIBCXX_VERSION macro to specify the version of GNU +# libstdc++ when it cannot be properly recognized, e.g. when used +# with Clang on Linux* OS. Inspired by a contribution from David A. +if (NOT TBB_USE_GLIBCXX_VERSION AND UNIX AND NOT APPLE) + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + # using Clang + string(REPLACE "." "0" TBB_USE_GLIBCXX_VERSION ${CMAKE_CXX_COMPILER_VERSION}) + endif() +endif() + +if (TBB_USE_GLIBCXX_VERSION) + target_compile_definitions(tbb_interface INTERFACE TBB_USE_GLIBCXX_VERSION=${TBB_USE_GLIBCXX_VERSION}) +endif() + +##------- + +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + check_cxx_compiler_flag ("-flifetime-dse=1" SUPPORTS_FLIFETIME) + if (SUPPORTS_FLIFETIME) + target_compile_options(tbb_interface INTERFACE -flifetime-dse=1) + endif() +endif() + +# Linker export definitions +if (APPLE) + set (ARCH_PREFIX "mac") +elseif(WIN32) + set (ARCH_PREFIX "win") +else() + set (ARCH_PREFIX "lin") +endif() + +if (CMAKE_SIZEOF_VOID_P EQUAL 8) + set(ARCH_PREFIX "${ARCH_PREFIX}64") +else() + set(ARCH_PREFIX "${ARCH_PREFIX}32") +endif() + +if (MINGW) + set (ARCH_PREFIX "${ARCH_PREFIX}-gcc") + # there's no win32-gcc-tbb-export.def, use lin32-tbb-export.def + execute_process (COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/lin32-tbb-export.def ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/win32-gcc-tbb-export.def) +endif() + +if (MSVC) + add_custom_command(OUTPUT tbb.def + COMMAND ${CMAKE_CXX_COMPILER} /TC /EP ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/${ARCH_PREFIX}-tbb-export.def -I ${CMAKE_CURRENT_SOURCE_DIR}/include > tbb.def + MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/${ARCH_PREFIX}-tbb-export.def + COMMENT "Preprocessing tbb.def" + ) + + add_custom_command(OUTPUT tbbmalloc.def + COMMAND ${CMAKE_CXX_COMPILER} /TC /EP ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/${ARCH_PREFIX}-tbbmalloc-export.def -I ${CMAKE_CURRENT_SOURCE_DIR}/include > tbbmalloc.def + MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/${ARCH_PREFIX}-tbbmalloc-export.def + COMMENT "Preprocessing tbbmalloc.def" + ) +else() + add_custom_command(OUTPUT tbb.def + COMMAND ${CMAKE_CXX_COMPILER} -xc++ -std=c++11 -E ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/${ARCH_PREFIX}-tbb-export.def -I ${CMAKE_CURRENT_SOURCE_DIR}/include -o tbb.def + MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/${ARCH_PREFIX}-tbb-export.def + COMMENT "Preprocessing tbb.def" + ) + + add_custom_command(OUTPUT tbbmalloc.def + COMMAND ${CMAKE_CXX_COMPILER} -xc++ -std=c++11 -E ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/${ARCH_PREFIX}-tbbmalloc-export.def -I ${CMAKE_CURRENT_SOURCE_DIR}/include -o tbbmalloc.def + MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/src/tbbmalloc/${ARCH_PREFIX}-tbbmalloc-export.def + COMMENT "Preprocessing tbbmalloc.def" + ) +endif() + +add_custom_target(tbb_def_files DEPENDS tbb.def tbbmalloc.def) + +# TBB library +if (TBB_BUILD_STATIC) + add_library(tbb_static STATIC ${tbb_src}) + target_link_libraries(tbb_static PRIVATE tbb_interface) + target_include_directories(tbb_static INTERFACE "$" "$") + set_property(TARGET tbb_static APPEND_STRING PROPERTY COMPILE_FLAGS ${ENABLE_RTTI}) + if (TBB_INSTALL_TARGETS) + install(TARGETS tbb_static ARCHIVE DESTINATION ${TBB_INSTALL_ARCHIVE_DIR}) + endif() + + target_compile_definitions(tbb_static + PRIVATE + -D__TBB_BUILD=1 + -D__TBB_DYNAMIC_LOAD_ENABLED=0 + -D__TBB_SOURCE_DIRECTLY_INCLUDED=1) + + if (MSVC) + target_compile_definitions(tbb_static + PUBLIC -D__TBB_NO_IMPLICIT_LINKAGE=1 + PRIVATE -D_CRT_SECURE_NO_WARNINGS) + endif() + + if (UNIX AND NOT APPLE) + target_link_libraries(tbb_static PUBLIC pthread dl) + endif() +endif() + +if (TBB_BUILD_SHARED) + add_library(tbb SHARED ${tbb_src}) + target_link_libraries(tbb PRIVATE tbb_interface) + target_include_directories(tbb INTERFACE "$" "$") + set_property(TARGET tbb APPEND_STRING PROPERTY COMPILE_FLAGS ${ENABLE_RTTI}) + if (TBB_SET_SOVERSION) + set_property(TARGET tbb PROPERTY SOVERSION 2) + endif () + + target_compile_definitions(tbb + PRIVATE -D__TBB_BUILD=1) + + if (MSVC) + target_compile_definitions(tbb + PUBLIC -D__TBB_NO_IMPLICIT_LINKAGE=1 + PRIVATE -D_CRT_SECURE_NO_WARNINGS) + endif() + + add_dependencies(tbb tbb_def_files) + + if (APPLE) + set_property(TARGET tbb APPEND PROPERTY LINK_FLAGS "-Wl,-exported_symbols_list,\"${CMAKE_CURRENT_BINARY_DIR}/tbb.def\"") + elseif (MSVC) + set_property(TARGET tbb APPEND PROPERTY LINK_FLAGS "/DEF:\"${CMAKE_CURRENT_BINARY_DIR}/tbb.def\"") + else () + set_property(TARGET tbb APPEND PROPERTY LINK_FLAGS "-Wl,-version-script,\"${CMAKE_CURRENT_BINARY_DIR}/tbb.def\"") + endif() + + if (TBB_INSTALL_TARGETS) + install(TARGETS tbb EXPORT TBB + LIBRARY DESTINATION ${TBB_INSTALL_LIBRARY_DIR} + ARCHIVE DESTINATION ${TBB_INSTALL_ARCHIVE_DIR} + RUNTIME DESTINATION ${TBB_INSTALL_RUNTIME_DIR}) + if (MSVC) + install(FILES $ DESTINATION ${TBB_INSTALL_RUNTIME_DIR} OPTIONAL) + endif() + endif() + + if (UNIX AND NOT APPLE) + target_link_libraries(tbb PUBLIC pthread dl) + endif() +endif() + + +if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + # Quench a warning on GCC + set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/governor.cpp COMPILE_FLAGS "-Wno-missing-field-initializers ") +elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + # Quench a warning on Clang + set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/itt_notify.cpp COMPILE_FLAGS "-Wno-varargs ") +elseif(MSVC) + # Quench a warning on MSVC + set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/src/tbb/scheduler.cpp COMPILE_FLAGS "/wd4458 ") +endif() + +if(TBB_BUILD_TBBMALLOC) + # TBB malloc library + if (TBB_BUILD_STATIC) + add_library(tbbmalloc_static STATIC ${tbbmalloc_static_src}) + target_link_libraries(tbbmalloc_static PRIVATE tbb_interface) + set_property(TARGET tbbmalloc_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBBMALLOC_BUILD=1") + set_property(TARGET tbbmalloc_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBB_DYNAMIC_LOAD_ENABLED=0") + set_property(TARGET tbbmalloc_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBB_SOURCE_DIRECTLY_INCLUDED=1") + set_property(TARGET tbbmalloc_static APPEND_STRING PROPERTY COMPILE_FLAGS ${DISABLE_RTTI}) + if (MSVC) + target_compile_definitions(tbbmalloc_static PUBLIC __TBB_NO_IMPLICIT_LINKAGE=1 __TBBMALLOC_NO_IMPLICIT_LINKAGE=1) + endif() + if (TBB_INSTALL_TARGETS) + install(TARGETS tbbmalloc_static ARCHIVE DESTINATION ${TBB_INSTALL_ARCHIVE_DIR}) + endif() + endif() + + if (TBB_BUILD_SHARED) + add_library(tbbmalloc SHARED ${tbbmalloc_src}) + target_link_libraries(tbbmalloc PRIVATE tbb_interface) + set_property(TARGET tbbmalloc APPEND PROPERTY COMPILE_DEFINITIONS "__TBBMALLOC_BUILD=1") + set_property(TARGET tbbmalloc APPEND_STRING PROPERTY COMPILE_FLAGS ${DISABLE_RTTI}) + if (TBB_SET_SOVERSION) + set_property(TARGET tbbmalloc PROPERTY SOVERSION 2) + endif () + add_dependencies(tbbmalloc tbb_def_files) + if (APPLE) + set_property(TARGET tbbmalloc APPEND PROPERTY LINK_FLAGS "-Wl,-exported_symbols_list,\"${CMAKE_CURRENT_BINARY_DIR}/tbbmalloc.def\"") + elseif (MSVC) + set_property(TARGET tbbmalloc APPEND PROPERTY LINK_FLAGS "/DEF:\"${CMAKE_CURRENT_BINARY_DIR}/tbbmalloc.def\"") + else () + set_property(TARGET tbbmalloc APPEND PROPERTY LINK_FLAGS "-Wl,-version-script,\"${CMAKE_CURRENT_BINARY_DIR}/tbbmalloc.def\"") + endif() + if (MSVC) + target_compile_definitions(tbbmalloc PUBLIC __TBB_NO_IMPLICIT_LINKAGE=1 __TBBMALLOC_NO_IMPLICIT_LINKAGE=1) + endif() + if (TBB_INSTALL_TARGETS) + install(TARGETS tbbmalloc EXPORT TBB + LIBRARY DESTINATION ${TBB_INSTALL_LIBRARY_DIR} + ARCHIVE DESTINATION ${TBB_INSTALL_ARCHIVE_DIR} + RUNTIME DESTINATION ${TBB_INSTALL_RUNTIME_DIR}) + if (MSVC) + install(FILES $ DESTINATION ${TBB_INSTALL_RUNTIME_DIR} OPTIONAL) + endif() + endif() + if (UNIX AND NOT APPLE) + target_link_libraries(tbbmalloc PUBLIC pthread dl) + endif() + endif() +endif() + +if(TBB_BUILD_TBBMALLOC_PROXY) + # TBB malloc proxy library + if (TBB_BUILD_STATIC) + add_library(tbbmalloc_proxy_static STATIC ${tbbmalloc_proxy_src}) + target_link_libraries(tbbmalloc_proxy_static PRIVATE tbb_interface) + set_property(TARGET tbbmalloc_proxy_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBBMALLOC_BUILD=1") + set_property(TARGET tbbmalloc_proxy_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBB_DYNAMIC_LOAD_ENABLED=0") + set_property(TARGET tbbmalloc_proxy_static APPEND PROPERTY COMPILE_DEFINITIONS "__TBB_SOURCE_DIRECTLY_INCLUDED=1") + set_property(TARGET tbbmalloc_proxy_static APPEND_STRING PROPERTY COMPILE_FLAGS ${DISABLE_RTTI}) + if (TBB_INSTALL_TARGETS) + install(TARGETS tbbmalloc_proxy_static ARCHIVE DESTINATION ${TBB_INSTALL_ARCHIVE_DIR}) + endif() + endif() + + if (TBB_BUILD_SHARED) + add_library(tbbmalloc_proxy SHARED ${tbbmalloc_proxy_src}) + target_link_libraries(tbbmalloc_proxy PRIVATE tbb_interface) + set_property(TARGET tbbmalloc_proxy APPEND PROPERTY COMPILE_DEFINITIONS "__TBBMALLOC_BUILD=1") + set_property(TARGET tbbmalloc_proxy APPEND_STRING PROPERTY COMPILE_FLAGS ${DISABLE_RTTI}) + if (TBB_SET_SOVERSION) + set_property(TARGET tbbmalloc_proxy PROPERTY SOVERSION 2) + endif () + target_link_libraries(tbbmalloc_proxy PUBLIC tbbmalloc) + if (TBB_INSTALL_TARGETS) + install(TARGETS tbbmalloc_proxy EXPORT TBB + LIBRARY DESTINATION ${TBB_INSTALL_LIBRARY_DIR} + ARCHIVE DESTINATION ${TBB_INSTALL_ARCHIVE_DIR} + RUNTIME DESTINATION ${TBB_INSTALL_RUNTIME_DIR}) + if (MSVC) + install(FILES $ DESTINATION ${TBB_INSTALL_RUNTIME_DIR} OPTIONAL) + endif() + endif() + if (UNIX AND NOT APPLE) + target_link_libraries(tbbmalloc_proxy PUBLIC pthread dl) + endif() + endif() +endif() + +if (TBB_INSTALL_TARGETS) + install(DIRECTORY include/tbb DESTINATION ${TBB_INSTALL_INCLUDE_DIR}) + if (TBB_BUILD_SHARED) + install(EXPORT TBB DESTINATION ${TBB_CMAKE_PACKAGE_INSTALL_DIR} NAMESPACE TBB:: FILE TBBConfig.cmake) + endif() +endif() + +# version file +if (TBB_INSTALL_TARGETS) + set (_VERSION_FILE ${CMAKE_CURRENT_SOURCE_DIR}/include/tbb/tbb_stddef.h) + file (STRINGS ${_VERSION_FILE} _VERSION_MAJOR_STRING REGEX ".*define[ ]+TBB_VERSION_MAJOR[ ]+[0-9]+.*") + file (STRINGS ${_VERSION_FILE} _VERSION_MINOR_STRING REGEX ".*define[ ]+TBB_VERSION_MINOR[ ]+[0-9]+.*") + string (REGEX REPLACE ".*TBB_VERSION_MAJOR[ ]+([0-9]+)" "\\1" TBB_MAJOR_VERSION ${_VERSION_MAJOR_STRING}) + string (REGEX REPLACE ".*TBB_VERSION_MINOR[ ]+([0-9]+)" "\\1" TBB_MINOR_VERSION ${_VERSION_MINOR_STRING}) + set (TBB_VERSION_STRING "${TBB_MAJOR_VERSION}.${TBB_MINOR_VERSION}") + include (CMakePackageConfigHelpers) + write_basic_package_version_file (TBBConfigVersion.cmake VERSION "${TBB_VERSION_STRING}" COMPATIBILITY AnyNewerVersion) + install (FILES ${CMAKE_CURRENT_BINARY_DIR}/TBBConfigVersion.cmake DESTINATION "${TBB_CMAKE_PACKAGE_INSTALL_DIR}") +endif() + +# version_string.ver +if (UNIX AND NOT TBB_NO_DATE) + execute_process (COMMAND date "+%a, %d %b %Y %H:%M:%S %z" + OUTPUT_VARIABLE _configure_date + OUTPUT_STRIP_TRAILING_WHITESPACE) +elseif (WIN32 AND NOT TBB_NO_DATE) + execute_process (COMMAND cmd " /C date /T" + OUTPUT_VARIABLE _configure_date + OUTPUT_STRIP_TRAILING_WHITESPACE) +else () + set (_configure_date "Unknown") +endif() +set (TBB_CONFIG_DATE "${_configure_date}" CACHE STRING "First time that TBB was configured") +set (_configure_date "${TBB_CONFIG_DATE}") +include_directories (${CMAKE_BINARY_DIR}) +configure_file (build/version_string.ver.in version_string.ver @ONLY) + +if (TBB_BUILD_TESTS) + enable_language (C) + enable_testing () + + find_library (LIBRT_LIBRARIES rt) + find_library (LIDL_LIBRARIES dl) + find_package (Threads) + if (NOT APPLE) + find_package (OpenMP) + endif() + + macro (tbb_add_test testname) + set (full_testname tbb_test_${testname}) + add_executable (${full_testname} src/test/test_${testname}.cpp) + target_link_libraries(${full_testname} PRIVATE tbb_interface) + if (TBB_BUILD_SHARED) + target_link_libraries (${full_testname} PRIVATE tbb tbbmalloc) + target_compile_definitions (${full_testname} PRIVATE __TBB_LIB_NAME=tbb) + else () + target_link_libraries (${full_testname} PRIVATE tbb_static tbbmalloc_static) + target_compile_definitions (${full_testname} PRIVATE __TBB_LIB_NAME=tbb_static) + endif () + if (LIBRT_LIBRARIES) + target_link_libraries (${full_testname} PRIVATE ${LIBRT_LIBRARIES}) + endif () + if (LIDL_LIBRARIES) + target_link_libraries (${full_testname} PRIVATE ${LIDL_LIBRARIES}) + endif () + if (Threads_FOUND) + target_link_libraries (${full_testname} PRIVATE ${CMAKE_THREAD_LIBS_INIT}) + endif () + if (OPENMP_FOUND AND "${testname}" MATCHES "openmp") + set_target_properties (${full_testname} PROPERTIES COMPILE_FLAGS "${OpenMP_CXX_FLAGS}") + set_target_properties (${full_testname} PROPERTIES LINK_FLAGS "${OpenMP_CXX_FLAGS}") + endif() + if (MINGW) + target_link_libraries (${full_testname} PRIVATE psapi) + endif () + add_test (NAME ${full_testname} COMMAND ${full_testname}) + endmacro () + + tbb_add_test (aggregator) + tbb_add_test (aligned_space) + tbb_add_test (assembly) + if (NOT WIN32) + tbb_add_test (async_msg) # msvc64/debug timeouts + endif() + tbb_add_test (async_node) + # tbb_add_test (atomic) # msvc64/debug timeouts: Compile-time initialization fails for static tbb::atomic variables + tbb_add_test (blocked_range2d) + tbb_add_test (blocked_range3d) + tbb_add_test (blocked_range) + tbb_add_test (broadcast_node) + tbb_add_test (buffer_node) + tbb_add_test (cache_aligned_allocator) + if (NOT WIN32) + tbb_add_test (cache_aligned_allocator_STL) + endif() + tbb_add_test (cilk_dynamic_load) + tbb_add_test (cilk_interop) + tbb_add_test (combinable) + tbb_add_test (composite_node) + tbb_add_test (concurrent_hash_map) + tbb_add_test (concurrent_lru_cache) + # tbb_add_test (concurrent_monitor) # too long + # tbb_add_test (concurrent_priority_queue) + if (NOT WIN32) + tbb_add_test (concurrent_queue) # msvc64/debug timeouts + endif() + # tbb_add_test (concurrent_queue_whitebox) + tbb_add_test (concurrent_unordered_map) + # tbb_add_test (concurrent_unordered_set) + tbb_add_test (concurrent_vector) + tbb_add_test (continue_node) + tbb_add_test (critical_section) + tbb_add_test (dynamic_link) + # tbb_add_test (eh_algorithms) + tbb_add_test (eh_flow_graph) + # tbb_add_test (eh_tasks) + tbb_add_test (enumerable_thread_specific) + tbb_add_test (examples_common_utility) + # tbb_add_test (fast_random) + tbb_add_test (flow_graph) + tbb_add_test (flow_graph_whitebox) + # tbb_add_test (fp) # mingw: harness_fp.h:66, assertion !checkConsistency || (ctl.mxcsr & SSE_RND_MODE_MASK) >> 3 == (ctl.x87cw & FE_RND_MODE_MASK): failed + # tbb_add_test (function_node) # mingw:random timeout + # tbb_add_test (global_control) + # tbb_add_test (global_control_whitebox) + tbb_add_test (halt) + tbb_add_test (handle_perror) + # tbb_add_test (hw_concurrency) + tbb_add_test (indexer_node) + tbb_add_test (inits_loop) + tbb_add_test (intrusive_list) + tbb_add_test (ittnotify) + # tbb_add_test (join_node) #msvc/64: fatal error C1128: number of sections exceeded object file format limit: compile with /bigob + tbb_add_test (lambda) + tbb_add_test (limiter_node) + # tbb_add_test (malloc_atexit) + # tbb_add_test (malloc_compliance) #mingw: Limits should be decreased for the test to work + tbb_add_test (malloc_init_shutdown) + # tbb_add_test (malloc_lib_unload) + # tbb_add_test (malloc_overload) + tbb_add_test (malloc_pools) + tbb_add_test (malloc_regression) + # tbb_add_test (malloc_used_by_lib) + # tbb_add_test (malloc_whitebox) + tbb_add_test (model_plugin) + # tbb_add_test (multifunction_node) # too long + tbb_add_test (mutex) + tbb_add_test (mutex_native_threads) + # tbb_add_test (opencl_node) + if (OPENMP_FOUND) + tbb_add_test (openmp) + endif () + tbb_add_test (overwrite_node) + # tbb_add_test (parallel_do) + # This seems to fail on CI platforms (AppVeyor/Travis), perhaps because the VM exposes just 1 core? + tbb_add_test (parallel_for) + tbb_add_test (parallel_for_each) + tbb_add_test (parallel_for_vectorization) + tbb_add_test (parallel_invoke) + tbb_add_test (parallel_pipeline) + tbb_add_test (parallel_reduce) + tbb_add_test (parallel_scan) + tbb_add_test (parallel_sort) + tbb_add_test (parallel_while) + # tbb_add_test (partitioner_whitebox) # too long + tbb_add_test (pipeline) + # tbb_add_test (pipeline_with_tbf) # takes forever on appveyor + tbb_add_test (priority_queue_node) + tbb_add_test (queue_node) + tbb_add_test (reader_writer_lock) + # tbb_add_test (runtime_loader) # LINK : fatal error LNK1104: cannot open file 'tbbproxy.lib' [C:\projects\tbb\test_runtime_loader.vcxproj] + tbb_add_test (rwm_upgrade_downgrade) + # tbb_add_test (ScalableAllocator) + if (NOT WIN32) + tbb_add_test (ScalableAllocator_STL) + endif() + tbb_add_test (semaphore) + # tbb_add_test (sequencer_node) # msvc: timeout + tbb_add_test (source_node) + tbb_add_test (split_node) + tbb_add_test (static_assert) + tbb_add_test (std_thread) + tbb_add_test (tagged_msg) + # tbb_add_test (task_arena) # LINK : fatal error LNK1104: cannot open file '__TBB_LIB_NAME.lib' [C:\projects\tbb\test_task_arena.vcxproj] + # tbb_add_test (task_assertions) + tbb_add_test (task_auto_init) + tbb_add_test (task) + # tbb_add_test (task_enqueue) # too long + tbb_add_test (task_group) + # tbb_add_test (task_leaks) + # tbb_add_test (task_priority) + # tbb_add_test (task_scheduler_init) # msvc: test_task_scheduler_init.cpp:68, assertion !test_mandatory_parallelism || Harness::CanReachConcurrencyLevel(threads): failed + tbb_add_test (task_scheduler_observer) + tbb_add_test (task_steal_limit) + tbb_add_test (tbb_condition_variable) + tbb_add_test (tbb_fork) + # tbb_add_test (tbb_header) + tbb_add_test (tbb_thread) + # tbb_add_test (tbb_version) + tbb_add_test (tick_count) + tbb_add_test (tuple) + tbb_add_test (write_once_node) + tbb_add_test (yield) +endif () + +if (TBB_BUILD_PYTHON) + find_package(PythonInterp) + find_package(PythonLibs ${PYTHON_VERSION_STRING} EXACT) + find_package(SWIG 3) + if (PythonLibs_FOUND AND SWIG_FOUND AND TBB_BUILD_SHARED) + include (${SWIG_USE_FILE}) + set_source_files_properties (python/tbb/api.i PROPERTIES CPLUSPLUS ON) + set (CMAKE_SWIG_FLAGS "-threads") + + # swig_add_module is deprecated + if (CMAKE_VERSION VERSION_LESS 3.8) + swig_add_module (api python python/tbb/api.i) + else () + swig_add_library (api LANGUAGE python SOURCES python/tbb/api.i) + endif () + + # UseSWIG generates now standard target names + if (CMAKE_VERSION VERSION_LESS 3.13) + set (module_target ${SWIG_MODULE_api_REAL_NAME}) + else () + set (module_target api) + endif () + + target_include_directories(${module_target} PRIVATE ${PYTHON_INCLUDE_DIRS}) + target_link_libraries(${module_target} PRIVATE tbb) + if(WIN32) + target_link_libraries(${module_target} ${PYTHON_LIBRARIES}) + elseif(APPLE) + set_target_properties(${module_target} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") + endif() + + if (WIN32) + set (PYTHON_SITE_PACKAGES Lib/site-packages) + else () + set (PYTHON_SITE_PACKAGES lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages) + endif () + if (TBB_INSTALL_TARGETS) + install(FILES python/TBB.py + DESTINATION ${PYTHON_SITE_PACKAGES}) + install(FILES python/tbb/__init__.py python/tbb/pool.py python/tbb/test.py python/tbb/__main__.py ${CMAKE_CURRENT_BINARY_DIR}/api.py + DESTINATION ${PYTHON_SITE_PACKAGES}/tbb) + install(TARGETS ${module_target} + DESTINATION ${PYTHON_SITE_PACKAGES}/tbb) + endif() + + if(UNIX AND NOT APPLE) + add_library(irml SHARED python/rml/ipc_server.cpp python/rml/ipc_utils.cpp src/tbb/cache_aligned_allocator.cpp src/tbb/dynamic_link.cpp src/tbb/tbb_misc_ex.cpp src/tbb/tbb_misc.cpp) + target_compile_definitions(irml PRIVATE DO_ITT_NOTIFY=0 USE_PTHREAD=1) + target_link_libraries(irml PRIVATE tbb) + set_target_properties(irml PROPERTIES VERSION 1) + if (TBB_INSTALL_TARGETS) + install(TARGETS irml DESTINATION ${TBB_INSTALL_LIBRARY_DIR}) + endif() + endif () + endif () +endif () diff --git a/blender-build/build_environment/patches/config_gmpxx.h b/blender-build/build_environment/patches/config_gmpxx.h new file mode 100644 index 0000000..842d6d5 --- /dev/null +++ b/blender-build/build_environment/patches/config_gmpxx.h @@ -0,0 +1,668 @@ +/* config.h. Generated from config.in by configure. */ +/* config.in. Generated from configure.ac by autoheader. */ + +/* + +Copyright 1996-2020 Free Software Foundation, Inc. + +This file is part of the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + +or + + * the GNU General Public License as published by the Free Software + Foundation; either version 2 of the License, or (at your option) any + later version. + +or both in parallel, as here. + +The GNU MP Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received copies of the GNU General Public License and the +GNU Lesser General Public License along with the GNU MP Library. If not, +see https://www.gnu.org/licenses/. +*/ + +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ + +/* The gmp-mparam.h file (a string) the tune program should suggest updating. + */ +#define GMP_MPARAM_H_SUGGEST "./mpn/x86_64/coreisbr/gmp-mparam.h" + +/* Define to 1 if you have the `alarm' function. */ +#define HAVE_ALARM 1 + +/* Define to 1 if alloca() works (via gmp-impl.h). */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +/* #undef HAVE_ALLOCA_H */ + +/* Define to 1 if the compiler accepts gcc style __attribute__ ((const)) */ +//#define HAVE_ATTRIBUTE_CONST 1 + +/* Define to 1 if the compiler accepts gcc style __attribute__ ((malloc)) */ +//#define HAVE_ATTRIBUTE_MALLOC 1 + +/* Define to 1 if the compiler accepts gcc style __attribute__ ((mode (XX))) + */ +//#define HAVE_ATTRIBUTE_MODE 1 + +/* Define to 1 if the compiler accepts gcc style __attribute__ ((noreturn)) */ +//#define HAVE_ATTRIBUTE_NORETURN 1 + +/* Define to 1 if you have the `attr_get' function. */ +/* #undef HAVE_ATTR_GET */ + +/* Define to 1 if tests/libtests has calling conventions checking for the CPU + */ +/* #undef HAVE_CALLING_CONVENTIONS */ + +/* Define to 1 if you have the `clock' function. */ +#define HAVE_CLOCK 1 + +/* Define to 1 if you have the `clock_gettime' function */ +/* #undef HAVE_CLOCK_GETTIME */ + +/* Define to 1 if you have the `cputime' function. */ +/* #undef HAVE_CPUTIME */ + +/* Define to 1 if you have the declaration of `fgetc', and to 0 if you don't. + */ +#define HAVE_DECL_FGETC 1 + +/* Define to 1 if you have the declaration of `fscanf', and to 0 if you don't. + */ +#define HAVE_DECL_FSCANF 1 + +/* Define to 1 if you have the declaration of `optarg', and to 0 if you don't. + */ +#define HAVE_DECL_OPTARG 1 + +/* Define to 1 if you have the declaration of `sys_errlist', and to 0 if you + don't. */ +#define HAVE_DECL_SYS_ERRLIST 0 + +/* Define to 1 if you have the declaration of `sys_nerr', and to 0 if you + don't. */ +#define HAVE_DECL_SYS_NERR 0 + +/* Define to 1 if you have the declaration of `ungetc', and to 0 if you don't. + */ +#define HAVE_DECL_UNGETC 1 + +/* Define to 1 if you have the declaration of `vfprintf', and to 0 if you + don't. */ +#define HAVE_DECL_VFPRINTF 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DLFCN_H */ + +/* Define one of the following to 1 for the format of a `double'. + If your format is not among these choices, or you don't know what it is, + then leave all undefined. + IEEE_LITTLE_SWAPPED means little endian, but with the two 4-byte halves + swapped, as used by ARM CPUs in little endian mode. */ +/* #undef HAVE_DOUBLE_IEEE_BIG_ENDIAN */ +#define HAVE_DOUBLE_IEEE_LITTLE_ENDIAN 1 +/* #undef HAVE_DOUBLE_IEEE_LITTLE_SWAPPED */ +/* #undef HAVE_DOUBLE_VAX_D */ +/* #undef HAVE_DOUBLE_VAX_G */ +/* #undef HAVE_DOUBLE_CRAY_CFP */ + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FLOAT_H 1 + +/* Define to 1 if you have the `getpagesize' function. */ +#define HAVE_GETPAGESIZE 1 + +/* Define to 1 if you have the `getrusage' function. */ +/* #undef HAVE_GETRUSAGE */ + +/* Define to 1 if you have the `getsysinfo' function. */ +/* #undef HAVE_GETSYSINFO */ + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if the compiler accepts gcc style __attribute__ ((visibility)) + and __attribute__ ((alias)) */ +#define HAVE_HIDDEN_ALIAS 1 + +/* Define one of these to 1 for the host CPU family. + If your CPU is not in any of these families, leave all undefined. + For an AMD64 chip, define "x86" in ABI=32, but not in ABI=64. */ +/* #undef HAVE_HOST_CPU_FAMILY_alpha */ +/* #undef HAVE_HOST_CPU_FAMILY_m68k */ +/* #undef HAVE_HOST_CPU_FAMILY_power */ +/* #undef HAVE_HOST_CPU_FAMILY_powerpc */ +/* #undef HAVE_HOST_CPU_FAMILY_x86 */ +#define HAVE_HOST_CPU_FAMILY_x86_64 1 + +/* Define one of the following to 1 for the host CPU, as per the output of + ./config.guess. If your CPU is not listed here, leave all undefined. */ +/* #undef HAVE_HOST_CPU_alphaev67 */ +/* #undef HAVE_HOST_CPU_alphaev68 */ +/* #undef HAVE_HOST_CPU_alphaev7 */ +/* #undef HAVE_HOST_CPU_m68020 */ +/* #undef HAVE_HOST_CPU_m68030 */ +/* #undef HAVE_HOST_CPU_m68040 */ +/* #undef HAVE_HOST_CPU_m68060 */ +/* #undef HAVE_HOST_CPU_m68360 */ +/* #undef HAVE_HOST_CPU_powerpc604 */ +/* #undef HAVE_HOST_CPU_powerpc604e */ +/* #undef HAVE_HOST_CPU_powerpc750 */ +/* #undef HAVE_HOST_CPU_powerpc7400 */ +/* #undef HAVE_HOST_CPU_supersparc */ +/* #undef HAVE_HOST_CPU_i386 */ +/* #undef HAVE_HOST_CPU_i586 */ +/* #undef HAVE_HOST_CPU_i686 */ +/* #undef HAVE_HOST_CPU_pentium */ +/* #undef HAVE_HOST_CPU_pentiummmx */ +/* #undef HAVE_HOST_CPU_pentiumpro */ +/* #undef HAVE_HOST_CPU_pentium2 */ +/* #undef HAVE_HOST_CPU_pentium3 */ +/* #undef HAVE_HOST_CPU_pentium4 */ +/* #undef HAVE_HOST_CPU_core2 */ +/* #undef HAVE_HOST_CPU_nehalem */ +/* #undef HAVE_HOST_CPU_westmere */ +/* #undef HAVE_HOST_CPU_sandybridge */ +#define HAVE_HOST_CPU_ivybridge 1 +/* #undef HAVE_HOST_CPU_haswell */ +/* #undef HAVE_HOST_CPU_broadwell */ +/* #undef HAVE_HOST_CPU_skylake */ +/* #undef HAVE_HOST_CPU_silvermont */ +/* #undef HAVE_HOST_CPU_goldmont */ +/* #undef HAVE_HOST_CPU_k8 */ +/* #undef HAVE_HOST_CPU_k10 */ +/* #undef HAVE_HOST_CPU_bulldozer */ +/* #undef HAVE_HOST_CPU_piledriver */ +/* #undef HAVE_HOST_CPU_steamroller */ +/* #undef HAVE_HOST_CPU_excavator */ +/* #undef HAVE_HOST_CPU_zen */ +/* #undef HAVE_HOST_CPU_bobcat */ +/* #undef HAVE_HOST_CPU_jaguar */ +/* #undef HAVE_HOST_CPU_s390_z900 */ +/* #undef HAVE_HOST_CPU_s390_z990 */ +/* #undef HAVE_HOST_CPU_s390_z9 */ +/* #undef HAVE_HOST_CPU_s390_z10 */ +/* #undef HAVE_HOST_CPU_s390_z196 */ + +/* Define to 1 iff we have a s390 with 64-bit registers. */ +/* #undef HAVE_HOST_CPU_s390_zarch */ + +/* Define to 1 if the system has the type `intmax_t'. */ +#define HAVE_INTMAX_T 1 + +/* Define to 1 if the system has the type `intptr_t'. */ +#define HAVE_INTPTR_T 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_INVENT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LANGINFO_H */ + +/* Define one of these to 1 for the endianness of `mp_limb_t'. + If the endianness is not a simple big or little, or you don't know what + it is, then leave both undefined. */ +/* #undef HAVE_LIMB_BIG_ENDIAN */ +#define HAVE_LIMB_LITTLE_ENDIAN 1 + +/* Define to 1 if you have the `localeconv' function. */ +#define HAVE_LOCALECONV 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if the system has the type `long double'. */ +#define HAVE_LONG_DOUBLE 1 + +/* Define to 1 if the system has the type `long long'. */ +#define HAVE_LONG_LONG 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACHINE_HAL_SYSINFO_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have the `mmap' function. */ +/* #undef HAVE_MMAP */ + +/* Define to 1 if you have the `mprotect' function. */ +#define HAVE_MPROTECT 1 + +/* Define to 1 each of the following for which a native (ie. CPU specific) + implementation of the corresponding routine exists. */ +#define HAVE_NATIVE_mpn_add_n 1 +/* #undef HAVE_NATIVE_mpn_add_n_sub_n */ +#define HAVE_NATIVE_mpn_add_nc 1 +/* #undef HAVE_NATIVE_mpn_addaddmul_1msb0 */ +#define HAVE_NATIVE_mpn_addlsh1_n 1 +#define HAVE_NATIVE_mpn_addlsh2_n 1 +#define HAVE_NATIVE_mpn_addlsh_n 1 +#define HAVE_NATIVE_mpn_addlsh1_nc 1 +#define HAVE_NATIVE_mpn_addlsh2_nc 1 +#define HAVE_NATIVE_mpn_addlsh_nc 1 +/* #undef HAVE_NATIVE_mpn_addlsh1_n_ip1 */ +/* #undef HAVE_NATIVE_mpn_addlsh2_n_ip1 */ +/* #undef HAVE_NATIVE_mpn_addlsh_n_ip1 */ +/* #undef HAVE_NATIVE_mpn_addlsh1_nc_ip1 */ +/* #undef HAVE_NATIVE_mpn_addlsh2_nc_ip1 */ +/* #undef HAVE_NATIVE_mpn_addlsh_nc_ip1 */ +/* #undef HAVE_NATIVE_mpn_addlsh1_n_ip2 */ +/* #undef HAVE_NATIVE_mpn_addlsh2_n_ip2 */ +/* #undef HAVE_NATIVE_mpn_addlsh_n_ip2 */ +/* #undef HAVE_NATIVE_mpn_addlsh1_nc_ip2 */ +/* #undef HAVE_NATIVE_mpn_addlsh2_nc_ip2 */ +/* #undef HAVE_NATIVE_mpn_addlsh_nc_ip2 */ +/* #undef HAVE_NATIVE_mpn_addmul_1c */ +#define HAVE_NATIVE_mpn_addmul_2 1 +/* #undef HAVE_NATIVE_mpn_addmul_3 */ +/* #undef HAVE_NATIVE_mpn_addmul_4 */ +/* #undef HAVE_NATIVE_mpn_addmul_5 */ +/* #undef HAVE_NATIVE_mpn_addmul_6 */ +/* #undef HAVE_NATIVE_mpn_addmul_7 */ +/* #undef HAVE_NATIVE_mpn_addmul_8 */ +/* #undef HAVE_NATIVE_mpn_addmul_2s */ +#define HAVE_NATIVE_mpn_and_n 1 +#define HAVE_NATIVE_mpn_andn_n 1 +#define HAVE_NATIVE_mpn_bdiv_dbm1c 1 +#define HAVE_NATIVE_mpn_bdiv_q_1 1 +#define HAVE_NATIVE_mpn_pi1_bdiv_q_1 1 +#define HAVE_NATIVE_mpn_cnd_add_n 1 +#define HAVE_NATIVE_mpn_cnd_sub_n 1 +#define HAVE_NATIVE_mpn_com 1 +#define HAVE_NATIVE_mpn_copyd 1 +#define HAVE_NATIVE_mpn_copyi 1 +/* #undef HAVE_NATIVE_mpn_div_qr_1n_pi1 */ +/* #undef HAVE_NATIVE_mpn_div_qr_2 */ +#define HAVE_NATIVE_mpn_divexact_1 1 +/* #undef HAVE_NATIVE_mpn_divexact_by3c */ +#define HAVE_NATIVE_mpn_divrem_1 1 +/* #undef HAVE_NATIVE_mpn_divrem_1c */ +#define HAVE_NATIVE_mpn_divrem_2 1 +/* #undef HAVE_NATIVE_mpn_gcd_1 */ +#define HAVE_NATIVE_mpn_gcd_11 1 +/* #undef HAVE_NATIVE_mpn_gcd_22 */ +#define HAVE_NATIVE_mpn_hamdist 1 +#define HAVE_NATIVE_mpn_invert_limb 1 +#define HAVE_NATIVE_mpn_ior_n 1 +#define HAVE_NATIVE_mpn_iorn_n 1 +#define HAVE_NATIVE_mpn_lshift 1 +#define HAVE_NATIVE_mpn_lshiftc 1 +/* #undef HAVE_NATIVE_mpn_lshsub_n */ +/* #undef HAVE_NATIVE_mpn_mod_1 */ +#define HAVE_NATIVE_mpn_mod_1_1p 1 +/* #undef HAVE_NATIVE_mpn_mod_1c */ +#define HAVE_NATIVE_mpn_mod_1s_2p 1 +#define HAVE_NATIVE_mpn_mod_1s_4p 1 +#define HAVE_NATIVE_mpn_mod_34lsub1 1 +#define HAVE_NATIVE_mpn_modexact_1_odd 1 +#define HAVE_NATIVE_mpn_modexact_1c_odd 1 +#define HAVE_NATIVE_mpn_mul_1 1 +#define HAVE_NATIVE_mpn_mul_1c 1 +#define HAVE_NATIVE_mpn_mul_2 1 +/* #undef HAVE_NATIVE_mpn_mul_3 */ +/* #undef HAVE_NATIVE_mpn_mul_4 */ +/* #undef HAVE_NATIVE_mpn_mul_5 */ +/* #undef HAVE_NATIVE_mpn_mul_6 */ +#define HAVE_NATIVE_mpn_mul_basecase 1 +#define HAVE_NATIVE_mpn_mullo_basecase 1 +#define HAVE_NATIVE_mpn_nand_n 1 +#define HAVE_NATIVE_mpn_nior_n 1 +#define HAVE_NATIVE_mpn_popcount 1 +#define HAVE_NATIVE_mpn_preinv_divrem_1 1 +/* #undef HAVE_NATIVE_mpn_preinv_mod_1 */ +#define HAVE_NATIVE_mpn_redc_1 1 +/* #undef HAVE_NATIVE_mpn_redc_2 */ +#define HAVE_NATIVE_mpn_rsblsh1_n 1 +#define HAVE_NATIVE_mpn_rsblsh2_n 1 +#define HAVE_NATIVE_mpn_rsblsh_n 1 +#define HAVE_NATIVE_mpn_rsblsh1_nc 1 +/* #undef HAVE_NATIVE_mpn_rsblsh2_nc */ +/* #undef HAVE_NATIVE_mpn_rsblsh_nc */ +#define HAVE_NATIVE_mpn_rsh1add_n 1 +#define HAVE_NATIVE_mpn_rsh1add_nc 1 +#define HAVE_NATIVE_mpn_rsh1sub_n 1 +#define HAVE_NATIVE_mpn_rsh1sub_nc 1 +#define HAVE_NATIVE_mpn_rshift 1 +/* #undef HAVE_NATIVE_mpn_sbpi1_bdiv_r */ +#define HAVE_NATIVE_mpn_sqr_basecase 1 +/* #undef HAVE_NATIVE_mpn_sqr_diagonal */ +#define HAVE_NATIVE_mpn_sqr_diag_addlsh1 1 +#define HAVE_NATIVE_mpn_sub_n 1 +#define HAVE_NATIVE_mpn_sub_nc 1 +#define HAVE_NATIVE_mpn_sublsh1_n 1 +#define HAVE_NATIVE_mpn_sublsh2_n 1 +/* #undef HAVE_NATIVE_mpn_sublsh_n */ +/* #undef HAVE_NATIVE_mpn_sublsh1_nc */ +/* #undef HAVE_NATIVE_mpn_sublsh2_nc */ +/* #undef HAVE_NATIVE_mpn_sublsh_nc */ +/* #undef HAVE_NATIVE_mpn_sublsh1_n_ip1 */ +/* #undef HAVE_NATIVE_mpn_sublsh2_n_ip1 */ +/* #undef HAVE_NATIVE_mpn_sublsh_n_ip1 */ +/* #undef HAVE_NATIVE_mpn_sublsh1_nc_ip1 */ +/* #undef HAVE_NATIVE_mpn_sublsh2_nc_ip1 */ +/* #undef HAVE_NATIVE_mpn_sublsh_nc_ip1 */ +/* #undef HAVE_NATIVE_mpn_submul_1c */ +/* #undef HAVE_NATIVE_mpn_tabselect */ +/* #undef HAVE_NATIVE_mpn_udiv_qrnnd */ +/* #undef HAVE_NATIVE_mpn_udiv_qrnnd_r */ +/* #undef HAVE_NATIVE_mpn_umul_ppmm */ +/* #undef HAVE_NATIVE_mpn_umul_ppmm_r */ +#define HAVE_NATIVE_mpn_xor_n 1 +#define HAVE_NATIVE_mpn_xnor_n 1 + +/* Define to 1 if you have the `nl_langinfo' function. */ +/* #undef HAVE_NL_LANGINFO */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NL_TYPES_H */ + +/* Define to 1 if you have the `obstack_vprintf' function. */ +/* #undef HAVE_OBSTACK_VPRINTF */ + +/* Define to 1 if you have the `popen' function. */ +#define HAVE_POPEN 1 + +/* Define to 1 if you have the `processor_info' function. */ +/* #undef HAVE_PROCESSOR_INFO */ + +/* Define to 1 if `struct pst_processor' exists and contains + `psp_iticksperclktick'. */ +/* #undef HAVE_PSP_ITICKSPERCLKTICK */ + +/* Define to 1 if you have the `pstat_getprocessor' function. */ +/* #undef HAVE_PSTAT_GETPROCESSOR */ + +/* Define to 1 if the system has the type `ptrdiff_t'. */ +#define HAVE_PTRDIFF_T 1 + +/* Define to 1 if the system has the type `quad_t'. */ +/* #undef HAVE_QUAD_T */ + +/* Define to 1 if you have the `raise' function. */ +#define HAVE_RAISE 1 + +/* Define to 1 if you have the `read_real_time' function. */ +/* #undef HAVE_READ_REAL_TIME */ + +/* Define to 1 if you have the `sigaction' function. */ +/* #undef HAVE_SIGACTION */ + +/* Define to 1 if you have the `sigaltstack' function. */ +/* #undef HAVE_SIGALTSTACK */ + +/* Define to 1 if you have the `sigstack' function. */ +/* #undef HAVE_SIGSTACK */ + +/* Tune directory speed_cyclecounter, undef=none, 1=32bits, 2=64bits) */ +#define HAVE_SPEED_CYCLECOUNTER 2 + +/* Define to 1 if you have the header file. */ +#define HAVE_SSTREAM 1 + +/* Define to 1 if the system has the type `stack_t'. */ +/* #undef HAVE_STACK_T */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if the system has the type `std::locale'. */ +#define HAVE_STD__LOCALE 1 + +/* Define to 1 if you have the `strchr' function. */ +#define HAVE_STRCHR 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strnlen' function. */ +#define HAVE_STRNLEN 1 + +/* Define to 1 if you have the `strtol' function. */ +#define HAVE_STRTOL 1 + +/* Define to 1 if you have the `strtoul' function. */ +#define HAVE_STRTOUL 1 + +/* Define to 1 if you have the `sysconf' function. */ +/* #undef HAVE_SYSCONF */ + +/* Define to 1 if you have the `sysctl' function. */ +/* #undef HAVE_SYSCTL */ + +/* Define to 1 if you have the `sysctlbyname' function. */ +/* #undef HAVE_SYSCTLBYNAME */ + +/* Define to 1 if you have the `syssgi' function. */ +/* #undef HAVE_SYSSGI */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_ATTRIBUTES_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_IOGRAPH_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_MMAN_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_PROCESSOR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_PSTAT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_RESOURCE_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SYSCTL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SYSINFO_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SYSSGI_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SYSTEMCFG_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_TIMES_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the `times' function. */ +/* #undef HAVE_TIMES */ + +/* Define to 1 if the system has the type `uint_least32_t'. */ +#define HAVE_UINT_LEAST32_T 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `vsnprintf' function and it works properly. */ +/* #undef HAVE_VSNPRINTF */ + +/* Define to 1 for Windos/64 */ +#define HOST_DOS64 1 + +/* Assembler local label prefix */ +#define LSYM_PREFIX "L" + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#define LT_OBJDIR ".libs/" + +/* Define to 1 to disable the use of inline assembly */ +/* #undef NO_ASM */ + +/* Name of package */ +#define PACKAGE "gmp" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "gmp-bugs@gmplib.org, see https://gmplib.org/manual/Reporting-Bugs.html" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "GNU MP" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "GNU MP 6.2.0" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "gmp" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "http://www.gnu.org/software/gmp/" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "6.2.0" + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* The size of `mp_limb_t', as computed by sizeof. */ +#define SIZEOF_MP_LIMB_T 8 + +/* The size of `unsigned', as computed by sizeof. */ +#define SIZEOF_UNSIGNED 4 + +/* The size of `unsigned long', as computed by sizeof. */ +#define SIZEOF_UNSIGNED_LONG 4 + +/* The size of `unsigned short', as computed by sizeof. */ +#define SIZEOF_UNSIGNED_SHORT 2 + +/* The size of `void *', as computed by sizeof. */ +#define SIZEOF_VOID_P 8 + +/* Define to 1 if sscanf requires writable inputs */ +/* #undef SSCANF_WRITABLE_INPUT */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Maximum size the tune program can test for SQR_TOOM2_THRESHOLD */ +/* #undef TUNE_SQR_TOOM2_MAX */ + +/* Version number of package */ +#define VERSION "6.2.0" + +/* Define to 1 to enable ASSERT checking, per --enable-assert */ +/* #undef WANT_ASSERT */ + +/* Define to 1 to enable GMP_CPU_TYPE faking cpuid, per --enable-fake-cpuid */ +/* #undef WANT_FAKE_CPUID */ + +/* Define to 1 when building a fat binary. */ +/* #undef WANT_FAT_BINARY */ + +/* Define to 1 to enable FFTs for multiplication, per --enable-fft */ +#define WANT_FFT 1 + +/* Define to 1 to enable old mpn_mul_fft_full for multiplication, per + --enable-old-fft-full */ +/* #undef WANT_OLD_FFT_FULL */ + +/* Define to 1 if --enable-profiling=gprof */ +/* #undef WANT_PROFILING_GPROF */ + +/* Define to 1 if --enable-profiling=instrument */ +/* #undef WANT_PROFILING_INSTRUMENT */ + +/* Define to 1 if --enable-profiling=prof */ +/* #undef WANT_PROFILING_PROF */ + +/* Define one of these to 1 for the desired temporary memory allocation + method, per --enable-alloca. */ +#define WANT_TMP_ALLOCA 1 +/* #undef WANT_TMP_REENTRANT */ +/* #undef WANT_TMP_NOTREENTRANT */ +/* #undef WANT_TMP_DEBUG */ + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +/* # undef WORDS_BIGENDIAN */ +# endif +#endif + +/* Define to 1 if the assembler understands the mulx instruction */ +/* #undef X86_ASM_MULX */ + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +/* #undef YYTEXT_POINTER */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to the equivalent of the C99 'restrict' keyword, or to + nothing if this is not supported. Do not define if restrict is + supported directly. */ +#define restrict __restrict +/* Work around a bug in Sun C++: it does not support _Restrict or + __restrict__, even though the corresponding Sun C compiler ends up with + "#define restrict _Restrict" or "#define restrict __restrict__" in the + previous line. Perhaps some future version of Sun C++ will work with + restrict; if so, hopefully it defines __RESTRICT like Sun C does. */ +#if defined __SUNPRO_CC && !defined __RESTRICT +# define _Restrict +# define __restrict__ +#endif + +/* Define to empty if the keyword `volatile' does not work. Warning: valid + code using `volatile' can become incorrect without. Disable with care. */ +/* #undef volatile */ diff --git a/blender-build/build_environment/patches/dpcpp.diff b/blender-build/build_environment/patches/dpcpp.diff new file mode 100644 index 0000000..a87d141 --- /dev/null +++ b/blender-build/build_environment/patches/dpcpp.diff @@ -0,0 +1,189 @@ +diff -Naur llvm-sycl-nightly-20220501.orig\opencl/CMakeLists.txt llvm-sycl-nightly-20220501\opencl/CMakeLists.txt +--- llvm-sycl-nightly-20220501.orig/opencl/CMakeLists.txt 2022-04-29 13:47:11 -0600 ++++ llvm-sycl-nightly-20220501/opencl/CMakeLists.txt 2022-05-21 15:25:06 -0600 +@@ -11,6 +11,11 @@ + ) + endif() + ++# Blender code below is determined to use FetchContent_Declare ++# temporarily allow it (but feed it our downloaded tarball ++# in the OpenCL_HEADERS variable ++set(FETCHCONTENT_FULLY_DISCONNECTED OFF) ++ + # Repo URLs + + set(OCL_HEADERS_REPO +@@ -77,5 +82,6 @@ + + FetchContent_MakeAvailable(ocl-icd) + add_library(OpenCL-ICD ALIAS OpenCL) ++set(FETCHCONTENT_FULLY_DISCONNECTED ON) + + add_subdirectory(opencl-aot) +diff -Naur llvm-sycl-nightly-20220208.orig/libdevice/cmake/modules/SYCLLibdevice.cmake llvm-sycl-nightly-20220208/libdevice/cmake/modules/SYCLLibdevice.cmake +--- llvm-sycl-nightly-20220208.orig/libdevice/cmake/modules/SYCLLibdevice.cmake 2022-02-08 09:17:24 -0700 ++++ llvm-sycl-nightly-20220208/libdevice/cmake/modules/SYCLLibdevice.cmake 2022-05-24 11:35:51 -0600 +@@ -36,7 +36,9 @@ + add_custom_target(libsycldevice-obj) + add_custom_target(libsycldevice-spv) + +-add_custom_target(libsycldevice DEPENDS ++# Blender: add ALL here otherwise this target will not build ++# and cause an error due to missing files during the install phase. ++add_custom_target(libsycldevice ALL DEPENDS + libsycldevice-obj + libsycldevice-spv) + +diff --git a/sycl/source/detail/program_manager/program_manager.cpp b/sycl/source/detail/program_manager/program_manager.cpp +index 17eeaafae194..09e6d2217aaa 100644 +--- a/sycl/source/detail/program_manager/program_manager.cpp ++++ b/sycl/source/detail/program_manager/program_manager.cpp +@@ -1647,46 +1647,120 @@ ProgramManager::getSYCLDeviceImagesWithCompatibleState( + } + assert(BinImages.size() > 0 && "Expected to find at least one device image"); + ++ // Ignore images with incompatible state. Image is considered compatible ++ // with a target state if an image is already in the target state or can ++ // be brought to target state by compiling/linking/building. ++ // ++ // Example: an image in "executable" state is not compatible with ++ // "input" target state - there is no operation to convert the image it ++ // to "input" state. An image in "input" state is compatible with ++ // "executable" target state because it can be built to get into ++ // "executable" state. ++ for (auto It = BinImages.begin(); It != BinImages.end();) { ++ if (getBinImageState(*It) > TargetState) ++ It = BinImages.erase(It); ++ else ++ ++It; ++ } ++ + std::vector SYCLDeviceImages; +- for (RTDeviceBinaryImage *BinImage : BinImages) { +- const bundle_state ImgState = getBinImageState(BinImage); +- +- // Ignore images with incompatible state. Image is considered compatible +- // with a target state if an image is already in the target state or can +- // be brought to target state by compiling/linking/building. +- // +- // Example: an image in "executable" state is not compatible with +- // "input" target state - there is no operation to convert the image it +- // to "input" state. An image in "input" state is compatible with +- // "executable" target state because it can be built to get into +- // "executable" state. +- if (ImgState > TargetState) +- continue; + +- for (const sycl::device &Dev : Devs) { ++ // If a non-input state is requested, we can filter out some compatible ++ // images and return only those with the highest compatible state for each ++ // device-kernel pair. This map tracks how many kernel-device pairs need each ++ // image, so that any unneeded ones are skipped. ++ // TODO this has no effect if the requested state is input, consider having ++ // a separate branch for that case to avoid unnecessary tracking work. ++ struct DeviceBinaryImageInfo { ++ std::shared_ptr> KernelIDs; ++ bundle_state State = bundle_state::input; ++ int RequirementCounter = 0; ++ }; ++ std::unordered_map ImageInfoMap; ++ ++ for (const sycl::device &Dev : Devs) { ++ // Track the highest image state for each requested kernel. ++ using StateImagesPairT = ++ std::pair>; ++ using KernelImageMapT = ++ std::map; ++ KernelImageMapT KernelImageMap; ++ if (!KernelIDs.empty()) ++ for (const kernel_id &KernelID : KernelIDs) ++ KernelImageMap.insert({KernelID, {}}); ++ ++ for (RTDeviceBinaryImage *BinImage : BinImages) { + if (!compatibleWithDevice(BinImage, Dev) || + !doesDevSupportImgAspects(Dev, *BinImage)) + continue; + +- std::shared_ptr> KernelIDs; +- // Collect kernel names for the image +- { +- std::lock_guard KernelIDsGuard(m_KernelIDsMutex); +- KernelIDs = m_BinImg2KernelIDs[BinImage]; +- // If the image does not contain any non-service kernels we can skip it. +- if (!KernelIDs || KernelIDs->empty()) +- continue; ++ auto InsertRes = ImageInfoMap.insert({BinImage, {}}); ++ DeviceBinaryImageInfo &ImgInfo = InsertRes.first->second; ++ if (InsertRes.second) { ++ ImgInfo.State = getBinImageState(BinImage); ++ // Collect kernel names for the image ++ { ++ std::lock_guard KernelIDsGuard(m_KernelIDsMutex); ++ ImgInfo.KernelIDs = m_BinImg2KernelIDs[BinImage]; ++ } + } ++ const bundle_state ImgState = ImgInfo.State; ++ const std::shared_ptr> &ImageKernelIDs = ++ ImgInfo.KernelIDs; ++ int &ImgRequirementCounter = ImgInfo.RequirementCounter; + +- DeviceImageImplPtr Impl = std::make_shared( +- BinImage, Ctx, Devs, ImgState, KernelIDs, /*PIProgram=*/nullptr); ++ // If the image does not contain any non-service kernels we can skip it. ++ if (!ImageKernelIDs || ImageKernelIDs->empty()) ++ continue; + +- SYCLDeviceImages.push_back( +- createSyclObjFromImpl(Impl)); +- break; ++ // Update tracked information. ++ for (kernel_id &KernelID : *ImageKernelIDs) { ++ StateImagesPairT *StateImagesPair; ++ // If only specific kernels are requested, ignore the rest. ++ if (!KernelIDs.empty()) { ++ auto It = KernelImageMap.find(KernelID); ++ if (It == KernelImageMap.end()) ++ continue; ++ StateImagesPair = &It->second; ++ } else ++ StateImagesPair = &KernelImageMap[KernelID]; ++ ++ auto &[KernelImagesState, KernelImages] = *StateImagesPair; ++ ++ if (KernelImages.empty()) { ++ KernelImagesState = ImgState; ++ KernelImages.push_back(BinImage); ++ ++ImgRequirementCounter; ++ } else if (KernelImagesState < ImgState) { ++ for (RTDeviceBinaryImage *Img : KernelImages) { ++ auto It = ImageInfoMap.find(Img); ++ assert(It != ImageInfoMap.end()); ++ assert(It->second.RequirementCounter > 0); ++ --(It->second.RequirementCounter); ++ } ++ KernelImages.clear(); ++ KernelImages.push_back(BinImage); ++ KernelImagesState = ImgState; ++ ++ImgRequirementCounter; ++ } else if (KernelImagesState == ImgState) { ++ KernelImages.push_back(BinImage); ++ ++ImgRequirementCounter; ++ } ++ } + } + } + ++ for (const auto &ImgInfoPair : ImageInfoMap) { ++ if (ImgInfoPair.second.RequirementCounter == 0) ++ continue; ++ ++ DeviceImageImplPtr Impl = std::make_shared( ++ ImgInfoPair.first, Ctx, Devs, ImgInfoPair.second.State, ++ ImgInfoPair.second.KernelIDs, /*PIProgram=*/nullptr); ++ ++ SYCLDeviceImages.push_back(createSyclObjFromImpl(Impl)); ++ } ++ + return SYCLDeviceImages; + } + diff --git a/blender-build/build_environment/patches/embree.diff b/blender-build/build_environment/patches/embree.diff new file mode 100644 index 0000000..fe69493 --- /dev/null +++ b/blender-build/build_environment/patches/embree.diff @@ -0,0 +1,80 @@ +diff --git a/kernels/CMakeLists.txt b/kernels/CMakeLists.txt +index 7c2f43d..106b1d5 100644 +--- a/kernels/CMakeLists.txt ++++ b/kernels/CMakeLists.txt +@@ -208,6 +208,12 @@ embree_files(EMBREE_LIBRARY_FILES_AVX512 ${AVX512}) + #message("AVX2: ${EMBREE_LIBRARY_FILES_AVX2}") + #message("AVX512: ${EMBREE_LIBRARY_FILES_AVX512}") + ++# Bundle Neon2x into the main static library. ++IF(EMBREE_ISA_NEON2X AND EMBREE_STATIC_LIB) ++ LIST(APPEND EMBREE_LIBRARY_FILES ${EMBREE_LIBRARY_FILES_AVX2}) ++ LIST(REMOVE_DUPLICATES EMBREE_LIBRARY_FILES) ++ENDIF() ++ + # replaces all .cpp files with a dummy file that includes that .cpp file + # this is to work around an ICC name mangling issue related to lambda functions under windows + MACRO (CreateISADummyFiles list isa) +@@ -311,7 +317,7 @@ IF (EMBREE_ISA_AVX AND EMBREE_LIBRARY_FILES_AVX) + ENDIF() + ENDIF() + +-IF (EMBREE_ISA_AVX2 AND EMBREE_LIBRARY_FILES_AVX2) ++IF (EMBREE_ISA_AVX2 AND EMBREE_LIBRARY_FILES_AVX2 AND NOT (EMBREE_ISA_NEON2X AND EMBREE_STATIC_LIB)) + DISABLE_STACK_PROTECTOR_FOR_INTERSECTORS(${EMBREE_LIBRARY_FILES_AVX2}) + ADD_LIBRARY(embree_avx2 STATIC ${EMBREE_LIBRARY_FILES_AVX2}) + TARGET_LINK_LIBRARIES(embree_avx2 PRIVATE tasking) +diff --git a/kernels/rthwif/rtbuild/rtbuild.cpp b/kernels/rthwif/rtbuild/rtbuild.cpp +index 6d439f939..367b1ce7b 100644 +--- a/kernels/rthwif/rtbuild/rtbuild.cpp ++++ b/kernels/rthwif/rtbuild/rtbuild.cpp +@@ -10,7 +10,7 @@ namespace embree + { + using namespace embree::isa; + +- static std::unique_ptr g_arena; ++ static tbb::task_arena g_arena(tbb::this_task_arena::max_concurrency(),tbb::this_task_arena::max_concurrency()); + + typedef enum _ze_raytracing_accel_format_internal_t { + ZE_RTAS_DEVICE_FORMAT_EXP_INVALID = 0, // invalid acceleration structure format +@@ -210,13 +210,10 @@ namespace embree + + RTHWIF_API void zeRTASInitExp() + { +- uint32_t numThreads = tbb::this_task_arena::max_concurrency(); +- g_arena.reset(new tbb::task_arena(numThreads,numThreads)); + } + + RTHWIF_API void zeRTASExitExp() + { +- g_arena.reset(); + } + + typedef struct _zet_base_desc_t +@@ -740,7 +737,7 @@ namespace embree + //if (op->hBuilder != hBuilder) + // return ZE_RESULT_ERROR_INVALID_ARGUMENT; + +- g_arena->execute([&](){ op->group.run([=](){ ++ g_arena.execute([&](){ op->group.run([=](){ + op->errorCode = zeRTASBuilderBuildExpInternal(args, + pScratchBuffer, scratchBufferSizeBytes, + pRtasBuffer, rtasBufferSizeBytes, +@@ -753,7 +750,7 @@ namespace embree + else + { + ze_result_t errorCode = ZE_RESULT_SUCCESS; +- g_arena->execute([&](){ errorCode = zeRTASBuilderBuildExpInternal(args, ++ g_arena.execute([&](){ errorCode = zeRTASBuilderBuildExpInternal(args, + pScratchBuffer, scratchBufferSizeBytes, + pRtasBuffer, rtasBufferSizeBytes, + pBuildUserPtr, pBounds, pRtasBufferSizeBytes); +@@ -801,7 +798,7 @@ namespace embree + VALIDATE(hParallelOperation); + + ze_rtas_parallel_operation_t* op = (ze_rtas_parallel_operation_t*) hParallelOperation; +- g_arena->execute([&](){ op->group.wait(); }); ++ g_arena.execute([&](){ op->group.wait(); }); + return op->errorCode; + } + } diff --git a/blender-build/build_environment/patches/epoxy.diff b/blender-build/build_environment/patches/epoxy.diff new file mode 100644 index 0000000..b0c3d7e --- /dev/null +++ b/blender-build/build_environment/patches/epoxy.diff @@ -0,0 +1,19 @@ +--- a/src/dispatch_wgl.c 2022-08-04 17:45:13.144924705 +0200 ++++ b/src/dispatch_wgl.c 2022-08-04 17:45:47.657482971 +0200 +@@ -78,6 +78,8 @@ + if (!first_context_current) { + first_context_current = true; + } else { ++ /* BLENDER: disable slow dispatch table switching. */ ++#if 0 + if (!already_switched_to_dispatch_table) { + already_switched_to_dispatch_table = true; + gl_switch_to_dispatch_table(); +@@ -86,6 +88,7 @@ + + gl_init_dispatch_table(); + wgl_init_dispatch_table(); ++#endif + } + } + diff --git a/blender-build/build_environment/patches/ffi.diff b/blender-build/build_environment/patches/ffi.diff new file mode 100644 index 0000000..84e7f04 --- /dev/null +++ b/blender-build/build_environment/patches/ffi.diff @@ -0,0 +1,11 @@ +--- Makefile.in 2014-11-12 06:59:58.000000000 -0500 ++++ Makefile.in 2018-09-17 13:36:10.974086554 -0400 +@@ -600,7 +600,7 @@ + target_os = @target_os@ + target_vendor = @target_vendor@ + toolexecdir = @toolexecdir@ +-toolexeclibdir = @toolexeclibdir@ ++toolexeclibdir = $(libdir) + top_build_prefix = @top_build_prefix@ + top_builddir = @top_builddir@ + top_srcdir = @top_srcdir@ diff --git a/blender-build/build_environment/patches/ffmpeg.diff b/blender-build/build_environment/patches/ffmpeg.diff new file mode 100644 index 0000000..960728a --- /dev/null +++ b/blender-build/build_environment/patches/ffmpeg.diff @@ -0,0 +1,11 @@ +--- a/configure 2018-08-27 13:46:41.071106150 +0200 ++++ b/configure 2018-08-27 13:46:28.162765762 +0200 +@@ -6013,7 +6013,7 @@ + require_pkg_config libopencv opencv opencv/cxcore.h cvCreateImageHeader; } + enabled libopenh264 && require_pkg_config libopenh264 openh264 wels/codec_api.h WelsGetCodecVersion + enabled libopenjpeg && { check_pkg_config libopenjpeg "libopenjp2 >= 2.1.0" openjpeg.h opj_version || +- { require_pkg_config libopenjpeg "libopenjp2 >= 2.1.0" openjpeg.h opj_version -DOPJ_STATIC && add_cppflags -DOPJ_STATIC; } } ++ { require_pkg_config libopenjpeg "libopenjp2 >= 2.1.0" openjpeg.h opj_version "-DOPJ_STATIC $pthreads_extralibs $libm_extralibs" && add_cppflags "-DOPJ_STATIC $pthreads_extralibs $libm_extralibs"; } } + enabled libopenmpt && require_pkg_config libopenmpt "libopenmpt >= 0.2.6557" libopenmpt/libopenmpt.h openmpt_module_create -lstdc++ && append libopenmpt_extralibs "-lstdc++" + enabled libopus && { + enabled libopus_decoder && { diff --git a/blender-build/build_environment/patches/fftw3.diff b/blender-build/build_environment/patches/fftw3.diff new file mode 100644 index 0000000..48d8841 --- /dev/null +++ b/blender-build/build_environment/patches/fftw3.diff @@ -0,0 +1,25 @@ +--- config.h.in 2014-03-04 11:44:58 -0700 ++++ config.h.in 2016-03-30 11:42:49 -0600 +@@ -142,9 +142,6 @@ + /* Define to 1 if you have the `gethrtime' function. */ + #undef HAVE_GETHRTIME + +-/* Define to 1 if you have the `gettimeofday' function. */ +-#undef HAVE_GETTIMEOFDAY +- + /* Define to 1 if hrtime_t is defined in */ + #undef HAVE_HRTIME_T + +--- kernel/assert.c 2014-03-04 11:41:03 -0700 ++++ kernel/assert.c 2016-04-01 09:41:05 -0600 +@@ -24,8 +24,10 @@ + + void X(assertion_failed)(const char *s, int line, const char *file) + { ++#if 0 + fflush(stdout); + fprintf(stderr, "fftw: %s:%d: assertion failed: %s\n", file, line, s); ++#endif + #ifdef HAVE_ABORT + abort(); + #else diff --git a/blender-build/build_environment/patches/gmp.diff b/blender-build/build_environment/patches/gmp.diff new file mode 100644 index 0000000..bf22f93 --- /dev/null +++ b/blender-build/build_environment/patches/gmp.diff @@ -0,0 +1,15 @@ +--- a/mpz/inp_raw.c Tue Dec 22 23:49:51 2020 +0100 ++++ b/mpz/inp_raw.c Thu Oct 21 19:06:49 2021 +0200 +@@ -88,8 +88,11 @@ + + abs_csize = ABS (csize); + ++ if (UNLIKELY (abs_csize > ~(mp_bitcnt_t) 0 / 8)) ++ return 0; /* Bit size overflows */ ++ + /* round up to a multiple of limbs */ +- abs_xsize = BITS_TO_LIMBS (abs_csize*8); ++ abs_xsize = BITS_TO_LIMBS ((mp_bitcnt_t) abs_csize * 8); + + if (abs_xsize != 0) + { diff --git a/blender-build/build_environment/patches/haru.diff b/blender-build/build_environment/patches/haru.diff new file mode 100644 index 0000000..fed551b --- /dev/null +++ b/blender-build/build_environment/patches/haru.diff @@ -0,0 +1,12 @@ +diff --git a/src/hpdf_image_ccitt.c b/src/hpdf_image_ccitt.c +index 8672763..9be531a 100644 +--- a/src/hpdf_image_ccitt.c ++++ b/src/hpdf_image_ccitt.c +@@ -21,7 +21,6 @@ + #include + #include + +-#define G3CODES + #include "t4.h" + + typedef unsigned int uint32; diff --git a/blender-build/build_environment/patches/igc_opencl_clang.diff b/blender-build/build_environment/patches/igc_opencl_clang.diff new file mode 100644 index 0000000..59c80fd --- /dev/null +++ b/blender-build/build_environment/patches/igc_opencl_clang.diff @@ -0,0 +1,44 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 1e972e6..84f9674 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -147,21 +147,24 @@ if(NOT USE_PREBUILT_LLVM) + ) + endif() + +- set(SPIRV_BASE_REVISION llvm_release_140) +- set(TARGET_BRANCH "ocl-open-140") +- get_filename_component(LLVM_MONOREPO_DIR ${LLVM_SOURCE_DIR} DIRECTORY) +- set(LLVM_PATCHES_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/patches/llvm +- ${CMAKE_CURRENT_SOURCE_DIR}/patches/clang) +- apply_patches(${LLVM_MONOREPO_DIR} +- "${LLVM_PATCHES_DIRS}" +- ${LLVM_BASE_REVISION} +- ${TARGET_BRANCH} +- ret) +- apply_patches(${SPIRV_SOURCE_DIR} +- ${CMAKE_CURRENT_SOURCE_DIR}/patches/spirv +- ${SPIRV_BASE_REVISION} +- ${TARGET_BRANCH} +- ret) ++ # ++ # Blender: We apply these manually in igc.cmake ++ # ++ #set(SPIRV_BASE_REVISION llvm_release_140) ++ #set(TARGET_BRANCH "ocl-open-140") ++ #get_filename_component(LLVM_MONOREPO_DIR ${LLVM_SOURCE_DIR} DIRECTORY) ++ #set(LLVM_PATCHES_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/patches/llvm ++ # ${CMAKE_CURRENT_SOURCE_DIR}/patches/clang) ++ #apply_patches(${LLVM_MONOREPO_DIR} ++ # "${LLVM_PATCHES_DIRS}" ++ # ${LLVM_BASE_REVISION} ++ # ${TARGET_BRANCH} ++ # ret) ++ #apply_patches(${SPIRV_SOURCE_DIR} ++ # ${CMAKE_CURRENT_SOURCE_DIR}/patches/spirv ++ # ${SPIRV_BASE_REVISION} ++ # ${TARGET_BRANCH} ++ # ret) + endif(NOT USE_PREBUILT_LLVM) + + # diff --git a/blender-build/build_environment/patches/ispc.diff b/blender-build/build_environment/patches/ispc.diff new file mode 100644 index 0000000..d0c0940 --- /dev/null +++ b/blender-build/build_environment/patches/ispc.diff @@ -0,0 +1,78 @@ +diff -Naur ispc-1.17.0.org/CMakeLists.txt ispc-1.17.0/CMakeLists.txt +--- ispc-1.17.0.org/CMakeLists.txt 2022-01-15 01:35:15 -0700 ++++ ispc-1.17.0/CMakeLists.txt 2022-02-12 12:44:24 -0700 +@@ -36,8 +36,12 @@ + cmake_minimum_required(VERSION 3.13) + + if (UNIX) +- set(CMAKE_C_COMPILER "clang") +- set(CMAKE_CXX_COMPILER "clang++") ++ if (NOT CMAKE_C_COMPILER) ++ set(CMAKE_C_COMPILER "clang") ++ endif() ++ if (NOT CMAKE_CXX_COMPILER) ++ set(CMAKE_CXX_COMPILER "clang++") ++ endif() + endif() + + set(PROJECT_NAME ispc) +@@ -443,7 +447,7 @@ + + # Include directories + target_include_directories(${PROJECT_NAME} PRIVATE +- ${LLVM_INCLUDE_DIRS} ++ ${LLVM_INCLUDE_DIRS} ${CLANG_INCLUDE_DIRS} + ${XE_DEPS_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/src + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}) +@@ -507,7 +511,7 @@ + + # Link against Clang libraries + foreach(clangLib ${CLANG_LIBRARY_LIST}) +- find_library(${clangLib}Path NAMES ${clangLib} HINTS ${LLVM_LIBRARY_DIRS}) ++ find_library(${clangLib}Path NAMES ${clangLib} HINTS ${LLVM_LIBRARY_DIRS} ${CLANG_LIBRARY_DIR}) + list(APPEND CLANG_LIBRARY_FULL_PATH_LIST ${${clangLib}Path}) + endforeach() + target_link_libraries(${PROJECT_NAME} ${CLANG_LIBRARY_FULL_PATH_LIST}) +@@ -546,6 +550,29 @@ + endif() + endif() + ++# Link against libstdc++.a which must be provided to the linker after ++# LLVM and CLang libraries. ++# This is needed because some of LLVM/CLang dependencies are using ++# std::make_shared, which is defined in one of those: ++# - libclang-cpp.so ++# - libstdc++.a ++# Using the former one is tricky because then generated binary depends ++# on a library which is outside of the LD_LIBRARY_PATH. ++# ++# Hence, using C++ implementation from G++ which seems to work just fine. ++# In fact, from investigation seems that libclang-cpp.so itself is pulling ++# std::_Sp_make_shared_tag from G++'s libstdc++.a. ++if(UNIX AND NOT APPLE) ++ execute_process( ++ COMMAND g++ --print-file-name libstdc++.a ++ OUTPUT_VARIABLE GCC_LIBSTDCXX_A ++ OUTPUT_STRIP_TRAILING_WHITESPACE ++ ) ++ if(GCC_LIBSTDCXX_A AND EXISTS ${GCC_LIBSTDCXX_A}) ++ target_link_libraries(${PROJECT_NAME} ${GCC_LIBSTDCXX_A}) ++ endif() ++endif() ++ + # Build target for utility checking host ISA + if (ISPC_INCLUDE_UTILS) + add_executable(check_isa "") +diff -Naur ispc-1.17.0.org/cmake/GenerateBuiltins.cmake ispc-1.17.0/cmake/GenerateBuiltins.cmake +--- ispc-1.17.0.org/cmake/GenerateBuiltins.cmake 2022-01-15 01:35:15 -0700 ++++ ispc-1.17.0/cmake/GenerateBuiltins.cmake 2022-02-12 12:44:24 -0700 +@@ -124,6 +124,8 @@ + + if ("${bit}" STREQUAL "32" AND ${arch} STREQUAL "x86") + set(target_arch "i686") ++ # Blender: disable 32bit due to build issues on Linux and being unnecessary. ++ set(SKIP ON) + elseif ("${bit}" STREQUAL "64" AND ${arch} STREQUAL "x86") + set(target_arch "x86_64") + elseif ("${bit}" STREQUAL "32" AND ${arch} STREQUAL "arm") diff --git a/blender-build/build_environment/patches/level-zero.diff b/blender-build/build_environment/patches/level-zero.diff new file mode 100644 index 0000000..2268016 --- /dev/null +++ b/blender-build/build_environment/patches/level-zero.diff @@ -0,0 +1,13 @@ +diff -Naur external_levelzero_org/CMakeLists.txt external_levelzero/CMakeLists.txt +--- external_levelzero_org/CMakeLists.txt 2022-03-07 13:22:11 -0700 ++++ external_levelzero/CMakeLists.txt 2022-03-29 13:22:15 -0600 +@@ -77,9 +77,6 @@ + #enabling Control Flow Guard + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /guard:cf") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /guard:cf") +- # enable Spectre Mitigation +- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Qspectre") +- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Qspectre") + endif() + + #CXX compiler support \ No newline at end of file diff --git a/blender-build/build_environment/patches/llvm.diff b/blender-build/build_environment/patches/llvm.diff new file mode 100644 index 0000000..5f89816 --- /dev/null +++ b/blender-build/build_environment/patches/llvm.diff @@ -0,0 +1,13 @@ +--- a/llvm/lib/Support/Unix/Path.inc 2020-02-17 09:24:26.000000000 +0100 ++++ b/llvm/lib/Support/Unix/Path.inc 2020-02-17 09:26:25.000000000 +0100 +@@ -1200,7 +1200,9 @@ + /// implementation. + std::error_code copy_file(const Twine &From, const Twine &To) { + uint32_t Flag = COPYFILE_DATA; +-#if __has_builtin(__builtin_available) && defined(COPYFILE_CLONE) ++ // BLENDER: This optimization makes LLVM not build on older Xcode versions, ++ // just disable until everyone has new enough Xcode versions. ++#if 0 + if (__builtin_available(macos 10.12, *)) { + bool IsSymlink; + if (std::error_code Error = is_symlink_file(From, IsSymlink)) diff --git a/blender-build/build_environment/patches/materialx.diff b/blender-build/build_environment/patches/materialx.diff new file mode 100644 index 0000000..024d4b6 --- /dev/null +++ b/blender-build/build_environment/patches/materialx.diff @@ -0,0 +1,13 @@ +diff -Naur orig/source/PyMaterialX/PyBind11/tools/FindPythonLibsNew.cmake external_materialx/source/PyMaterialX/PyBind11/tools/FindPythonLibsNew.cmake +--- orig/source/PyMaterialX/PyBind11/tools/FindPythonLibsNew.cmake 2022-11-04 14:23:29 -0600 ++++ external_materialx/source/PyMaterialX/PyBind11/tools/FindPythonLibsNew.cmake 2022-11-08 11:58:45 -0700 +@@ -181,6 +181,9 @@ + string(REGEX REPLACE "\\\\" "/" PYTHON_SITE_PACKAGES "${PYTHON_SITE_PACKAGES}") + + if(CMAKE_HOST_WIN32) ++ if(PYTHON_EXECUTABLE MATCHES "_d.exe$") ++ set(PYTHON_LIBRARY_SUFFIX ${PYTHON_LIBRARY_SUFFIX}_d) ++ endif() + set(PYTHON_LIBRARY "${PYTHON_PREFIX}/libs/python${PYTHON_LIBRARY_SUFFIX}.lib") + + # when run in a venv, PYTHON_PREFIX points to it. But the libraries remain in the \ No newline at end of file diff --git a/blender-build/build_environment/patches/ming32sh.cmd b/blender-build/build_environment/patches/ming32sh.cmd new file mode 100644 index 0000000..3259d9d --- /dev/null +++ b/blender-build/build_environment/patches/ming32sh.cmd @@ -0,0 +1,7 @@ +@title MinGW-w64 32-bit GCC build environment + +@echo Setting up environment for MinGW-w64 GCC 32-bit... + +@set PATH=%CD%\bin;%CD%\msys\1.0\bin;%cd%\..\..\perl32\site\bin;%cd%\..\..\perl32\bin;%cd%\..\..\c\bin;%PATH% + + diff --git a/blender-build/build_environment/patches/ming64sh.cmd b/blender-build/build_environment/patches/ming64sh.cmd new file mode 100644 index 0000000..18fea38 --- /dev/null +++ b/blender-build/build_environment/patches/ming64sh.cmd @@ -0,0 +1,7 @@ +@title MinGW-w64 64-bit GCC build environment + +@echo Setting up environment for MinGW-w64 GCC 64-bit... + +@set PATH=%CD%\bin;%CD%\msys\1.0\bin;%cd%\..\..\perl\site\bin;%cd%\..\..\perl\bin;%cd%\..\..\c\bin;%PATH% + + diff --git a/blender-build/build_environment/patches/nasm.diff b/blender-build/build_environment/patches/nasm.diff new file mode 100644 index 0000000..821e1a1 --- /dev/null +++ b/blender-build/build_environment/patches/nasm.diff @@ -0,0 +1,129 @@ +diff --git a/output/macho.h b/output/macho.h +index 538c531e..fd5e8849 100644 +--- a/output/macho.h ++++ b/output/macho.h +@@ -60,6 +60,8 @@ + #define LC_SEGMENT 0x1 + #define LC_SEGMENT_64 0x19 + #define LC_SYMTAB 0x2 ++#define LC_VERSION_MIN_MACOSX 0x24 ++#define LC_BUILD_VERSION 0x32 + + /* Symbol type bits */ + #define N_STAB 0xe0 +diff --git a/output/outmacho.c b/output/outmacho.c +index 08147883..de6ec902 100644 +--- a/output/outmacho.c ++++ b/output/outmacho.c +@@ -38,6 +38,8 @@ + + #include "compiler.h" + ++#include ++ + #include "nctype.h" + + #include "nasm.h" +@@ -64,6 +66,8 @@ + #define MACHO_SYMCMD_SIZE 24 + #define MACHO_NLIST_SIZE 12 + #define MACHO_RELINFO_SIZE 8 ++#define MACHO_BUILD_VERSION_SIZE 24 ++#define MACHO_VERSION_MIN_MACOSX_SIZE 16 + + #define MACHO_HEADER64_SIZE 32 + #define MACHO_SEGCMD64_SIZE 72 +@@ -1224,6 +1228,46 @@ static void macho_layout_symbols (uint32_t *numsyms, + } + } + ++static bool get_full_version_from_env (const char *variable_name, ++ int *r_major, ++ int *r_minor, ++ int *r_patch) { ++ *r_major = 0; ++ *r_minor = 0; ++ *r_patch = 0; ++ ++ const char *value = getenv(variable_name); ++ if (value == NULL || value[0] == '\0') { ++ return false; ++ } ++ ++ const char *current_value = value; ++ const char *end_value = value + strlen(value); ++ ++ char *endptr; ++ ++ *r_major = strtol(current_value, &endptr, 10); ++ if (endptr >= end_value) { ++ return true; ++ } ++ current_value = endptr + 1; ++ ++ *r_minor = strtol(current_value, &endptr, 10); ++ if (endptr >= end_value) { ++ return true; ++ } ++ current_value = endptr + 1; ++ ++ *r_patch = strtol(current_value, &endptr, 10); ++ ++ return true; ++} ++ ++static bool need_version_min_macosx_command (void) { ++ return getenv("MACOSX_DEPLOYMENT_TARGET") && ++ getenv("MACOSX_SDK_VERSION"); ++} ++ + /* Calculate some values we'll need for writing later. */ + + static void macho_calculate_sizes (void) +@@ -1270,6 +1314,12 @@ static void macho_calculate_sizes (void) + head_sizeofcmds += fmt.segcmd_size + seg_nsects * fmt.sectcmd_size; + } + ++ /* LC_VERSION_MIN_MACOSX */ ++ if (need_version_min_macosx_command()) { ++ ++head_ncmds; ++ head_sizeofcmds += MACHO_VERSION_MIN_MACOSX_SIZE; ++ } ++ + if (nsyms > 0) { + ++head_ncmds; + head_sizeofcmds += MACHO_SYMCMD_SIZE; +@@ -1653,6 +1703,33 @@ static void macho_write (void) + else + nasm_warn(WARN_OTHER, "no sections?"); + ++#define ENCODE_BUILD_VERSION(major, minor, patch) \ ++ (((major) << 16) | ((minor) << 8) | (patch)) ++ ++ if (0) { ++ fwriteint32_t(LC_BUILD_VERSION, ofile); /* cmd == LC_BUILD_VERSION */ ++ fwriteint32_t(MACHO_BUILD_VERSION_SIZE, ofile); /* size of load command */ ++ fwriteint32_t(1, ofile); /* platform */ ++ fwriteint32_t(ENCODE_BUILD_VERSION(10, 13, 0), ofile); /* minos, X.Y.Z is encoded in nibbles xxxx.yy.zz */ ++ fwriteint32_t(ENCODE_BUILD_VERSION(10, 15, 4), ofile); /* sdk, X.Y.Z is encoded in nibbles xxxx.yy.zz */ ++ fwriteint32_t(0, ofile); /* number of tool entries following this */ ++ } ++ ++ if (need_version_min_macosx_command()) { ++ int sdk_major, sdk_minor, sdk_patch; ++ get_full_version_from_env("MACOSX_SDK_VERSION", &sdk_major, &sdk_minor, &sdk_patch); ++ ++ int version_major, version_minor, version_patch; ++ get_full_version_from_env("MACOSX_DEPLOYMENT_TARGET", &version_major, &version_minor, &version_patch); ++ ++ fwriteint32_t(LC_VERSION_MIN_MACOSX, ofile); /* cmd == LC_VERSION_MIN_MACOSX */ ++ fwriteint32_t(MACHO_VERSION_MIN_MACOSX_SIZE, ofile); /* size of load command */ ++ fwriteint32_t(ENCODE_BUILD_VERSION(version_major, version_minor, version_patch), ofile); /* minos, X.Y.Z is encoded in nibbles xxxx.yy.zz */ ++ fwriteint32_t(ENCODE_BUILD_VERSION(sdk_major, sdk_minor, sdk_patch), ofile); /* sdk, X.Y.Z is encoded in nibbles xxxx.yy.zz */ ++ } ++ ++#undef ENCODE_BUILD_VERSION ++ + if (nsyms > 0) { + /* write out symbol command */ + fwriteint32_t(LC_SYMTAB, ofile); /* cmd == LC_SYMTAB */ diff --git a/blender-build/build_environment/patches/ocloc.diff b/blender-build/build_environment/patches/ocloc.diff new file mode 100644 index 0000000..11fb8a6 --- /dev/null +++ b/blender-build/build_environment/patches/ocloc.diff @@ -0,0 +1,14 @@ +diff --git a/shared/offline_compiler/source/ocloc_fatbinary.cpp b/shared/offline_compiler/source/ocloc_fatbinary.cpp +index 98a1c0e..4d9b5b0 100644 +--- a/shared/offline_compiler/source/ocloc_fatbinary.cpp ++++ b/shared/offline_compiler/source/ocloc_fatbinary.cpp +@@ -286,7 +286,9 @@ int buildFatBinaryForTarget(int retVal, const std::vector &argsCopy + productConfig = ProductConfigHelper::parseMajorMinorRevisionValue(argHelper->productConfigHelper->getProductConfigFromDeviceName(product)); + } + +- fatbinary.appendFileEntry(pointerSize + "." + productConfig, pCompiler->getPackedDeviceBinaryOutput()); ++ // Storing binaries under the hardware prefix instead of the full architecture version number, ++ // as they would otherwise be ignored if they do not fully match that of the execution device. ++ fatbinary.appendFileEntry(pointerSize + "." + NEO::hardwarePrefix[argHelper->productConfigHelper->getProductFamilyFromDeviceName(productConfig)], pCompiler->getPackedDeviceBinaryOutput()); + return retVal; + } diff --git a/blender-build/build_environment/patches/ogg.diff b/blender-build/build_environment/patches/ogg.diff new file mode 100644 index 0000000..fca426e --- /dev/null +++ b/blender-build/build_environment/patches/ogg.diff @@ -0,0 +1,12 @@ +diff --git a/include/ogg/os_types.h b/include/ogg/os_types.h +index eb8a322..6f73b72 100644 +--- a/include/ogg/os_types.h ++++ b/include/ogg/os_types.h +@@ -71,6 +71,7 @@ + #elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ + + # include ++# include + typedef int16_t ogg_int16_t; + typedef uint16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; diff --git a/blender-build/build_environment/patches/oiio_3984.diff b/blender-build/build_environment/patches/oiio_3984.diff new file mode 100644 index 0000000..dd7897c --- /dev/null +++ b/blender-build/build_environment/patches/oiio_3984.diff @@ -0,0 +1,13 @@ +diff --git a/src/libOpenImageIO/exif.cpp b/src/libOpenImageIO/exif.cpp +index 90eaaec6e9..1fbf04140e 100644 +--- a/src/libOpenImageIO/exif.cpp ++++ b/src/libOpenImageIO/exif.cpp +@@ -1302,6 +1302,8 @@ encode_exif(const ImageSpec& spec, std::vector& blob, + TIFFHeader head; + head.tiff_magic = (endianreq == endian::little) ? 0x4949 : 0x4d4d; + head.tiff_version = 42; ++ if (endianreq != endian::native) ++ swap_endian(&head.tiff_version); + // N.B. need to swap_endian head.tiff_diroff below, once we know the sizes + append(blob, head); + diff --git a/blender-build/build_environment/patches/oiio_3996.diff b/blender-build/build_environment/patches/oiio_3996.diff new file mode 100644 index 0000000..0e50be6 --- /dev/null +++ b/blender-build/build_environment/patches/oiio_3996.diff @@ -0,0 +1,29 @@ +diff --git a/src/include/OpenImageIO/fmath.h b/src/include/OpenImageIO/fmath.h +index 0bd71ba9b..419e5e378 100644 +--- a/src/include/OpenImageIO/fmath.h ++++ b/src/include/OpenImageIO/fmath.h +@@ -1229,6 +1229,7 @@ convert_type (const S &src) + /// shifted fully to the right. + template + inline OIIO_HOSTDEVICE unsigned int bit_range_convert(unsigned int in) { ++ static_assert(FROM_BITS > 0, "FROM_BITS cannot be 0"); + unsigned int out = 0; + int shift = TO_BITS - FROM_BITS; + for (; shift > 0; shift -= FROM_BITS) +@@ -1244,10 +1245,12 @@ inline OIIO_HOSTDEVICE unsigned int + bit_range_convert(unsigned int in, unsigned int FROM_BITS, unsigned int TO_BITS) + { + unsigned int out = 0; +- int shift = TO_BITS - FROM_BITS; +- for (; shift > 0; shift -= FROM_BITS) +- out |= in << shift; +- out |= in >> -shift; ++ if (FROM_BITS) { ++ int shift = TO_BITS - FROM_BITS; ++ for (; shift > 0; shift -= FROM_BITS) ++ out |= in << shift; ++ out |= in >> -shift; ++ } + return out; + } + diff --git a/blender-build/build_environment/patches/oiio_deadlock.diff b/blender-build/build_environment/patches/oiio_deadlock.diff new file mode 100644 index 0000000..cfaa6fd --- /dev/null +++ b/blender-build/build_environment/patches/oiio_deadlock.diff @@ -0,0 +1,62 @@ +diff -Naur orig/src/idiff/idiff.cpp external_openimageio/src/idiff/idiff.cpp +--- orig/src/idiff/idiff.cpp 2023-06-07 07:47:42 -0600 ++++ external_openimageio/src/idiff/idiff.cpp 2023-06-07 09:46:47 -0600 +@@ -399,5 +399,6 @@ + + imagecache->invalidate_all(true); + ImageCache::destroy(imagecache); ++ default_thread_pool()->resize(0); + return ret; + } +diff -Naur orig/src/libutil/thread.cpp external_openimageio/src/libutil/thread.cpp +--- orig/src/libutil/thread.cpp 2023-06-07 07:47:42 -0600 ++++ external_openimageio/src/libutil/thread.cpp 2023-06-07 09:45:39 -0600 +@@ -151,9 +151,10 @@ + this->set_thread(i); + } + } else { // the number of threads is decreased ++ std::vector> terminating_threads; + for (int i = oldNThreads - 1; i >= nThreads; --i) { + *this->flags[i] = true; // this thread will finish +- this->terminating_threads.push_back( ++ terminating_threads.push_back( + std::move(this->threads[i])); + this->threads.erase(this->threads.begin() + i); + } +@@ -162,6 +163,11 @@ + std::unique_lock lock(this->mutex); + this->cv.notify_all(); + } ++ // wait for the terminated threads to finish ++ for (auto& thread : terminating_threads) { ++ if (thread->joinable()) ++ thread->join(); ++ } + this->threads.resize( + nThreads); // safe to delete because the threads are detached + this->flags.resize( +@@ -238,16 +244,10 @@ + if (thread->joinable()) + thread->join(); + } +- // wait for the terminated threads to finish +- for (auto& thread : this->terminating_threads) { +- if (thread->joinable()) +- thread->join(); +- } + // if there were no threads in the pool but some functors in the queue, the functors are not deleted by the threads + // therefore delete them here + this->clear_queue(); + this->threads.clear(); +- this->terminating_threads.clear(); + this->flags.clear(); + } + +@@ -349,7 +349,6 @@ + } + + std::vector> threads; +- std::vector> terminating_threads; + std::vector>> flags; + mutable pvt::ThreadsafeQueue*> q; + std::atomic isDone; diff --git a/blender-build/build_environment/patches/oiio_webp.diff b/blender-build/build_environment/patches/oiio_webp.diff new file mode 100644 index 0000000..5adfc7d --- /dev/null +++ b/blender-build/build_environment/patches/oiio_webp.diff @@ -0,0 +1,78 @@ +diff -Naur oiio-2.4.15.0/src/cmake/modules/FindWebP.cmake external_openimageio/src/cmake/modules/FindWebP.cmake +--- oiio-2.4.15.0/src/cmake/modules/FindWebP.cmake 2023-09-01 10:48:29.000000000 -0600 ++++ external_openimageio/src/cmake/modules/FindWebP.cmake 2023-09-21 14:47:19.366083900 -0600 +@@ -25,15 +25,30 @@ + ENV WEBP_INCLUDE_PATH + DOC "The directory where Webp headers reside") + +-find_library (WEBP_LIBRARY webp ++find_library (WEBP_LIBRARY ++ NAMES ++ webp ++ libwebp + HINTS + ${WEBP_LIBRARY_PATH} + ENV WEBP_LIBRARY_PATH) +-find_library (WEBPDEMUX_LIBRARY webpdemux ++find_library (WEBPDEMUX_LIBRARY ++ NAMES ++ webpdemux ++ libwebpdemux ++ HINTS ++ ${WEBP_LIBRARY_PATH} ++ ENV WEBP_LIBRARY_PATH) ++# New in WebP 1.3 ++find_library (WEBP_SHARPYUV_LIBRARY ++ NAMES ++ sharpyuv ++ libsharpyuv + HINTS + ${WEBP_LIBRARY_PATH} + ENV WEBP_LIBRARY_PATH) + ++ + include (FindPackageHandleStandardArgs) + find_package_handle_standard_args (WebP + REQUIRED_VARS WEBP_INCLUDE_DIR +@@ -42,7 +57,7 @@ + + if (WebP_FOUND) + set (WEBP_INCLUDES "${WEBP_INCLUDE_DIR}") +- set (WEBP_LIBRARIES ${WEBP_LIBRARY} ${WEBPDEMUX_LIBRARY}) ++ set (WEBP_LIBRARIES ${WEBP_LIBRARY} ${WEBPDEMUX_LIBRARY} ${WEBP_SHARPYUV_LIBRARY}) + + if (NOT TARGET WebP::webp) + add_library(WebP::webp UNKNOWN IMPORTED) +@@ -58,10 +73,18 @@ + set_property(TARGET WebP::webpdemux APPEND PROPERTY + IMPORTED_LOCATION ${WEBPDEMUX_LIBRARY}) + endif () ++ if (WEBP_SHARPYUV_LIBRARY AND NOT TARGET WebP::sharpyuv) ++ add_library(WebP::sharpyuv UNKNOWN IMPORTED) ++ set_target_properties(WebP::sharpyuv PROPERTIES ++ INTERFACE_INCLUDE_DIRECTORIES ${WEBP_INCLUDES}) ++ set_property(TARGET WebP::sharpyuv APPEND PROPERTY ++ IMPORTED_LOCATION ${WEBP_SHARPYUV_LIBRARY}) ++ endif () + endif () + + mark_as_advanced ( + WEBP_INCLUDE_DIR + WEBP_LIBRARY + WEBPDEMUX_LIBRARY ++ WEBP_SHARPYUV_LIBRARY + ) + +diff --git a/src/webp.imageio/CMakeLists.txt b/src/webp.imageio/CMakeLists.txt +index ccf1146..c646e99 100644 +--- a/src/webp.imageio/CMakeLists.txt ++++ b/src/webp.imageio/CMakeLists.txt +@@ -4,7 +4,7 @@ + + if (WebP_FOUND) + add_oiio_plugin (webpinput.cpp webpoutput.cpp +- LINK_LIBRARIES WebP::webp WebP::webpdemux ++ LINK_LIBRARIES WebP::webp WebP::webpdemux WebP::sharpyuv + DEFINITIONS "-DUSE_WEBP=1") + else () + message (STATUS "WebP plugin will not be built") diff --git a/blender-build/build_environment/patches/opencollada.diff b/blender-build/build_environment/patches/opencollada.diff new file mode 100644 index 0000000..edb831d --- /dev/null +++ b/blender-build/build_environment/patches/opencollada.diff @@ -0,0 +1,169 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 95abbe2..4f14f30 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -254,11 +254,11 @@ if(USE_STATIC_MSVC_RUNTIME) + endif() + + #adding PCRE +-find_package(PCRE) ++#find_package(PCRE) + if (PCRE_FOUND) + message(STATUS "SUCCESSFUL: PCRE found") + else () # if pcre not found building its local copy from ./Externals +- if (WIN32 OR APPLE) ++ if (1) + message("WARNING: Native PCRE not found, taking PCRE from ./Externals") + add_definitions(-DPCRE_STATIC) + add_subdirectory(${EXTERNAL_LIBRARIES}/pcre) +diff --git a/DAEValidator/CMakeLists.txt b/DAEValidator/CMakeLists.txt +index 03ad540..f7d05cf 100644 +--- a/DAEValidator/CMakeLists.txt ++++ b/DAEValidator/CMakeLists.txt +@@ -98,7 +98,7 @@ if (WIN32) + # C4710: 'function' : function not inlined + # C4711: function 'function' selected for inline expansion + # C4820: 'bytes' bytes padding added after construct 'member_name' +- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /Wall /WX /wd4505 /wd4514 /wd4592 /wd4710 /wd4711 /wd4820") ++ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /Wall /wd4505 /wd4514 /wd4592 /wd4710 /wd4711 /wd4820") + else () + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Werror") + endif () +diff --git a/DAEValidator/library/include/no_warning_begin b/DAEValidator/library/include/no_warning_begin +index 7a69c32..defb315 100644 +--- a/DAEValidator/library/include/no_warning_begin ++++ b/DAEValidator/library/include/no_warning_begin +@@ -2,6 +2,9 @@ + #if defined(_WIN32) + # pragma warning(push) + # pragma warning(disable:4668) ++# if _MSC_VER >=1900 ++# pragma warning(disable:5031) ++# endif + # if defined(_MSC_VER) && defined(_DEBUG) + # pragma warning(disable:4548) + # endif +diff --git a/DAEValidator/library/src/ArgumentParser.cpp b/DAEValidator/library/src/ArgumentParser.cpp +index 897e4dc..98a69ff 100644 +--- a/DAEValidator/library/src/ArgumentParser.cpp ++++ b/DAEValidator/library/src/ArgumentParser.cpp +@@ -6,10 +6,10 @@ + + using namespace std; + +-#ifdef _MSC_VER +-#define NOEXCEPT _NOEXCEPT +-#else ++#ifndef _NOEXCEPT + #define NOEXCEPT noexcept ++#else ++#define NOEXCEPT _NOEXCEPT + #endif + + namespace opencollada +diff --git a/Externals/LibXML/CMakeLists.txt b/Externals/LibXML/CMakeLists.txt +index 40081e7..e1d1bfa 100644 +--- a/Externals/LibXML/CMakeLists.txt ++++ b/Externals/LibXML/CMakeLists.txt +@@ -9,6 +9,7 @@ add_definitions( + -DLIBXML_SCHEMAS_ENABLED + -DLIBXML_XPATH_ENABLED + -DLIBXML_TREE_ENABLED ++ -DLIBXML_STATIC + ) + + if(USE_STATIC_MSVC_RUNTIME) +diff --git a/GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp b/GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp +index 1f9a3ee..d151e9a 100644 +--- a/GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp ++++ b/GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp +@@ -1553,7 +1553,7 @@ namespace GeneratedSaxParser + #if defined(COLLADABU_OS_WIN) && !defined(__MINGW32__) + return _isnan( value ) ? true : false; + #else +-#ifdef isnan ++#if defined(isnan) || defined(__APPLE__) + return isnan( value ); + #else + return std::isnan(value); + + +diff --git a/DAEValidator/library/src/Dae.cpp b/DAEValidator/library/src/Dae.cpp +index 9256ee1..241ad67 100644 +--- a/DAEValidator/library/src/Dae.cpp ++++ b/DAEValidator/library/src/Dae.cpp +@@ -304,7 +304,7 @@ namespace opencollada + if (auto root_node = root()) + { + const auto & nodes = root_node.selectNodes("//*[@id]"); +- for (const auto & node : nodes) ++ for (const auto node : nodes) + { + string id = node.attribute("id").value(); + mIdCache.insert(id); +@@ -312,4 +312,4 @@ namespace opencollada + } + } + } +-} +\ No newline at end of file ++} +diff --git a/DAEValidator/library/src/DaeValidator.cpp b/DAEValidator/library/src/DaeValidator.cpp +index 715d903..24423ce 100644 +--- a/DAEValidator/library/src/DaeValidator.cpp ++++ b/DAEValidator/library/src/DaeValidator.cpp +@@ -162,7 +162,7 @@ namespace opencollada + + // Find xsi:schemaLocation attributes in dae and try to validate against specified xsd documents + const auto & elements = dae.root().selectNodes("//*[@xsi:schemaLocation]"); +- for (const auto & element : elements) ++ for (const auto element : elements) + { + if (auto schemaLocation = element.attribute("schemaLocation")) + { +@@ -274,7 +274,7 @@ namespace opencollada + int result = 0; + map ids; + const auto & nodes = dae.root().selectNodes("//*[@id]"); +- for (const auto & node : nodes) ++ for (const auto node : nodes) + { + string id = node.attribute("id").value(); + size_t line = node.line(); +diff -Naur a/CMakeLists.txt b/CMakeLists.txt +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -274,7 +274,7 @@ + add_subdirectory(${EXTERNAL_LIBRARIES}/UTF) + add_subdirectory(common/libBuffer) + add_subdirectory(${EXTERNAL_LIBRARIES}/MathMLSolver) +-add_subdirectory(${EXTERNAL_LIBRARIES}/zlib) ++#add_subdirectory(${EXTERNAL_LIBRARIES}/zlib) + + # building OpenCOLLADA libs + add_subdirectory(COLLADABaseUtils) +@@ -284,10 +284,10 @@ + add_subdirectory(COLLADAStreamWriter) + + # building COLLADAValidator app +-add_subdirectory(COLLADAValidator) ++#add_subdirectory(COLLADAValidator) + + # DAE validator app +-add_subdirectory(DAEValidator) ++#add_subdirectory(DAEValidator) + + # Library export + install(EXPORT LibraryExport DESTINATION ${OPENCOLLADA_INST_CMAKECONFIG} FILE OpenCOLLADATargets.cmake) +diff -Naur OpenCOLLADA-1.6.68/common/libBuffer/include/CommonFWriteBufferFlusher.h external_opencollada/common/libBuffer/include/CommonFWriteBufferFlusher.h +--- OpenCOLLADA-1.6.68/common/libBuffer/include/CommonFWriteBufferFlusher.h 2018-11-26 14:43:10 -0700 ++++ external_opencollada/common/libBuffer/include/CommonFWriteBufferFlusher.h 2022-08-19 11:36:04 -0600 +@@ -23,7 +23,7 @@ + # include + #endif + +-#ifdef _LIBCPP_VERSION ++#if defined(_LIBCPP_VERSION) || defined(WIN32) + // If we're compiling with libc++, create a namespace alias for tr1 that points to std. + // Not particularly elegant, and largely should be filed under "hack", but it works for OS X with clang for now. + namespace std { \ No newline at end of file diff --git a/blender-build/build_environment/patches/opencolorio.diff b/blender-build/build_environment/patches/opencolorio.diff new file mode 100644 index 0000000..278dfe0 --- /dev/null +++ b/blender-build/build_environment/patches/opencolorio.diff @@ -0,0 +1,28 @@ +diff --git a/share/cmake/modules/Findpystring.cmake b/share/cmake/modules/Findpystring.cmake +index 7b894a45..92618215 100644 +--- a/share/cmake/modules/Findpystring.cmake ++++ b/share/cmake/modules/Findpystring.cmake +@@ -113,6 +113,11 @@ if(NOT pystring_FOUND) + -DCMAKE_INSTALL_MESSAGE=${CMAKE_INSTALL_MESSAGE} + -DCMAKE_INSTALL_PREFIX=${_EXT_DIST_ROOT} + -DCMAKE_OBJECT_PATH_MAX=${CMAKE_OBJECT_PATH_MAX} ++ -DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES} ++ -DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET} ++ -DCMAKE_OSX_SYSROOT=${CMAKE_OSX_SYSROOT} ++ -DCMAKE_CXX_FLAGS_DEBUG=${CMAKE_CXX_FLAGS_DEBUG} ++ -DCMAKE_CXX_FLAGS_RELEASE=${CMAKE_CXX_FLAGS_RELEASE} + ) + if(CMAKE_TOOLCHAIN_FILE) + set(pystring_CMAKE_ARGS +--- a/src/OpenColorIO/FileRules.cpp ++++ b/src/OpenColorIO/FileRules.cpp +@@ -7,6 +7,9 @@ + #include + #include + ++/* NOTE: this has been applied up-stream, this edit can be removed after upgrading OpenColorIO. */ ++#include ++ + #include + + #include "CustomKeys.h" diff --git a/blender-build/build_environment/patches/openexr_b18905772e.diff b/blender-build/build_environment/patches/openexr_b18905772e.diff new file mode 100644 index 0000000..c6e72b6 --- /dev/null +++ b/blender-build/build_environment/patches/openexr_b18905772e.diff @@ -0,0 +1,1023 @@ +From b18905772e9dd98658f8a37d16c6e53c7c17adaa Mon Sep 17 00:00:00 2001 +From: Kimball Thurston +Date: Sat, 22 Apr 2023 15:58:43 +1200 +Subject: [PATCH] Change setNumThreads to wait for thread start (#1291) + +Fix Issue #890, issue with windows shutdown when exiting quickly prior to +threads actually starting. We do this by having a data block that is passed +by shared_ptr to the thread to avoid dereferencing a deleted object. + +Further, greatly simplify the ThreadPool code by using atomic shared_ptr +functions instead of trying to manually implement something similar and +otherwise modernizing the thread code. + +Fix a few potential null dereference locations and also fix an issue when +systems are overloaded enabling the TaskGroup destructor to destroy +the semaphore while code is still using it, causing undefined memory +corruption if some other thread immediately allocates that same block + +Originally based on a proposed patch by Dieter De Baets @debaetsd + +Signed-off-by: Kimball Thurston +--- + src/lib/IlmThread/IlmThreadPool.cpp | 740 ++++++++++--------------- + src/lib/IlmThread/IlmThreadSemaphore.h | 8 +- + 2 files changed, 303 insertions(+), 445 deletions(-) + +diff --git a/src/lib/IlmThread/IlmThreadPool.cpp b/src/lib/IlmThread/IlmThreadPool.cpp +index 0ddcf8d52..f4578a510 100644 +--- a/src/lib/IlmThread/IlmThreadPool.cpp ++++ b/src/lib/IlmThread/IlmThreadPool.cpp +@@ -15,12 +15,17 @@ + #include "Iex.h" + + #include ++#include + #include + #include + #include + #include + +-using namespace std; ++#if (defined(_WIN32) || defined(_WIN64)) ++# include ++#else ++# include ++#endif + + ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER + +@@ -28,380 +33,301 @@ ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER + # define ENABLE_THREADING + #endif + +-#if defined(__GNU_LIBRARY__) && ( __GLIBC__ < 2 || ( __GLIBC__ == 2 && __GLIBC_MINOR__ < 21 ) ) +-# define ENABLE_SEM_DTOR_WORKAROUND +-#endif +- +-#ifdef ENABLE_THREADING +- +-struct TaskGroup::Data ++namespace + { +- Data (); +- ~Data (); +- +- void addTask () ; +- void removeTask (); +- std::atomic numPending; +- Semaphore isEmpty; // used to signal that the taskgroup is empty +-#if defined(ENABLE_SEM_DTOR_WORKAROUND) +- // this mutex is also used to lock numPending in the legacy c++ mode... +- std::mutex dtorMutex; // used to work around the glibc bug: +- // http://sources.redhat.com/bugzilla/show_bug.cgi?id=12674 +-#endif +-}; + +- +-struct ThreadPool::Data ++static inline void ++handleProcessTask (Task* task) + { +- typedef ThreadPoolProvider *TPPointer; +- +- Data (); +- ~Data(); +- Data (const Data&) = delete; +- Data &operator= (const Data&) = delete; +- Data (Data&&) = delete; +- Data &operator= (Data&&) = delete; +- +- struct SafeProvider ++ if (task) + { +- SafeProvider (Data *d, ThreadPoolProvider *p) : _data( d ), _ptr( p ) +- { +- } +- +- ~SafeProvider() +- { +- if ( _data ) +- _data->coalesceProviderUse(); +- } +- SafeProvider (const SafeProvider &o) +- : _data( o._data ), _ptr( o._ptr ) +- { +- if ( _data ) +- _data->bumpProviderUse(); +- } +- SafeProvider &operator= (const SafeProvider &o) +- { +- if ( this != &o ) +- { +- if ( o._data ) +- o._data->bumpProviderUse(); +- if ( _data ) +- _data->coalesceProviderUse(); +- _data = o._data; +- _ptr = o._ptr; +- } +- return *this; +- } +- SafeProvider( SafeProvider &&o ) +- : _data( o._data ), _ptr( o._ptr ) +- { +- o._data = nullptr; +- } +- SafeProvider &operator=( SafeProvider &&o ) +- { +- std::swap( _data, o._data ); +- std::swap( _ptr, o._ptr ); +- return *this; +- } +- +- inline ThreadPoolProvider *get () const +- { +- return _ptr; +- } +- ThreadPoolProvider *operator-> () const +- { +- return get(); +- } +- +- Data *_data; +- ThreadPoolProvider *_ptr; +- }; +- +- // NB: In C++20, there is full support for atomic shared_ptr, but that is not +- // yet in use or finalized. Once stabilized, add appropriate usage here +- inline SafeProvider getProvider (); +- inline void coalesceProviderUse (); +- inline void bumpProviderUse (); +- inline void setProvider (ThreadPoolProvider *p); +- +- std::atomic provUsers; +- std::atomic provider; +-}; +- ++ TaskGroup* taskGroup = task->group (); + ++ task->execute (); + +-namespace { ++ // kill the task prior to notifying the group ++ // such that any internal reference-based ++ // semantics will be handled prior to ++ // the task group destructor letting it out ++ // of the scope of those references ++ delete task; + +-class DefaultWorkerThread; ++ if (taskGroup) taskGroup->finishOneTask (); ++ } ++} + +-struct DefaultWorkData ++#ifdef ENABLE_THREADING ++struct DefaultThreadPoolData + { +- Semaphore taskSemaphore; // threads wait on this for ready tasks +- mutable std::mutex taskMutex; // mutual exclusion for the tasks list +- vector tasks; // the list of tasks to execute ++ Semaphore _taskSemaphore; // threads wait on this for ready tasks ++ mutable std::mutex _taskMutex; // mutual exclusion for the tasks list ++ std::vector _tasks; // the list of tasks to execute + +- Semaphore threadSemaphore; // signaled when a thread starts executing +- mutable std::mutex threadMutex; // mutual exclusion for threads list +- vector threads; // the list of all threads +- +- std::atomic hasThreads; +- std::atomic stopping; ++ mutable std::mutex _threadMutex; // mutual exclusion for threads list ++ std::vector _threads; // the list of all threads ++ ++ std::atomic _threadCount; ++ std::atomic _stopping; + + inline bool stopped () const + { +- return stopping.load( std::memory_order_relaxed ); ++ return _stopping.load (std::memory_order_relaxed); + } + +- inline void stop () ++ inline void stop () { _stopping = true; } ++ ++ inline void resetAtomics () + { +- stopping = true; ++ _threadCount = 0; ++ _stopping = false; + } + }; ++#endif + +-// +-// class WorkerThread +-// +-class DefaultWorkerThread: public Thread ++} // namespace ++ ++#ifdef ENABLE_THREADING ++ ++struct TaskGroup::Data + { +- public: ++ Data (); ++ ~Data (); ++ Data (const Data&) = delete; ++ Data& operator= (const Data&) = delete; ++ Data (Data&&) = delete; ++ Data& operator= (Data&&) = delete; + +- DefaultWorkerThread (DefaultWorkData* data); ++ void addTask (); ++ void removeTask (); + +- virtual void run (); +- +- private: ++ void waitForEmpty (); + +- DefaultWorkData * _data; ++ std::atomic numPending; ++ std::atomic inFlight; ++ Semaphore isEmpty; // used to signal that the taskgroup is empty + }; + + +-DefaultWorkerThread::DefaultWorkerThread (DefaultWorkData* data): +- _data (data) ++struct ThreadPool::Data + { +- start(); +-} +- ++ using ProviderPtr = std::shared_ptr; + +-void +-DefaultWorkerThread::run () +-{ +- // +- // Signal that the thread has started executing +- // ++ Data (); ++ ~Data (); ++ Data (const Data&) = delete; ++ Data& operator= (const Data&) = delete; ++ Data (Data&&) = delete; ++ Data& operator= (Data&&) = delete; + +- _data->threadSemaphore.post(); ++ ProviderPtr getProvider () const { return std::atomic_load (&_provider); } + +- while (true) ++ void setProvider (ProviderPtr provider) + { +- // +- // Wait for a task to become available +- // +- +- _data->taskSemaphore.wait(); +- +- { +- std::unique_lock taskLock (_data->taskMutex); +- +- // +- // If there is a task pending, pop off the next task in the FIFO +- // ++ ProviderPtr curp = std::atomic_exchange (&_provider, provider); ++ if (curp && curp != provider) curp->finish (); ++ } + +- if (!_data->tasks.empty()) +- { +- Task* task = _data->tasks.back(); +- _data->tasks.pop_back(); +- // release the mutex while we process +- taskLock.unlock(); ++ std::shared_ptr _provider; ++}; + +- TaskGroup* taskGroup = task->group(); +- task->execute(); + +- delete task; +- +- taskGroup->_data->removeTask (); +- } +- else if (_data->stopped()) +- { +- break; +- } +- } +- } +-} + ++namespace { + + // + // class DefaultThreadPoolProvider + // + class DefaultThreadPoolProvider : public ThreadPoolProvider + { +- public: +- DefaultThreadPoolProvider(int count); +- virtual ~DefaultThreadPoolProvider(); ++public: ++ DefaultThreadPoolProvider (int count); ++ DefaultThreadPoolProvider (const DefaultThreadPoolProvider&) = delete; ++ DefaultThreadPoolProvider& ++ operator= (const DefaultThreadPoolProvider&) = delete; ++ DefaultThreadPoolProvider (DefaultThreadPoolProvider&&) = delete; ++ DefaultThreadPoolProvider& operator= (DefaultThreadPoolProvider&&) = delete; ++ ~DefaultThreadPoolProvider () override; ++ ++ int numThreads () const override; ++ void setNumThreads (int count) override; ++ void addTask (Task* task) override; + +- virtual int numThreads() const; +- virtual void setNumThreads(int count); +- virtual void addTask(Task *task); ++ void finish () override; + +- virtual void finish(); ++private: ++ void lockedFinish (); ++ void threadLoop (std::shared_ptr d); + +- private: +- DefaultWorkData _data; ++ std::shared_ptr _data; + }; + + DefaultThreadPoolProvider::DefaultThreadPoolProvider (int count) ++ : _data (std::make_shared ()) + { +- setNumThreads(count); ++ _data->resetAtomics (); ++ setNumThreads (count); + } + + DefaultThreadPoolProvider::~DefaultThreadPoolProvider () +-{ +- finish(); +-} ++{} + + int + DefaultThreadPoolProvider::numThreads () const + { +- std::lock_guard lock (_data.threadMutex); +- return static_cast (_data.threads.size()); ++ return _data->_threadCount.load (); + } + + void + DefaultThreadPoolProvider::setNumThreads (int count) + { +- // +- // Lock access to thread list and size +- // ++ // since we're a private class, the thread pool won't call us if ++ // we aren't changing size so no need to check that... + +- std::lock_guard lock (_data.threadMutex); ++ std::lock_guard lock (_data->_threadMutex); + +- size_t desired = static_cast(count); +- if (desired > _data.threads.size()) +- { +- // +- // Add more threads +- // ++ size_t curThreads = _data->_threads.size (); ++ size_t nToAdd = static_cast (count); + +- while (_data.threads.size() < desired) +- _data.threads.push_back (new DefaultWorkerThread (&_data)); +- } +- else if ((size_t)count < _data.threads.size()) ++ if (nToAdd < curThreads) + { +- // +- // Wait until all existing threads are finished processing, +- // then delete all threads. +- // +- finish (); +- +- // +- // Add in new threads +- // +- +- while (_data.threads.size() < desired) +- _data.threads.push_back (new DefaultWorkerThread (&_data)); ++ // no easy way to only shutdown the n threads at the end of ++ // the vector (well, really, guaranteeing they are the ones to ++ // be woken up), so just kill all of the threads ++ lockedFinish (); ++ curThreads = 0; + } + +- _data.hasThreads = !(_data.threads.empty()); ++ _data->_threads.resize (nToAdd); ++ for (size_t i = curThreads; i < nToAdd; ++i) ++ { ++ _data->_threads[i] = ++ std::thread (&DefaultThreadPoolProvider::threadLoop, this, _data); ++ } ++ _data->_threadCount = static_cast (_data->_threads.size ()); + } + + void + DefaultThreadPoolProvider::addTask (Task *task) + { +- // +- // Lock the threads, needed to access numThreads +- // +- bool doPush = _data.hasThreads.load( std::memory_order_relaxed ); +- +- if ( doPush ) ++ // the thread pool will kill us and switch to a null provider ++ // if the thread count is set to 0, so we can always ++ // go ahead and lock and assume we have a thread to do the ++ // processing + { +- // +- // Get exclusive access to the tasks queue +- // ++ std::lock_guard taskLock (_data->_taskMutex); + +- { +- std::lock_guard taskLock (_data.taskMutex); +- +- // +- // Push the new task into the FIFO +- // +- _data.tasks.push_back (task); +- } +- + // +- // Signal that we have a new task to process ++ // Push the new task into the FIFO + // +- _data.taskSemaphore.post (); +- } +- else +- { +- // this path shouldn't normally happen since we have the +- // NullThreadPoolProvider, but just in case... +- task->execute (); +- task->group()->_data->removeTask (); +- delete task; ++ _data->_tasks.push_back (task); + } ++ ++ // ++ // Signal that we have a new task to process ++ // ++ _data->_taskSemaphore.post (); + } + + void + DefaultThreadPoolProvider::finish () + { +- _data.stop(); ++ std::lock_guard lock (_data->_threadMutex); ++ ++ lockedFinish (); ++} ++ ++void ++DefaultThreadPoolProvider::lockedFinish () ++{ ++ _data->stop (); + + // + // Signal enough times to allow all threads to stop. + // +- // Wait until all threads have started their run functions. +- // If we do not wait before we destroy the threads then it's +- // possible that the threads have not yet called their run +- // functions. +- // If this happens then the run function will be called off +- // of an invalid object and we will crash, most likely with +- // an error like: "pure virtual method called" ++ // NB: we must do this as many times as we have threads. + // +- +- size_t curT = _data.threads.size(); ++ // If there is still work in the queue, or this call happens "too ++ // quickly", threads will not be waiting on the semaphore, so we ++ // need to ensure the semaphore is at a count equal to the amount ++ // of work left plus the number of threads to ensure exit of a ++ // thread. There can be threads in a few states: ++ // - still starting up (successive calls to setNumThreads) ++ // - in the middle of processing a task / looping ++ // - waiting in the semaphore ++ size_t curT = _data->_threads.size (); + for (size_t i = 0; i != curT; ++i) +- { +- if (_data.threads[i]->joinable()) +- { +- _data.taskSemaphore.post(); +- _data.threadSemaphore.wait(); +- } +- } ++ _data->_taskSemaphore.post (); + + // +- // Join all the threads ++ // We should not need to check joinability, they should all, by ++ // definition, be joinable (assuming normal start) + // + for (size_t i = 0; i != curT; ++i) + { +- if (_data.threads[i]->joinable()) +- _data.threads[i]->join(); +- delete _data.threads[i]; ++ // This isn't quite right in that the thread may have actually ++ // be in an exited / signalled state (needing the ++ // WaitForSingleObject call), and so already have an exit code ++ // (I think, but the docs are vague), but if we don't do the ++ // join, the stl thread seems to then throw an exception. The ++ // join should just return invalid handle and continue, and is ++ // more of a windows bug... except maybe someone needs to work ++ // around it... ++ //# ifdef TEST_FOR_WIN_THREAD_STATUS ++ // ++ // // per OIIO issue #2038, on exit / dll unload, windows may ++ // // kill the thread, double check that it is still active prior ++ // // to joining. ++ // DWORD tstatus; ++ // if (GetExitCodeThread (_threads[i].native_handle (), &tstatus)) ++ // { ++ // if (tstatus != STILL_ACTIVE) { continue; } ++ // } ++ //# endif ++ ++ _data->_threads[i].join (); + } + +- std::lock_guard lk( _data.taskMutex ); +- +- _data.threads.clear(); +- _data.tasks.clear(); ++ _data->_threads.clear (); + +- _data.stopping = false; ++ _data->resetAtomics (); + } + +- +-class NullThreadPoolProvider : public ThreadPoolProvider ++void ++DefaultThreadPoolProvider::threadLoop ( ++ std::shared_ptr data) + { +- virtual ~NullThreadPoolProvider() {} +- virtual int numThreads () const { return 0; } +- virtual void setNumThreads (int count) +- { +- } +- virtual void addTask (Task *t) ++ while (true) + { +- t->execute (); +- t->group()->_data->removeTask (); +- delete t; ++ // ++ // Wait for a task to become available ++ // ++ ++ data->_taskSemaphore.wait (); ++ ++ { ++ std::unique_lock taskLock (data->_taskMutex); ++ ++ // ++ // If there is a task pending, pop off the next task in the FIFO ++ // ++ ++ if (!data->_tasks.empty ()) ++ { ++ Task* task = data->_tasks.back (); ++ data->_tasks.pop_back (); ++ ++ // release the mutex while we process ++ taskLock.unlock (); ++ ++ handleProcessTask (task); ++ ++ // do not need to reacquire the lock at all since we ++ // will just loop around, pull any other task ++ } ++ else if (data->stopped ()) { break; } ++ } + } +- virtual void finish () {} +-}; ++} + + } //namespace + +@@ -409,81 +335,69 @@ class NullThreadPoolProvider : public ThreadPoolProvider + // struct TaskGroup::Data + // + +-TaskGroup::Data::Data () : numPending (0), isEmpty (1) +-{ +- // empty +-} ++TaskGroup::Data::Data () : numPending (0), inFlight (0), isEmpty (1) ++{} + + + TaskGroup::Data::~Data () ++{} ++ ++void ++TaskGroup::Data::waitForEmpty () + { + // + // A TaskGroup acts like an "inverted" semaphore: if the count +- // is above 0 then waiting on the taskgroup will block. This ++ // is above 0 then waiting on the taskgroup will block. The + // destructor waits until the taskgroup is empty before returning. + // + + isEmpty.wait (); + +-#ifdef ENABLE_SEM_DTOR_WORKAROUND +- // Update: this was fixed in v. 2.2.21, so this ifdef checks for that +- // +- // Alas, given the current bug in glibc we need a secondary +- // syncronisation primitive here to account for the fact that +- // destructing the isEmpty Semaphore in this thread can cause +- // an error for a separate thread that is issuing the post() call. +- // We are entitled to destruct the semaphore at this point, however, +- // that post() call attempts to access data out of the associated +- // memory *after* it has woken the waiting threads, including this one, +- // potentially leading to invalid memory reads. +- // http://sources.redhat.com/bugzilla/show_bug.cgi?id=12674 +- +- std::lock_guard lock (dtorMutex); +-#endif ++ // pseudo spin to wait for the notifying thread to finish the post ++ // to avoid a premature deletion of the semaphore ++ int count = 0; ++ while (inFlight.load () > 0) ++ { ++ ++count; ++ if (count > 100) ++ { ++ std::this_thread::yield (); ++ count = 0; ++ } ++ } + } + + + void + TaskGroup::Data::addTask () + { +- // +- // in c++11, we use an atomic to protect numPending to avoid the +- // extra lock but for c++98, to add the ability for custom thread +- // pool we add the lock here +- // +- if (numPending++ == 0) +- isEmpty.wait (); ++ inFlight.fetch_add (1); ++ ++ // if we are the first task off the rank, clear the ++ // isEmpty semaphore such that the group will actually pause ++ // until the task finishes ++ if (numPending.fetch_add (1) == 0) { isEmpty.wait (); } + } + + + void + TaskGroup::Data::removeTask () + { +- // Alas, given the current bug in glibc we need a secondary +- // syncronisation primitive here to account for the fact that +- // destructing the isEmpty Semaphore in a separate thread can +- // cause an error. Issuing the post call here the current libc +- // implementation attempts to access memory *after* it has woken +- // waiting threads. +- // Since other threads are entitled to delete the semaphore the +- // access to the memory location can be invalid. +- // http://sources.redhat.com/bugzilla/show_bug.cgi?id=12674 +- // Update: this bug has been fixed, but how do we know which +- // glibc version we're in? +- +- // Further update: ++ // if we are the last task, notify the group we're done ++ if (numPending.fetch_sub (1) == 1) { isEmpty.post (); } ++ ++ // in theory, a background thread could actually finish a task ++ // prior to the next task being added. The fetch_add / fetch_sub ++ // logic between addTask and removeTask are fine to keep the ++ // inverted semaphore straight. All addTask must happen prior to ++ // the TaskGroup destructor. + // +- // we could remove this if it is a new enough glibc, however +- // we've changed the API to enable a custom override of a +- // thread pool. In order to provide safe access to the numPending, +- // we need the lock anyway, except for c++11 or newer +- if (--numPending == 0) +- { +-#ifdef ENABLE_SEM_DTOR_WORKAROUND +- std::lock_guard lk (dtorMutex); +-#endif +- isEmpty.post (); +- } ++ // But to let the taskgroup thread waiting know we're actually ++ // finished with the last one and finished posting (the semaphore ++ // might wake up the other thread while in the middle of post) so ++ // we don't destroy the semaphore while posting to it, keep a ++ // separate counter that is modified pre / post semaphore ++ inFlight.fetch_sub (1); + } + + +@@ -491,8 +405,7 @@ TaskGroup::Data::removeTask () + // struct ThreadPool::Data + // + +-ThreadPool::Data::Data (): +- provUsers (0), provider (NULL) ++ThreadPool::Data::Data () + { + // empty + } +@@ -500,82 +413,7 @@ ThreadPool::Data::Data (): + + ThreadPool::Data::~Data() + { +- ThreadPoolProvider *p = provider.load( std::memory_order_relaxed ); +- p->finish(); +- delete p; +-} +- +-inline ThreadPool::Data::SafeProvider +-ThreadPool::Data::getProvider () +-{ +- provUsers.fetch_add( 1, std::memory_order_relaxed ); +- return SafeProvider( this, provider.load( std::memory_order_relaxed ) ); +-} +- +- +-inline void +-ThreadPool::Data::coalesceProviderUse () +-{ +- int ov = provUsers.fetch_sub( 1, std::memory_order_relaxed ); +- // ov is the previous value, so one means that now it might be 0 +- if ( ov == 1 ) +- { +- // do we have anything to do here? +- } +-} +- +- +-inline void +-ThreadPool::Data::bumpProviderUse () +-{ +- provUsers.fetch_add( 1, std::memory_order_relaxed ); +-} +- +- +-inline void +-ThreadPool::Data::setProvider (ThreadPoolProvider *p) +-{ +- ThreadPoolProvider *old = provider.load( std::memory_order_relaxed ); +- // work around older gcc bug just in case +- do +- { +- if ( ! provider.compare_exchange_weak( old, p, std::memory_order_release, std::memory_order_relaxed ) ) +- continue; +- } while (false); // NOSONAR - suppress SonarCloud bug report. +- +- // wait for any other users to finish prior to deleting, given +- // that these are just mostly to query the thread count or push a +- // task to the queue (so fast), just spin... +- // +- // (well, and normally, people don't do this mid stream anyway, so +- // this will be 0 99.999% of the time, but just to be safe) +- // +- while ( provUsers.load( std::memory_order_relaxed ) > 0 ) +- std::this_thread::yield(); +- +- if ( old ) +- { +- old->finish(); +- delete old; +- } +- +- // NB: the shared_ptr mechanism is safer and means we don't have +- // to have the provUsers counter since the shared_ptr keeps that +- // for us. However, gcc 4.8/9 compilers which many people are +- // still using even though it is 2018 forgot to add the shared_ptr +- // functions... once that compiler is fully deprecated, switch to +- // using the below, change provider to a std::shared_ptr and remove +- // provUsers... +- // +-// std::shared_ptr newp( p ); +-// std::shared_ptr curp = std::atomic_load_explicit( &provider, std::memory_order_relaxed ); +-// do +-// { +-// if ( ! std::atomic_compare_exchange_weak_explicit( &provider, &curp, newp, std::memory_order_release, std::memory_order_relaxed ) ) +-// continue; +-// } while ( false ); +-// if ( curp ) +-// curp->finish(); ++ setProvider (nullptr); + } + + #endif // ENABLE_THREADING +@@ -608,7 +446,7 @@ Task::group () + + TaskGroup::TaskGroup (): + #ifdef ENABLE_THREADING +- _data (new Data()) ++ _data (new Data) + #else + _data (nullptr) + #endif +@@ -620,6 +458,7 @@ TaskGroup::TaskGroup (): + TaskGroup::~TaskGroup () + { + #ifdef ENABLE_THREADING ++ _data->waitForEmpty (); + delete _data; + #endif + } +@@ -660,10 +499,7 @@ ThreadPool::ThreadPool (unsigned nthreads): + #endif + { + #ifdef ENABLE_THREADING +- if ( nthreads == 0 ) +- _data->setProvider( new NullThreadPoolProvider ); +- else +- _data->setProvider( new DefaultThreadPoolProvider( int(nthreads) ) ); ++ setNumThreads (static_cast (nthreads)); + #endif + } + +@@ -671,6 +507,8 @@ ThreadPool::ThreadPool (unsigned nthreads): + ThreadPool::~ThreadPool () + { + #ifdef ENABLE_THREADING ++ // ensures any jobs / threads are finished & shutdown ++ _data->setProvider (nullptr); + delete _data; + #endif + } +@@ -680,7 +518,8 @@ int + ThreadPool::numThreads () const + { + #ifdef ENABLE_THREADING +- return _data->getProvider ()->numThreads (); ++ Data::ProviderPtr sp = _data->getProvider (); ++ return (sp) ? sp->numThreads () : 0; + #else + return 0; + #endif +@@ -695,36 +534,30 @@ ThreadPool::setNumThreads (int count) + throw IEX_INTERNAL_NAMESPACE::ArgExc ("Attempt to set the number of threads " + "in a thread pool to a negative value."); + +- bool doReset = false; + { +- Data::SafeProvider sp = _data->getProvider (); +- int curT = sp->numThreads (); +- if ( curT == count ) +- return; +- +- if ( curT == 0 ) ++ Data::ProviderPtr sp = _data->getProvider (); ++ if (sp) + { +- NullThreadPoolProvider *npp = dynamic_cast( sp.get() ); +- if ( npp ) +- doReset = true; +- } +- else if ( count == 0 ) +- { +- DefaultThreadPoolProvider *dpp = dynamic_cast( sp.get() ); +- if ( dpp ) +- doReset = true; ++ bool doReset = false; ++ int curT = sp->numThreads (); ++ if (curT == count) return; ++ ++ if (count != 0) ++ { ++ sp->setNumThreads (count); ++ return; ++ } + } +- if ( ! doReset ) +- sp->setNumThreads( count ); + } + +- if ( doReset ) +- { +- if ( count == 0 ) +- _data->setProvider( new NullThreadPoolProvider ); +- else +- _data->setProvider( new DefaultThreadPoolProvider( count ) ); +- } ++ // either a null provider or a case where we should switch from ++ // a default provider to a null one or vice-versa ++ if (count == 0) ++ _data->setProvider (nullptr); ++ else ++ _data->setProvider ( ++ std::make_shared (count)); ++ + #else + // just blindly ignore + (void)count; +@@ -736,7 +569,8 @@ void + ThreadPool::setThreadProvider (ThreadPoolProvider *provider) + { + #ifdef ENABLE_THREADING +- _data->setProvider (provider); ++ // contract is we take ownership and will free the provider ++ _data->setProvider (Data::ProviderPtr (provider)); + #else + throw IEX_INTERNAL_NAMESPACE::ArgExc ( + "Attempt to set a thread provider on a system with threads" +@@ -748,12 +582,19 @@ ThreadPool::setThreadProvider (ThreadPoolProvider *provider) + void + ThreadPool::addTask (Task* task) + { ++ if (task) ++ { + #ifdef ENABLE_THREADING +- _data->getProvider ()->addTask (task); +-#else +- task->execute (); +- delete task; ++ Data::ProviderPtr p = _data->getProvider (); ++ if (p) ++ { ++ p->addTask (task); ++ return; ++ } + #endif ++ ++ handleProcessTask (task); ++ } + } + + +@@ -780,7 +621,24 @@ unsigned + ThreadPool::estimateThreadCountForFileIO () + { + #ifdef ENABLE_THREADING +- return std::thread::hardware_concurrency (); ++ unsigned rv = std::thread::hardware_concurrency (); ++ // hardware concurrency is not required to work ++ if (rv == 0 || ++ rv > static_cast (std::numeric_limits::max ())) ++ { ++ rv = 1; ++# if (defined(_WIN32) || defined(_WIN64)) ++ SYSTEM_INFO si; ++ GetNativeSystemInfo (&si); ++ ++ rv = si.dwNumberOfProcessors; ++# else ++ // linux, bsd, and mac are fine with this ++ // other *nix should be too, right? ++ rv = sysconf (_SC_NPROCESSORS_ONLN); ++# endif ++ } ++ return rv; + #else + return 0; + #endif +diff --git a/src/lib/IlmThread/IlmThreadSemaphore.h b/src/lib/IlmThread/IlmThreadSemaphore.h +index f26e48a09..576968aa6 100644 +--- a/src/lib/IlmThread/IlmThreadSemaphore.h ++++ b/src/lib/IlmThread/IlmThreadSemaphore.h +@@ -64,10 +64,10 @@ class ILMTHREAD_EXPORT_TYPE Semaphore + mutable HANDLE _semaphore; + + #elif ILMTHREAD_THREADING_ENABLED +- // +- // If the platform has threads but no semapohores, +- // then we implement them ourselves using condition variables +- // ++ // ++ // If the platform has threads but no semaphores, ++ // then we implement them ourselves using condition variables ++ // + + struct sema_t + { diff --git a/blender-build/build_environment/patches/openimageio.diff b/blender-build/build_environment/patches/openimageio.diff new file mode 100644 index 0000000..f4a4627 --- /dev/null +++ b/blender-build/build_environment/patches/openimageio.diff @@ -0,0 +1,23 @@ +diff -Naur orig/CMakeLists.txt external_openimageio/CMakeLists.txt +--- orig/CMakeLists.txt 2020-05-10 21:43:52 -0600 ++++ external_openimageio/CMakeLists.txt 2020-05-13 17:03:35 -0600 +@@ -170,7 +170,7 @@ + add_subdirectory (src/iinfo) + add_subdirectory (src/maketx) + add_subdirectory (src/oiiotool) +- add_subdirectory (src/testtex) ++ #add_subdirectory (src/testtex) + add_subdirectory (src/iv) + endif () + +diff -Naur orig/src/cmake/compiler.cmake external_openimageio/src/cmake/compiler.cmake +--- orig/src/cmake/compiler.cmake 2020-05-10 21:43:52 -0600 ++++ external_openimageio/src/cmake/compiler.cmake 2020-05-13 17:02:54 -0600 +@@ -172,6 +172,7 @@ + add_definitions (-D_CRT_NONSTDC_NO_WARNINGS) + add_definitions (-D_SCL_SECURE_NO_WARNINGS) + add_definitions (-DJAS_WIN_MSVC_BUILD) ++ add_definitions (-DOPJ_STATIC) + endif (MSVC) + + if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" diff --git a/blender-build/build_environment/patches/openmp.diff b/blender-build/build_environment/patches/openmp.diff new file mode 100644 index 0000000..201ab5c --- /dev/null +++ b/blender-build/build_environment/patches/openmp.diff @@ -0,0 +1,23 @@ +diff --git a/runtime/src/z_Linux_asm.S b/runtime/src/z_Linux_asm.S +index 0d8885e..42aa5ad 100644 +--- a/runtime/src/z_Linux_asm.S ++++ b/runtime/src/z_Linux_asm.S +@@ -1540,10 +1540,12 @@ __kmp_unnamed_critical_addr: + .comm .gomp_critical_user_,32,8 + .data + .align 8 +- .global __kmp_unnamed_critical_addr +-__kmp_unnamed_critical_addr: ++ .global ___kmp_unnamed_critical_addr ++___kmp_unnamed_critical_addr: + .8byte .gomp_critical_user_ +- .size __kmp_unnamed_critical_addr,8 ++# if !(KMP_OS_DARWIN) ++ .size ___kmp_unnamed_critical_addr,8 ++# endif + #endif /* KMP_ARCH_PPC64 || KMP_ARCH_AARCH64 */ + + #if KMP_OS_LINUX + + + diff --git a/blender-build/build_environment/patches/openvdb.diff b/blender-build/build_environment/patches/openvdb.diff new file mode 100644 index 0000000..d3f1998 --- /dev/null +++ b/blender-build/build_environment/patches/openvdb.diff @@ -0,0 +1,114 @@ +diff -Naur openvdb-8.0.0/openvdb/openvdb/CMakeLists.txt openvdb/openvdb/openvdb/CMakeLists.txt +--- openvdb-8.0.0/openvdb/openvdb/CMakeLists.txt 2020-12-24 10:13:14 -0700 ++++ openvdb/openvdb/openvdb/CMakeLists.txt 2021-02-05 11:18:33 -0700 +@@ -146,6 +148,7 @@ + Boost::disable_autolinking # add -DBOOST_ALL_NO_LIB + ) + endif() ++ add_definitions(-D__TBB_NO_IMPLICIT_LINKAGE -DOPENVDB_OPENEXR_STATICLIB) + endif() + + if(USE_EXR) +@@ -379,7 +382,12 @@ + # imported targets. + + if(OPENVDB_CORE_SHARED) +- add_library(openvdb_shared SHARED ${OPENVDB_LIBRARY_SOURCE_FILES}) ++ if(WIN32) ++ configure_file(version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY) ++ add_library(openvdb_shared SHARED ${OPENVDB_LIBRARY_SOURCE_FILES} ${CMAKE_CURRENT_BINARY_DIR}/version.rc) ++ else() ++ add_library(openvdb_shared SHARED ${OPENVDB_LIBRARY_SOURCE_FILES}) ++ endif() + endif() + + if(OPENVDB_CORE_STATIC) +diff -Naur openvdb-8.0.0/openvdb/openvdb/version.rc.in openvdb/openvdb/openvdb/version.rc.in +--- openvdb-8.0.0/openvdb/openvdb/version.rc.in 1969-12-31 17:00:00 -0700 ++++ openvdb/openvdb/openvdb/version.rc.in 2021-02-05 11:18:33 -0700 +@@ -0,0 +1,48 @@ ++#include ++ ++#define VER_FILEVERSION @OpenVDB_MAJOR_VERSION@,@OpenVDB_MINOR_VERSION@,@OpenVDB_PATCH_VERSION@,0 ++#define VER_FILEVERSION_STR "@OpenVDB_MAJOR_VERSION@.@OpenVDB_MINOR_VERSION@.@OpenVDB_PATCH_VERSION@.0\0" ++ ++#define VER_PRODUCTVERSION @OpenVDB_MAJOR_VERSION@,@OpenVDB_MINOR_VERSION@,@OpenVDB_PATCH_VERSION@,0 ++#define VER_PRODUCTVERSION_STR "@OpenVDB_MAJOR_VERSION@.@OpenVDB_MINOR_VERSION@\0" ++ ++#ifndef DEBUG ++#define VER_DEBUG 0 ++#else ++#define VER_DEBUG VS_FF_DEBUG ++#endif ++ ++VS_VERSION_INFO VERSIONINFO ++FILEVERSION VER_FILEVERSION ++PRODUCTVERSION VER_PRODUCTVERSION ++FILEFLAGSMASK VS_FFI_FILEFLAGSMASK ++FILEFLAGS (VER_DEBUG) ++FILEOS VOS__WINDOWS32 ++FILETYPE VFT_DLL ++FILESUBTYPE VFT2_UNKNOWN ++BEGIN ++ BLOCK "StringFileInfo" ++ BEGIN ++ BLOCK "040904E4" ++ BEGIN ++ VALUE "FileDescription", "OpenVDB" ++ VALUE "FileVersion", VER_FILEVERSION_STR ++ VALUE "InternalName", "OpenVDB" ++ VALUE "ProductName", "OpenVDB" ++ VALUE "ProductVersion", VER_PRODUCTVERSION_STR ++ END ++ END ++ ++ BLOCK "VarFileInfo" ++ BEGIN ++ /* The following line should only be modified for localized versions. */ ++ /* It consists of any number of WORD,WORD pairs, with each pair */ ++ /* describing a language,codepage combination supported by the file. */ ++ /* */ ++ /* For example, a file might have values "0x409,1252" indicating that it */ ++ /* supports English language (0x409) in the Windows ANSI codepage (1252). */ ++ ++ VALUE "Translation", 0x409, 1252 ++ ++ END ++END +diff -Naur orig/openvdb/openvdb/tree/ValueAccessor.h openvdb/openvdb/openvdb/tree/ValueAccessor.h +--- orig/openvdb/openvdb/tree/ValueAccessor.h 2022-11-02 13:58:26 -0600 ++++ openvdb/openvdb/openvdb/tree/ValueAccessor.h 2022-11-02 18:55:09 -0600 +@@ -872,7 +872,10 @@ + using LeafNodeType = typename NodeType::LeafNodeType; + using CoordLimits = std::numeric_limits; + +- static_assert(std::is_same::value); ++ // Blender: Technically not an issue in OpenVDB, but USD 21.11 still builds ++ // as C++14 which does not support terse asserts yet. Add a message to ++ // explicitly select the C++14 supported static assert. ++ static_assert(std::is_same::value, "cache item node type is not leaf node type"); + + CacheItem(TreeCacheT& parent) + : mParent(&parent) +diff --git a/nanovdb/nanovdb/NanoVDB.h b/nanovdb/nanovdb/NanoVDB.h +index f7fc304..fde5c47 100644 +--- a/nanovdb/nanovdb/NanoVDB.h ++++ b/nanovdb/nanovdb/NanoVDB.h +@@ -1877,7 +1877,7 @@ __hostdev__ static inline uint32_t FindLowestOn(uint64_t v) + { + NANOVDB_ASSERT(v); + #if (defined(__CUDA_ARCH__) || defined(__HIP__)) && defined(NANOVDB_USE_INTRINSICS) +- return __ffsll(v); ++ return __ffsll(static_cast(v)); + #elif defined(_MSC_VER) && defined(NANOVDB_USE_INTRINSICS) + unsigned long index; + _BitScanForward64(&index, v); +@@ -2592,7 +2592,7 @@ public: + /// + /// @note This method is only defined for IndexGrid = NanoGrid + template +- __hostdev__ typename enable_if::value, uint64_t>::type valueCount() const {return DataType::mData1;} ++ __hostdev__ typename enable_if::value, const uint64_t&>::type valueCount() const {return DataType::mData1;} + + /// @brief Return a const reference to the tree + __hostdev__ const TreeT& tree() const { return *reinterpret_cast(this->treePtr()); } diff --git a/blender-build/build_environment/patches/openvdb_metal.diff b/blender-build/build_environment/patches/openvdb_metal.diff new file mode 100644 index 0000000..ba3e5bc --- /dev/null +++ b/blender-build/build_environment/patches/openvdb_metal.diff @@ -0,0 +1,7976 @@ +diff --git a/nanovdb/nanovdb/NanoVDB.h b/nanovdb/nanovdb/NanoVDB.h +index fde5c47..cff460a 100644 +--- a/nanovdb/nanovdb/NanoVDB.h ++++ b/nanovdb/nanovdb/NanoVDB.h +@@ -140,7 +140,27 @@ + #define NANOVDB_ALIGN(n) alignas(n) + #endif // !defined(NANOVDB_ALIGN) + +-#ifdef __CUDACC_RTC__ ++#ifdef __KERNEL_METAL__ ++ ++using namespace metal; ++#define std metal ++#define double uint64_t ++#define __global__ device ++#define __local__ thread ++#define __constant__ constant ++#define sqrtf sqrt ++#define rintf rint ++#define fminf fmin ++#define fmaxf fmax ++#define floorf floor ++#define ceilf ceil ++#define fabs abs ++#define fmaf fma ++#define tanf tan ++ ++#define NANOVDB_ASSERT(x) ++ ++#elif defined(__CUDACC_RTC__) + + typedef signed char int8_t; + typedef short int16_t; +@@ -157,6 +177,10 @@ typedef unsigned long long uint64_t; + + #else // !__CUDACC_RTC__ + ++#define __constant__ const ++#define __global__ ++#define __local__ ++ + #include // for abs in clang7 + #include // for types like int32_t etc + #include // for size_t type +@@ -262,7 +286,7 @@ enum class GridType : uint32_t { Unknown = 0, + Index = 19,// index into an external array of values + End = 20 }; + +-#ifndef __CUDACC_RTC__ ++#if !defined(__CUDACC_RTC__) && !defined(__KERNEL_METAL__) + /// @brief Retuns a c-string used to describe a GridType + inline const char* toStr(GridType gridType) + { +@@ -289,7 +313,7 @@ enum class GridClass : uint32_t { Unknown = 0, + IndexGrid = 8,// grid whose values are offsets, e.g. into an external array + End = 9 }; + +-#ifndef __CUDACC_RTC__ ++#if !defined(__CUDACC_RTC__) && !defined(__KERNEL_METAL__) + /// @brief Retuns a c-string used to describe a GridClass + inline const char* toStr(GridClass gridClass) + { +@@ -313,7 +337,7 @@ enum class GridFlags : uint32_t { + End = 1 << 6, + }; + +-#ifndef __CUDACC_RTC__ ++#if !defined(__CUDACC_RTC__) && !defined(__KERNEL_METAL__) + /// @brief Retuns a c-string used to describe a GridFlags + inline const char* toStr(GridFlags gridFlags) + { +@@ -355,13 +379,13 @@ enum class GridBlindDataSemantic : uint32_t { Unknown = 0, + template + struct is_same + { +- static constexpr bool value = false; ++ static __constant__ constexpr bool value = false; + }; + + template + struct is_same + { +- static constexpr bool value = true; ++ static __constant__ constexpr bool value = true; + }; + + // --------------------------> enable_if <------------------------------------ +@@ -383,13 +407,13 @@ struct enable_if + template + struct is_const + { +- static constexpr bool value = false; ++ static __constant__ constexpr bool value = false; + }; + + template + struct is_const + { +- static constexpr bool value = true; ++ static __constant__ constexpr bool value = true; + }; + + // --------------------------> remove_const <------------------------------------ +@@ -412,7 +436,7 @@ struct remove_const + template + struct is_floating_point + { +- static const bool value = is_same::value || is_same::value; ++ static __constant__ const bool value = is_same::value || is_same::value; + }; + + // --------------------------> is_specialization <------------------------------------ +@@ -425,12 +449,12 @@ struct is_floating_point + template class TemplateType> + struct is_specialization + { +- static const bool value = false; ++ static __constant__ const bool value = false; + }; + template class TemplateType> + struct is_specialization, TemplateType> + { +- static const bool value = true; ++ static __constant__ const bool value = true; + }; + + // --------------------------> Value Map <------------------------------------ +@@ -495,19 +519,19 @@ struct BuildToValueMap + // --------------------------> utility functions related to alignment <------------------------------------ + + /// @brief return true if the specified pointer is aligned +-__hostdev__ inline static bool isAligned(const void* p) ++__hostdev__ inline static bool isAligned(__global__ const void* p) + { + return uint64_t(p) % NANOVDB_DATA_ALIGNMENT == 0; + } + + /// @brief return true if the specified pointer is aligned and not NULL +-__hostdev__ inline static bool isValid(const void* p) ++__hostdev__ inline static bool isValid(__global__ const void* p) + { + return p != nullptr && uint64_t(p) % NANOVDB_DATA_ALIGNMENT == 0; + } + + /// @brief return the smallest number of bytes that when added to the specified pointer results in an aligned pointer +-__hostdev__ inline static uint64_t alignmentPadding(const void* p) ++__hostdev__ inline static uint64_t alignmentPadding(__global__ const void* p) + { + NANOVDB_ASSERT(p); + return (NANOVDB_DATA_ALIGNMENT - (uint64_t(p) % NANOVDB_DATA_ALIGNMENT)) % NANOVDB_DATA_ALIGNMENT; +@@ -515,43 +539,66 @@ __hostdev__ inline static uint64_t alignmentPadding(const void* p) + + /// @brief offset the specified pointer so it is aligned. + template +-__hostdev__ inline static T* alignPtr(T* p) ++__hostdev__ inline static __global__ T* alignPtr(__global__ T* p) + { + NANOVDB_ASSERT(p); +- return reinterpret_cast( (uint8_t*)p + alignmentPadding(p) ); ++ return reinterpret_cast<__global__ T*>( (__global__ uint8_t*)p + alignmentPadding(p) ); + } + + /// @brief offset the specified pointer so it is aligned. + template +-__hostdev__ inline static const T* alignPtr(const T* p) ++__hostdev__ inline static __global__ const T* alignPtr(__global__ const T* p) + { + NANOVDB_ASSERT(p); +- return reinterpret_cast( (const uint8_t*)p + alignmentPadding(p) ); ++ return reinterpret_cast<__global__ const T*>( (__global__ const uint8_t*)p + alignmentPadding(p) ); + } + + // --------------------------> PtrDiff PtrAdd <------------------------------------ + + template +-__hostdev__ inline static int64_t PtrDiff(const T1* p, const T2* q) ++__hostdev__ inline static int64_t PtrDiff(__global__ const T1* p, __global__ const T2* q) + { + NANOVDB_ASSERT(p && q); +- return reinterpret_cast(p) - reinterpret_cast(q); ++ return reinterpret_cast<__global__ const char*>(p) - reinterpret_cast<__global__ const char*>(q); + } ++#if defined(__KERNEL_METAL__) ++template ++__hostdev__ inline static int64_t PtrDiff(__local__ const T1* p, __local__ const T2* q) ++{ ++ NANOVDB_ASSERT(p && q); ++ return reinterpret_cast<__local__ const char*>(p) - reinterpret_cast<__local__ const char*>(q); ++} ++#endif + + template +-__hostdev__ inline static DstT* PtrAdd(SrcT *p, int64_t offset) ++__hostdev__ inline static __global__ DstT* PtrAdd(__global__ SrcT *p, int64_t offset) + { + NANOVDB_ASSERT(p); +- return reinterpret_cast(reinterpret_cast(p) + offset); ++ return reinterpret_cast<__global__ DstT*>(reinterpret_cast<__global__ char*>(p) + offset); + } ++#if defined(__KERNEL_METAL__) ++template ++__hostdev__ inline static __local__ DstT* PtrAdd(__local__ SrcT *p, int64_t offset) ++{ ++ NANOVDB_ASSERT(p); ++ return reinterpret_cast<__local__ DstT*>(reinterpret_cast<__local__ char*>(p) + offset); ++} ++#endif + + template +-__hostdev__ inline static const DstT* PtrAdd(const SrcT *p, int64_t offset) ++__hostdev__ inline static __global__ const DstT* PtrAdd(__global__ const SrcT *p, int64_t offset) + { + NANOVDB_ASSERT(p); +- return reinterpret_cast(reinterpret_cast(p) + offset); ++ return reinterpret_cast<__global__ const DstT*>(reinterpret_cast<__global__ const char*>(p) + offset); + } +- ++#if defined(__KERNEL_METAL__) ++template ++__hostdev__ inline static __local__ const DstT* PtrAdd(__local__ const SrcT *p, int64_t offset) ++{ ++ NANOVDB_ASSERT(p); ++ return reinterpret_cast<__local__ const DstT*>(reinterpret_cast<__local__ const char*>(p) + offset); ++} ++#endif + // --------------------------> Rgba8 <------------------------------------ + + /// @brief 8-bit red, green, blue, alpha packed into 32 bit unsigned int +@@ -562,13 +609,13 @@ class Rgba8 + uint32_t packed;// 32 bit packed representation + } mData; + public: +- static const int SIZE = 4; ++ static __constant__ const int SIZE = 4; + using ValueType = uint8_t; + +- Rgba8(const Rgba8&) = default; +- Rgba8(Rgba8&&) = default; +- Rgba8& operator=(Rgba8&&) = default; +- Rgba8& operator=(const Rgba8&) = default; ++ Rgba8(__global__ const Rgba8&) = default; ++ Rgba8(__global__ Rgba8&&) = default; ++ __global__ Rgba8& operator=(__global__ Rgba8&&) __global__ = default; ++ __global__ Rgba8& operator=(__global__ const Rgba8&) __global__ = default; + __hostdev__ Rgba8() : mData{0,0,0,0} {static_assert(sizeof(uint32_t) == sizeof(Rgba8),"Unexpected sizeof");} + __hostdev__ Rgba8(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255u) : mData{r, g, b, a} {} + explicit __hostdev__ Rgba8(uint8_t v) : Rgba8(v,v,v,v) {} +@@ -579,8 +626,8 @@ public: + (uint8_t(0.5f + a * 255.0f))}// round to nearest + { + } +- __hostdev__ bool operator<(const Rgba8& rhs) const { return mData.packed < rhs.mData.packed; } +- __hostdev__ bool operator==(const Rgba8& rhs) const { return mData.packed == rhs.mData.packed; } ++ __hostdev__ bool operator<(__global__ const Rgba8& rhs) const { return mData.packed < rhs.mData.packed; } ++ __hostdev__ bool operator==(__global__ const Rgba8& rhs) const { return mData.packed == rhs.mData.packed; } + __hostdev__ float lengthSqr() const + { + return 0.0000153787005f*(float(mData.c[0])*mData.c[0] + +@@ -588,18 +635,18 @@ public: + float(mData.c[2])*mData.c[2]);//1/255^2 + } + __hostdev__ float length() const { return sqrtf(this->lengthSqr() ); } +- __hostdev__ const uint8_t& operator[](int n) const { return mData.c[n]; } +- __hostdev__ uint8_t& operator[](int n) { return mData.c[n]; } +- __hostdev__ const uint32_t& packed() const { return mData.packed; } +- __hostdev__ uint32_t& packed() { return mData.packed; } +- __hostdev__ const uint8_t& r() const { return mData.c[0]; } +- __hostdev__ const uint8_t& g() const { return mData.c[1]; } +- __hostdev__ const uint8_t& b() const { return mData.c[2]; } +- __hostdev__ const uint8_t& a() const { return mData.c[3]; } +- __hostdev__ uint8_t& r() { return mData.c[0]; } +- __hostdev__ uint8_t& g() { return mData.c[1]; } +- __hostdev__ uint8_t& b() { return mData.c[2]; } +- __hostdev__ uint8_t& a() { return mData.c[3]; } ++ __hostdev__ __global__ const uint8_t& operator[](int n) const __global__ { return mData.c[n]; } ++ __hostdev__ __global__ uint8_t& operator[](int n) __global__ { return mData.c[n]; } ++ __hostdev__ __global__ const uint32_t& packed() const __global__ { return mData.packed; } ++ __hostdev__ __global__ uint32_t& packed() __global__ { return mData.packed; } ++ __hostdev__ __global__ const uint8_t& r() const __global__ { return mData.c[0]; } ++ __hostdev__ __global__ const uint8_t& g() const __global__ { return mData.c[1]; } ++ __hostdev__ __global__ const uint8_t& b() const __global__ { return mData.c[2]; } ++ __hostdev__ __global__ const uint8_t& a() const __global__ { return mData.c[3]; } ++ __hostdev__ __global__ uint8_t& r() __global__ { return mData.c[0]; } ++ __hostdev__ __global__ uint8_t& g() __global__ { return mData.c[1]; } ++ __hostdev__ __global__ uint8_t& b() __global__ { return mData.c[2]; } ++ __hostdev__ __global__ uint8_t& a() __global__ { return mData.c[3]; } + };// Rgba8 + + using PackedRGBA8 = Rgba8;// for backwards compatibility +@@ -660,17 +707,17 @@ public: + NANOVDB_ASSERT(minor < (1u << 11));// max value of minor is 2047 + NANOVDB_ASSERT(patch < (1u << 10));// max value of patch is 1023 + } +- __hostdev__ bool operator==(const Version &rhs) const {return mData == rhs.mData;} +- __hostdev__ bool operator< (const Version &rhs) const {return mData < rhs.mData;} +- __hostdev__ bool operator<=(const Version &rhs) const {return mData <= rhs.mData;} +- __hostdev__ bool operator> (const Version &rhs) const {return mData > rhs.mData;} +- __hostdev__ bool operator>=(const Version &rhs) const {return mData >= rhs.mData;} ++ __hostdev__ bool operator==(__global__ const Version &rhs) const {return mData == rhs.mData;} ++ __hostdev__ bool operator< (__global__ const Version &rhs) const {return mData < rhs.mData;} ++ __hostdev__ bool operator<=(__global__ const Version &rhs) const {return mData <= rhs.mData;} ++ __hostdev__ bool operator> (__global__ const Version &rhs) const {return mData > rhs.mData;} ++ __hostdev__ bool operator>=(__global__ const Version &rhs) const {return mData >= rhs.mData;} + __hostdev__ uint32_t id() const { return mData; } + __hostdev__ uint32_t getMajor() const { return (mData >> 21) & ((1u << 11) - 1);} + __hostdev__ uint32_t getMinor() const { return (mData >> 10) & ((1u << 11) - 1);} + __hostdev__ uint32_t getPatch() const { return mData & ((1u << 10) - 1);} + +-#ifndef __CUDACC_RTC__ ++#if !defined(__CUDACC_RTC__) && !defined(__KERNEL_METAL__) + const char* c_str() const + { + char *buffer = (char*)malloc(4 + 1 + 4 + 1 + 4 + 1);// xxxx.xxxx.xxxx\0 +@@ -749,7 +796,7 @@ struct Maximum + //@} + + template +-__hostdev__ inline bool isApproxZero(const Type& x) ++__hostdev__ inline bool isApproxZero(__global__ const Type& x) + { + return !(x > Tolerance::value()) && !(x < -Tolerance::value()); + } +@@ -771,10 +818,12 @@ __hostdev__ inline float Min(float a, float b) + { + return fminf(a, b); + } ++#ifndef __KERNEL_METAL__ + __hostdev__ inline double Min(double a, double b) + { + return fmin(a, b); + } ++#endif + template + __hostdev__ inline Type Max(Type a, Type b) + { +@@ -793,45 +842,55 @@ __hostdev__ inline float Max(float a, float b) + { + return fmaxf(a, b); + } ++#ifndef __KERNEL_METAL__ + __hostdev__ inline double Max(double a, double b) + { + return fmax(a, b); + } ++#endif + __hostdev__ inline float Clamp(float x, float a, float b) + { + return Max(Min(x, b), a); + } ++#ifndef __KERNEL_METAL__ + __hostdev__ inline double Clamp(double x, double a, double b) + { + return Max(Min(x, b), a); + } ++#endif + + __hostdev__ inline float Fract(float x) + { + return x - floorf(x); + } ++#ifndef __KERNEL_METAL__ + __hostdev__ inline double Fract(double x) + { + return x - floor(x); + } ++#endif + + __hostdev__ inline int32_t Floor(float x) + { + return int32_t(floorf(x)); + } ++#ifndef __KERNEL_METAL__ + __hostdev__ inline int32_t Floor(double x) + { + return int32_t(floor(x)); + } ++#endif + + __hostdev__ inline int32_t Ceil(float x) + { + return int32_t(ceilf(x)); + } ++#ifndef __KERNEL_METAL__ + __hostdev__ inline int32_t Ceil(double x) + { + return int32_t(ceil(x)); + } ++#endif + + template + __hostdev__ inline T Pow2(T x) +@@ -875,46 +934,78 @@ __hostdev__ inline int Abs(int x) + } + + template class Vec3T> +-__hostdev__ inline CoordT Round(const Vec3T& xyz); ++__hostdev__ inline CoordT Round(__global__ const Vec3T& xyz); ++#if defined(__KERNEL_METAL__) ++template class Vec3T> ++__hostdev__ inline CoordT Round(__local__ const Vec3T& xyz); ++#endif + + template class Vec3T> +-__hostdev__ inline CoordT Round(const Vec3T& xyz) ++__hostdev__ inline CoordT Round(__global__ const Vec3T& xyz) + { + return CoordT(int32_t(rintf(xyz[0])), int32_t(rintf(xyz[1])), int32_t(rintf(xyz[2]))); + //return CoordT(int32_t(roundf(xyz[0])), int32_t(roundf(xyz[1])), int32_t(roundf(xyz[2])) ); + //return CoordT(int32_t(floorf(xyz[0] + 0.5f)), int32_t(floorf(xyz[1] + 0.5f)), int32_t(floorf(xyz[2] + 0.5f))); + } ++#if defined(__KERNEL_METAL__) ++template class Vec3T> ++__hostdev__ inline CoordT Round(__local__ const Vec3T& xyz) ++{ ++ return CoordT(int32_t(rintf(xyz[0])), int32_t(rintf(xyz[1])), int32_t(rintf(xyz[2]))); ++ //return CoordT(int32_t(roundf(xyz[0])), int32_t(roundf(xyz[1])), int32_t(roundf(xyz[2])) ); ++ //return CoordT(int32_t(floorf(xyz[0] + 0.5f)), int32_t(floorf(xyz[1] + 0.5f)), int32_t(floorf(xyz[2] + 0.5f))); ++} ++#endif + + template class Vec3T> +-__hostdev__ inline CoordT Round(const Vec3T& xyz) ++__hostdev__ inline CoordT Round(__global__ const Vec3T& xyz) + { + return CoordT(int32_t(floor(xyz[0] + 0.5)), int32_t(floor(xyz[1] + 0.5)), int32_t(floor(xyz[2] + 0.5))); + } ++#if defined(__KERNEL_METAL__) ++template class Vec3T> ++__hostdev__ inline CoordT Round(__local__ const Vec3T& xyz) ++{ ++ return CoordT(int32_t(floor(xyz[0] + 0.5)), int32_t(floor(xyz[1] + 0.5)), int32_t(floor(xyz[2] + 0.5))); ++} ++#endif + + template class Vec3T> +-__hostdev__ inline CoordT RoundDown(const Vec3T& xyz) ++__hostdev__ inline CoordT RoundDown(__global__ const Vec3T& xyz) + { + return CoordT(Floor(xyz[0]), Floor(xyz[1]), Floor(xyz[2])); + } +- ++#if defined(__KERNEL_METAL__) ++template class Vec3T> ++__hostdev__ inline CoordT RoundDown(__local__ const Vec3T& xyz) ++{ ++ return CoordT(Floor(xyz[0]), Floor(xyz[1]), Floor(xyz[2])); ++} ++#endif + //@{ + /// Return the square root of a floating-point value. + __hostdev__ inline float Sqrt(float x) + { + return sqrtf(x); + } ++#ifndef __KERNEL_METAL__ + __hostdev__ inline double Sqrt(double x) + { + return sqrt(x); + } ++#endif + //@} + + /// Return the sign of the given value as an integer (either -1, 0 or 1). + template +-__hostdev__ inline T Sign(const T &x) { return ((T(0) < x)?T(1):T(0)) - ((x < T(0))?T(1):T(0)); } ++__hostdev__ inline T Sign(__global__ const T &x) { return ((T(0) < x)?T(1):T(0)) - ((x < T(0))?T(1):T(0)); } ++#if defined(__KERNEL_METAL__) ++template ++__hostdev__ inline T Sign(__local__ const T &x) { return ((T(0) < x)?T(1):T(0)) - ((x < T(0))?T(1):T(0)); } ++#endif + + template +-__hostdev__ inline int MinIndex(const Vec3T& v) ++__hostdev__ inline int MinIndex(__global__ const Vec3T& v) + { + #if 0 + static const int hashTable[8] = {2, 1, 9, 1, 2, 9, 0, 0}; //9 are dummy values +@@ -930,8 +1021,27 @@ __hostdev__ inline int MinIndex(const Vec3T& v) + #endif + } + ++#if defined(__KERNEL_METAL__) + template +-__hostdev__ inline int MaxIndex(const Vec3T& v) ++__hostdev__ inline int MinIndex(__local__ const Vec3T& v) ++{ ++#if 0 ++ static const int hashTable[8] = {2, 1, 9, 1, 2, 9, 0, 0}; //9 are dummy values ++ const int hashKey = ((v[0] < v[1]) << 2) + ((v[0] < v[2]) << 1) + (v[1] < v[2]); // ?*4+?*2+?*1 ++ return hashTable[hashKey]; ++#else ++ if (v[0] < v[1] && v[0] < v[2]) ++ return 0; ++ if (v[1] < v[2]) ++ return 1; ++ else ++ return 2; ++#endif ++} ++#endif ++ ++template ++__hostdev__ inline int MaxIndex(__global__ const Vec3T& v) + { + #if 0 + static const int hashTable[8] = {2, 1, 9, 1, 2, 9, 0, 0}; //9 are dummy values +@@ -947,6 +1057,25 @@ __hostdev__ inline int MaxIndex(const Vec3T& v) + #endif + } + ++#if defined(__KERNEL_METAL__) ++template ++__hostdev__ inline int MaxIndex(__local__ const Vec3T& v) ++{ ++#if 0 ++ static const int hashTable[8] = {2, 1, 9, 1, 2, 9, 0, 0}; //9 are dummy values ++ const int hashKey = ((v[0] > v[1]) << 2) + ((v[0] > v[2]) << 1) + (v[1] > v[2]); // ?*4+?*2+?*1 ++ return hashTable[hashKey]; ++#else ++ if (v[0] > v[1] && v[0] > v[2]) ++ return 0; ++ if (v[1] > v[2]) ++ return 1; ++ else ++ return 2; ++#endif ++} ++#endif ++ + /// @brief round up byteSize to the nearest wordSize, e.g. to align to machine word: AlignUp +- __hostdev__ Coord& operator=(const CoordT &other) ++ __hostdev__ __global__ Coord& operator=(__global__ const CoordT &other) __global__ + { + static_assert(sizeof(Coord) == sizeof(CoordT), "Mis-matched sizeof"); + mVec[0] = other[0]; +@@ -1025,6 +1160,17 @@ public: + mVec[2] = other[2]; + return *this; + } ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ __local__ Coord& operator=(__local__ const CoordT &other) __local__ ++ { ++ static_assert(sizeof(Coord) == sizeof(CoordT), "Mis-matched sizeof"); ++ mVec[0] = other[0]; ++ mVec[1] = other[1]; ++ mVec[2] = other[2]; ++ return *this; ++ } ++#endif + + /// @brief Return a new instance with coordinates masked by the given unsigned integer. + __hostdev__ Coord operator&(IndexType n) const { return Coord(mVec[0] & n, mVec[1] & n, mVec[2] & n); } +@@ -1036,52 +1182,52 @@ public: + __hostdev__ Coord operator>>(IndexType n) const { return Coord(mVec[0] >> n, mVec[1] >> n, mVec[2] >> n); } + + /// @brief Return true if this Coord is lexicographically less than the given Coord. +- __hostdev__ bool operator<(const Coord& rhs) const ++ __hostdev__ bool operator<(__global__ const Coord& rhs) const + { + return mVec[0] < rhs[0] ? true : mVec[0] > rhs[0] ? false : mVec[1] < rhs[1] ? true : mVec[1] > rhs[1] ? false : mVec[2] < rhs[2] ? true : false; + } + + // @brief Return true if the Coord components are identical. +- __hostdev__ bool operator==(const Coord& rhs) const { return mVec[0] == rhs[0] && mVec[1] == rhs[1] && mVec[2] == rhs[2]; } +- __hostdev__ bool operator!=(const Coord& rhs) const { return mVec[0] != rhs[0] || mVec[1] != rhs[1] || mVec[2] != rhs[2]; } +- __hostdev__ Coord& operator&=(int n) ++ __hostdev__ bool operator==(__global__ const Coord& rhs) const { return mVec[0] == rhs[0] && mVec[1] == rhs[1] && mVec[2] == rhs[2]; } ++ __hostdev__ bool operator!=(__global__ const Coord& rhs) const { return mVec[0] != rhs[0] || mVec[1] != rhs[1] || mVec[2] != rhs[2]; } ++ __hostdev__ __global__ Coord& operator&=(int n) __global__ + { + mVec[0] &= n; + mVec[1] &= n; + mVec[2] &= n; + return *this; + } +- __hostdev__ Coord& operator<<=(uint32_t n) ++ __hostdev__ __global__ Coord& operator<<=(uint32_t n) __global__ + { + mVec[0] <<= n; + mVec[1] <<= n; + mVec[2] <<= n; + return *this; + } +- __hostdev__ Coord& operator>>=(uint32_t n) ++ __hostdev__ __global__ Coord& operator>>=(uint32_t n) __global__ + { + mVec[0] >>= n; + mVec[1] >>= n; + mVec[2] >>= n; + return *this; + } +- __hostdev__ Coord& operator+=(int n) ++ __hostdev__ __global__ Coord& operator+=(int n) __global__ + { + mVec[0] += n; + mVec[1] += n; + mVec[2] += n; + return *this; + } +- __hostdev__ Coord operator+(const Coord& rhs) const { return Coord(mVec[0] + rhs[0], mVec[1] + rhs[1], mVec[2] + rhs[2]); } +- __hostdev__ Coord operator-(const Coord& rhs) const { return Coord(mVec[0] - rhs[0], mVec[1] - rhs[1], mVec[2] - rhs[2]); } +- __hostdev__ Coord& operator+=(const Coord& rhs) ++ __hostdev__ Coord operator+(__global__ const Coord& rhs) const { return Coord(mVec[0] + rhs[0], mVec[1] + rhs[1], mVec[2] + rhs[2]); } ++ __hostdev__ Coord operator-(__global__ const Coord& rhs) const { return Coord(mVec[0] - rhs[0], mVec[1] - rhs[1], mVec[2] - rhs[2]); } ++ __hostdev__ __global__ Coord& operator+=(__global__ const Coord& rhs) __global__ + { + mVec[0] += rhs[0]; + mVec[1] += rhs[1]; + mVec[2] += rhs[2]; + return *this; + } +- __hostdev__ Coord& operator-=(const Coord& rhs) ++ __hostdev__ __global__ Coord& operator-=(__global__ const Coord& rhs) __global__ + { + mVec[0] -= rhs[0]; + mVec[1] -= rhs[1]; +@@ -1090,7 +1236,7 @@ public: + } + + /// @brief Perform a component-wise minimum with the other Coord. +- __hostdev__ Coord& minComponent(const Coord& other) ++ __hostdev__ __global__ Coord& minComponent(__global__ const Coord& other) __global__ + { + if (other[0] < mVec[0]) + mVec[0] = other[0]; +@@ -1102,7 +1248,7 @@ public: + } + + /// @brief Perform a component-wise maximum with the other Coord. +- __hostdev__ Coord& maxComponent(const Coord& other) ++ __hostdev__ __global__ Coord& maxComponent(__global__ const Coord& other) __global__ + { + if (other[0] > mVec[0]) + mVec[0] = other[0]; +@@ -1113,16 +1259,16 @@ public: + return *this; + } + +- __hostdev__ Coord offsetBy(ValueType dx, ValueType dy, ValueType dz) const ++ __hostdev__ Coord offsetBy(ValueType dx, ValueType dy, ValueType dz) const __global__ + { + return Coord(mVec[0] + dx, mVec[1] + dy, mVec[2] + dz); + } + +- __hostdev__ Coord offsetBy(ValueType n) const { return this->offsetBy(n, n, n); } ++ __hostdev__ Coord offsetBy(ValueType n) const __global__ { return this->offsetBy(n, n, n); } + + /// Return true if any of the components of @a a are smaller than the + /// corresponding components of @a b. +- __hostdev__ static inline bool lessThan(const Coord& a, const Coord& b) ++ __hostdev__ static inline bool lessThan(__global__ const Coord& a, __global__ const Coord& b) + { + return (a[0] < b[0] || a[1] < b[1] || a[2] < b[2]); + } +@@ -1130,7 +1276,13 @@ public: + /// @brief Return the largest integer coordinates that are not greater + /// than @a xyz (node centered conversion). + template +- __hostdev__ static Coord Floor(const Vec3T& xyz) { return Coord(nanovdb::Floor(xyz[0]), nanovdb::Floor(xyz[1]), nanovdb::Floor(xyz[2])); } ++ __hostdev__ static Coord Floor(__global__ const Vec3T& xyz) { return Coord(nanovdb::Floor(xyz[0]), nanovdb::Floor(xyz[1]), nanovdb::Floor(xyz[2])); } ++#if defined __KERNEL_METAL__ ++ /// @brief Return the largest integer coordinates that are not greater ++ /// than @a xyz (node centered conversion). ++ template ++ __hostdev__ static Coord Floor(__local__ const Vec3T& xyz) { return Coord(nanovdb::Floor(xyz[0]), nanovdb::Floor(xyz[1]), nanovdb::Floor(xyz[2])); } ++#endif + + /// @brief Return a hash key derived from the existing coordinates. + /// @details For details on this hash function please see the VDB paper. +@@ -1159,7 +1311,7 @@ class Vec3 + T mVec[3]; + + public: +- static const int SIZE = 3; ++ static __constant__ const int SIZE = 3; + using ValueType = T; + Vec3() = default; + __hostdev__ explicit Vec3(T x) +@@ -1171,30 +1323,36 @@ public: + { + } + template +- __hostdev__ explicit Vec3(const Vec3& v) ++ __hostdev__ explicit Vec3(__global__ const Vec3& v) + : mVec{T(v[0]), T(v[1]), T(v[2])} + { + } +- __hostdev__ explicit Vec3(const Coord& ijk) ++ __hostdev__ explicit Vec3(__global__ const Coord& ijk) + : mVec{T(ijk[0]), T(ijk[1]), T(ijk[2])} + { + } +- __hostdev__ bool operator==(const Vec3& rhs) const { return mVec[0] == rhs[0] && mVec[1] == rhs[1] && mVec[2] == rhs[2]; } +- __hostdev__ bool operator!=(const Vec3& rhs) const { return mVec[0] != rhs[0] || mVec[1] != rhs[1] || mVec[2] != rhs[2]; } ++ __hostdev__ bool operator==(__global__ const Vec3& rhs) const { return mVec[0] == rhs[0] && mVec[1] == rhs[1] && mVec[2] == rhs[2]; } ++ __hostdev__ bool operator!=(__global__ const Vec3& rhs) const { return mVec[0] != rhs[0] || mVec[1] != rhs[1] || mVec[2] != rhs[2]; } + template +- __hostdev__ Vec3& operator=(const Vec3T& rhs) ++ __hostdev__ __global__ Vec3& operator=(__global__ const Vec3T& rhs) + { + mVec[0] = rhs[0]; + mVec[1] = rhs[1]; + mVec[2] = rhs[2]; + return *this; + } +- __hostdev__ const T& operator[](int i) const { return mVec[i]; } +- __hostdev__ T& operator[](int i) { return mVec[i]; } ++ __hostdev__ __global__ const T& operator[](int i) const __global__ { return mVec[i]; } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ __local__ const T& operator[](int i) const __local__ { return mVec[i]; } ++#endif ++ __hostdev__ __global__ T& operator[](int i) __global__ { return mVec[i]; } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ __local__ T& operator[](int i) __local__ { return mVec[i]; } ++#endif + template +- __hostdev__ T dot(const Vec3T& v) const { return mVec[0] * v[0] + mVec[1] * v[1] + mVec[2] * v[2]; } ++ __hostdev__ T dot(__global__ const Vec3T& v) const { return mVec[0] * v[0] + mVec[1] * v[1] + mVec[2] * v[2]; } + template +- __hostdev__ Vec3 cross(const Vec3T& v) const ++ __hostdev__ Vec3 cross(__global__ const Vec3T& v) const + { + return Vec3(mVec[1] * v[2] - mVec[2] * v[1], + mVec[2] * v[0] - mVec[0] * v[2], +@@ -1206,37 +1364,62 @@ public: + } + __hostdev__ T length() const { return Sqrt(this->lengthSqr()); } + __hostdev__ Vec3 operator-() const { return Vec3(-mVec[0], -mVec[1], -mVec[2]); } +- __hostdev__ Vec3 operator*(const Vec3& v) const { return Vec3(mVec[0] * v[0], mVec[1] * v[1], mVec[2] * v[2]); } +- __hostdev__ Vec3 operator/(const Vec3& v) const { return Vec3(mVec[0] / v[0], mVec[1] / v[1], mVec[2] / v[2]); } +- __hostdev__ Vec3 operator+(const Vec3& v) const { return Vec3(mVec[0] + v[0], mVec[1] + v[1], mVec[2] + v[2]); } +- __hostdev__ Vec3 operator-(const Vec3& v) const { return Vec3(mVec[0] - v[0], mVec[1] - v[1], mVec[2] - v[2]); } +- __hostdev__ Vec3 operator*(const T& s) const { return Vec3(s * mVec[0], s * mVec[1], s * mVec[2]); } +- __hostdev__ Vec3 operator/(const T& s) const { return (T(1) / s) * (*this); } +- __hostdev__ Vec3& operator+=(const Vec3& v) ++ __hostdev__ Vec3 operator*(__global__ const Vec3& v) const { return Vec3(mVec[0] * v[0], mVec[1] * v[1], mVec[2] * v[2]); } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ Vec3 operator*(__local__ const Vec3& v) const { return Vec3(mVec[0] * v[0], mVec[1] * v[1], mVec[2] * v[2]); } ++#endif ++ __hostdev__ Vec3 operator/(__global__ const Vec3& v) const { return Vec3(mVec[0] / v[0], mVec[1] / v[1], mVec[2] / v[2]); } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ Vec3 operator/(__local__ const Vec3& v) const { return Vec3(mVec[0] / v[0], mVec[1] / v[1], mVec[2] / v[2]); } ++#endif ++ __hostdev__ Vec3 operator+(__global__ const Vec3& v) const { return Vec3(mVec[0] + v[0], mVec[1] + v[1], mVec[2] + v[2]); } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ Vec3 operator-(__local__ const Vec3& v) const { return Vec3(mVec[0] - v[0], mVec[1] - v[1], mVec[2] - v[2]); } ++ __hostdev__ Vec3 operator+(__local__ const Vec3& v) const { return Vec3(mVec[0] + v[0], mVec[1] + v[1], mVec[2] + v[2]); } ++#endif ++ __hostdev__ Vec3 operator-(__global__ const Vec3& v) const { return Vec3(mVec[0] - v[0], mVec[1] - v[1], mVec[2] - v[2]); } ++ __hostdev__ Vec3 operator*(__global__ const T& s) const { return Vec3(s * mVec[0], s * mVec[1], s * mVec[2]); } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ Vec3 operator*(__local__ const T& s) const { return Vec3(s * mVec[0], s * mVec[1], s * mVec[2]); } ++#endif ++ __hostdev__ Vec3 operator/(__global__ const T& s) const { return (T(1) / s) * (*this); } ++ __hostdev__ __global__ Vec3& operator+=(__global__ const Vec3& v) + { + mVec[0] += v[0]; + mVec[1] += v[1]; + mVec[2] += v[2]; + return *this; + } +- __hostdev__ Vec3& operator-=(const Vec3& v) ++ __hostdev__ __global__ Vec3& operator-=(__global__ const Vec3& v) + { + mVec[0] -= v[0]; + mVec[1] -= v[1]; + mVec[2] -= v[2]; + return *this; + } +- __hostdev__ Vec3& operator*=(const T& s) ++ __hostdev__ __global__ Vec3& operator*=(__global__ const T& s) + { + mVec[0] *= s; + mVec[1] *= s; + mVec[2] *= s; + return *this; + } +- __hostdev__ Vec3& operator/=(const T& s) { return (*this) *= T(1) / s; } +- __hostdev__ Vec3& normalize() { return (*this) /= this->length(); } ++#if defined __KERNEL_METAL__ ++ __hostdev__ __local__ Vec3& operator*=(__local__ const T& s) ++ { ++ mVec[0] *= s; ++ mVec[1] *= s; ++ mVec[2] *= s; ++ return *this; ++ } ++#endif ++ __hostdev__ __global__ Vec3& operator/=(__global__ const T& s) { return (*this) *= T(1) / s; } ++#if defined __KERNEL_METAL__ ++ __hostdev__ __local__ Vec3& operator/=(__local__ const T& s) { return (*this) *= T(1) / s; } ++#endif ++ __hostdev__ __global__ Vec3& normalize() { return (*this) /= this->length(); } + /// @brief Perform a component-wise minimum with the other Coord. +- __hostdev__ Vec3& minComponent(const Vec3& other) ++ __hostdev__ __global__ Vec3& minComponent(__global__ const Vec3& other) + { + if (other[0] < mVec[0]) + mVec[0] = other[0]; +@@ -1248,7 +1431,7 @@ public: + } + + /// @brief Perform a component-wise maximum with the other Coord. +- __hostdev__ Vec3& maxComponent(const Vec3& other) ++ __hostdev__ __global__ Vec3& maxComponent(__global__ const Vec3& other) + { + if (other[0] > mVec[0]) + mVec[0] = other[0]; +@@ -1274,15 +1457,29 @@ public: + }; // Vec3 + + template +-__hostdev__ inline Vec3 operator*(T1 scalar, const Vec3& vec) ++__hostdev__ inline Vec3 operator*(T1 scalar, __global__ const Vec3& vec) + { + return Vec3(scalar * vec[0], scalar * vec[1], scalar * vec[2]); + } ++#if defined(__KERNEL_METAL__) + template +-__hostdev__ inline Vec3 operator/(T1 scalar, const Vec3& vec) ++__hostdev__ inline Vec3 operator*(T1 scalar, __local__ const Vec3& vec) ++{ ++ return Vec3(scalar * vec[0], scalar * vec[1], scalar * vec[2]); ++} ++#endif ++template ++__hostdev__ inline Vec3 operator/(T1 scalar, __global__ const Vec3& vec) + { + return Vec3(scalar / vec[0], scalar / vec[1], scalar / vec[2]); + } ++#if defined(__KERNEL_METAL__) ++template ++__hostdev__ inline Vec3 operator/(T1 scalar, __local__ const Vec3& vec) ++{ ++ return Vec3(scalar / vec[0], scalar / vec[1], scalar / vec[2]); ++} ++#endif + + using Vec3R = Vec3; + using Vec3d = Vec3; +@@ -1304,7 +1501,7 @@ class Vec4 + T mVec[4]; + + public: +- static const int SIZE = 4; ++ static __constant__ const int SIZE = 4; + using ValueType = T; + Vec4() = default; + __hostdev__ explicit Vec4(T x) +@@ -1316,14 +1513,14 @@ public: + { + } + template +- __hostdev__ explicit Vec4(const Vec4& v) ++ __hostdev__ explicit Vec4(__global__ const Vec4& v) + : mVec{T(v[0]), T(v[1]), T(v[2]), T(v[3])} + { + } +- __hostdev__ bool operator==(const Vec4& rhs) const { return mVec[0] == rhs[0] && mVec[1] == rhs[1] && mVec[2] == rhs[2] && mVec[3] == rhs[3]; } +- __hostdev__ bool operator!=(const Vec4& rhs) const { return mVec[0] != rhs[0] || mVec[1] != rhs[1] || mVec[2] != rhs[2] || mVec[3] != rhs[3]; } ++ __hostdev__ bool operator==(__global__ const Vec4& rhs) const { return mVec[0] == rhs[0] && mVec[1] == rhs[1] && mVec[2] == rhs[2] && mVec[3] == rhs[3]; } ++ __hostdev__ bool operator!=(__global__ const Vec4& rhs) const { return mVec[0] != rhs[0] || mVec[1] != rhs[1] || mVec[2] != rhs[2] || mVec[3] != rhs[3]; } + template +- __hostdev__ Vec4& operator=(const Vec4T& rhs) ++ __hostdev__ __global__ Vec4& operator=(__global__ const Vec4T& rhs) + { + mVec[0] = rhs[0]; + mVec[1] = rhs[1]; +@@ -1331,23 +1528,23 @@ public: + mVec[3] = rhs[3]; + return *this; + } +- __hostdev__ const T& operator[](int i) const { return mVec[i]; } +- __hostdev__ T& operator[](int i) { return mVec[i]; } ++ __hostdev__ __global__ const T& operator[](int i) const { return mVec[i]; } ++ __hostdev__ __global__ T& operator[](int i) { return mVec[i]; } + template +- __hostdev__ T dot(const Vec4T& v) const { return mVec[0] * v[0] + mVec[1] * v[1] + mVec[2] * v[2] + mVec[3] * v[3]; } ++ __hostdev__ T dot(__global__ const Vec4T& v) const { return mVec[0] * v[0] + mVec[1] * v[1] + mVec[2] * v[2] + mVec[3] * v[3]; } + __hostdev__ T lengthSqr() const + { + return mVec[0] * mVec[0] + mVec[1] * mVec[1] + mVec[2] * mVec[2] + mVec[3] * mVec[3]; // 7 flops + } + __hostdev__ T length() const { return Sqrt(this->lengthSqr()); } + __hostdev__ Vec4 operator-() const { return Vec4(-mVec[0], -mVec[1], -mVec[2], -mVec[3]); } +- __hostdev__ Vec4 operator*(const Vec4& v) const { return Vec4(mVec[0] * v[0], mVec[1] * v[1], mVec[2] * v[2], mVec[3] * v[3]); } +- __hostdev__ Vec4 operator/(const Vec4& v) const { return Vec4(mVec[0] / v[0], mVec[1] / v[1], mVec[2] / v[2], mVec[3] / v[3]); } +- __hostdev__ Vec4 operator+(const Vec4& v) const { return Vec4(mVec[0] + v[0], mVec[1] + v[1], mVec[2] + v[2], mVec[3] + v[3]); } +- __hostdev__ Vec4 operator-(const Vec4& v) const { return Vec4(mVec[0] - v[0], mVec[1] - v[1], mVec[2] - v[2], mVec[3] - v[3]); } +- __hostdev__ Vec4 operator*(const T& s) const { return Vec4(s * mVec[0], s * mVec[1], s * mVec[2], s * mVec[3]); } +- __hostdev__ Vec4 operator/(const T& s) const { return (T(1) / s) * (*this); } +- __hostdev__ Vec4& operator+=(const Vec4& v) ++ __hostdev__ Vec4 operator*(__global__ const Vec4& v) const { return Vec4(mVec[0] * v[0], mVec[1] * v[1], mVec[2] * v[2], mVec[3] * v[3]); } ++ __hostdev__ Vec4 operator/(__global__ const Vec4& v) const { return Vec4(mVec[0] / v[0], mVec[1] / v[1], mVec[2] / v[2], mVec[3] / v[3]); } ++ __hostdev__ Vec4 operator+(__global__ const Vec4& v) const { return Vec4(mVec[0] + v[0], mVec[1] + v[1], mVec[2] + v[2], mVec[3] + v[3]); } ++ __hostdev__ Vec4 operator-(__global__ const Vec4& v) const { return Vec4(mVec[0] - v[0], mVec[1] - v[1], mVec[2] - v[2], mVec[3] - v[3]); } ++ __hostdev__ Vec4 operator*(__global__ const T& s) const { return Vec4(s * mVec[0], s * mVec[1], s * mVec[2], s * mVec[3]); } ++ __hostdev__ Vec4 operator/(__global__ const T& s) const { return (T(1) / s) * (*this); } ++ __hostdev__ __global__ Vec4& operator+=(__global__ const Vec4& v) + { + mVec[0] += v[0]; + mVec[1] += v[1]; +@@ -1355,7 +1552,7 @@ public: + mVec[3] += v[3]; + return *this; + } +- __hostdev__ Vec4& operator-=(const Vec4& v) ++ __hostdev__ __global__ Vec4& operator-=(__global__ const Vec4& v) + { + mVec[0] -= v[0]; + mVec[1] -= v[1]; +@@ -1363,7 +1560,7 @@ public: + mVec[3] -= v[3]; + return *this; + } +- __hostdev__ Vec4& operator*=(const T& s) ++ __hostdev__ __global__ Vec4& operator*=(__global__ const T& s) + { + mVec[0] *= s; + mVec[1] *= s; +@@ -1371,10 +1568,10 @@ public: + mVec[3] *= s; + return *this; + } +- __hostdev__ Vec4& operator/=(const T& s) { return (*this) *= T(1) / s; } +- __hostdev__ Vec4& normalize() { return (*this) /= this->length(); } ++ __hostdev__ __global__ Vec4& operator/=(__global__ const T& s) { return (*this) *= T(1) / s; } ++ __hostdev__ __global__ Vec4& normalize() { return (*this) /= this->length(); } + /// @brief Perform a component-wise minimum with the other Coord. +- __hostdev__ Vec4& minComponent(const Vec4& other) ++ __hostdev__ __global__ Vec4& minComponent(__global__ const Vec4& other) + { + if (other[0] < mVec[0]) + mVec[0] = other[0]; +@@ -1388,7 +1585,7 @@ public: + } + + /// @brief Perform a component-wise maximum with the other Coord. +- __hostdev__ Vec4& maxComponent(const Vec4& other) ++ __hostdev__ __global__ Vec4& maxComponent(__global__ const Vec4& other) + { + if (other[0] > mVec[0]) + mVec[0] = other[0]; +@@ -1403,12 +1600,12 @@ public: + }; // Vec4 + + template +-__hostdev__ inline Vec4 operator*(T1 scalar, const Vec4& vec) ++__hostdev__ inline Vec4 operator*(T1 scalar, __global__ const Vec4& vec) + { + return Vec4(scalar * vec[0], scalar * vec[1], scalar * vec[2], scalar * vec[3]); + } + template +-__hostdev__ inline Vec4 operator/(T1 scalar, const Vec3& vec) ++__hostdev__ inline Vec4 operator/(T1 scalar, __global__ const Vec3& vec) + { + return Vec4(scalar / vec[0], scalar / vec[1], scalar / vec[2], scalar / vec[3]); + } +@@ -1428,23 +1625,23 @@ struct TensorTraits; + template + struct TensorTraits + { +- static const int Rank = 0; // i.e. scalar +- static const bool IsScalar = true; +- static const bool IsVector = false; +- static const int Size = 1; ++ static __constant__ const int Rank = 0; // i.e. scalar ++ static __constant__ const bool IsScalar = true; ++ static __constant__ const bool IsVector = false; ++ static __constant__ const int Size = 1; + using ElementType = T; +- static T scalar(const T& s) { return s; } ++ static T scalar(__global__ const T& s) { return s; } + }; + + template + struct TensorTraits + { +- static const int Rank = 1; // i.e. vector +- static const bool IsScalar = false; +- static const bool IsVector = true; +- static const int Size = T::SIZE; ++ static __constant__ const int Rank = 1; // i.e. vector ++ static __constant__ const bool IsScalar = false; ++ static __constant__ const bool IsVector = true; ++ static __constant__ const int Size = T::SIZE; + using ElementType = typename T::ValueType; +- static ElementType scalar(const T& v) { return v.length(); } ++ static ElementType scalar(__global__ const T& v) { return v.length(); } + }; + + // ----------------------------> FloatTraits <-------------------------------------- +@@ -1528,71 +1725,80 @@ __hostdev__ inline GridType mapToGridType() + // ----------------------------> matMult <-------------------------------------- + + template +-__hostdev__ inline Vec3T matMult(const float* mat, const Vec3T& xyz) ++__hostdev__ inline Vec3T matMult(__global__ const float* mat, __global__ const Vec3T& xyz) + { + return Vec3T(fmaf(xyz[0], mat[0], fmaf(xyz[1], mat[1], xyz[2] * mat[2])), + fmaf(xyz[0], mat[3], fmaf(xyz[1], mat[4], xyz[2] * mat[5])), + fmaf(xyz[0], mat[6], fmaf(xyz[1], mat[7], xyz[2] * mat[8]))); // 6 fmaf + 3 mult = 9 flops + } +- ++#if defined(__KERNEL_METAL__) + template +-__hostdev__ inline Vec3T matMult(const double* mat, const Vec3T& xyz) ++__hostdev__ inline Vec3T matMult(__global__ const float* mat, __local__ const Vec3T& xyz) ++{ ++ return Vec3T(fmaf(xyz[0], mat[0], fmaf(xyz[1], mat[1], xyz[2] * mat[2])), ++ fmaf(xyz[0], mat[3], fmaf(xyz[1], mat[4], xyz[2] * mat[5])), ++ fmaf(xyz[0], mat[6], fmaf(xyz[1], mat[7], xyz[2] * mat[8]))); // 6 fmaf + 3 mult = 9 flops ++} ++#endif ++#ifndef __KERNEL_METAL__ ++template ++__hostdev__ inline Vec3T matMult(__global__ const double* mat, __global__ const Vec3T& xyz) + { + return Vec3T(fma(static_cast(xyz[0]), mat[0], fma(static_cast(xyz[1]), mat[1], static_cast(xyz[2]) * mat[2])), + fma(static_cast(xyz[0]), mat[3], fma(static_cast(xyz[1]), mat[4], static_cast(xyz[2]) * mat[5])), + fma(static_cast(xyz[0]), mat[6], fma(static_cast(xyz[1]), mat[7], static_cast(xyz[2]) * mat[8]))); // 6 fmaf + 3 mult = 9 flops + } +- ++#endif + template +-__hostdev__ inline Vec3T matMult(const float* mat, const float* vec, const Vec3T& xyz) ++__hostdev__ inline Vec3T matMult(__global__ const float* mat, __global__ const float* vec, __global__ const Vec3T& xyz) + { + return Vec3T(fmaf(xyz[0], mat[0], fmaf(xyz[1], mat[1], fmaf(xyz[2], mat[2], vec[0]))), + fmaf(xyz[0], mat[3], fmaf(xyz[1], mat[4], fmaf(xyz[2], mat[5], vec[1]))), + fmaf(xyz[0], mat[6], fmaf(xyz[1], mat[7], fmaf(xyz[2], mat[8], vec[2])))); // 9 fmaf = 9 flops + } +- ++#ifndef __KERNEL_METAL__ + template +-__hostdev__ inline Vec3T matMult(const double* mat, const double* vec, const Vec3T& xyz) ++__hostdev__ inline Vec3T matMult(__global__ const double* mat, __global__ const double* vec, __global__ const Vec3T& xyz) + { + return Vec3T(fma(static_cast(xyz[0]), mat[0], fma(static_cast(xyz[1]), mat[1], fma(static_cast(xyz[2]), mat[2], vec[0]))), + fma(static_cast(xyz[0]), mat[3], fma(static_cast(xyz[1]), mat[4], fma(static_cast(xyz[2]), mat[5], vec[1]))), + fma(static_cast(xyz[0]), mat[6], fma(static_cast(xyz[1]), mat[7], fma(static_cast(xyz[2]), mat[8], vec[2])))); // 9 fma = 9 flops + } +- ++#endif + // matMultT: Multiply with the transpose: + + template +-__hostdev__ inline Vec3T matMultT(const float* mat, const Vec3T& xyz) ++__hostdev__ inline Vec3T matMultT(__global__ const float* mat, __global__ const Vec3T& xyz) + { + return Vec3T(fmaf(xyz[0], mat[0], fmaf(xyz[1], mat[3], xyz[2] * mat[6])), + fmaf(xyz[0], mat[1], fmaf(xyz[1], mat[4], xyz[2] * mat[7])), + fmaf(xyz[0], mat[2], fmaf(xyz[1], mat[5], xyz[2] * mat[8]))); // 6 fmaf + 3 mult = 9 flops + } +- ++#ifndef __KERNEL_METAL__ + template +-__hostdev__ inline Vec3T matMultT(const double* mat, const Vec3T& xyz) ++__hostdev__ inline Vec3T matMultT(__global__ const double* mat, __global__ const Vec3T& xyz) + { + return Vec3T(fma(static_cast(xyz[0]), mat[0], fma(static_cast(xyz[1]), mat[3], static_cast(xyz[2]) * mat[6])), + fma(static_cast(xyz[0]), mat[1], fma(static_cast(xyz[1]), mat[4], static_cast(xyz[2]) * mat[7])), + fma(static_cast(xyz[0]), mat[2], fma(static_cast(xyz[1]), mat[5], static_cast(xyz[2]) * mat[8]))); // 6 fmaf + 3 mult = 9 flops + } +- ++#endif + template +-__hostdev__ inline Vec3T matMultT(const float* mat, const float* vec, const Vec3T& xyz) ++__hostdev__ inline Vec3T matMultT(__global__ const float* mat, __global__ const float* vec, __global__ const Vec3T& xyz) + { + return Vec3T(fmaf(xyz[0], mat[0], fmaf(xyz[1], mat[3], fmaf(xyz[2], mat[6], vec[0]))), + fmaf(xyz[0], mat[1], fmaf(xyz[1], mat[4], fmaf(xyz[2], mat[7], vec[1]))), + fmaf(xyz[0], mat[2], fmaf(xyz[1], mat[5], fmaf(xyz[2], mat[8], vec[2])))); // 9 fmaf = 9 flops + } +- ++#ifndef __KERNEL_METAL__ + template +-__hostdev__ inline Vec3T matMultT(const double* mat, const double* vec, const Vec3T& xyz) ++__hostdev__ inline Vec3T matMultT(__global__ const double* mat, __global__ const double* vec, __global__ const Vec3T& xyz) + { + return Vec3T(fma(static_cast(xyz[0]), mat[0], fma(static_cast(xyz[1]), mat[3], fma(static_cast(xyz[2]), mat[6], vec[0]))), + fma(static_cast(xyz[0]), mat[1], fma(static_cast(xyz[1]), mat[4], fma(static_cast(xyz[2]), mat[7], vec[1]))), + fma(static_cast(xyz[0]), mat[2], fma(static_cast(xyz[1]), mat[5], fma(static_cast(xyz[2]), mat[8], vec[2])))); // 9 fma = 9 flops + } +- ++#endif + // ----------------------------> BBox <------------------------------------- + + // Base-class for static polymorphism (cannot be constructed directly) +@@ -1600,22 +1806,34 @@ template + struct BaseBBox + { + Vec3T mCoord[2]; +- __hostdev__ bool operator==(const BaseBBox& rhs) const { return mCoord[0] == rhs.mCoord[0] && mCoord[1] == rhs.mCoord[1]; }; +- __hostdev__ bool operator!=(const BaseBBox& rhs) const { return mCoord[0] != rhs.mCoord[0] || mCoord[1] != rhs.mCoord[1]; }; +- __hostdev__ const Vec3T& operator[](int i) const { return mCoord[i]; } +- __hostdev__ Vec3T& operator[](int i) { return mCoord[i]; } +- __hostdev__ Vec3T& min() { return mCoord[0]; } +- __hostdev__ Vec3T& max() { return mCoord[1]; } +- __hostdev__ const Vec3T& min() const { return mCoord[0]; } +- __hostdev__ const Vec3T& max() const { return mCoord[1]; } +- __hostdev__ Coord& translate(const Vec3T& xyz) ++ __hostdev__ bool operator==(__global__ const BaseBBox& rhs) const __global__ { return mCoord[0] == rhs.mCoord[0] && mCoord[1] == rhs.mCoord[1]; }; ++ __hostdev__ bool operator!=(__global__ const BaseBBox& rhs) const __global__ { return mCoord[0] != rhs.mCoord[0] || mCoord[1] != rhs.mCoord[1]; }; ++ __hostdev__ __global__ const Vec3T& operator[](int i) const __global__ { return mCoord[i]; } ++ __hostdev__ __global__ Vec3T& operator[](int i) __global__ { return mCoord[i]; } ++ __hostdev__ __global__ Vec3T& min() __global__ { return mCoord[0]; } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ __global__ Vec3T& min() __local__ { return mCoord[0]; } ++#endif ++ __hostdev__ __global__ Vec3T& max() __global__ { return mCoord[1]; } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ __global__ Vec3T& max() __local__ { return mCoord[1]; } ++#endif ++ __hostdev__ __global__ const Vec3T& min() const __global__ { return mCoord[0]; } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ __local__ const Vec3T& min() const __local__ { return mCoord[0]; } ++#endif ++ __hostdev__ __global__ const Vec3T& max() const __global__ { return mCoord[1]; } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ __local__ const Vec3T& max() const __local__ { return mCoord[1]; } ++#endif ++ __hostdev__ __global__ Coord& translate(__global__ const Vec3T& xyz) __global__ + { + mCoord[0] += xyz; + mCoord[1] += xyz; + return *this; + } + // @brief Expand this bounding box to enclose point (i, j, k). +- __hostdev__ BaseBBox& expand(const Vec3T& xyz) ++ __hostdev__ __global__ BaseBBox& expand(__global__ const Vec3T& xyz) __global__ + { + mCoord[0].minComponent(xyz); + mCoord[1].maxComponent(xyz); +@@ -1623,7 +1841,7 @@ struct BaseBBox + } + + /// @brief Intersect this bounding box with the given bounding box. +- __hostdev__ BaseBBox& intersect(const BaseBBox& bbox) ++ __hostdev__ __global__ BaseBBox& intersect(__global__ const BaseBBox& bbox) __global__ + { + mCoord[0].maxComponent(bbox.min()); + mCoord[1].minComponent(bbox.max()); +@@ -1634,7 +1852,7 @@ struct BaseBBox + //{ + // return BaseBBox(mCoord[0].offsetBy(-padding),mCoord[1].offsetBy(padding)); + //} +- __hostdev__ bool isInside(const Vec3T& xyz) ++ __hostdev__ bool isInside(__global__ const Vec3T& xyz) + { + if (xyz[0] < mCoord[0][0] || xyz[1] < mCoord[0][1] || xyz[2] < mCoord[0][2]) + return false; +@@ -1642,10 +1860,20 @@ struct BaseBBox + return false; + return true; + } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ bool isInside(__local__ const Vec3T& xyz) ++ { ++ if (xyz[0] < mCoord[0][0] || xyz[1] < mCoord[0][1] || xyz[2] < mCoord[0][2]) ++ return false; ++ if (xyz[0] > mCoord[1][0] || xyz[1] > mCoord[1][1] || xyz[2] > mCoord[1][2]) ++ return false; ++ return true; ++ } ++#endif + + protected: + __hostdev__ BaseBBox() {} +- __hostdev__ BaseBBox(const Vec3T& min, const Vec3T& max) ++ __hostdev__ BaseBBox(__global__ const Vec3T& min, __global__ const Vec3T& max) + : mCoord{min, max} + { + } +@@ -1659,38 +1887,45 @@ struct BBox; + /// @note Min is inclusive and max is exclusive. If min = max the dimension of + /// the bounding box is zero and therefore it is also empty. + template +-struct BBox : public BaseBBox ++struct BBox ++#if !defined(__KERNEL_METAL__) ++ : public BaseBBox ++#endif + { + using Vec3Type = Vec3T; + using ValueType = typename Vec3T::ValueType; + static_assert(is_floating_point::value, "Expected a floating point coordinate type"); + using BaseT = BaseBBox; ++#if defined(__KERNEL_METAL__) ++ BaseBBox mCoord; ++#else + using BaseT::mCoord; ++#endif ++ + __hostdev__ BBox() + : BaseT(Vec3T( Maximum::value()), + Vec3T(-Maximum::value())) + { + } +- __hostdev__ BBox(const Vec3T& min, const Vec3T& max) ++ __hostdev__ BBox(__global__ const Vec3T& min, __global__ const Vec3T& max) + : BaseT(min, max) + { + } +- __hostdev__ BBox(const Coord& min, const Coord& max) ++ __hostdev__ BBox(__global__ const Coord& min, __global__ const Coord& max) + : BaseT(Vec3T(ValueType(min[0]), ValueType(min[1]), ValueType(min[2])), + Vec3T(ValueType(max[0] + 1), ValueType(max[1] + 1), ValueType(max[2] + 1))) + { + } +- __hostdev__ static BBox createCube(const Coord& min, typename Coord::ValueType dim) ++ __hostdev__ static BBox createCube(__global__ const Coord& min, typename Coord::ValueType dim) + { + return BBox(min, min.offsetBy(dim)); + } +- +- __hostdev__ BBox(const BaseBBox& bbox) : BBox(bbox[0], bbox[1]) {} ++ __hostdev__ BBox(__global__ const BaseBBox& bbox) __global__ : BBox(bbox[0], bbox[1]) {} + __hostdev__ bool empty() const { return mCoord[0][0] >= mCoord[1][0] || + mCoord[0][1] >= mCoord[1][1] || + mCoord[0][2] >= mCoord[1][2]; } + __hostdev__ Vec3T dim() const { return this->empty() ? Vec3T(0) : this->max() - this->min(); } +- __hostdev__ bool isInside(const Vec3T& p) const ++ __hostdev__ bool isInside(__global__ const Vec3T& p) const + { + return p[0] > mCoord[0][0] && p[1] > mCoord[0][1] && p[2] > mCoord[0][2] && + p[0] < mCoord[1][0] && p[1] < mCoord[1][1] && p[2] < mCoord[1][2]; +@@ -1703,24 +1938,32 @@ struct BBox : public BaseBBox + /// @note Both min and max are INCLUDED in the bbox so dim = max - min + 1. So, + /// if min = max the bounding box contains exactly one point and dim = 1! + template +-struct BBox : public BaseBBox ++struct BBox ++#if !defined(__KERNEL_METAL__) ++ : public BaseBBox ++#endif + { ++ + static_assert(is_same::value, "Expected \"int\" coordinate type"); + using BaseT = BaseBBox; ++#if defined(__KERNEL_METAL__) ++ BaseBBox mCoord; ++#else + using BaseT::mCoord; ++#endif + /// @brief Iterator over the domain covered by a BBox + /// @details z is the fastest-moving coordinate. + class Iterator + { +- const BBox& mBBox; ++ __global__ const BBox& mBBox; + CoordT mPos; + public: +- __hostdev__ Iterator(const BBox& b) ++ __hostdev__ Iterator(__global__ const BBox& b) + : mBBox(b) + , mPos(b.min()) + { + } +- __hostdev__ Iterator& operator++() ++ __hostdev__ __global__ Iterator& operator++() + { + if (mPos[2] < mBBox[1][2]) {// this is the most common case + ++mPos[2]; +@@ -1734,7 +1977,7 @@ struct BBox : public BaseBBox + } + return *this; + } +- __hostdev__ Iterator operator++(int) ++ __hostdev__ Iterator operator++(int) __global__ + { + auto tmp = *this; + ++(*this); +@@ -1742,20 +1985,20 @@ struct BBox : public BaseBBox + } + /// @brief Return @c true if the iterator still points to a valid coordinate. + __hostdev__ operator bool() const { return mPos[0] <= mBBox[1][0]; } +- __hostdev__ const CoordT& operator*() const { return mPos; } ++ __hostdev__ __global__ const CoordT& operator*() const { return mPos; } + }; // Iterator + __hostdev__ Iterator begin() const { return Iterator{*this}; } + __hostdev__ BBox() + : BaseT(CoordT::max(), CoordT::min()) + { + } +- __hostdev__ BBox(const CoordT& min, const CoordT& max) ++ __hostdev__ BBox(__global__ const CoordT& min, __global__ const CoordT& max) + : BaseT(min, max) + { + } + + template +- __hostdev__ BBox(BBox& other, const SplitT&) ++ __hostdev__ BBox(__global__ BBox& other, __global__ const SplitT&) + : BaseT(other.mCoord[0], other.mCoord[1]) + { + NANOVDB_ASSERT(this->is_divisible()); +@@ -1764,7 +2007,7 @@ struct BBox : public BaseBBox + other.mCoord[0][n] = mCoord[1][n] + 1; + } + +- __hostdev__ static BBox createCube(const CoordT& min, typename CoordT::ValueType dim) ++ __hostdev__ static BBox createCube(__global__ const CoordT& min, typename CoordT::ValueType dim) + { + return BBox(min, min.offsetBy(dim - 1)); + } +@@ -1778,15 +2021,23 @@ struct BBox : public BaseBBox + mCoord[0][2] > mCoord[1][2]; } + __hostdev__ CoordT dim() const { return this->empty() ? Coord(0) : this->max() - this->min() + Coord(1); } + __hostdev__ uint64_t volume() const { auto d = this->dim(); return uint64_t(d[0])*uint64_t(d[1])*uint64_t(d[2]); } +- __hostdev__ bool isInside(const CoordT& p) const { return !(CoordT::lessThan(p, this->min()) || CoordT::lessThan(this->max(), p)); } +- /// @brief Return @c true if the given bounding box is inside this bounding box. +- __hostdev__ bool isInside(const BBox& b) const ++ __hostdev__ bool isInside(__global__ const CoordT& p) const { return !(CoordT::lessThan(p, this->min()) || CoordT::lessThan(this->max(), p)); } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ bool isInside(__local__ const CoordT& p) const { return !(CoordT::lessThan(p, this->min()) || CoordT::lessThan(this->max(), p)); } ++#endif ++ __hostdev__ bool isInside(__global__ const BBox& b) const + { + return !(CoordT::lessThan(b.min(), this->min()) || CoordT::lessThan(this->max(), b.max())); + } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ bool isInside(__local__ const BBox& b) const ++ { ++ return !(CoordT::lessThan(b.min(), this->min()) || CoordT::lessThan(this->max(), b.max())); ++ } ++#endif + + /// @brief Return @c true if the given bounding box overlaps with this bounding box. +- __hostdev__ bool hasOverlap(const BBox& b) const ++ __hostdev__ bool hasOverlap(__global__ const BBox& b) const + { + return !(CoordT::lessThan(this->max(), b.min()) || CoordT::lessThan(b.max(), this->min())); + } +@@ -1826,6 +2077,8 @@ __hostdev__ static inline uint32_t FindLowestOn(uint32_t v) + return static_cast(index); + #elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS) + return static_cast(__builtin_ctzl(v)); ++#elif defined(__KERNEL_METAL__) ++ return ctz(v); + #else + //#warning Using software implementation for FindLowestOn(uint32_t) + static const unsigned char DeBruijn[32] = { +@@ -1856,6 +2109,8 @@ __hostdev__ static inline uint32_t FindHighestOn(uint32_t v) + return static_cast(index); + #elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS) + return sizeof(unsigned long) * 8 - 1 - __builtin_clzl(v); ++#elif defined(__KERNEL_METAL__) ++ return clz(v); + #else + //#warning Using software implementation for FindHighestOn(uint32_t) + static const unsigned char DeBruijn[32] = { +@@ -1884,6 +2139,8 @@ __hostdev__ static inline uint32_t FindLowestOn(uint64_t v) + return static_cast(index); + #elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS) + return static_cast(__builtin_ctzll(v)); ++#elif defined(__KERNEL_METAL__) ++ return ctz(v); + #else + //#warning Using software implementation for FindLowestOn(uint64_t) + static const unsigned char DeBruijn[64] = { +@@ -1918,6 +2175,8 @@ __hostdev__ static inline uint32_t FindHighestOn(uint64_t v) + return static_cast(index); + #elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS) + return sizeof(unsigned long) * 8 - 1 - __builtin_clzll(v); ++#elif defined(__KERNEL_METAL__) ++ return clz(v); + #else + const uint32_t* p = reinterpret_cast(&v); + return p[1] ? 32u + FindHighestOn(p[1]) : FindHighestOn(p[0]); +@@ -1955,8 +2214,8 @@ __hostdev__ inline uint32_t CountOn(uint64_t v) + template + class Mask + { +- static constexpr uint32_t SIZE = 1U << (3 * LOG2DIM); // Number of bits in mask +- static constexpr uint32_t WORD_COUNT = SIZE >> 6; // Number of 64 bit words ++ static __constant__ constexpr uint32_t SIZE = 1U << (3 * LOG2DIM); // Number of bits in mask ++ static __constant__ constexpr uint32_t WORD_COUNT = SIZE >> 6; // Number of 64 bit words + uint64_t mWords[WORD_COUNT]; + + public: +@@ -1973,7 +2232,7 @@ public: + __hostdev__ uint32_t countOn() const + { + uint32_t sum = 0, n = WORD_COUNT; +- for (const uint64_t* w = mWords; n--; ++w) ++ for (__global__ const uint64_t* w = mWords; n--; ++w) + sum += CountOn(*w); + return sum; + } +@@ -1982,7 +2241,7 @@ public: + inline __hostdev__ uint32_t countOn(uint32_t i) const + { + uint32_t n = i >> 6, sum = CountOn( mWords[n] & ((uint64_t(1) << (i & 63u))-1u) ); +- for (const uint64_t* w = mWords; n--; ++w) sum += CountOn(*w); ++ for (__global__ const uint64_t* w = mWords; n--; ++w) sum += CountOn(*w); + return sum; + } + +@@ -1990,13 +2249,21 @@ public: + class Iterator + { + public: +- __hostdev__ Iterator() : mPos(Mask::SIZE), mParent(nullptr){} +- __hostdev__ Iterator(uint32_t pos, const Mask* parent) : mPos(pos), mParent(parent){} +- Iterator& operator=(const Iterator&) = default; ++ __hostdev__ Iterator() ++ : mPos(Mask::SIZE) ++ , mParent(nullptr) ++ { ++ } ++ __hostdev__ Iterator(uint32_t pos, __global__ const Mask* parent) ++ : mPos(pos) ++ , mParent(parent) ++ { ++ } ++ __global__ Iterator& operator=(__global__ const Iterator&) = default; + __hostdev__ uint32_t operator*() const { return mPos; } + __hostdev__ uint32_t pos() const { return mPos; } + __hostdev__ operator bool() const { return mPos != Mask::SIZE; } +- __hostdev__ Iterator& operator++() ++ __hostdev__ __global__ Iterator& operator++() + { + mPos = mParent->findNext(mPos + 1); + return *this; +@@ -2010,7 +2277,7 @@ public: + + private: + uint32_t mPos; +- const Mask* mParent; ++ __global__ const Mask* mParent; + }; // Member class Iterator + + using OnIterator = Iterator; +@@ -2034,7 +2301,7 @@ public: + } + + /// @brief Copy constructor +- __hostdev__ Mask(const Mask& other) ++ __hostdev__ Mask(__global__ const Mask& other) + { + for (uint32_t i = 0; i < WORD_COUNT; ++i) + mWords[i] = other.mWords[i]; +@@ -2042,36 +2309,36 @@ public: + + /// @brief Return a const reference to the nth word of the bit mask, for a word of arbitrary size. + template +- __hostdev__ const WordT& getWord(int n) const ++ __hostdev__ __global__ const WordT& getWord(int n) const + { + NANOVDB_ASSERT(n * 8 * sizeof(WordT) < SIZE); +- return reinterpret_cast(mWords)[n]; ++ return reinterpret_cast<__global__ const WordT*>(mWords)[n]; + } + + /// @brief Return a reference to the nth word of the bit mask, for a word of arbitrary size. + template +- __hostdev__ WordT& getWord(int n) ++ __hostdev__ __global__ WordT& getWord(int n) + { + NANOVDB_ASSERT(n * 8 * sizeof(WordT) < SIZE); +- return reinterpret_cast(mWords)[n]; ++ return reinterpret_cast<__global__ WordT*>(mWords)[n]; + } + + /// @brief Assignment operator that works with openvdb::util::NodeMask + template +- __hostdev__ Mask& operator=(const MaskT& other) ++ __hostdev__ __global__ Mask& operator=(__global__ const MaskT& other) + { + static_assert(sizeof(Mask) == sizeof(MaskT), "Mismatching sizeof"); + static_assert(WORD_COUNT == MaskT::WORD_COUNT, "Mismatching word count"); + static_assert(LOG2DIM == MaskT::LOG2DIM, "Mismatching LOG2DIM"); +- auto *src = reinterpret_cast(&other); +- uint64_t *dst = mWords; ++ __global__ auto *src = reinterpret_cast<__global__ const uint64_t*>(&other); ++ __global__ uint64_t *dst = mWords; + for (uint32_t i = 0; i < WORD_COUNT; ++i) { + *dst++ = *src++; + } + return *this; + } + +- __hostdev__ bool operator==(const Mask& other) const ++ __hostdev__ bool operator==(__global__ const Mask& other) const + { + for (uint32_t i = 0; i < WORD_COUNT; ++i) { + if (mWords[i] != other.mWords[i]) return false; +@@ -2079,22 +2346,33 @@ public: + return true; + } + +- __hostdev__ bool operator!=(const Mask& other) const { return !((*this) == other); } ++ __hostdev__ bool operator!=(__global__ const Mask& other) const { return !((*this) == other); } + + /// @brief Return true if the given bit is set. +- __hostdev__ bool isOn(uint32_t n) const { return 0 != (mWords[n >> 6] & (uint64_t(1) << (n & 63))); } +- ++ __hostdev__ bool isOn(uint32_t n) const __global__ { return 0 != (mWords[n >> 6] & (uint64_t(1) << (n & 63))); } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ bool isOn(uint32_t n) const __local__ { return 0 != (mWords[n >> 6] & (uint64_t(1) << (n & 63))); } ++#endif + /// @brief Return true if the given bit is NOT set. +- __hostdev__ bool isOff(uint32_t n) const { return 0 == (mWords[n >> 6] & (uint64_t(1) << (n & 63))); } ++ __hostdev__ bool isOff(uint32_t n) const __global__ { return 0 == (mWords[n >> 6] & (uint64_t(1) << (n & 63))); } + + /// @brief Return true if all the bits are set in this Mask. +- __hostdev__ bool isOn() const ++ __hostdev__ bool isOn() const __global__ + { + for (uint32_t i = 0; i < WORD_COUNT; ++i) + if (mWords[i] != ~uint64_t(0)) + return false; + return true; + } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ bool isOn() const __local__ ++ { ++ for (uint32_t i = 0; i < WORD_COUNT; ++i) ++ if (mWords[i] != ~uint64_t(0)) ++ return false; ++ return true; ++ } ++#endif + + /// @brief Return true if none of the bits are set in this Mask. + __hostdev__ bool isOff() const +@@ -2115,7 +2393,7 @@ public: + __hostdev__ void set(uint32_t n, bool On) + { + #if 1 // switch between branchless +- auto &word = mWords[n >> 6]; ++ __global__ auto &word = mWords[n >> 6]; + n &= 63; + word &= ~(uint64_t(1) << n); + word |= uint64_t(On) << n; +@@ -2149,40 +2427,40 @@ public: + __hostdev__ void toggle() + { + uint32_t n = WORD_COUNT; +- for (auto* w = mWords; n--; ++w) ++ for (__global__ auto* w = mWords; n--; ++w) + *w = ~*w; + } + __hostdev__ void toggle(uint32_t n) { mWords[n >> 6] ^= uint64_t(1) << (n & 63); } + + /// @brief Bitwise intersection +- __hostdev__ Mask& operator&=(const Mask& other) ++ __hostdev__ __global__ Mask& operator&=(__global__ const Mask& other) + { +- uint64_t *w1 = mWords; +- const uint64_t *w2 = other.mWords; ++ __global__ uint64_t *w1 = mWords; ++ __global__ const uint64_t *w2 = other.mWords; + for (uint32_t n = WORD_COUNT; n--; ++w1, ++w2) *w1 &= *w2; + return *this; + } + /// @brief Bitwise union +- __hostdev__ Mask& operator|=(const Mask& other) ++ __hostdev__ __global__ Mask& operator|=(__global__ const Mask& other) + { +- uint64_t *w1 = mWords; +- const uint64_t *w2 = other.mWords; ++ __global__ uint64_t *w1 = mWords; ++ __global__ const uint64_t *w2 = other.mWords; + for (uint32_t n = WORD_COUNT; n--; ++w1, ++w2) *w1 |= *w2; + return *this; + } + /// @brief Bitwise difference +- __hostdev__ Mask& operator-=(const Mask& other) ++ __hostdev__ __global__ Mask& operator-=(__global__ const Mask& other) + { +- uint64_t *w1 = mWords; +- const uint64_t *w2 = other.mWords; ++ __global__ uint64_t *w1 = mWords; ++ __global__ const uint64_t *w2 = other.mWords; + for (uint32_t n = WORD_COUNT; n--; ++w1, ++w2) *w1 &= ~*w2; + return *this; + } + /// @brief Bitwise XOR +- __hostdev__ Mask& operator^=(const Mask& other) ++ __hostdev__ __global__ Mask& operator^=(__global__ const Mask& other) + { +- uint64_t *w1 = mWords; +- const uint64_t *w2 = other.mWords; ++ __global__ uint64_t *w1 = mWords; ++ __global__ const uint64_t *w2 = other.mWords; + for (uint32_t n = WORD_COUNT; n--; ++w1, ++w2) *w1 ^= *w2; + return *this; + } +@@ -2194,7 +2472,7 @@ private: + __hostdev__ uint32_t findFirst() const + { + uint32_t n = 0; +- const uint64_t* w = mWords; ++ __global__ const uint64_t* w = mWords; + for (; n +- __hostdev__ void set(const Mat3T& mat, const Mat3T& invMat, const Vec3T& translate, double taper); ++ __hostdev__ void set(__global__ const Mat3T& mat, __global__ const Mat3T& invMat, __global__ const Vec3T& translate, double taper) __global__; + + /// @brief Initialize the member data + /// @note The last (4th) row of invMat is actually ignored. + template +- __hostdev__ void set(const Mat4T& mat, const Mat4T& invMat, double taper) {this->set(mat, invMat, mat[3], taper);} ++ __hostdev__ void set(__global__ const Mat4T& mat, __global__ const Mat4T& invMat, double taper) __global__ {this->set(mat, invMat, mat[3], taper);} + + template +- __hostdev__ void set(double scale, const Vec3T &translation, double taper); ++ __hostdev__ void set(double scale, __global__ const Vec3T &translation, double taper) __global__; + + template +- __hostdev__ Vec3T applyMap(const Vec3T& xyz) const { return matMult(mMatD, mVecD, xyz); } ++ __hostdev__ Vec3T applyMap(__global__ const Vec3T& xyz) const { return matMult(mMatD, mVecD, xyz); } + template +- __hostdev__ Vec3T applyMapF(const Vec3T& xyz) const { return matMult(mMatF, mVecF, xyz); } ++ __hostdev__ Vec3T applyMapF(__global__ const Vec3T& xyz) const { return matMult(mMatF, mVecF, xyz); } + + template +- __hostdev__ Vec3T applyJacobian(const Vec3T& xyz) const { return matMult(mMatD, xyz); } ++ __hostdev__ Vec3T applyJacobian(__global__ const Vec3T& xyz) const { return matMult(mMatD, xyz); } + template +- __hostdev__ Vec3T applyJacobianF(const Vec3T& xyz) const { return matMult(mMatF, xyz); } ++ __hostdev__ Vec3T applyJacobianF(__global__ const Vec3T& xyz) const { return matMult(mMatF, xyz); } + + template +- __hostdev__ Vec3T applyInverseMap(const Vec3T& xyz) const ++ __hostdev__ Vec3T applyInverseMap(__global__ const Vec3T& xyz) const __global__ + { + return matMult(mInvMatD, Vec3T(xyz[0] - mVecD[0], xyz[1] - mVecD[1], xyz[2] - mVecD[2])); + } ++#if defined(__KERNEL_METAL__) + template +- __hostdev__ Vec3T applyInverseMapF(const Vec3T& xyz) const ++ __hostdev__ Vec3T applyInverseMap(__local__ const Vec3T& xyz) const __global__ ++ { ++ return matMult(mInvMatD, Vec3T(xyz[0] - mVecD[0], xyz[1] - mVecD[1], xyz[2] - mVecD[2])); ++ } ++#endif ++ template ++ __hostdev__ Vec3T applyInverseMapF(const __global__ Vec3T& xyz) const __global__ + { + return matMult(mInvMatF, Vec3T(xyz[0] - mVecF[0], xyz[1] - mVecF[1], xyz[2] - mVecF[2])); + } ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ Vec3T applyInverseMapF(const __local__ Vec3T& xyz) const __global__ ++ { ++ return matMult(mInvMatF, Vec3T(xyz[0] - mVecF[0], xyz[1] - mVecF[1], xyz[2] - mVecF[2])); ++ } ++#endif + + template +- __hostdev__ Vec3T applyInverseJacobian(const Vec3T& xyz) const { return matMult(mInvMatD, xyz); } ++ __hostdev__ Vec3T applyInverseJacobian(__global__ const Vec3T& xyz) const __global__ { return matMult(mInvMatD, xyz); } + template +- __hostdev__ Vec3T applyInverseJacobianF(const Vec3T& xyz) const { return matMult(mInvMatF, xyz); } ++ __hostdev__ Vec3T applyInverseJacobianF(__global__ const Vec3T& xyz) const __global__ { return matMult(mInvMatF, xyz); } ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ Vec3T applyInverseJacobianF(__local__ const Vec3T& xyz) const __global__ { return matMult(mInvMatF, xyz); } ++#endif + + template +- __hostdev__ Vec3T applyIJT(const Vec3T& xyz) const { return matMultT(mInvMatD, xyz); } ++ __hostdev__ Vec3T applyIJT(__global__ const Vec3T& xyz) const { return matMultT(mInvMatD, xyz); } + template +- __hostdev__ Vec3T applyIJTF(const Vec3T& xyz) const { return matMultT(mInvMatF, xyz); } ++ __hostdev__ Vec3T applyIJTF(__global__ const Vec3T& xyz) const { return matMultT(mInvMatF, xyz); } + }; // Map + + template +-__hostdev__ inline void Map::set(const Mat3T& mat, const Mat3T& invMat, const Vec3T& translate, double taper) ++__hostdev__ inline void Map::set(__global__ const Mat3T& mat, __global__ const Mat3T& invMat, __global__ const Vec3T& translate, double taper) __global__ + { +- float *mf = mMatF, *vf = mVecF, *mif = mInvMatF; +- double *md = mMatD, *vd = mVecD, *mid = mInvMatD; ++ __global__ float * mf = mMatF, *vf = mVecF; ++ __global__ float* mif = mInvMatF; ++ __global__ double *md = mMatD, *vd = mVecD; ++ __global__ double* mid = mInvMatD; + mTaperF = static_cast(taper); + mTaperD = taper; + for (int i = 0; i < 3; ++i) { +@@ -2295,8 +2593,19 @@ __hostdev__ inline void Map::set(const Mat3T& mat, const Mat3T& invMat, const Ve + } + + template +-__hostdev__ inline void Map::set(double dx, const Vec3T &trans, double taper) ++__hostdev__ inline void Map::set(double dx, __global__ const Vec3T &trans, double taper) __global__ + { ++#if defined __KERNEL_METAL__ ++ const float mat[3][3] = { ++ {(float)dx, 0.0, 0.0}, // row 0 ++ {0.0, (float)dx, 0.0}, // row 1 ++ {0.0, 0.0, (float)dx}, // row 2 ++ }, idx = 1.0/(float)dx, invMat[3][3] = { ++ {idx, 0.0, 0.0}, // row 0 ++ {0.0, idx, 0.0}, // row 1 ++ {0.0, 0.0, idx}, // row 2 ++ }; ++#else + const double mat[3][3] = { + {dx, 0.0, 0.0}, // row 0 + {0.0, dx, 0.0}, // row 1 +@@ -2306,6 +2615,7 @@ __hostdev__ inline void Map::set(double dx, const Vec3T &trans, double taper) + {0.0, idx, 0.0}, // row 1 + {0.0, 0.0, idx}, // row 2 + }; ++#endif + this->set(mat, invMat, trans, taper); + } + +@@ -2313,7 +2623,7 @@ __hostdev__ inline void Map::set(double dx, const Vec3T &trans, double taper) + + struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridBlindMetaData + { +- static const int MaxNameSize = 256;// due to NULL termination the maximum length is one less! ++ static __constant__ const int MaxNameSize = 256;// due to NULL termination the maximum length is one less! + int64_t mByteOffset; // byte offset to the blind data, relative to the GridData. + uint64_t mElementCount; // number of elements, e.g. point count + uint32_t mFlags; // flags +@@ -2328,10 +2638,10 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridBlindMetaData + return blindDataCount * sizeof(GridBlindMetaData); + } + +- __hostdev__ void setBlindData(void *ptr) { mByteOffset = PtrDiff(ptr, this); } ++ __hostdev__ void setBlindData(__global__ void *ptr) __global__ { mByteOffset = PtrDiff(ptr, this); } + + template +- __hostdev__ const T* getBlindData() const { return PtrAdd(this, mByteOffset); } ++ __hostdev__ __global__ const T* getBlindData() const { return PtrAdd(this, mByteOffset); } + + }; // GridBlindMetaData + +@@ -2430,7 +2740,7 @@ struct NodeTrait + /// @note No client code should (or can) interface with this struct so it can safely be ignored! + struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridData + {// sizeof(GridData) = 672B +- static const int MaxNameSize = 256;// due to NULL termination the maximum length is one less ++ static __constant__ const int MaxNameSize = 256;// due to NULL termination the maximum length is one less + uint64_t mMagic; // 8B (0) magic to validate it is valid grid data. + uint64_t mChecksum; // 8B (8). Checksum of grid buffer. + Version mVersion;// 4B (16) major, minor, and patch version numbers +@@ -2450,8 +2760,8 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridData + uint64_t mData1, mData2;// 2x8B (656) padding to 32 B alignment. mData1 is use for the total number of values indexed by an IndexGrid + + // Set and unset various bit flags +- __hostdev__ void setFlagsOff() { mFlags = uint32_t(0); } +- __hostdev__ void setMinMaxOn(bool on = true) ++ __hostdev__ void setFlagsOff() __global__ { mFlags = uint32_t(0); } ++ __hostdev__ void setMinMaxOn(bool on = true) __global__ + { + if (on) { + mFlags |= static_cast(GridFlags::HasMinMax); +@@ -2459,7 +2769,7 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridData + mFlags &= ~static_cast(GridFlags::HasMinMax); + } + } +- __hostdev__ void setBBoxOn(bool on = true) ++ __hostdev__ void setBBoxOn(bool on = true) __global__ + { + if (on) { + mFlags |= static_cast(GridFlags::HasBBox); +@@ -2467,7 +2777,7 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridData + mFlags &= ~static_cast(GridFlags::HasBBox); + } + } +- __hostdev__ void setLongGridNameOn(bool on = true) ++ __hostdev__ void setLongGridNameOn(bool on = true) __global__ + { + if (on) { + mFlags |= static_cast(GridFlags::HasLongGridName); +@@ -2475,7 +2785,7 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridData + mFlags &= ~static_cast(GridFlags::HasLongGridName); + } + } +- __hostdev__ void setAverageOn(bool on = true) ++ __hostdev__ void setAverageOn(bool on = true) __global__ + { + if (on) { + mFlags |= static_cast(GridFlags::HasAverage); +@@ -2483,7 +2793,7 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridData + mFlags &= ~static_cast(GridFlags::HasAverage); + } + } +- __hostdev__ void setStdDeviationOn(bool on = true) ++ __hostdev__ void setStdDeviationOn(bool on = true) __global__ + { + if (on) { + mFlags |= static_cast(GridFlags::HasStdDeviation); +@@ -2491,7 +2801,7 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridData + mFlags &= ~static_cast(GridFlags::HasStdDeviation); + } + } +- __hostdev__ void setBreadthFirstOn(bool on = true) ++ __hostdev__ void setBreadthFirstOn(bool on = true) __global__ + { + if (on) { + mFlags |= static_cast(GridFlags::IsBreadthFirst); +@@ -2502,37 +2812,49 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridData + + // Affine transformations based on double precision + template +- __hostdev__ Vec3T applyMap(const Vec3T& xyz) const { return mMap.applyMap(xyz); } // Pos: index -> world ++ __hostdev__ Vec3T applyMap(__global__ const Vec3T& xyz) const __global__ { return mMap.applyMap(xyz); } // Pos: index -> world + template +- __hostdev__ Vec3T applyInverseMap(const Vec3T& xyz) const { return mMap.applyInverseMap(xyz); } // Pos: world -> index ++ __hostdev__ Vec3T applyInverseMap(__global__ const Vec3T& xyz) const __global__ { return mMap.applyInverseMap(xyz); } // Pos: world -> index ++#if defined(__KERNEL_METAL__) + template +- __hostdev__ Vec3T applyJacobian(const Vec3T& xyz) const { return mMap.applyJacobian(xyz); } // Dir: index -> world ++ __hostdev__ Vec3T applyInverseMap(__local__ const Vec3T& xyz) const __global__ { return mMap.applyInverseMap(xyz); } // Pos: world -> index ++#endif + template +- __hostdev__ Vec3T applyInverseJacobian(const Vec3T& xyz) const { return mMap.applyInverseJacobian(xyz); } // Dir: world -> index ++ __hostdev__ Vec3T applyJacobian(__global__ const Vec3T& xyz) const __global__ { return mMap.applyJacobian(xyz); } // Dir: index -> world + template +- __hostdev__ Vec3T applyIJT(const Vec3T& xyz) const { return mMap.applyIJT(xyz); } ++ __hostdev__ Vec3T applyInverseJacobian(__global__ const Vec3T& xyz) const __global__ { return mMap.applyInverseJacobian(xyz); } // Dir: world -> index ++ template ++ __hostdev__ Vec3T applyIJT(__global__ const Vec3T& xyz) const __global__ { return mMap.applyIJT(xyz); } + // Affine transformations based on single precision + template +- __hostdev__ Vec3T applyMapF(const Vec3T& xyz) const { return mMap.applyMapF(xyz); } // Pos: index -> world ++ __hostdev__ Vec3T applyMapF(__global__ const Vec3T& xyz) const __global__ { return mMap.applyMapF(xyz); } // Pos: index -> world + template +- __hostdev__ Vec3T applyInverseMapF(const Vec3T& xyz) const { return mMap.applyInverseMapF(xyz); } // Pos: world -> index ++ __hostdev__ Vec3T applyInverseMapF(__global__ const Vec3T& xyz) const __global__ { return mMap.applyInverseMapF(xyz); } // Pos: world -> index ++#if defined(__KERNEL_METAL__) + template +- __hostdev__ Vec3T applyJacobianF(const Vec3T& xyz) const { return mMap.applyJacobianF(xyz); } // Dir: index -> world ++ __hostdev__ Vec3T applyInverseMapF(__local__ const Vec3T& xyz) const __global__ { return mMap.applyInverseMapF(xyz); } // Pos: world -> index ++#endif + template +- __hostdev__ Vec3T applyInverseJacobianF(const Vec3T& xyz) const { return mMap.applyInverseJacobianF(xyz); } // Dir: world -> index ++ __hostdev__ Vec3T applyJacobianF(__global__ const Vec3T& xyz) const __global__ { return mMap.applyJacobianF(xyz); } // Dir: index -> world + template +- __hostdev__ Vec3T applyIJTF(const Vec3T& xyz) const { return mMap.applyIJTF(xyz); } ++ __hostdev__ Vec3T applyInverseJacobianF(__global__ const Vec3T& xyz) const __global__ { return mMap.applyInverseJacobianF(xyz); } // Dir: world -> index ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ Vec3T applyInverseJacobianF(__local__ const Vec3T& xyz) const __global__ { return mMap.applyInverseJacobianF(xyz); } // Dir: world -> index ++#endif ++ template ++ __hostdev__ Vec3T applyIJTF(__global__ const Vec3T& xyz) const __global__ { return mMap.applyIJTF(xyz); } + + // @brief Return a non-const void pointer to the tree +- __hostdev__ void* treePtr() { return this + 1; } ++ __hostdev__ __global__ void* treePtr() __global__ { return this + 1; } + + // @brief Return a const void pointer to the tree +- __hostdev__ const void* treePtr() const { return this + 1; } ++ __hostdev__ __global__ const void* treePtr() const __global__ { return this + 1; } + + /// @brief Returns a const reference to the blindMetaData at the specified linear offset. + /// + /// @warning The linear offset is assumed to be in the valid range +- __hostdev__ const GridBlindMetaData* blindMetaData(uint32_t n) const ++ __hostdev__ __global__ const GridBlindMetaData* blindMetaData(uint32_t n) const __global__ + { + NANOVDB_ASSERT(n < mBlindMetadataCount); + return PtrAdd(this, mBlindMetadataOffset) + n; +@@ -2552,8 +2874,17 @@ using DefaultReadAccessor = ReadAccessor; + /// + /// @note This the API of this class to interface with client code + template +-class Grid : private GridData ++class Grid ++#if !defined(__KERNEL_METAL__) ++ : private GridData ++#endif + { ++#if defined(__KERNEL_METAL__) ++ GridData _base; ++#define BASE(v) _base.v ++#else ++#define BASE(v) DataType::v ++#endif + public: + using TreeType = TreeT; + using RootType = typename TreeT::RootType; +@@ -2566,183 +2897,195 @@ public: + /// @brief Disallow constructions, copy and assignment + /// + /// @note Only a Serializer, defined elsewhere, can instantiate this class +- Grid(const Grid&) = delete; +- Grid& operator=(const Grid&) = delete; ++ Grid(__global__ const Grid&) __global__ = delete; ++ __global__ Grid& operator=(__global__ const Grid&) __global__ = delete; + ~Grid() = delete; + +- __hostdev__ Version version() const { return DataType::mVersion; } ++ __hostdev__ Version version() const __global__ { return BASE(mVersion); } + +- __hostdev__ DataType* data() { return reinterpret_cast(this); } ++ __hostdev__ __global__ DataType* data() __global__ { return reinterpret_cast<__global__ DataType*>(this); } + +- __hostdev__ const DataType* data() const { return reinterpret_cast(this); } ++ __hostdev__ __global__ const DataType* data() const __global__ { return reinterpret_cast<__global__ const DataType*>(this); } + + /// @brief Return memory usage in bytes for this class only. + __hostdev__ static uint64_t memUsage() { return sizeof(GridData); } + + /// @brief Return the memory footprint of the entire grid, i.e. including all nodes and blind data +- __hostdev__ uint64_t gridSize() const { return DataType::mGridSize; } ++ __hostdev__ uint64_t gridSize() const __global__ { return BASE(mGridSize); } + + /// @brief Return index of this grid in the buffer +- __hostdev__ uint32_t gridIndex() const { return DataType::mGridIndex; } ++ __hostdev__ uint32_t gridIndex() const __global__ { return BASE(mGridIndex); } + + /// @brief Return total number of grids in the buffer +- __hostdev__ uint32_t gridCount() const { return DataType::mGridCount; } ++ __hostdev__ uint32_t gridCount() const __global__ { return BASE(mGridCount); } + + /// @brief @brief Return the total number of values indexed by this IndexGrid + /// + /// @note This method is only defined for IndexGrid = NanoGrid + template +- __hostdev__ typename enable_if::value, const uint64_t&>::type valueCount() const {return DataType::mData1;} ++ __hostdev__ typename enable_if::value, uint64_t>::type valueCount() const {return BASE(mData1);} + + /// @brief Return a const reference to the tree +- __hostdev__ const TreeT& tree() const { return *reinterpret_cast(this->treePtr()); } ++ __hostdev__ __global__ const TreeT& tree() const __global__ { return *reinterpret_cast<__global__ const TreeT*>(BASE(treePtr)()); } + + /// @brief Return a non-const reference to the tree +- __hostdev__ TreeT& tree() { return *reinterpret_cast(this->treePtr()); } ++ __hostdev__ __global__ TreeT& tree() __global__ { return *reinterpret_cast<__global__ TreeT*>(BASE(treePtr)()); } + + /// @brief Return a new instance of a ReadAccessor used to access values in this grid +- __hostdev__ AccessorType getAccessor() const { return AccessorType(this->tree().root()); } ++ __hostdev__ AccessorType getAccessor() const __global__ { return AccessorType(this->tree().root()); } + + /// @brief Return a const reference to the size of a voxel in world units +- __hostdev__ const Vec3R& voxelSize() const { return DataType::mVoxelSize; } ++ __hostdev__ const __global__ Vec3R& voxelSize() const __global__ { return BASE(mVoxelSize); } + + /// @brief Return a const reference to the Map for this grid +- __hostdev__ const Map& map() const { return DataType::mMap; } ++ __hostdev__ const __global__ Map& map() const __global__ { return BASE(mMap); } + + /// @brief world to index space transformation + template +- __hostdev__ Vec3T worldToIndex(const Vec3T& xyz) const { return this->applyInverseMap(xyz); } ++ __hostdev__ Vec3T worldToIndex(__global__ const Vec3T& xyz) const __global__ { return BASE(applyInverseMap)(xyz); } ++ ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ Vec3T worldToIndex(__local__ const Vec3T& xyz) const __global__ { return BASE(applyInverseMap)(xyz); } ++#endif + + /// @brief index to world space transformation + template +- __hostdev__ Vec3T indexToWorld(const Vec3T& xyz) const { return this->applyMap(xyz); } ++ __hostdev__ Vec3T indexToWorld(__global__ const Vec3T& xyz) const __global__ { return this->applyMap(xyz); } + + /// @brief transformation from index space direction to world space direction + /// @warning assumes dir to be normalized + template +- __hostdev__ Vec3T indexToWorldDir(const Vec3T& dir) const { return this->applyJacobian(dir); } ++ __hostdev__ Vec3T indexToWorldDir(__global__ const Vec3T& dir) const __global__ { return this->applyJacobian(dir); } + + /// @brief transformation from world space direction to index space direction + /// @warning assumes dir to be normalized + template +- __hostdev__ Vec3T worldToIndexDir(const Vec3T& dir) const { return this->applyInverseJacobian(dir); } ++ __hostdev__ Vec3T worldToIndexDir(__global__ const Vec3T& dir) const __global__ { return this->applyInverseJacobian(dir); } + + /// @brief transform the gradient from index space to world space. + /// @details Applies the inverse jacobian transform map. + template +- __hostdev__ Vec3T indexToWorldGrad(const Vec3T& grad) const { return this->applyIJT(grad); } ++ __hostdev__ Vec3T indexToWorldGrad(__global__ const Vec3T& grad) const __global__ { return this->applyIJT(grad); } + + /// @brief world to index space transformation + template +- __hostdev__ Vec3T worldToIndexF(const Vec3T& xyz) const { return this->applyInverseMapF(xyz); } ++ __hostdev__ Vec3T worldToIndexF(__global__ const Vec3T& xyz) const __global__ { return BASE(applyInverseMapF)(xyz); } ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ Vec3T worldToIndexF(__local__ const Vec3T& xyz) const __global__ { return BASE(applyInverseMapF)(xyz); } ++#endif + + /// @brief index to world space transformation + template +- __hostdev__ Vec3T indexToWorldF(const Vec3T& xyz) const { return this->applyMapF(xyz); } ++ __hostdev__ Vec3T indexToWorldF(__global__ const Vec3T& xyz) const __global__ { return this->applyMapF(xyz); } + + /// @brief transformation from index space direction to world space direction + /// @warning assumes dir to be normalized + template +- __hostdev__ Vec3T indexToWorldDirF(const Vec3T& dir) const { return this->applyJacobianF(dir); } ++ __hostdev__ Vec3T indexToWorldDirF(__global__ const Vec3T& dir) const __global__ { return this->applyJacobianF(dir); } + + /// @brief transformation from world space direction to index space direction + /// @warning assumes dir to be normalized + template +- __hostdev__ Vec3T worldToIndexDirF(const Vec3T& dir) const { return this->applyInverseJacobianF(dir); } ++ __hostdev__ Vec3T worldToIndexDirF(__global__ const Vec3T& dir) const __global__ { return BASE(applyInverseJacobianF)(dir); } ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ Vec3T worldToIndexDirF(__local__ const Vec3T& dir) const __global__ { return BASE(applyInverseJacobianF)(dir); } ++#endif + + /// @brief Transforms the gradient from index space to world space. + /// @details Applies the inverse jacobian transform map. + template +- __hostdev__ Vec3T indexToWorldGradF(const Vec3T& grad) const { return DataType::applyIJTF(grad); } ++ __hostdev__ Vec3T indexToWorldGradF(__global__ const Vec3T& grad) const __global__ { return BASE(applyIJTF(grad)); } + + /// @brief Computes a AABB of active values in world space +- __hostdev__ const BBox& worldBBox() const { return DataType::mWorldBBox; } ++ __hostdev__ __global__ const BBox& worldBBox() const __global__ { return BASE(mWorldBBox); } + + /// @brief Computes a AABB of active values in index space + /// + /// @note This method is returning a floating point bounding box and not a CoordBBox. This makes + /// it more useful for clipping rays. +- __hostdev__ const BBox& indexBBox() const { return this->tree().bbox(); } ++ __hostdev__ __global__ const BBox& indexBBox() const __global__ { return this->tree().bbox(); } + + /// @brief Return the total number of active voxels in this tree. +- __hostdev__ uint64_t activeVoxelCount() const { return this->tree().activeVoxelCount(); } ++ __hostdev__ uint64_t activeVoxelCount() const __global__ { return this->tree().activeVoxelCount(); } + + /// @brief Methods related to the classification of this grid +- __hostdev__ bool isValid() const { return DataType::mMagic == NANOVDB_MAGIC_NUMBER; } +- __hostdev__ const GridType& gridType() const { return DataType::mGridType; } +- __hostdev__ const GridClass& gridClass() const { return DataType::mGridClass; } +- __hostdev__ bool isLevelSet() const { return DataType::mGridClass == GridClass::LevelSet; } +- __hostdev__ bool isFogVolume() const { return DataType::mGridClass == GridClass::FogVolume; } +- __hostdev__ bool isStaggered() const { return DataType::mGridClass == GridClass::Staggered; } +- __hostdev__ bool isPointIndex() const { return DataType::mGridClass == GridClass::PointIndex; } +- __hostdev__ bool isGridIndex() const { return DataType::mGridClass == GridClass::IndexGrid; } +- __hostdev__ bool isPointData() const { return DataType::mGridClass == GridClass::PointData; } +- __hostdev__ bool isMask() const { return DataType::mGridClass == GridClass::Topology; } +- __hostdev__ bool isUnknown() const { return DataType::mGridClass == GridClass::Unknown; } +- __hostdev__ bool hasMinMax() const { return DataType::mFlags & static_cast(GridFlags::HasMinMax); } +- __hostdev__ bool hasBBox() const { return DataType::mFlags & static_cast(GridFlags::HasBBox); } +- __hostdev__ bool hasLongGridName() const { return DataType::mFlags & static_cast(GridFlags::HasLongGridName); } +- __hostdev__ bool hasAverage() const { return DataType::mFlags & static_cast(GridFlags::HasAverage); } +- __hostdev__ bool hasStdDeviation() const { return DataType::mFlags & static_cast(GridFlags::HasStdDeviation); } +- __hostdev__ bool isBreadthFirst() const { return DataType::mFlags & static_cast(GridFlags::IsBreadthFirst); } ++ __hostdev__ bool isValid() const __global__ { return BASE(mMagic) == NANOVDB_MAGIC_NUMBER; } ++ __hostdev__ const __global__ GridType& gridType() const __global__ { return BASE(mGridType); } ++ __hostdev__ const __global__ GridClass& gridClass() const __global__ { return BASE(mGridClass); } ++ __hostdev__ bool isLevelSet() const __global__ { return BASE(mGridClass) == GridClass::LevelSet; } ++ __hostdev__ bool isFogVolume() const __global__ { return BASE(mGridClass) == GridClass::FogVolume; } ++ __hostdev__ bool isStaggered() const __global__ { return BASE(mGridClass) == GridClass::Staggered; } ++ __hostdev__ bool isPointIndex() const __global__ { return BASE(mGridClass) == GridClass::PointIndex; } ++ __hostdev__ bool isGridIndex() const __global__ { return BASE(mGridClass) == GridClass::IndexGrid; } ++ __hostdev__ bool isPointData() const __global__ { return BASE(mGridClass) == GridClass::PointData; } ++ __hostdev__ bool isMask() const __global__ { return BASE(mGridClass) == GridClass::Topology; } ++ __hostdev__ bool isUnknown() const __global__ { return BASE(mGridClass) == GridClass::Unknown; } ++ __hostdev__ bool hasMinMax() const __global__ { return BASE(mFlags) & static_cast(GridFlags::HasMinMax); } ++ __hostdev__ bool hasBBox() const __global__ { return BASE(mFlags) & static_cast(GridFlags::HasBBox); } ++ __hostdev__ bool hasLongGridName() const __global__ { return BASE(mFlags) & static_cast(GridFlags::HasLongGridName); } ++ __hostdev__ bool hasAverage() const __global__ { return BASE(mFlags) & static_cast(GridFlags::HasAverage); } ++ __hostdev__ bool hasStdDeviation() const __global__ { return BASE(mFlags) & static_cast(GridFlags::HasStdDeviation); } ++ __hostdev__ bool isBreadthFirst() const __global__ { return BASE(mFlags) & static_cast(GridFlags::IsBreadthFirst); } + + /// @brief return true if the specified node type is layed out breadth-first in memory and has a fixed size. + /// This allows for sequential access to the nodes. + template +- __hostdev__ bool isSequential() const { return NodeT::FIXED_SIZE && this->isBreadthFirst(); } ++ __hostdev__ bool isSequential() const __global__ { return NodeT::FIXED_SIZE && this->isBreadthFirst(); } + + /// @brief return true if the specified node level is layed out breadth-first in memory and has a fixed size. + /// This allows for sequential access to the nodes. + template +- __hostdev__ bool isSequential() const { return NodeTrait::type::FIXED_SIZE && this->isBreadthFirst(); } ++ __hostdev__ bool isSequential() const __global__ { return NodeTrait::type::FIXED_SIZE && this->isBreadthFirst(); } + + /// @brief Return a c-string with the name of this grid +- __hostdev__ const char* gridName() const ++ __hostdev__ __global__ const char* gridName() const __global__ + { + if (this->hasLongGridName()) { + NANOVDB_ASSERT(DataType::mBlindMetadataCount>0); +- const auto &metaData = this->blindMetaData(DataType::mBlindMetadataCount-1);// always the last ++ __global__ const auto &metaData = this->blindMetaData(BASE(mBlindMetadataCount)-1);// always the last + NANOVDB_ASSERT(metaData.mDataClass == GridBlindDataClass::GridName); + return metaData.template getBlindData(); + } +- return DataType::mGridName; ++ return BASE(mGridName); + } + + /// @brief Return a c-string with the name of this grid, truncated to 255 characters +- __hostdev__ const char* shortGridName() const { return DataType::mGridName; } +- ++ __hostdev__ __global__ const char* shortGridName() const __global__ { return BASE(mGridName); } + /// @brief Return checksum of the grid buffer. +- __hostdev__ uint64_t checksum() const { return DataType::mChecksum; } ++ __hostdev__ uint64_t checksum() const __global__ { return BASE(mChecksum); } + + /// @brief Return true if this grid is empty, i.e. contains no values or nodes. +- __hostdev__ bool isEmpty() const { return this->tree().isEmpty(); } ++ __hostdev__ bool isEmpty() const __global__ { return this->tree().isEmpty(); } + + /// @brief Return the count of blind-data encoded in this grid +- __hostdev__ uint32_t blindDataCount() const { return DataType::mBlindMetadataCount; } ++ __hostdev__ uint32_t blindDataCount() const __global__ { return BASE(mBlindMetadataCount); } + + /// @brief Return the index of the blind data with specified semantic if found, otherwise -1. +- __hostdev__ int findBlindDataForSemantic(GridBlindDataSemantic semantic) const; ++ __hostdev__ int findBlindDataForSemantic(GridBlindDataSemantic semantic) const __global__; + + /// @brief Returns a const pointer to the blindData at the specified linear offset. + /// + /// @warning Point might be NULL and the linear offset is assumed to be in the valid range +- __hostdev__ const void* blindData(uint32_t n) const ++ __hostdev__ __global__ const void* blindData(uint32_t n) const __global__ + { +- if (DataType::mBlindMetadataCount == 0u) { ++ if (BASE(mBlindMetadataCount) == 0u) { + return nullptr; + } + NANOVDB_ASSERT(n < DataType::mBlindMetadataCount); + return this->blindMetaData(n).template getBlindData(); + } +- +- __hostdev__ const GridBlindMetaData& blindMetaData(uint32_t n) const { return *DataType::blindMetaData(n); } ++ ++ __hostdev__ __global__ const GridBlindMetaData& blindMetaData(uint32_t n) const __global__ { return *BASE(blindMetaData)(n); } + + private: + static_assert(sizeof(GridData) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(GridData) is misaligned"); + }; // Class Grid + + template +-__hostdev__ int Grid::findBlindDataForSemantic(GridBlindDataSemantic semantic) const ++__hostdev__ int Grid::findBlindDataForSemantic(GridBlindDataSemantic semantic) const __global__ + { + for (uint32_t i = 0, n = this->blindDataCount(); i < n; ++i) + if (this->blindMetaData(i).mSemantic == semantic) +@@ -2762,14 +3105,14 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) TreeData + uint64_t mVoxelCount;// 8B, total number of active voxels in the root and all its child nodes. + // No padding since it's always 32B aligned + template +- __hostdev__ void setRoot(const RootT* root) { mNodeOffset[3] = PtrDiff(root, this); } ++ __hostdev__ void setRoot(__global__ const RootT* root) __global__ { mNodeOffset[3] = PtrDiff(root, this); } + template +- __hostdev__ RootT* getRoot() { return PtrAdd(this, mNodeOffset[3]); } ++ __hostdev__ __global__ RootT* getRoot() __global__ { return PtrAdd(this, mNodeOffset[3]); } + template +- __hostdev__ const RootT* getRoot() const { return PtrAdd(this, mNodeOffset[3]); } ++ __hostdev__ __global__ const RootT* getRoot() const __global__ { return PtrAdd(this, mNodeOffset[3]); } + + template +- __hostdev__ void setFirstNode(const NodeT* node) ++ __hostdev__ void setFirstNode(__global__ const NodeT* node) __global__ + { + mNodeOffset[NodeT::LEVEL] = node ? PtrDiff(node, this) : 0; + } +@@ -2795,8 +3138,17 @@ struct GridTree + + /// @brief VDB Tree, which is a thin wrapper around a RootNode. + template +-class Tree : private TreeData ++class Tree ++#if !defined(__KERNEL_METAL__) ++ : private TreeData ++#endif + { ++#if defined(__KERNEL_METAL__) ++ TreeData _base; ++#define BASE(v) _base.v ++#else ++#define BASE(v) DataType::v ++#endif + static_assert(RootT::LEVEL == 3, "Tree depth is not supported"); + static_assert(RootT::ChildNodeType::LOG2DIM == 5, "Tree configuration is not supported"); + static_assert(RootT::ChildNodeType::ChildNodeType::LOG2DIM == 4, "Tree configuration is not supported"); +@@ -2817,79 +3169,86 @@ public: + using Node0 = LeafNodeType; + + /// @brief This class cannot be constructed or deleted +- Tree() = delete; +- Tree(const Tree&) = delete; +- Tree& operator=(const Tree&) = delete; +- ~Tree() = delete; ++ Tree() __global__ = delete; ++ Tree(__global__ const Tree&) __global__ = delete; ++ __global__ Tree& operator=(__global__ const Tree&) __global__ = delete; ++ ~Tree() __global__ = delete; + +- __hostdev__ DataType* data() { return reinterpret_cast(this); } ++ __hostdev__ __global__ DataType* data() __global__ { return reinterpret_cast<__global__ DataType*>(this); } + +- __hostdev__ const DataType* data() const { return reinterpret_cast(this); } ++ __hostdev__ __global__ const DataType* data() const __global__ { return reinterpret_cast<__global__ const DataType*>(this); } + + /// @brief return memory usage in bytes for the class + __hostdev__ static uint64_t memUsage() { return sizeof(DataType); } + +- __hostdev__ RootT& root() { return *DataType::template getRoot(); } ++ __hostdev__ __global__ RootT& root() __global__ { return *BASE(template) getRoot(); } + +- __hostdev__ const RootT& root() const { return *DataType::template getRoot(); } ++ __hostdev__ __global__ const RootT& root() const __global__ { return *BASE(template) getRoot(); } + +- __hostdev__ AccessorType getAccessor() const { return AccessorType(this->root()); } ++ __hostdev__ AccessorType getAccessor() const __global__ { return AccessorType(this->root()); } + + /// @brief Return the value of the given voxel (regardless of state or location in the tree.) +- __hostdev__ ValueType getValue(const CoordType& ijk) const { return this->root().getValue(ijk); } ++ __hostdev__ ValueType getValue(__global__ const CoordType& ijk) const __global__ { return this->root().getValue(ijk); } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ ValueType getValue(__local__ const CoordType& ijk) const __global__ { return this->root().getValue(ijk); } ++#endif + + /// @brief Return the active state of the given voxel (regardless of state or location in the tree.) +- __hostdev__ bool isActive(const CoordType& ijk) const { return this->root().isActive(ijk); } ++ __hostdev__ bool isActive(__global__ const CoordType& ijk) const __global__ { return this->root().isActive(ijk); } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ bool isActive(__local__ const CoordType& ijk) const __global__ { return this->root().isActive(ijk); } ++ __hostdev__ bool isActive(__local__ const CoordType& ijk) const __local__ { return this->root().isActive(ijk); } ++#endif + + /// @brief Return true if this tree is empty, i.e. contains no values or nodes +- __hostdev__ bool isEmpty() const { return this->root().isEmpty(); } ++ __hostdev__ bool isEmpty() const __global__ { return this->root().isEmpty(); } + + /// @brief Combines the previous two methods in a single call +- __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const { return this->root().probeValue(ijk, v); } ++ __hostdev__ bool probeValue(__global__ const CoordType& ijk, __global__ ValueType& v) const { return this->root().probeValue(ijk, v); } + + /// @brief Return a const reference to the background value. +- __hostdev__ const ValueType& background() const { return this->root().background(); } ++ __hostdev__ __global__ const ValueType& background() const __global__ { return this->root().background(); } + + /// @brief Sets the extrema values of all the active values in this tree, i.e. in all nodes of the tree +- __hostdev__ void extrema(ValueType& min, ValueType& max) const; ++ __hostdev__ void extrema(__global__ ValueType& min, __global__ ValueType& max) const __global__; + + /// @brief Return a const reference to the index bounding box of all the active values in this tree, i.e. in all nodes of the tree +- __hostdev__ const BBox& bbox() const { return this->root().bbox(); } ++ __hostdev__ __global__ const BBox& bbox() const __global__ { return this->root().bbox(); } + + /// @brief Return the total number of active voxels in this tree. +- __hostdev__ uint64_t activeVoxelCount() const { return DataType::mVoxelCount; } ++ __hostdev__ uint64_t activeVoxelCount() const __global__ { return BASE(mVoxelCount); } + + /// @brief Return the total number of active tiles at the specified level of the tree. + /// + /// @details level = 1,2,3 corresponds to active tile count in lower internal nodes, upper + /// internal nodes, and the root level. Note active values at the leaf level are + /// referred to as active voxels (see activeVoxelCount defined above). +- __hostdev__ const uint32_t& activeTileCount(uint32_t level) const ++ __hostdev__ __global__ const uint32_t& activeTileCount(uint32_t level) const __global__ + { + NANOVDB_ASSERT(level > 0 && level <= 3);// 1, 2, or 3 +- return DataType::mTileCount[level - 1]; ++ return BASE(mTileCount)[level - 1]; + } + + template +- __hostdev__ uint32_t nodeCount() const ++ __hostdev__ uint32_t nodeCount() const __global__ + { + static_assert(NodeT::LEVEL < 3, "Invalid NodeT"); +- return DataType::mNodeCount[NodeT::LEVEL]; ++ return BASE(mNodeCount)[NodeT::LEVEL]; + } + +- __hostdev__ uint32_t nodeCount(int level) const ++ __hostdev__ uint32_t nodeCount(int level) const __global__ + { + NANOVDB_ASSERT(level < 3); +- return DataType::mNodeCount[level]; ++ return BASE(mNodeCount)[level]; + } + + /// @brief return a pointer to the first node of the specified type + /// + /// @warning Note it may return NULL if no nodes exist + template +- __hostdev__ NodeT* getFirstNode() ++ __hostdev__ __global__ NodeT* getFirstNode() __global__ + { +- const uint64_t offset = DataType::mNodeOffset[NodeT::LEVEL]; ++ const uint64_t offset = BASE(mNodeOffset)[NodeT::LEVEL]; + return offset>0 ? PtrAdd(this, offset) : nullptr; + } + +@@ -2897,9 +3256,9 @@ public: + /// + /// @warning Note it may return NULL if no nodes exist + template +- __hostdev__ const NodeT* getFirstNode() const ++ __hostdev__ __global__ const NodeT* getFirstNode() const __global__ + { +- const uint64_t offset = DataType::mNodeOffset[NodeT::LEVEL]; ++ const uint64_t offset = BASE(mNodeOffset)[NodeT::LEVEL]; + return offset>0 ? PtrAdd(this, offset) : nullptr; + } + +@@ -2907,8 +3266,8 @@ public: + /// + /// @warning Note it may return NULL if no nodes exist + template +- __hostdev__ typename NodeTrait::type* +- getFirstNode() ++ __hostdev__ __global__ typename NodeTrait::type* ++ getFirstNode() __global__ + { + return this->template getFirstNode::type>(); + } +@@ -2917,27 +3276,28 @@ public: + /// + /// @warning Note it may return NULL if no nodes exist + template +- __hostdev__ const typename NodeTrait::type* +- getFirstNode() const ++ __hostdev__ __global__ const typename NodeTrait::type* ++ getFirstNode() const __global__ + { + return this->template getFirstNode::type>(); + } + + /// @brief Template specializations of getFirstNode +- __hostdev__ LeafNodeType* getFirstLeaf() {return this->getFirstNode();} +- __hostdev__ const LeafNodeType* getFirstLeaf() const {return this->getFirstNode();} +- __hostdev__ typename NodeTrait::type* getFirstLower() {return this->getFirstNode<1>();} +- __hostdev__ const typename NodeTrait::type* getFirstLower() const {return this->getFirstNode<1>();} +- __hostdev__ typename NodeTrait::type* getFirstUpper() {return this->getFirstNode<2>();} +- __hostdev__ const typename NodeTrait::type* getFirstUpper() const {return this->getFirstNode<2>();} ++ __hostdev__ __global__ LeafNodeType* getFirstLeaf() {return this->getFirstNode();} ++ __hostdev__ __global__ const LeafNodeType* getFirstLeaf() const {return this->getFirstNode();} ++ __hostdev__ __global__ typename NodeTrait::type* getFirstLower() {return this->getFirstNode<1>();} ++ __hostdev__ __global__ const typename NodeTrait::type* getFirstLower() const {return this->getFirstNode<1>();} ++ __hostdev__ __global__ typename NodeTrait::type* getFirstUpper() {return this->getFirstNode<2>();} ++ __hostdev__ __global__ const typename NodeTrait::type* getFirstUpper() const {return this->getFirstNode<2>();} + + private: + static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(TreeData) is misaligned"); + ++#undef BASE + }; // Tree class + + template +-__hostdev__ void Tree::extrema(ValueType& min, ValueType& max) const ++__hostdev__ void Tree::extrema(__global__ ValueType& min, __global__ ValueType& max) const __global__ + { + min = this->root().minimum(); + max = this->root().maximum(); +@@ -2955,13 +3315,13 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) RootData + using BuildT = typename ChildT::BuildType;// in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool + using CoordT = typename ChildT::CoordType; + using StatsT = typename ChildT::FloatType; +- static constexpr bool FIXED_SIZE = false; ++ static __constant__ constexpr bool FIXED_SIZE = false; + + /// @brief Return a key based on the coordinates of a voxel + #ifdef USE_SINGLE_ROOT_KEY + using KeyT = uint64_t; + template +- __hostdev__ static KeyT CoordToKey(const CoordType& ijk) ++ __hostdev__ static KeyT CoordToKey(__global__ const CoordType& ijk) + { + static_assert(sizeof(CoordT) == sizeof(CoordType), "Mismatching sizeof"); + static_assert(32 - ChildT::TOTAL <= 21, "Cannot use 64 bit root keys"); +@@ -2969,17 +3329,28 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) RootData + (KeyT(uint32_t(ijk[1]) >> ChildT::TOTAL) << 21) | // y is the middle 21 bits + (KeyT(uint32_t(ijk[0]) >> ChildT::TOTAL) << 42); // x is the upper 21 bits + } +- __hostdev__ static CoordT KeyToCoord(const KeyT& key) ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ static KeyT CoordToKey(__local__ const CoordType& ijk) ++ { ++ static_assert(sizeof(CoordT) == sizeof(CoordType), "Mismatching sizeof"); ++ static_assert(32 - ChildT::TOTAL <= 21, "Cannot use 64 bit root keys"); ++ return (KeyT(uint32_t(ijk[2]) >> ChildT::TOTAL)) | // z is the lower 21 bits ++ (KeyT(uint32_t(ijk[1]) >> ChildT::TOTAL) << 21) | // y is the middle 21 bits ++ (KeyT(uint32_t(ijk[0]) >> ChildT::TOTAL) << 42); // x is the upper 21 bits ++ } ++#endif ++ static __constant__ constexpr uint64_t MASK = (1u << 21) - 1; ++ __hostdev__ static CoordT KeyToCoord(__global__ const KeyT& key) + { +- static constexpr uint64_t MASK = (1u << 21) - 1; + return CoordT(((key >> 42) & MASK) << ChildT::TOTAL, + ((key >> 21) & MASK) << ChildT::TOTAL, + (key & MASK) << ChildT::TOTAL); + } + #else + using KeyT = CoordT; +- __hostdev__ static KeyT CoordToKey(const CoordT& ijk) { return ijk & ~ChildT::MASK; } +- __hostdev__ static CoordT KeyToCoord(const KeyT& key) { return key; } ++ __hostdev__ static KeyT CoordToKey(__global__ const CoordT& ijk) { return ijk & ~ChildT::MASK; } ++ __hostdev__ static CoordT KeyToCoord(__global__ const KeyT& key) { return key; } + #endif + BBox mBBox; // 24B. AABB of active values in index space. + uint32_t mTableSize; // 4B. number of tiles and child pointers in the root node +@@ -3000,23 +3371,23 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) RootData + struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) Tile + { + template +- __hostdev__ void setChild(const CoordType& k, const ChildT *ptr, const RootData *data) ++ __hostdev__ void setChild(__global__ const CoordType& k, __global__ const ChildT *ptr, __global__ const RootData *data) + { + key = CoordToKey(k); + child = PtrDiff(ptr, data); + } + template +- __hostdev__ void setValue(const CoordType& k, bool s, const ValueType &v) ++ __hostdev__ void setValue(__global__ const CoordType& k, bool s, __global__ const ValueType &v) + { + key = CoordToKey(k); + state = s; + value = v; + child = 0; + } +- __hostdev__ bool isChild() const { return child!=0; } +- __hostdev__ bool isValue() const { return child==0; } +- __hostdev__ bool isActive() const { return child==0 && state; } +- __hostdev__ CoordT origin() const { return KeyToCoord(key); } ++ __hostdev__ bool isChild() const __global__ { return child!=0; } ++ __hostdev__ bool isValue() const __global__ { return child==0; } ++ __hostdev__ bool isActive() const __global__ { return child==0 && state; } ++ __hostdev__ CoordT origin() const __global__ { return KeyToCoord(key); } + KeyT key; // USE_SINGLE_ROOT_KEY ? 8B : 12B + int64_t child; // 8B. signed byte offset from this node to the child node. 0 means it is a constant tile, so use value. + uint32_t state; // 4B. state of tile value +@@ -3026,53 +3397,64 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) RootData + /// @brief Returns a non-const reference to the tile at the specified linear offset. + /// + /// @warning The linear offset is assumed to be in the valid range +- __hostdev__ const Tile* tile(uint32_t n) const ++ __hostdev__ __global__ const Tile* tile(uint32_t n) const + { + NANOVDB_ASSERT(n < mTableSize); +- return reinterpret_cast(this + 1) + n; ++ return reinterpret_cast<__global__ const Tile*>(this + 1) + n; + } +- __hostdev__ Tile* tile(uint32_t n) ++ __hostdev__ __global__ Tile* tile(uint32_t n) + { + NANOVDB_ASSERT(n < mTableSize); +- return reinterpret_cast(this + 1) + n; ++ return reinterpret_cast<__global__ Tile*>(this + 1) + n; + } + + /// @brief Returns a const reference to the child node in the specified tile. + /// + /// @warning A child node is assumed to exist in the specified tile +- __hostdev__ ChildT* getChild(const Tile* tile) ++ __hostdev__ __global__ ChildT* getChild(__global__ const Tile* tile) __global__ + { + NANOVDB_ASSERT(tile->child); + return PtrAdd(this, tile->child); + } +- __hostdev__ const ChildT* getChild(const Tile* tile) const ++ __hostdev__ __global__ const ChildT* getChild(__global__ const Tile* tile) const __global__ + { + NANOVDB_ASSERT(tile->child); + return PtrAdd(this, tile->child); + } + +- __hostdev__ const ValueT& getMin() const { return mMinimum; } +- __hostdev__ const ValueT& getMax() const { return mMaximum; } +- __hostdev__ const StatsT& average() const { return mAverage; } +- __hostdev__ const StatsT& stdDeviation() const { return mStdDevi; } ++ __hostdev__ __global__ const ValueT& getMin() const { return mMinimum; } ++ __hostdev__ __global__ const ValueT& getMax() const { return mMaximum; } ++ __hostdev__ __global__ const StatsT& average() const { return mAverage; } ++ __hostdev__ __global__ const StatsT& stdDeviation() const { return mStdDevi; } + +- __hostdev__ void setMin(const ValueT& v) { mMinimum = v; } +- __hostdev__ void setMax(const ValueT& v) { mMaximum = v; } +- __hostdev__ void setAvg(const StatsT& v) { mAverage = v; } +- __hostdev__ void setDev(const StatsT& v) { mStdDevi = v; } ++ __hostdev__ void setMin(__global__ const ValueT& v) { mMinimum = v; } ++ __hostdev__ void setMax(__global__ const ValueT& v) { mMaximum = v; } ++ __hostdev__ void setAvg(__global__ const StatsT& v) { mAverage = v; } ++ __hostdev__ void setDev(__global__ const StatsT& v) { mStdDevi = v; } + + /// @brief This class cannot be constructed or deleted + RootData() = delete; +- RootData(const RootData&) = delete; +- RootData& operator=(const RootData&) = delete; ++ RootData(__global__ const RootData&) = delete; ++ __global__ RootData& operator=(__global__ const RootData&) = delete; + ~RootData() = delete; + }; // RootData + + /// @brief Top-most node of the VDB tree structure. + template +-class RootNode : private RootData ++class RootNode ++#if !defined(__KERNEL_METAL__) ++ : private RootData ++#endif + { + public: ++#if defined(__KERNEL_METAL__) ++ ++ RootData _base; ++#define BASE(v) _base.v ++#else ++#define BASE(v) DataType::v ++#endif ++ + using DataType = RootData; + using LeafNodeType = typename ChildT::LeafNodeType; + using ChildNodeType = ChildT; +@@ -3086,27 +3468,27 @@ public: + using BBoxType = BBox; + using AccessorType = DefaultReadAccessor; + using Tile = typename DataType::Tile; +- static constexpr bool FIXED_SIZE = DataType::FIXED_SIZE; ++ static __constant__ constexpr bool FIXED_SIZE = DataType::FIXED_SIZE; + +- static constexpr uint32_t LEVEL = 1 + ChildT::LEVEL; // level 0 = leaf ++ static __constant__ constexpr uint32_t LEVEL = 1 + ChildT::LEVEL; // level 0 = leaf + + class ChildIterator + { +- const DataType *mParent; +- uint32_t mPos, mSize; ++ __global__ const DataType *mParent; ++ uint32_t mPos, mSize; + public: + __hostdev__ ChildIterator() : mParent(nullptr), mPos(0), mSize(0) {} +- __hostdev__ ChildIterator(const RootNode *parent) : mParent(parent->data()), mPos(0), mSize(parent->tileCount()) { ++ __hostdev__ ChildIterator(__global__ const RootNode *parent) : mParent(parent->data()), mPos(0), mSize(parent->tileCount()) { + NANOVDB_ASSERT(mParent); + while (mPostile(mPos)->isChild()) ++mPos; + } +- ChildIterator& operator=(const ChildIterator&) = default; +- __hostdev__ const ChildT& operator*() const {NANOVDB_ASSERT(*this); return *mParent->getChild(mParent->tile(mPos));} +- __hostdev__ const ChildT* operator->() const {NANOVDB_ASSERT(*this); return mParent->getChild(mParent->tile(mPos));} ++ __global__ ChildIterator& operator=(__global__ const ChildIterator&) = default; ++ __hostdev__ __global__ const ChildT& operator*() const {NANOVDB_ASSERT(*this); return *mParent->getChild(mParent->tile(mPos));} ++ __hostdev__ __global__ const ChildT* operator->() const {NANOVDB_ASSERT(*this); return mParent->getChild(mParent->tile(mPos));} + __hostdev__ CoordType getOrigin() const { NANOVDB_ASSERT(*this); mParent->tile(mPos)->origin();} + __hostdev__ operator bool() const {return mPos < mSize;} + __hostdev__ uint32_t pos() const {return mPos;} +- __hostdev__ ChildIterator& operator++() { ++ __hostdev__ __global__ ChildIterator& operator++() { + NANOVDB_ASSERT(mParent); + ++mPos; + while (mPos < mSize && mParent->tile(mPos)->isValue()) ++mPos; +@@ -3123,21 +3505,21 @@ public: + + class ValueIterator + { +- const DataType *mParent; +- uint32_t mPos, mSize; ++ __global__ const DataType *mParent; ++ uint32_t mPos, mSize; + public: + __hostdev__ ValueIterator() : mParent(nullptr), mPos(0), mSize(0) {} +- __hostdev__ ValueIterator(const RootNode *parent) : mParent(parent->data()), mPos(0), mSize(parent->tileCount()){ ++ __hostdev__ ValueIterator(__global__ const RootNode *parent) : mParent(parent->data()), mPos(0), mSize(parent->tileCount()){ + NANOVDB_ASSERT(mParent); + while (mPos < mSize && mParent->tile(mPos)->isChild()) ++mPos; + } +- ValueIterator& operator=(const ValueIterator&) = default; ++ __global__ ValueIterator& operator=(__global__ const ValueIterator&) = default; + __hostdev__ ValueType operator*() const {NANOVDB_ASSERT(*this); return mParent->tile(mPos)->value;} + __hostdev__ bool isActive() const {NANOVDB_ASSERT(*this); return mParent->tile(mPos)->state;} + __hostdev__ operator bool() const {return mPos < mSize;} + __hostdev__ uint32_t pos() const {return mPos;} + __hostdev__ CoordType getOrigin() const { NANOVDB_ASSERT(*this); mParent->tile(mPos)->origin();} +- __hostdev__ ValueIterator& operator++() { ++ __hostdev__ __global__ ValueIterator& operator++() { + NANOVDB_ASSERT(mParent); + ++mPos; + while (mPos < mSize && mParent->tile(mPos)->isChild()) ++mPos; +@@ -3154,20 +3536,20 @@ public: + + class ValueOnIterator + { +- const DataType *mParent; ++ __global__ const DataType *mParent; + uint32_t mPos, mSize; + public: + __hostdev__ ValueOnIterator() : mParent(nullptr), mPos(0), mSize(0) {} +- __hostdev__ ValueOnIterator(const RootNode *parent) : mParent(parent->data()), mPos(0), mSize(parent->tileCount()){ ++ __hostdev__ ValueOnIterator(__global__ const RootNode *parent) : mParent(parent->data()), mPos(0), mSize(parent->tileCount()){ + NANOVDB_ASSERT(mParent); + while (mPos < mSize && !mParent->tile(mPos)->isActive()) ++mPos; + } +- ValueOnIterator& operator=(const ValueOnIterator&) = default; ++ __global__ ValueOnIterator& operator=(__global__ const ValueOnIterator&) = default; + __hostdev__ ValueType operator*() const {NANOVDB_ASSERT(*this); return mParent->tile(mPos)->value;} + __hostdev__ operator bool() const {return mPos < mSize;} + __hostdev__ uint32_t pos() const {return mPos;} + __hostdev__ CoordType getOrigin() const { NANOVDB_ASSERT(*this); mParent->tile(mPos)->origin();} +- __hostdev__ ValueOnIterator& operator++() { ++ __hostdev__ __global__ ValueOnIterator& operator++() { + NANOVDB_ASSERT(mParent); + ++mPos; + while (mPos < mSize && !mParent->tile(mPos)->isActive()) ++mPos; +@@ -3183,75 +3565,107 @@ public: + ValueOnIterator beginValueOn() const {return ValueOnIterator(this);} + + /// @brief This class cannot be constructed or deleted +- RootNode() = delete; +- RootNode(const RootNode&) = delete; +- RootNode& operator=(const RootNode&) = delete; +- ~RootNode() = delete; ++ RootNode() __global__ = delete; ++ RootNode(__global__ const RootNode&) __global__ = delete; ++ __global__ RootNode& operator=(__global__ const RootNode&) __global__ = delete; ++ ~RootNode() __global__ = delete; + +- __hostdev__ AccessorType getAccessor() const { return AccessorType(*this); } ++ __hostdev__ AccessorType getAccessor() const __global__ { return AccessorType(*this); } + +- __hostdev__ DataType* data() { return reinterpret_cast(this); } ++ __hostdev__ __global__ DataType* data() __global__ { return reinterpret_cast<__global__ DataType*>(this); } + +- __hostdev__ const DataType* data() const { return reinterpret_cast(this); } ++ __hostdev__ __global__ const DataType* data() const __global__ { return reinterpret_cast<__global__ const DataType*>(this); } + + /// @brief Return a const reference to the index bounding box of all the active values in this tree, i.e. in all nodes of the tree +- __hostdev__ const BBoxType& bbox() const { return DataType::mBBox; } ++ __hostdev__ __global__ const BBoxType& bbox() const __global__ { return BASE(mBBox); } + + /// @brief Return the total number of active voxels in the root and all its child nodes. + + /// @brief Return a const reference to the background value, i.e. the value associated with + /// any coordinate location that has not been set explicitly. +- __hostdev__ const ValueType& background() const { return DataType::mBackground; } ++ __hostdev__ __global__ const ValueType& background() const __global__ { return DataType::mBackground; } + + /// @brief Return the number of tiles encoded in this root node +- __hostdev__ const uint32_t& tileCount() const { return DataType::mTableSize; } ++ __hostdev__ __global__ const uint32_t& tileCount() const __global__ { return DataType::mTableSize; } + + /// @brief Return a const reference to the minimum active value encoded in this root node and any of its child nodes +- __hostdev__ const ValueType& minimum() const { return this->getMin(); } ++ __hostdev__ __global__ const ValueType& minimum() const __global__ { return this->getMin(); } + + /// @brief Return a const reference to the maximum active value encoded in this root node and any of its child nodes +- __hostdev__ const ValueType& maximum() const { return this->getMax(); } ++ __hostdev__ __global__ const ValueType& maximum() const __global__ { return this->getMax(); } + + /// @brief Return a const reference to the average of all the active values encoded in this root node and any of its child nodes +- __hostdev__ const FloatType& average() const { return DataType::mAverage; } ++ __hostdev__ __global__ const FloatType& average() const __global__ { return DataType::mAverage; } + + /// @brief Return the variance of all the active values encoded in this root node and any of its child nodes +- __hostdev__ FloatType variance() const { return DataType::mStdDevi * DataType::mStdDevi; } ++ __hostdev__ FloatType variance() const __global__ { return DataType::mStdDevi * DataType::mStdDevi; } + + /// @brief Return a const reference to the standard deviation of all the active values encoded in this root node and any of its child nodes +- __hostdev__ const FloatType& stdDeviation() const { return DataType::mStdDevi; } ++ __hostdev__ __global__ const FloatType& stdDeviation() const __global__ { return DataType::mStdDevi; } + + /// @brief Return the expected memory footprint in bytes with the specified number of tiles + __hostdev__ static uint64_t memUsage(uint32_t tableSize) { return sizeof(RootNode) + tableSize * sizeof(Tile); } + + /// @brief Return the actual memory footprint of this root node +- __hostdev__ uint64_t memUsage() const { return sizeof(RootNode) + DataType::mTableSize * sizeof(Tile); } ++ __hostdev__ uint64_t memUsage() const __global__ { return sizeof(RootNode) + DataType::mTableSize * sizeof(Tile); } + + /// @brief Return the value of the given voxel +- __hostdev__ ValueType getValue(const CoordType& ijk) const ++ __hostdev__ ValueType getValue(__global__ const CoordType& ijk) const __global__ + { +- if (const Tile* tile = this->probeTile(ijk)) { ++ if (__global__ const Tile* tile = this->probeTile(ijk)) { + return tile->isChild() ? this->getChild(tile)->getValue(ijk) : tile->value; + } + return DataType::mBackground; + } +- +- __hostdev__ bool isActive(const CoordType& ijk) const ++#if defined(__KERNEL_METAL__) ++ __hostdev__ ValueType getValue(__local__ const CoordType& ijk) const __global__ + { +- if (const Tile* tile = this->probeTile(ijk)) { +- return tile->isChild() ? this->getChild(tile)->isActive(ijk) : tile->state; ++ if (__global__ const Tile* tile = this->findTile(ijk)) { ++ return tile->isChild() ? this->getChild(tile)->getValue(ijk) : tile->value; ++ } ++ return DataType::mBackground; ++ } ++ __hostdev__ ValueType getValue(__local__ const CoordType& ijk) const __local__ ++ { ++ if (__global__ const Tile* tile = this->findTile(ijk)) { ++ return tile->isChild() ? this->getChild(tile)->getValue(ijk) : tile->value; ++ } ++ return DataType::mBackground; ++ } ++#endif ++ ++ __hostdev__ bool isActive(__global__ const CoordType& ijk) const __global__ ++ { ++ if (__global__ const Tile* tile = this->findTile(ijk)) { ++ return tile->isChild() ? BASE(getChild)(tile)->isActive(ijk) : tile->state; + } + return false; + } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ bool isActive(__local__ const CoordType& ijk) const __global__ ++ { ++ if (__global__ const Tile* tile = this->findTile(ijk)) { ++ return tile->isChild() ? BASE(getChild)(tile)->isActive(ijk) : tile->state; ++ } ++ return false; ++ } ++ __hostdev__ bool isActive(__local__ const CoordType& ijk) const __local__ ++ { ++ if (__global__ const Tile* tile = this->findTile(ijk)) { ++ return tile->isChild() ? BASE(getChild)(tile)->isActive(ijk) : tile->state; ++ } ++ return false; ++ } ++#endif + + /// @brief Return true if this RootNode is empty, i.e. contains no values or nodes +- __hostdev__ bool isEmpty() const { return DataType::mTableSize == uint32_t(0); } ++ __hostdev__ bool isEmpty() const __global__ { return BASE(mTableSize) == uint32_t(0); } + +- __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const ++ __hostdev__ bool probeValue(__global__ const CoordType& ijk, __global__ ValueType& v) const __global__ + { +- if (const Tile* tile = this->probeTile(ijk)) { ++ if (__global__ const Tile* tile = this->probeTile(ijk)) { + if (tile->isChild()) { +- const auto *child = this->getChild(tile); ++ __global__ const auto *child = this->getChild(tile); + return child->probeValue(ijk, v); + } + v = tile->value; +@@ -3260,33 +3674,49 @@ public: + v = DataType::mBackground; + return false; + } +- +- __hostdev__ const LeafNodeType* probeLeaf(const CoordType& ijk) const ++#if defined(__KERNEL_METAL__) ++ __hostdev__ bool probeValue(__local__ const CoordType& ijk, __local__ ValueType& v) const __global__ + { +- const Tile* tile = this->probeTile(ijk); ++ if (__global__ const Tile* tile = this->findTile(ijk)) { ++ if (tile->isChild()) { ++ __global__ const auto *child = BASE(getChild)(tile); ++ return child->probeValue(ijk, v); ++ } ++ v = tile->value; ++ return tile->state; ++ } ++ v = BASE(mBackground); ++ return false; ++ } ++#endif ++ ++ __hostdev__ __global__ const LeafNodeType* probeLeaf(__global__ const CoordType& ijk) const ++ { ++ __global__ const Tile* tile = this->probeTile(ijk); + if (tile && tile->isChild()) { +- const auto *child = this->getChild(tile); ++ const __global__ auto *child = this->getChild(tile); + return child->probeLeaf(ijk); + } + return nullptr; + } + +- __hostdev__ const ChildNodeType* probeChild(const CoordType& ijk) const ++ __hostdev__ __global__ const ChildNodeType* probeChild(__global__ const CoordType& ijk) const + { +- const Tile* tile = this->probeTile(ijk); ++ __global__ const Tile* tile = this->probeTile(ijk); + if (tile && tile->isChild()) { + return this->getChild(tile); + } + return nullptr; + } + ++ + /// @brief Find and return a Tile of this root node +- __hostdev__ const Tile* probeTile(const CoordType& ijk) const ++ __hostdev__ __global__ const Tile* probeTile(__global__ const CoordType& ijk) const __global__ + { +- const Tile* tiles = reinterpret_cast(this + 1); +- const auto key = DataType::CoordToKey(ijk); ++ __global__ const Tile* tiles = reinterpret_cast<__global__ const Tile*>(this + 1); ++ const auto key = BASE(CoordToKey)(ijk); + #if 1 // switch between linear and binary seach +- for (uint32_t i = 0; i < DataType::mTableSize; ++i) { ++ for (uint32_t i = 0; i < BASE(mTableSize); ++i) { + if (tiles[i].key == key) return &tiles[i]; + } + #else// do not enable binary search if tiles are not guaranteed to be sorted!!!!!! +@@ -3306,6 +3736,33 @@ public: + #endif + return nullptr; + } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ __global__ const Tile* findTile(__local__ const CoordType& ijk) const __global__ ++ { ++ __global__ const Tile* tiles = reinterpret_cast<__global__ const Tile*>(this + 1); ++ const auto key = BASE(CoordToKey)(ijk); ++#if 1 // switch between linear and binary seach ++ for (uint32_t i = 0; i < BASE(mTableSize); ++i) { ++ if (tiles[i].key == key) return &tiles[i]; ++ } ++#else// do not enable binary search if tiles are not guaranteed to be sorted!!!!!! ++ // binary-search of pre-sorted elements ++ int32_t low = 0, high = DataType::mTableSize; // low is inclusive and high is exclusive ++ while (low != high) { ++ int mid = low + ((high - low) >> 1); ++ const Tile* tile = &tiles[mid]; ++ if (tile->key == key) { ++ return tile; ++ } else if (tile->key < key) { ++ low = mid + 1; ++ } else { ++ high = mid; ++ } ++ } ++#endif ++ return nullptr; ++ } ++#endif + + private: + static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(RootData) is misaligned"); +@@ -3319,12 +3776,12 @@ private: + + /// @brief Private method to return node information and update a ReadAccessor + template +- __hostdev__ typename AccT::NodeInfo getNodeInfoAndCache(const CoordType& ijk, const AccT& acc) const ++ __hostdev__ typename AccT::NodeInfo getNodeInfoAndCache(__global__ const CoordType& ijk, __global__ const AccT& acc) const + { + using NodeInfoT = typename AccT::NodeInfo; +- if (const Tile* tile = this->probeTile(ijk)) { ++ if (__global__ const Tile* tile = this->probeTile(ijk)) { + if (tile->isChild()) { +- const auto *child = this->getChild(tile); ++ __global__ const auto *child = this->getChild(tile); + acc.insert(ijk, child); + return child->getNodeInfoAndCache(ijk, acc); + } +@@ -3337,11 +3794,11 @@ private: + + /// @brief Private method to return a voxel value and update a ReadAccessor + template +- __hostdev__ ValueType getValueAndCache(const CoordType& ijk, const AccT& acc) const ++ __hostdev__ ValueType getValueAndCache(__global__ const CoordType& ijk, __global__ const AccT& acc) const __global__ + { +- if (const Tile* tile = this->probeTile(ijk)) { ++ if (__global__ const Tile* tile = this->probeTile(ijk)) { + if (tile->isChild()) { +- const auto *child = this->getChild(tile); ++ __global__ const auto *child = this->getChild(tile); + acc.insert(ijk, child); + return child->getValueAndCache(ijk, acc); + } +@@ -3349,25 +3806,66 @@ private: + } + return DataType::mBackground; + } ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ ValueType getValueAndCache(__local__ const CoordType& ijk, __local__ const AccT& acc) const __global__ ++ { ++ if (__global__ const Tile* tile = this->findTile(ijk)) { ++ if (tile->isChild()) { ++ __global__ const auto *child = BASE(getChild)(tile); ++ acc.insert(ijk, child); ++ return child->getValueAndCache(ijk, acc); ++ } ++ return tile->value; ++ } ++ return BASE(mBackground); ++ } ++ template ++ __hostdev__ ValueType getValueAndCache(__local__ const CoordType& ijk, __local__ const AccT& acc) const __local__ ++ { ++ if (__global__ const Tile* tile = this->findTile(ijk)) { ++ if (tile->isChild()) { ++ __global__ const auto *child = BASE(getChild)(tile); ++ acc.insert(ijk, child); ++ return child->getValueAndCache(ijk, acc); ++ } ++ return tile->value; ++ } ++ return BASE(mBackground); ++ } ++#endif + + template +- __hostdev__ bool isActiveAndCache(const CoordType& ijk, const AccT& acc) const ++ __hostdev__ bool isActiveAndCache(__global__ const CoordType& ijk, __global__ const AccT& acc) const + { +- const Tile* tile = this->probeTile(ijk); ++ __global__ const Tile* tile = this->probeTile(ijk); + if (tile && tile->isChild()) { +- const auto *child = this->getChild(tile); ++ __global__ const auto *child = BASE(getChild)(tile); + acc.insert(ijk, child); + return child->isActiveAndCache(ijk, acc); + } + return false; + } ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ bool isActiveAndCache(__local__ const CoordType& ijk, __local__ const AccT& acc) const __global__ ++ { ++ __global__ const Tile* tile = this->findTile(ijk); ++ if (tile && tile->isChild()) { ++ __global__ const auto *child = BASE(getChild)(tile); ++ acc.insert(ijk, child); ++ return child->isActiveAndCache(ijk, acc); ++ } ++ return false; ++ } ++#endif + + template +- __hostdev__ bool probeValueAndCache(const CoordType& ijk, ValueType& v, const AccT& acc) const ++ __hostdev__ bool probeValueAndCache(__global__ const CoordType& ijk, __global__ ValueType& v, __global__ const AccT& acc) const + { +- if (const Tile* tile = this->probeTile(ijk)) { ++ if (__global__ const Tile* tile = this->probeTile(ijk)) { + if (tile->isChild()) { +- const auto *child = this->getChild(tile); ++ __global__ const auto *child = BASE(getChild)(tile); + acc.insert(ijk, child); + return child->probeValueAndCache(ijk, v, acc); + } +@@ -3379,11 +3877,11 @@ private: + } + + template +- __hostdev__ const LeafNodeType* probeLeafAndCache(const CoordType& ijk, const AccT& acc) const ++ __hostdev__ __global__ const LeafNodeType* probeLeafAndCache(__global__ const CoordType& ijk, __global__ const AccT& acc) const + { +- const Tile* tile = this->probeTile(ijk); ++ __global__ const Tile* tile = this->probeTile(ijk); + if (tile && tile->isChild()) { +- const auto *child = this->getChild(tile); ++ __global__ const auto *child = BASE(getChild)(tile); + acc.insert(ijk, child); + return child->probeLeafAndCache(ijk, acc); + } +@@ -3391,11 +3889,11 @@ private: + } + + template +- __hostdev__ uint32_t getDimAndCache(const CoordType& ijk, const RayT& ray, const AccT& acc) const ++ __hostdev__ uint32_t getDimAndCache(__global__ const CoordType& ijk, __global__ const RayT& ray, __global__ const AccT& acc) const __global__ + { +- if (const Tile* tile = this->probeTile(ijk)) { ++ if (__global__ const Tile* tile = this->probeTile(ijk)) { + if (tile->isChild()) { +- const auto *child = this->getChild(tile); ++ __global__ const auto *child = BASE(getChild)(tile); + acc.insert(ijk, child); + return child->getDimAndCache(ijk, ray, acc); + } +@@ -3403,7 +3901,23 @@ private: + } + return ChildNodeType::dim(); // background + } ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ uint32_t getDimAndCache(__local__ const CoordType& ijk, __local__ const RayT& ray, __local__ const AccT& acc) const __global__ ++ { ++ if (__global__ const Tile* tile = this->probeTile(ijk)) { ++ if (tile->isChild()) { ++ __global__ const auto *child = BASE(getChild)(tile); ++ acc.insert(ijk, child); ++ return child->getDimAndCache(ijk, ray, acc); ++ } ++ return 1 << ChildT::TOTAL; //tile value ++ } ++ return ChildNodeType::dim(); // background ++ } ++#endif + ++#undef BASE + }; // RootNode class + + // After the RootNode the memory layout is assumed to be the sorted Tiles +@@ -3421,7 +3935,7 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) InternalData + using StatsT = typename ChildT::FloatType; + using CoordT = typename ChildT::CoordType; + using MaskT = typename ChildT::template MaskType; +- static constexpr bool FIXED_SIZE = true; ++ static __constant__ constexpr bool FIXED_SIZE = true; + + union Tile + { +@@ -3429,8 +3943,8 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) InternalData + int64_t child;//signed 64 bit byte offset relative to the InternalData!! + /// @brief This class cannot be constructed or deleted + Tile() = delete; +- Tile(const Tile&) = delete; +- Tile& operator=(const Tile&) = delete; ++ Tile(__global__ const Tile&) = delete; ++ __global__ Tile& operator=(__global__ const Tile&) = delete; + ~Tile() = delete; + }; + +@@ -3456,32 +3970,32 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) InternalData + + __hostdev__ static uint64_t memUsage() { return sizeof(InternalData); } + +- __hostdev__ void setChild(uint32_t n, const void *ptr) ++ __hostdev__ void setChild(uint32_t n, __global__ const void *ptr) + { + NANOVDB_ASSERT(mChildMask.isOn(n)); + mTable[n].child = PtrDiff(ptr, this); + } + + template +- __hostdev__ void setValue(uint32_t n, const ValueT &v) ++ __hostdev__ void setValue(uint32_t n, __global__ const ValueT &v) + { + NANOVDB_ASSERT(!mChildMask.isOn(n)); + mTable[n].value = v; + } + + /// @brief Returns a pointer to the child node at the specifed linear offset. +- __hostdev__ ChildT* getChild(uint32_t n) ++ __hostdev__ __global__ ChildT* getChild(uint32_t n) __global__ + { + NANOVDB_ASSERT(mChildMask.isOn(n)); + return PtrAdd(this, mTable[n].child); + } +- __hostdev__ const ChildT* getChild(uint32_t n) const ++ __hostdev__ __global__ const ChildT* getChild(uint32_t n) const __global__ + { + NANOVDB_ASSERT(mChildMask.isOn(n)); + return PtrAdd(this, mTable[n].child); + } + +- __hostdev__ ValueT getValue(uint32_t n) const ++ __hostdev__ ValueT getValue(uint32_t n) const __global__ + { + NANOVDB_ASSERT(!mChildMask.isOn(n)); + return mTable[n].value; +@@ -3496,29 +4010,38 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) InternalData + __hostdev__ bool isChild(uint32_t n) const {return mChildMask.isOn(n);} + + template +- __hostdev__ void setOrigin(const T& ijk) { mBBox[0] = ijk; } ++ __hostdev__ void setOrigin(__global__ const T& ijk) { mBBox[0] = ijk; } + +- __hostdev__ const ValueT& getMin() const { return mMinimum; } +- __hostdev__ const ValueT& getMax() const { return mMaximum; } +- __hostdev__ const StatsT& average() const { return mAverage; } +- __hostdev__ const StatsT& stdDeviation() const { return mStdDevi; } ++ __hostdev__ __global__ const ValueT& getMin() const { return mMinimum; } ++ __hostdev__ __global__ const ValueT& getMax() const { return mMaximum; } ++ __hostdev__ __global__ const StatsT& average() const { return mAverage; } ++ __hostdev__ __global__ const StatsT& stdDeviation() const { return mStdDevi; } + +- __hostdev__ void setMin(const ValueT& v) { mMinimum = v; } +- __hostdev__ void setMax(const ValueT& v) { mMaximum = v; } +- __hostdev__ void setAvg(const StatsT& v) { mAverage = v; } +- __hostdev__ void setDev(const StatsT& v) { mStdDevi = v; } ++ __hostdev__ void setMin(__global__ const ValueT& v) { mMinimum = v; } ++ __hostdev__ void setMax(__global__ const ValueT& v) { mMaximum = v; } ++ __hostdev__ void setAvg(__global__ const StatsT& v) { mAverage = v; } ++ __hostdev__ void setDev(__global__ const StatsT& v) { mStdDevi = v; } + + /// @brief This class cannot be constructed or deleted + InternalData() = delete; +- InternalData(const InternalData&) = delete; +- InternalData& operator=(const InternalData&) = delete; ++ InternalData(__global__ const InternalData&) = delete; ++ __global__ InternalData& operator=(__global__ const InternalData&) = delete; + ~InternalData() = delete; + }; // InternalData + + /// @brief Internal nodes of a VDB treedim(), + template +-class InternalNode : private InternalData ++class InternalNode ++#if !defined(__KERNEL_METAL__) ++ : private InternalData ++#endif + { ++#if defined(__KERNEL_METAL__) ++ InternalData _base; ++#define BASE(v) _base.v ++#else ++#define BASE(v) DataType::v ++#endif + public: + using DataType = InternalData; + using ValueType = typename DataType::ValueT; +@@ -3527,76 +4050,109 @@ public: + using LeafNodeType = typename ChildT::LeafNodeType; + using ChildNodeType = ChildT; + using CoordType = typename ChildT::CoordType; +- static constexpr bool FIXED_SIZE = DataType::FIXED_SIZE; ++ static __constant__ constexpr bool FIXED_SIZE = DataType::FIXED_SIZE; + template + using MaskType = typename ChildT::template MaskType; + template + using MaskIterT = typename Mask::template Iterator; + +- static constexpr uint32_t LOG2DIM = Log2Dim; +- static constexpr uint32_t TOTAL = LOG2DIM + ChildT::TOTAL; // dimension in index space +- static constexpr uint32_t DIM = 1u << TOTAL; // number of voxels along each axis of this node +- static constexpr uint32_t SIZE = 1u << (3 * LOG2DIM); // number of tile values (or child pointers) +- static constexpr uint32_t MASK = (1u << TOTAL) - 1u; +- static constexpr uint32_t LEVEL = 1 + ChildT::LEVEL; // level 0 = leaf +- static constexpr uint64_t NUM_VALUES = uint64_t(1) << (3 * TOTAL); // total voxel count represented by this node ++ static __constant__ constexpr uint32_t LOG2DIM = Log2Dim; ++ static __constant__ constexpr uint32_t TOTAL = LOG2DIM + ChildT::TOTAL; // dimension in index space ++ static __constant__ constexpr uint32_t DIM = 1u << TOTAL; // number of voxels along each axis of this node ++ static __constant__ constexpr uint32_t SIZE = 1u << (3 * LOG2DIM); // number of tile values (or child pointers) ++ static __constant__ constexpr uint32_t MASK = (1u << TOTAL) - 1u; ++ static __constant__ constexpr uint32_t LEVEL = 1 + ChildT::LEVEL; // level 0 = leaf ++ static __constant__ constexpr uint64_t NUM_VALUES = uint64_t(1) << (3 * TOTAL); // total voxel count represented by this node + + /// @brief Visits child nodes of this node only +- class ChildIterator : public MaskIterT ++ class ChildIterator ++#if !defined (__KERNEL_METAL__) ++ : public MaskIterT ++#endif + { ++#if defined (__KERNEL_METAL__) ++ MaskIterT BaseT; ++#define BASE(v) BaseT.v ++#else + using BaseT = MaskIterT; +- const DataType *mParent; ++#define BASE(v) BaseT::v ++#endif ++ __global__ const DataType *mParent; + public: + __hostdev__ ChildIterator() : BaseT(), mParent(nullptr) {} +- __hostdev__ ChildIterator(const InternalNode* parent) : BaseT(parent->data()->mChildMask.beginOn()), mParent(parent->data()) {} +- ChildIterator& operator=(const ChildIterator&) = default; +- __hostdev__ const ChildT& operator*() const {NANOVDB_ASSERT(*this); return *mParent->getChild(BaseT::pos());} +- __hostdev__ const ChildT* operator->() const {NANOVDB_ASSERT(*this); return mParent->getChild(BaseT::pos());} ++ __hostdev__ ChildIterator(__global__ const InternalNode* parent) : BaseT(parent->data()->mChildMask.beginOn()), mParent(parent->data()) {} ++ __global__ ChildIterator& operator=(__global__ const ChildIterator&) = default; ++ __hostdev__ __global__ const ChildT& operator*() const {NANOVDB_ASSERT(*this); return *mParent->getChild(BASE(pos)());} ++ __hostdev__ __global__ const ChildT* operator->() const {NANOVDB_ASSERT(*this); return mParent->getChild(BASE(pos)());} + __hostdev__ CoordType getOrigin() const { NANOVDB_ASSERT(*this); return (*this)->origin();} + }; // Member class ChildIterator + + ChildIterator beginChild() const {return ChildIterator(this);} + + /// @brief Visits all tile values in this node, i.e. both inactive and active tiles +- class ValueIterator : public MaskIterT ++ class ValueIterator ++#if !defined (__KERNEL_METAL__) ++ : public MaskIterT ++#endif + { ++#if defined (__KERNEL_METAL__) ++ MaskIterT BaseT; ++#define BASE(v) BaseT.v ++#else + using BaseT = MaskIterT; +- const InternalNode *mParent; ++#define BASE(v) BaseT::v ++#endif ++ __global__ const InternalNode *mParent; + public: + __hostdev__ ValueIterator() : BaseT(), mParent(nullptr) {} +- __hostdev__ ValueIterator(const InternalNode* parent) : BaseT(parent->data()->mChildMask.beginOff()), mParent(parent) {} +- ValueIterator& operator=(const ValueIterator&) = default; +- __hostdev__ ValueType operator*() const {NANOVDB_ASSERT(*this); return mParent->data()->getValue(BaseT::pos());} +- __hostdev__ CoordType getOrigin() const { NANOVDB_ASSERT(*this); return mParent->localToGlobalCoord(BaseT::pos());} +- __hostdev__ bool isActive() const { NANOVDB_ASSERT(*this); return mParent->data()->isActive(BaseT::mPos);} ++ __hostdev__ ValueIterator(__global__ const InternalNode* parent) : BaseT(parent->data()->mChildMask.beginOff()), mParent(parent) {} ++ __global__ ValueIterator& operator=(__global__ const ValueIterator&) = default; ++ __hostdev__ ValueType operator*() const {NANOVDB_ASSERT(*this); return mParent->data()->getValue(BASE(pos)());} ++ __hostdev__ CoordType getOrigin() const { NANOVDB_ASSERT(*this); return mParent->localToGlobalCoord(BASE(pos)());} ++ __hostdev__ bool isActive() const { NANOVDB_ASSERT(*this); return mParent->data()->isActive(BASE(mPos));} + }; // Member class ValueIterator + + ValueIterator beginValue() const {return ValueIterator(this);} + + /// @brief Visits active tile values of this node only +- class ValueOnIterator : public MaskIterT ++ class ValueOnIterator ++#if !defined (__KERNEL_METAL__) ++ : public MaskIterT ++#endif + { ++#if defined (__KERNEL_METAL__) ++ MaskIterT BaseT; ++#define BASE(v) BaseT.v ++#else + using BaseT = MaskIterT; +- const InternalNode *mParent; ++#define BASE(v) BaseT::v ++#endif ++ __global__ const InternalNode *mParent; + public: + __hostdev__ ValueOnIterator() : BaseT(), mParent(nullptr) {} +- __hostdev__ ValueOnIterator(const InternalNode* parent) : BaseT(parent->data()->mValueMask.beginOn()), mParent(parent) {} +- ValueOnIterator& operator=(const ValueOnIterator&) = default; +- __hostdev__ ValueType operator*() const {NANOVDB_ASSERT(*this); return mParent->data()->getValue(BaseT::pos());} +- __hostdev__ CoordType getOrigin() const { NANOVDB_ASSERT(*this); return mParent->localToGlobalCoord(BaseT::pos());} ++ __hostdev__ ValueOnIterator(__global__ const InternalNode* parent) : BaseT(parent->data()->mValueMask.beginOn()), mParent(parent) {} ++ __global__ ValueOnIterator& operator=(__global__ const ValueOnIterator&) = default; ++ __hostdev__ ValueType operator*() const {NANOVDB_ASSERT(*this); return mParent->data()->getValue(BASE(pos)());} ++ __hostdev__ CoordType getOrigin() const { NANOVDB_ASSERT(*this); return mParent->localToGlobalCoord(BASE(pos)());} + }; // Member class ValueOnIterator + + ValueOnIterator beginValueOn() const {return ValueOnIterator(this);} + ++#if defined(__KERNEL_METAL__) ++#define BASE(v) _base.v ++#else ++#define BASE(v) DataType::v ++#endif ++ + /// @brief This class cannot be constructed or deleted +- InternalNode() = delete; +- InternalNode(const InternalNode&) = delete; +- InternalNode& operator=(const InternalNode&) = delete; ++ InternalNode() __global__ = delete; ++ InternalNode(__global__ const InternalNode&) __global__ = delete; ++ __global__ InternalNode& operator=(__global__ const InternalNode&) __global__ = delete; + ~InternalNode() = delete; + +- __hostdev__ DataType* data() { return reinterpret_cast(this); } ++ __hostdev__ __global__ DataType* data() __global__ { return reinterpret_cast<__global__ DataType*>(this); } + +- __hostdev__ const DataType* data() const { return reinterpret_cast(this); } ++ __hostdev__ __global__ const DataType* data() const __global__ { return reinterpret_cast<__global__ const DataType*>(this); } + + /// @brief Return the dimension, in voxel units, of this internal node (typically 8*16 or 8*16*32) + __hostdev__ static uint32_t dim() { return 1u << TOTAL; } +@@ -3605,47 +4161,66 @@ public: + __hostdev__ static size_t memUsage() { return DataType::memUsage(); } + + /// @brief Return a const reference to the bit mask of active voxels in this internal node +- __hostdev__ const MaskType& valueMask() const { return DataType::mValueMask; } ++ __hostdev__ __global__ const MaskType& valueMask() const __global__ { return BASE(mValueMask); } + + /// @brief Return a const reference to the bit mask of child nodes in this internal node +- __hostdev__ const MaskType& childMask() const { return DataType::mChildMask; } ++ __hostdev__ __global__ const MaskType& childMask() const __global__ { return DataType::mChildMask; } + + /// @brief Return the origin in index space of this leaf node +- __hostdev__ CoordType origin() const { return DataType::mBBox.min() & ~MASK; } ++ __hostdev__ CoordType origin() const __global__ { return DataType::mBBox.min() & ~MASK; } + + /// @brief Return a const reference to the minimum active value encoded in this internal node and any of its child nodes +- __hostdev__ const ValueType& minimum() const { return this->getMin(); } ++ __hostdev__ __global__ const ValueType& minimum() const __global__ { return this->getMin(); } + + /// @brief Return a const reference to the maximum active value encoded in this internal node and any of its child nodes +- __hostdev__ const ValueType& maximum() const { return this->getMax(); } ++ __hostdev__ __global__ const ValueType& maximum() const __global__ { return this->getMax(); } + + /// @brief Return a const reference to the average of all the active values encoded in this internal node and any of its child nodes +- __hostdev__ const FloatType& average() const { return DataType::mAverage; } ++ __hostdev__ __global__ const FloatType& average() const __global__ { return DataType::mAverage; } + + /// @brief Return the variance of all the active values encoded in this internal node and any of its child nodes +- __hostdev__ FloatType variance() const { return DataType::mStdDevi*DataType::mStdDevi; } ++ __hostdev__ FloatType variance() const __global__ { return DataType::mStdDevi*DataType::mStdDevi; } + + /// @brief Return a const reference to the standard deviation of all the active values encoded in this internal node and any of its child nodes +- __hostdev__ const FloatType& stdDeviation() const { return DataType::mStdDevi; } ++ __hostdev__ __global__ const FloatType& stdDeviation() const __global__ { return DataType::mStdDevi; } + + /// @brief Return a const reference to the bounding box in index space of active values in this internal node and any of its child nodes +- __hostdev__ const BBox& bbox() const { return DataType::mBBox; } ++ __hostdev__ __global__ const BBox& bbox() const __global__ { return DataType::mBBox; } + + /// @brief Return the value of the given voxel +- __hostdev__ ValueType getValue(const CoordType& ijk) const ++ __hostdev__ ValueType getValue(__global__ const CoordType& ijk) const __global__ + { + const uint32_t n = CoordToOffset(ijk); + return DataType::mChildMask.isOn(n) ? this->getChild(n)->getValue(ijk) : DataType::getValue(n); + } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ ValueType getValue(__local__ const CoordType& ijk) const __global__ ++ { ++ const uint32_t n = CoordToOffset(ijk); ++ return DataType::mChildMask.isOn(n) ? this->getChild(n)->getValue(ijk) : DataType::mTable[n].value; ++ } ++#endif + +- __hostdev__ bool isActive(const CoordType& ijk) const ++ __hostdev__ bool isActive(__global__ const CoordType& ijk) const __global__ + { + const uint32_t n = CoordToOffset(ijk); + return DataType::mChildMask.isOn(n) ? this->getChild(n)->isActive(ijk) : DataType::isActive(n); + } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ bool isActive(__local__ const CoordType& ijk) const __global__ ++ { ++ const uint32_t n = CoordToOffset(ijk); ++ return DataType::mChildMask.isOn(n) ? this->getChild(n)->isActive(ijk) : DataType::isActive(n); ++ } ++ __hostdev__ bool isActive(__local__ const CoordType& ijk) const __local__ ++ { ++ const uint32_t n = CoordToOffset(ijk); ++ return DataType::mChildMask.isOn(n) ? this->getChild(n)->isActive(ijk) : DataType::isActive(n); ++ } ++#endif + + /// @brief return the state and updates the value of the specified voxel +- __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const ++ __hostdev__ bool probeValue(__global__ const CoordType& ijk, __global__ ValueType& v) const __global__ + { + const uint32_t n = CoordToOffset(ijk); + if (DataType::mChildMask.isOn(n)) +@@ -3653,8 +4228,18 @@ public: + v = DataType::getValue(n); + return DataType::isActive(n); + } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ bool probeValue(__local__ const CoordType& ijk, __local__ ValueType& v) const __global__ ++ { ++ const uint32_t n = CoordToOffset(ijk); ++ if (DataType::mChildMask.isOn(n)) ++ return this->getChild(n)->probeValue(ijk, v); ++ v = DataType::getValue(n); ++ return DataType::isActive(n); ++ } ++#endif + +- __hostdev__ const LeafNodeType* probeLeaf(const CoordType& ijk) const ++ __hostdev__ __global__ const LeafNodeType* probeLeaf(__global__ const CoordType& ijk) const __global__ + { + const uint32_t n = CoordToOffset(ijk); + if (DataType::mChildMask.isOn(n)) +@@ -3662,14 +4247,14 @@ public: + return nullptr; + } + +- __hostdev__ const ChildNodeType* probeChild(const CoordType& ijk) const ++ __hostdev__ __global__ const ChildNodeType* probeChild(__global__ const CoordType& ijk) const __global__ + { + const uint32_t n = CoordToOffset(ijk); + return DataType::mChildMask.isOn(n) ? this->getChild(n) : nullptr; + } + + /// @brief Return the linear offset corresponding to the given coordinate +- __hostdev__ static uint32_t CoordToOffset(const CoordType& ijk) ++ __hostdev__ static uint32_t CoordToOffset(__global__ const CoordType& ijk) + { + #if 0 + return (((ijk[0] & MASK) >> ChildT::TOTAL) << (2 * LOG2DIM)) + +@@ -3681,6 +4266,20 @@ public: + ((ijk[2] & MASK) >> ChildT::TOTAL); + #endif + } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ static uint32_t CoordToOffset(__local__ const CoordType& ijk) ++ { ++#if 0 ++ return (((ijk[0] & MASK) >> ChildT::TOTAL) << (2 * LOG2DIM)) + ++ (((ijk[1] & MASK) >> ChildT::TOTAL) << (LOG2DIM)) + ++ ((ijk[2] & MASK) >> ChildT::TOTAL); ++#else ++ return (((ijk[0] & MASK) >> ChildT::TOTAL) << (2 * LOG2DIM)) | ++ (((ijk[1] & MASK) >> ChildT::TOTAL) << (LOG2DIM)) | ++ ((ijk[2] & MASK) >> ChildT::TOTAL); ++#endif ++ } ++#endif + + /// @return the local coordinate of the n'th tile or child node + __hostdev__ static Coord OffsetToLocalCoord(uint32_t n) +@@ -3691,13 +4290,13 @@ public: + } + + /// @brief modifies local coordinates to global coordinates of a tile or child node +- __hostdev__ void localToGlobalCoord(Coord& ijk) const ++ __hostdev__ void localToGlobalCoord(__global__ Coord& ijk) const __global__ + { + ijk <<= ChildT::TOTAL; + ijk += this->origin(); + } + +- __hostdev__ Coord offsetToGlobalCoord(uint32_t n) const ++ __hostdev__ Coord offsetToGlobalCoord(uint32_t n) const __global__ + { + Coord ijk = InternalNode::OffsetToLocalCoord(n); + this->localToGlobalCoord(ijk); +@@ -3705,13 +4304,24 @@ public: + } + + /// @brief Return true if this node or any of its child nodes contain active values +- __hostdev__ bool isActive() const ++ __hostdev__ bool isActive() const __global__ + { + return DataType::mFlags & uint32_t(2); + } ++#if defined(__KERNEL_METAL__) ++ /// @brief Retrun true if this node or any of its child nodes contain active values ++ __hostdev__ bool isActive() const __local__ ++ { ++ return DataType::mFlags & uint32_t(2); ++ } ++#endif + + private: ++#if !defined(__KERNEL_METAL__) + static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(InternalData) is misaligned"); ++#else ++ static_assert(sizeof(_base) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(InternalData) is misaligned"); ++#endif + //static_assert(offsetof(DataType, mTable) % 32 == 0, "InternalData::mTable is misaligned"); + + template +@@ -3724,18 +4334,30 @@ private: + + /// @brief Private read access method used by the ReadAccessor + template +- __hostdev__ ValueType getValueAndCache(const CoordType& ijk, const AccT& acc) const ++ __hostdev__ ValueType getValueAndCache(__global__ const CoordType& ijk, __global__ const AccT& acc) const __global__ + { + const uint32_t n = CoordToOffset(ijk); + if (!DataType::mChildMask.isOn(n)) +- return DataType::getValue(n); +- const ChildT* child = this->getChild(n); ++ return BASE(getValue)(n); ++ __global__ const ChildT* child = BASE(getChild)(n); + acc.insert(ijk, child); + return child->getValueAndCache(ijk, acc); + } ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ ValueType getValueAndCache(__local__ const CoordType& ijk, __local__ const AccT& acc) const __global__ ++ { ++ const uint32_t n = CoordToOffset(ijk); ++ if (!BASE(mChildMask).isOn(n)) ++ return BASE(getValue)(n); ++ __global__ const ChildT* child = BASE(getChild)(n); ++ acc.insert(ijk, child); ++ return child->getValueAndCache(ijk, acc); ++ } ++#endif + + template +- __hostdev__ typename AccT::NodeInfo getNodeInfoAndCache(const CoordType& ijk, const AccT& acc) const ++ __hostdev__ typename AccT::NodeInfo getNodeInfoAndCache(__global__ const CoordType& ijk, __global__ const AccT& acc) const __global__ + { + using NodeInfoT = typename AccT::NodeInfo; + const uint32_t n = CoordToOffset(ijk); +@@ -3743,61 +4365,91 @@ private: + return NodeInfoT{LEVEL, this->dim(), this->minimum(), this->maximum(), this->average(), + this->stdDeviation(), this->bbox()[0], this->bbox()[1]}; + } +- const ChildT* child = this->getChild(n); ++ __global__ const ChildT* child = BASE(getChild)(n); + acc.insert(ijk, child); + return child->getNodeInfoAndCache(ijk, acc); + } + + template +- __hostdev__ bool isActiveAndCache(const CoordType& ijk, const AccT& acc) const ++ __hostdev__ bool isActiveAndCache(__global__ const CoordType& ijk, __global__ const AccT& acc) const __global__ + { + const uint32_t n = CoordToOffset(ijk); + if (!DataType::mChildMask.isOn(n)) + return DataType::isActive(n); +- const ChildT* child = this->getChild(n); ++ __global__ const ChildT* child = BASE(getChild)(n); + acc.insert(ijk, child); + return child->isActiveAndCache(ijk, acc); + } ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ bool isActiveAndCache(__local__ const CoordType& ijk, __local__ const AccT& acc) const __global__ ++ { ++ const uint32_t n = CoordToOffset(ijk); ++ if (!BASE(mChildMask).isOn(n)) ++ return BASE(mValueMask).isOn(n); ++ __global__ const ChildT* child = BASE(getChild)(n); ++ acc.insert(ijk, child); ++ return child->isActiveAndCache(ijk, acc); ++ } ++#endif + + template +- __hostdev__ bool probeValueAndCache(const CoordType& ijk, ValueType& v, const AccT& acc) const ++ __hostdev__ bool probeValueAndCache(__global__ const CoordType& ijk, __global__ ValueType& v, __global__ const AccT& acc) const __global__ + { + const uint32_t n = CoordToOffset(ijk); + if (!DataType::mChildMask.isOn(n)) { + v = DataType::getValue(n); + return DataType::isActive(n); + } +- const ChildT* child = this->getChild(n); ++ __global__ const ChildT* child = BASE(getChild)(n); + acc.insert(ijk, child); + return child->probeValueAndCache(ijk, v, acc); + } + + template +- __hostdev__ const LeafNodeType* probeLeafAndCache(const CoordType& ijk, const AccT& acc) const ++ __hostdev__ __global__ const LeafNodeType* probeLeafAndCache(__global__ const CoordType& ijk, __global__ const AccT& acc) const __global__ + { + const uint32_t n = CoordToOffset(ijk); + if (!DataType::mChildMask.isOn(n)) + return nullptr; +- const ChildT* child = this->getChild(n); ++ __global__ const ChildT* child = BASE(getChild)(n); + acc.insert(ijk, child); + return child->probeLeafAndCache(ijk, acc); + } + + template +- __hostdev__ uint32_t getDimAndCache(const CoordType& ijk, const RayT& ray, const AccT& acc) const ++ __hostdev__ uint32_t getDimAndCache(__global__ const CoordType& ijk, __global__ const RayT& ray, __global__ const AccT& acc) const __global__ + { + if (DataType::mFlags & uint32_t(1u)) return this->dim(); // skip this node if the 1st bit is set + //if (!ray.intersects( this->bbox() )) return 1<getChild(n); ++ __global__ const ChildT* child = BASE(getChild)(n); + acc.insert(ijk, child); + return child->getDimAndCache(ijk, ray, acc); + } + return ChildNodeType::dim(); // tile value + } ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ uint32_t getDimAndCache(__local__ const CoordType& ijk, __local__ const RayT& ray, __local__ const AccT& acc) const __global__ ++ { ++ if (BASE(mFlags) & uint32_t(1)) ++ this->dim(); //ship this node if first bit is set ++ //if (!ray.intersects( this->bbox() )) return 1<getDimAndCache(ijk, ray, acc); ++ } ++ return ChildNodeType::dim(); // tile value ++ } ++#endif ++ ++#undef BASE + }; // InternalNode class + + // --------------------------> LeafNode <------------------------------------ +@@ -3814,7 +4466,7 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData + using BuildType = ValueT; + using FloatType = typename FloatTraits::FloatType; + using ArrayType = ValueT;// type used for the internal mValue array +- static constexpr bool FIXED_SIZE = true; ++ static __constant__ constexpr bool FIXED_SIZE = true; + + CoordT mBBoxMin; // 12B. + uint8_t mBBoxDif[3]; // 3B. +@@ -3826,7 +4478,7 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData + FloatType mAverage; // typically 4B, average of all the active values in this node and its child nodes + FloatType mStdDevi; // typically 4B, standard deviation of all the active values in this node and its child nodes + alignas(32) ValueType mValues[1u << 3 * LOG2DIM]; +- ++ + /// @brief Return padding of this class in bytes, due to aliasing and 32B alignment + /// + /// @note The extra bytes are not necessarily at the end, but can come from aliasing of individual data members. +@@ -3838,32 +4490,35 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData + __hostdev__ static uint64_t memUsage() { return sizeof(LeafData); } + + //__hostdev__ const ValueType* values() const { return mValues; } +- __hostdev__ ValueType getValue(uint32_t i) const { return mValues[i]; } +- __hostdev__ void setValueOnly(uint32_t offset, const ValueType& value) { mValues[offset] = value; } +- __hostdev__ void setValue(uint32_t offset, const ValueType& value) ++ __hostdev__ ValueType getValue(uint32_t i) const __global__ { return mValues[i]; } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ ValueType getValue(uint32_t i) const __local__ { return mValues[i]; } ++#endif ++ __hostdev__ void setValueOnly(uint32_t offset, __global__ const ValueType& value) __global__ { mValues[offset] = value; } ++ __hostdev__ void setValue(uint32_t offset, __global__ const ValueType& value) __global__ + { + mValueMask.setOn(offset); + mValues[offset] = value; + } + +- __hostdev__ ValueType getMin() const { return mMinimum; } +- __hostdev__ ValueType getMax() const { return mMaximum; } +- __hostdev__ FloatType getAvg() const { return mAverage; } +- __hostdev__ FloatType getDev() const { return mStdDevi; } ++ __hostdev__ ValueType getMin() const __global__ { return mMinimum; } ++ __hostdev__ ValueType getMax() const __global__ { return mMaximum; } ++ __hostdev__ FloatType getAvg() const __global__ { return mAverage; } ++ __hostdev__ FloatType getDev() const __global__ { return mStdDevi; } + +- __hostdev__ void setMin(const ValueType& v) { mMinimum = v; } +- __hostdev__ void setMax(const ValueType& v) { mMaximum = v; } +- __hostdev__ void setAvg(const FloatType& v) { mAverage = v; } +- __hostdev__ void setDev(const FloatType& v) { mStdDevi = v; } ++ __hostdev__ void setMin(__global__ const ValueType& v) __global__ { mMinimum = v; } ++ __hostdev__ void setMax(__global__ const ValueType& v) __global__ { mMaximum = v; } ++ __hostdev__ void setAvg(__global__ const FloatType& v) __global__ { mAverage = v; } ++ __hostdev__ void setDev(__global__ const FloatType& v) __global__ { mStdDevi = v; } + + template +- __hostdev__ void setOrigin(const T& ijk) { mBBoxMin = ijk; } ++ __hostdev__ void setOrigin(__global__ const T& ijk) __global__ { mBBoxMin = ijk; } + + /// @brief This class cannot be constructed or deleted +- LeafData() = delete; +- LeafData(const LeafData&) = delete; +- LeafData& operator=(const LeafData&) = delete; +- ~LeafData() = delete; ++ LeafData() __global__ = delete; ++ LeafData(__global__ const LeafData&) __global__ = delete; ++ __global__ LeafData& operator=(__global__ const LeafData&) __global__ = delete; ++ ~LeafData() __global__ = delete; + }; // LeafData + + /// @brief Base-class for quantized float leaf nodes +@@ -3892,39 +4547,39 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafFnBase + __hostdev__ static constexpr uint32_t padding() { + return sizeof(LeafFnBase) - (12 + 3 + 1 + sizeof(MaskT) + 2*4 + 4*2); + } +- __hostdev__ void init(float min, float max, uint8_t bitWidth) ++ __hostdev__ void init(float min, float max, uint8_t bitWidth) __global__ + { + mMinimum = min; + mQuantum = (max - min)/float((1 << bitWidth)-1); + } + + /// @brief return the quantized minimum of the active values in this node +- __hostdev__ float getMin() const { return mMin*mQuantum + mMinimum; } ++ __hostdev__ float getMin() const __global__ { return mMin*mQuantum + mMinimum; } + + /// @brief return the quantized maximum of the active values in this node +- __hostdev__ float getMax() const { return mMax*mQuantum + mMinimum; } ++ __hostdev__ float getMax() const __global__ { return mMax*mQuantum + mMinimum; } + + /// @brief return the quantized average of the active values in this node +- __hostdev__ float getAvg() const { return mAvg*mQuantum + mMinimum; } ++ __hostdev__ float getAvg() const __global__ { return mAvg*mQuantum + mMinimum; } + /// @brief return the quantized standard deviation of the active values in this node + + /// @note 0 <= StdDev <= max-min or 0 <= StdDev/(max-min) <= 1 +- __hostdev__ float getDev() const { return mDev*mQuantum; } ++ __hostdev__ float getDev() const __global__ { return mDev*mQuantum; } + + /// @note min <= X <= max or 0 <= (X-min)/(min-max) <= 1 +- __hostdev__ void setMin(float min) { mMin = uint16_t((min - mMinimum)/mQuantum + 0.5f); } ++ __hostdev__ void setMin(float min) __global__ { mMin = uint16_t((min - mMinimum)/mQuantum + 0.5f); } + + /// @note min <= X <= max or 0 <= (X-min)/(min-max) <= 1 +- __hostdev__ void setMax(float max) { mMax = uint16_t((max - mMinimum)/mQuantum + 0.5f); } ++ __hostdev__ void setMax(float max) __global__ { mMax = uint16_t((max - mMinimum)/mQuantum + 0.5f); } + + /// @note min <= avg <= max or 0 <= (avg-min)/(min-max) <= 1 +- __hostdev__ void setAvg(float avg) { mAvg = uint16_t((avg - mMinimum)/mQuantum + 0.5f); } ++ __hostdev__ void setAvg(float avg) __global__ { mAvg = uint16_t((avg - mMinimum)/mQuantum + 0.5f); } + + /// @note 0 <= StdDev <= max-min or 0 <= StdDev/(max-min) <= 1 +- __hostdev__ void setDev(float dev) { mDev = uint16_t(dev/mQuantum + 0.5f); } ++ __hostdev__ void setDev(float dev) __global__ { mDev = uint16_t(dev/mQuantum + 0.5f); } + + template +- __hostdev__ void setOrigin(const T& ijk) { mBBoxMin = ijk; } ++ __hostdev__ void setOrigin(__global__ const T& ijk) __global__ { mBBoxMin = ijk; } + };// LeafFnBase + + /// @brief Stuct with all the member data of the LeafNode (useful during serialization of an openvdb LeafNode) +@@ -3932,12 +4587,24 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafFnBase + /// @note No client code should (or can) interface with this struct so it can safely be ignored! + template class MaskT, uint32_t LOG2DIM> + struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData ++#if !defined(__KERNEL_METAL__) + : public LeafFnBase ++#endif + { ++#if defined(__KERNEL_METAL__) ++ LeafFnBase _base; ++#define BASE(v) _base.v ++#else ++#define BASE(v) BaseT::v ++#endif + using BaseT = LeafFnBase; + using BuildType = Fp4; + using ArrayType = uint8_t;// type used for the internal mValue array +- static constexpr bool FIXED_SIZE = true; ++#if defined(__KERNEL_METAL__) ++ using ValueType = typename BaseT::ValueType; ++ using FloatType = typename BaseT::FloatType; ++#endif ++ static __constant__ constexpr bool FIXED_SIZE = true; + alignas(32) uint8_t mCode[1u << (3 * LOG2DIM - 1)];// LeafFnBase is 32B aligned and so is mCode + + __hostdev__ static constexpr uint64_t memUsage() { return sizeof(LeafData); } +@@ -3947,31 +4614,53 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData>1]; + return ( (i&1) ? c >> 4 : c & uint8_t(15) )*BaseT::mQuantum + BaseT::mMinimum; + #else +- return ((mCode[i>>1] >> ((i&1)<<2)) & uint8_t(15))*BaseT::mQuantum + BaseT::mMinimum; ++ return ((mCode[i>>1] >> ((i&1)<<2)) & uint8_t(15))*BASE(mQuantum) + BASE(mMinimum); + #endif + } ++#endif ++#if defined(__KERNEL_METAL__) ++__hostdev__ float getValue(uint32_t i) const __local__ ++ { ++#if 0 ++ const uint8_t c = mCode[i>>1]; ++ return ( (i&1) ? c >> 4 : c & uint8_t(15) )*BaseT::mQuantum + BaseT::mMinimum; ++#else ++ return ((mCode[i>>1] >> ((i&1)<<2)) & uint8_t(15))*BASE(mQuantum) + BASE(mMinimum); ++#endif ++ } ++#endif + + /// @brief This class cannot be constructed or deleted +- LeafData() = delete; +- LeafData(const LeafData&) = delete; +- LeafData& operator=(const LeafData&) = delete; +- ~LeafData() = delete; ++ LeafData() __global__ = delete; ++ LeafData(__global__ const LeafData&) __global__ = delete; ++ __global__ LeafData& operator=(__global__ const LeafData&) __global__ = delete; ++ ~LeafData() __global__ = delete; ++#undef BASE + }; // LeafData + + template class MaskT, uint32_t LOG2DIM> + struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData ++#if !defined(__KERNEL_METAL__) + : public LeafFnBase ++#endif + { ++#if defined(__KERNEL_METAL__) ++ LeafFnBase _base; ++#define BASE(v) _base.v ++#else ++#define BASE(v) BaseT::v ++#endif + using BaseT = LeafFnBase; + using BuildType = Fp8; + using ArrayType = uint8_t;// type used for the internal mValue array +- static constexpr bool FIXED_SIZE = true; ++ static __constant__ constexpr bool FIXED_SIZE = true; + alignas(32) uint8_t mCode[1u << 3 * LOG2DIM]; + __hostdev__ static constexpr int64_t memUsage() { return sizeof(LeafData); } + __hostdev__ static constexpr uint32_t padding() { +@@ -3980,25 +4669,44 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData + + template class MaskT, uint32_t LOG2DIM> + struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData ++#if !defined(__KERNEL_METAL__) + : public LeafFnBase ++#endif + { ++#if defined(__KERNEL_METAL__) ++ LeafFnBase _base; ++#define BASE(v) _base.v ++#else ++#define BASE(v) BaseT::v ++#endif + using BaseT = LeafFnBase; + using BuildType = Fp16; + using ArrayType = uint16_t;// type used for the internal mValue array +- static constexpr bool FIXED_SIZE = true; ++#if defined(__KERNEL_METAL__) ++ using ValueType = typename BaseT::ValueType; ++ using FloatType = typename BaseT::FloatType; ++#endif ++ static __constant__ constexpr bool FIXED_SIZE = true; + alignas(32) uint16_t mCode[1u << 3 * LOG2DIM]; + + __hostdev__ static constexpr uint64_t memUsage() { return sizeof(LeafData); } +@@ -4008,35 +4716,93 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData + + template class MaskT, uint32_t LOG2DIM> + struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData ++#if !defined(__KERNEL_METAL__) + : public LeafFnBase ++#endif + {// this class has no data members, however every instance is immediately followed + // bitWidth*64 bytes. Since its base class is 32B aligned so are the bitWidth*64 bytes ++#if defined(__KERNEL_METAL__) ++ LeafFnBase _base; ++#define BASE(v) _base.v ++#else ++#define BASE(v) BaseT::v ++#endif + using BaseT = LeafFnBase; + using BuildType = FpN; +- static constexpr bool FIXED_SIZE = false; ++ static __constant__ constexpr bool FIXED_SIZE = false; ++#if defined(__KERNEL_METAL__) ++ using ValueType = typename BaseT::ValueType; ++ using FloatType = typename BaseT::FloatType; ++#endif + __hostdev__ static constexpr uint32_t padding() { + static_assert(BaseT::padding()==0, "expected no padding in LeafFnBase"); + return 0; + } + +- __hostdev__ uint8_t bitWidth() const { return 1 << (BaseT::mFlags >> 5); }// 4,8,16,32 = 2^(2,3,4,5) +- __hostdev__ size_t memUsage() const { return sizeof(*this) + this->bitWidth()*64; } ++ __hostdev__ uint8_t bitWidth() const __global__ { return 1 << (BaseT::mFlags >> 5); }// 4,8,16,32 = 2^(2,3,4,5) ++ __hostdev__ size_t memUsage() const __global__ { return sizeof(*this) + this->bitWidth()*64; } + __hostdev__ static size_t memUsage(uint32_t bitWidth) { return 96u + bitWidth*64; } +- __hostdev__ float getValue(uint32_t i) const ++ __hostdev__ float getValue(uint32_t i) const __global__ ++ { ++#ifdef NANOVDB_FPN_BRANCHLESS// faster ++ const int b = BASE(mFlags) >> 5;// b = 0, 1, 2, 3, 4 corresponding to 1, 2, 4, 8, 16 bits ++#if 0// use LUT ++ uint16_t code = reinterpret_cast(this + 1)[i >> (4 - b)]; ++ const static uint8_t shift[5] = {15, 7, 3, 1, 0}; ++ const static uint16_t mask[5] = {1, 3, 15, 255, 65535}; ++ code >>= (i & shift[b]) << b; ++ code &= mask[b]; ++#else// no LUT ++ uint32_t code = reinterpret_cast<__global__ const uint32_t*>(this + 1)[i >> (5 - b)]; ++ //code >>= (i & ((16 >> b) - 1)) << b; ++ code >>= (i & ((32 >> b) - 1)) << b; ++ code &= (1 << (1 << b)) - 1; ++#endif ++#else// use branched version (slow) ++ float code; ++ __global__ auto *values = reinterpret_cast(this+1); ++ switch (BaseT::mFlags >> 5) { ++ case 0u:// 1 bit float ++ code = float((values[i>>3] >> (i&7) ) & uint8_t(1)); ++ break; ++ case 1u:// 2 bits float ++ code = float((values[i>>2] >> ((i&3)<<1)) & uint8_t(3)); ++ break; ++ case 2u:// 4 bits float ++ code = float((values[i>>1] >> ((i&1)<<2)) & uint8_t(15)); ++ break; ++ case 3u:// 8 bits float ++ code = float(values[i]); ++ break; ++ default:// 16 bits float ++ code = float(reinterpret_cast(values)[i]); ++ } ++#endif ++ return float(code) * BASE(mQuantum) + BASE(mMinimum);// code * (max-min)/UNITS + min ++ } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ float getValue(uint32_t i) const __local__ + { + #ifdef NANOVDB_FPN_BRANCHLESS// faster + const int b = BaseT::mFlags >> 5;// b = 0, 1, 2, 3, 4 corresponding to 1, 2, 4, 8, 16 bits +@@ -4047,14 +4813,14 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData>= (i & shift[b]) << b; + code &= mask[b]; + #else// no LUT +- uint32_t code = reinterpret_cast(this + 1)[i >> (5 - b)]; ++ uint32_t code = reinterpret_cast<__global__ const uint32_t*>(this + 1)[i >> (5 - b)]; + //code >>= (i & ((16 >> b) - 1)) << b; + code >>= (i & ((32 >> b) - 1)) << b; + code &= (1 << (1 << b)) - 1; + #endif + #else// use branched version (slow) + float code; +- auto *values = reinterpret_cast(this+1); ++ __global__ auto *values = reinterpret_cast(this+1); + switch (BaseT::mFlags >> 5) { + case 0u:// 1 bit float + code = float((values[i>>3] >> (i&7) ) & uint8_t(1)); +@@ -4074,12 +4840,15 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData + + // Partial template specialization of LeafData with bool +@@ -4092,7 +4861,7 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData;// type used for the internal mValue array +- static constexpr bool FIXED_SIZE = true; ++ static __constant__ constexpr bool FIXED_SIZE = true; + + CoordT mBBoxMin; // 12B. + uint8_t mBBoxDif[3]; // 3B. +@@ -4104,31 +4873,34 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData) - 16u;} + __hostdev__ static uint64_t memUsage() { return sizeof(LeafData); } + +- //__hostdev__ const ValueType* values() const { return nullptr; } +- __hostdev__ bool getValue(uint32_t i) const { return mValues.isOn(i); } +- __hostdev__ bool getMin() const { return false; }// dummy +- __hostdev__ bool getMax() const { return false; }// dummy +- __hostdev__ bool getAvg() const { return false; }// dummy +- __hostdev__ bool getDev() const { return false; }// dummy +- __hostdev__ void setValue(uint32_t offset, bool v) ++ //__hostdev__ __global__ const ValueType* values() const __global__ { return nullptr; } ++ __hostdev__ bool getValue(uint32_t i) const __global__ { return mValues.isOn(i); } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ bool getValue(uint32_t i) const __local__ { return mValues.isOn(i); } ++#endif ++ __hostdev__ bool getMin() const __global__ { return false; }// dummy ++ __hostdev__ bool getMax() const __global__ { return false; }// dummy ++ __hostdev__ bool getAvg() const __global__ { return false; }// dummy ++ __hostdev__ bool getDev() const __global__ { return false; }// dummy ++ __hostdev__ void setValue(uint32_t offset, bool v) __global__ + { + mValueMask.setOn(offset); + mValues.set(offset, v); + } + +- __hostdev__ void setMin(const bool&) {}// no-op +- __hostdev__ void setMax(const bool&) {}// no-op +- __hostdev__ void setAvg(const bool&) {}// no-op +- __hostdev__ void setDev(const bool&) {}// no-op ++ __hostdev__ void setMin(__global__ const bool&) __global__ {}// no-op ++ __hostdev__ void setMax(__global__ const bool&) __global__ {}// no-op ++ __hostdev__ void setAvg(__global__ const bool&) __global__ {}// no-op ++ __hostdev__ void setDev(__global__ const bool&) __global__ {}// no-op + + template +- __hostdev__ void setOrigin(const T& ijk) { mBBoxMin = ijk; } ++ __hostdev__ void setOrigin(__global__ const T& ijk) __global__ { mBBoxMin = ijk; } + + /// @brief This class cannot be constructed or deleted +- LeafData() = delete; +- LeafData(const LeafData&) = delete; +- LeafData& operator=(const LeafData&) = delete; +- ~LeafData() = delete; ++ LeafData() __global__ = delete; ++ LeafData(__global__ const LeafData&) __global__ = delete; ++ __global__ LeafData& operator=(__global__ const LeafData&) __global__ = delete; ++ ~LeafData() __global__ = delete; + }; // LeafData + + // Partial template specialization of LeafData with ValueMask +@@ -4141,7 +4913,7 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData +- __hostdev__ void setOrigin(const T& ijk) { mBBoxMin = ijk; } ++ __hostdev__ void setOrigin(__global__ const T& ijk) __global__ { mBBoxMin = ijk; } + + /// @brief This class cannot be constructed or deleted +- LeafData() = delete; +- LeafData(const LeafData&) = delete; +- LeafData& operator=(const LeafData&) = delete; +- ~LeafData() = delete; ++ LeafData() __global__ = delete; ++ LeafData(__global__ const LeafData&) __global__ = delete; ++ __global__ LeafData& operator=(__global__ const LeafData&) __global__ = delete; ++ ~LeafData() __global__ = delete; + }; // LeafData + + // Partial template specialization of LeafData with ValueIndex +@@ -4191,7 +4966,7 @@ struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData +- __hostdev__ void setMin(const T &min, T *p) { NANOVDB_ASSERT(mStatsOff); p[mStatsOff + 0] = min; } ++ __hostdev__ void setMin(__global__ const T &min, __global__ T *p) __global__ { NANOVDB_ASSERT(mStatsOff); p[mStatsOff + 0] = min; } + template +- __hostdev__ void setMax(const T &max, T *p) { NANOVDB_ASSERT(mStatsOff); p[mStatsOff + 1] = max; } ++ __hostdev__ void setMax(__global__ const T &max, __global__ T *p) __global__ { NANOVDB_ASSERT(mStatsOff); p[mStatsOff + 1] = max; } + template +- __hostdev__ void setAvg(const T &avg, T *p) { NANOVDB_ASSERT(mStatsOff); p[mStatsOff + 2] = avg; } ++ __hostdev__ void setAvg(__global__ const T &avg, __global__ T *p) __global__ { NANOVDB_ASSERT(mStatsOff); p[mStatsOff + 2] = avg; } + template +- __hostdev__ void setDev(const T &dev, T *p) { NANOVDB_ASSERT(mStatsOff); p[mStatsOff + 3] = dev; } ++ __hostdev__ void setDev(__global__ const T &dev, __global__ T *p) __global__ { NANOVDB_ASSERT(mStatsOff); p[mStatsOff + 3] = dev; } + template +- __hostdev__ void setOrigin(const T &ijk) { mBBoxMin = ijk; } ++ __hostdev__ void setOrigin(__global__ const T &ijk) __global__ { mBBoxMin = ijk; } + + /// @brief This class cannot be constructed or deleted +- LeafData() = delete; +- LeafData(const LeafData&) = delete; +- LeafData& operator=(const LeafData&) = delete; +- ~LeafData() = delete; ++ LeafData() __global__ = delete; ++ LeafData(__global__ const LeafData&) __global__ = delete; ++ __global__ LeafData& operator=(__global__ const LeafData&) __global__ = delete; ++ ~LeafData() __global__ = delete; + }; // LeafData + + /// @brief Leaf nodes of the VDB tree. (defaults to 8x8x8 = 512 voxels) +@@ -4248,13 +5031,22 @@ template class MaskT = Mask, + uint32_t Log2Dim = 3> +-class LeafNode : private LeafData ++class LeafNode ++#if !defined(__KERNEL_METAL__) ++ : private LeafData ++#endif + { ++#if defined(__KERNEL_METAL__) ++ LeafData _base; ++#define BASE(v) _base.v ++#else ++#define BASE(v) DataType::v ++#endif + public: + struct ChildNodeType + { +- static constexpr uint32_t TOTAL = 0; +- static constexpr uint32_t DIM = 1; ++ static __constant__ constexpr uint32_t TOTAL = 0; ++ static __constant__ constexpr uint32_t DIM = 1; + __hostdev__ static uint32_t dim() { return 1u; } + }; // Voxel + using LeafNodeType = LeafNode; +@@ -4263,38 +5055,56 @@ public: + using FloatType = typename DataType::FloatType; + using BuildType = typename DataType::BuildType; + using CoordType = CoordT; +- static constexpr bool FIXED_SIZE = DataType::FIXED_SIZE; ++ static __constant__ constexpr bool FIXED_SIZE = DataType::FIXED_SIZE; + template + using MaskType = MaskT; + template + using MaskIterT = typename Mask::template Iterator; + + /// @brief Visits all active values in a leaf node +- class ValueOnIterator : public MaskIterT ++ class ValueOnIterator ++#if !defined (__KERNEL_METAL__) ++ : public MaskIterT ++#endif + { ++#if defined(__KERNEL_METAL__) ++ MaskIterT BaseT; ++#define BASE(v) BaseT.v ++#else + using BaseT = MaskIterT; +- const LeafNode *mParent; ++#define BASE(v) BaseT::v ++#endif ++ __global__ const LeafNode *mParent; + public: + __hostdev__ ValueOnIterator() : BaseT(), mParent(nullptr) {} +- __hostdev__ ValueOnIterator(const LeafNode* parent) : BaseT(parent->data()->mValueMask.beginOn()), mParent(parent) {} +- ValueOnIterator& operator=(const ValueOnIterator&) = default; +- __hostdev__ ValueType operator*() const {NANOVDB_ASSERT(*this); return mParent->getValue(BaseT::pos());} +- __hostdev__ CoordT getCoord() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(BaseT::pos());} ++ __hostdev__ ValueOnIterator(__global__ const LeafNode* parent) : BaseT(parent->data()->mValueMask.beginOn()), mParent(parent) {} ++ __global__ ValueOnIterator& operator=(__global__ const ValueOnIterator&) = default; ++ __hostdev__ ValueType operator*() const {NANOVDB_ASSERT(*this); return mParent->getValue(BASE(pos)());} ++ __hostdev__ CoordT getCoord() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(BASE(pos)());} + }; // Member class ValueOnIterator + + ValueOnIterator beginValueOn() const {return ValueOnIterator(this);} + + /// @brief Visits all inactive values in a leaf node +- class ValueOffIterator : public MaskIterT ++ class ValueOffIterator ++#if !defined (__KERNEL_METAL__) ++ : public MaskIterT ++#endif + { ++#if defined(__KERNEL_METAL__) ++ MaskIterT BaseT; ++#define BASE(v) BaseT.v ++#else + using BaseT = MaskIterT; +- const LeafNode *mParent; ++#define BASE(v) BaseT::v ++#endif ++ __global__ const LeafNode *mParent; + public: + __hostdev__ ValueOffIterator() : BaseT(), mParent(nullptr) {} +- __hostdev__ ValueOffIterator(const LeafNode* parent) : BaseT(parent->data()->mValueMask.beginOff()), mParent(parent) {} +- ValueOffIterator& operator=(const ValueOffIterator&) = default; +- __hostdev__ ValueType operator*() const {NANOVDB_ASSERT(*this); return mParent->getValue(BaseT::pos());} +- __hostdev__ CoordT getCoord() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(BaseT::pos());} ++ __hostdev__ ValueOffIterator(__global__ const LeafNode* parent) : BaseT(parent->data()->mValueMask.beginOff()), mParent(parent) {} ++ __global__ ValueOffIterator& operator=(__global__ const ValueOffIterator&) = default; ++ __hostdev__ ValueType operator*() const {NANOVDB_ASSERT(*this); return mParent->getValue(BASE(pos)());} ++ __hostdev__ CoordT getCoord() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(BASE(pos)());} + }; // Member class ValueOffIterator + + ValueOffIterator beginValueOff() const {return ValueOffIterator(this);} +@@ -4302,17 +5112,17 @@ public: + /// @brief Visits all values in a leaf node, i.e. both active and inactive values + class ValueIterator + { +- const LeafNode *mParent; ++ __global__ const LeafNode *mParent; + uint32_t mPos; + public: + __hostdev__ ValueIterator() : mParent(nullptr), mPos(1u << 3 * Log2Dim) {} +- __hostdev__ ValueIterator(const LeafNode* parent) : mParent(parent), mPos(0) {NANOVDB_ASSERT(parent);} +- ValueIterator& operator=(const ValueIterator&) = default; ++ __hostdev__ ValueIterator(__global__ const LeafNode* parent) : mParent(parent), mPos(0) {NANOVDB_ASSERT(parent);} ++ __global__ ValueIterator& operator=(__global__ const ValueIterator&) = default; + __hostdev__ ValueType operator*() const { NANOVDB_ASSERT(*this); return mParent->getValue(mPos);} + __hostdev__ CoordT getCoord() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(mPos);} + __hostdev__ bool isActive() const { NANOVDB_ASSERT(*this); return mParent->isActive(mPos);} + __hostdev__ operator bool() const {return mPos < (1u << 3 * Log2Dim);} +- __hostdev__ ValueIterator& operator++() {++mPos; return *this;} ++ __hostdev__ __global__ ValueIterator& operator++() {++mPos; return *this;} + __hostdev__ ValueIterator operator++(int) { + auto tmp = *this; + ++(*this); +@@ -4320,43 +5130,49 @@ public: + } + }; // Member class ValueIterator + ++#if defined(__KERNEL_METAL__) ++#define BASE(v) _base.v ++#else ++#define BASE(v) DataType::v ++#endif ++ + ValueIterator beginValue() const {return ValueIterator(this);} + + static_assert(is_same::Type>::value, "Mismatching BuildType"); +- static constexpr uint32_t LOG2DIM = Log2Dim; +- static constexpr uint32_t TOTAL = LOG2DIM; // needed by parent nodes +- static constexpr uint32_t DIM = 1u << TOTAL; // number of voxels along each axis of this node +- static constexpr uint32_t SIZE = 1u << 3 * LOG2DIM; // total number of voxels represented by this node +- static constexpr uint32_t MASK = (1u << LOG2DIM) - 1u; // mask for bit operations +- static constexpr uint32_t LEVEL = 0; // level 0 = leaf +- static constexpr uint64_t NUM_VALUES = uint64_t(1) << (3 * TOTAL); // total voxel count represented by this node ++ static __constant__ constexpr uint32_t LOG2DIM = Log2Dim; ++ static __constant__ constexpr uint32_t TOTAL = LOG2DIM; // needed by parent nodes ++ static __constant__ constexpr uint32_t DIM = 1u << TOTAL; // number of voxels along each axis of this node ++ static __constant__ constexpr uint32_t SIZE = 1u << 3 * LOG2DIM; // total number of voxels represented by this node ++ static __constant__ constexpr uint32_t MASK = (1u << LOG2DIM) - 1u; // mask for bit operations ++ static __constant__ constexpr uint32_t LEVEL = 0; // level 0 = leaf ++ static __constant__ constexpr uint64_t NUM_VALUES = uint64_t(1) << (3 * TOTAL); // total voxel count represented by this node + +- __hostdev__ DataType* data() { return reinterpret_cast(this); } ++ __hostdev__ __global__ DataType* data() __global__ { return reinterpret_cast<__global__ DataType*>(this); } + +- __hostdev__ const DataType* data() const { return reinterpret_cast(this); } ++ __hostdev__ __global__ const DataType* data() __global__ const { return reinterpret_cast<__global__ const DataType*>(this); } + + /// @brief Return a const reference to the bit mask of active voxels in this leaf node +- __hostdev__ const MaskType& valueMask() const { return DataType::mValueMask; } ++ __hostdev__ __global__ const MaskType& valueMask() const __global__ { return DataType::mValueMask; } + + /// @brief Return a const reference to the minimum active value encoded in this leaf node +- __hostdev__ ValueType minimum() const { return this->getMin(); } ++ __hostdev__ ValueType minimum() const __global__ { return this->getMin(); } + + /// @brief Return a const reference to the maximum active value encoded in this leaf node +- __hostdev__ ValueType maximum() const { return this->getMax(); } ++ __hostdev__ ValueType maximum() const __global__ { return this->getMax(); } + + /// @brief Return a const reference to the average of all the active values encoded in this leaf node +- __hostdev__ FloatType average() const { return DataType::getAvg(); } ++ __hostdev__ FloatType average() const __global__ { return DataType::getAvg(); } + + /// @brief Return the variance of all the active values encoded in this leaf node +- __hostdev__ FloatType variance() const { return DataType::getDev()*DataType::getDev(); } ++ __hostdev__ FloatType variance() const __global__ { return DataType::getDev()*DataType::getDev(); } + + /// @brief Return a const reference to the standard deviation of all the active values encoded in this leaf node +- __hostdev__ FloatType stdDeviation() const { return DataType::getDev(); } ++ __hostdev__ FloatType stdDeviation() const __global__ { return DataType::getDev(); } + +- __hostdev__ uint8_t flags() const { return DataType::mFlags; } ++ __hostdev__ uint8_t flags() const __global__ { return DataType::mFlags; } + + /// @brief Return the origin in index space of this leaf node +- __hostdev__ CoordT origin() const { return DataType::mBBoxMin & ~MASK; } ++ __hostdev__ CoordT origin() const __global__ { return DataType::mBBoxMin & ~MASK; } + + __hostdev__ static CoordT OffsetToLocalCoord(uint32_t n) + { +@@ -4366,9 +5182,9 @@ public: + } + + /// @brief Converts (in place) a local index coordinate to a global index coordinate +- __hostdev__ void localToGlobalCoord(Coord& ijk) const { ijk += this->origin(); } ++ __hostdev__ void localToGlobalCoord(__global__ Coord& ijk) const __global__ { ijk += this->origin(); } + +- __hostdev__ CoordT offsetToGlobalCoord(uint32_t n) const ++ __hostdev__ CoordT offsetToGlobalCoord(uint32_t n) const __global__ + { + return OffsetToLocalCoord(n) + this->origin(); + } +@@ -4377,7 +5193,7 @@ public: + __hostdev__ static uint32_t dim() { return 1u << LOG2DIM; } + + /// @brief Return the bounding box in index space of active values in this leaf node +- __hostdev__ BBox bbox() const ++ __hostdev__ BBox bbox() const __global__ + { + BBox bbox(DataType::mBBoxMin, DataType::mBBoxMin); + if ( this->hasBBox() ) { +@@ -4399,54 +5215,85 @@ public: + __hostdev__ uint64_t memUsage() { return DataType::memUsage(); } + + /// @brief This class cannot be constructed or deleted +- LeafNode() = delete; +- LeafNode(const LeafNode&) = delete; +- LeafNode& operator=(const LeafNode&) = delete; +- ~LeafNode() = delete; ++ LeafNode() __global__ = delete; ++ LeafNode(__global__ const LeafNode&) __global__ = delete; ++ __global__ LeafNode& operator=(__global__ const LeafNode&) __global__ = delete; ++ ~LeafNode() __global__ = delete; + + /// @brief Return the voxel value at the given offset. +- __hostdev__ ValueType getValue(uint32_t offset) const { return DataType::getValue(offset); } ++ ++ __hostdev__ ValueType getValue(uint32_t offset) const __global__ { return DataType::getValue(offset); } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ ValueType getValue(uint32_t offset) const __local__ { return DataType::getValue(offset); } ++#endif + + /// @brief Return the voxel value at the given coordinate. +- __hostdev__ ValueType getValue(const CoordT& ijk) const { return DataType::getValue(CoordToOffset(ijk)); } ++ __hostdev__ ValueType getValue(__global__ const CoordT& ijk) const __global__ { return BASE(getValue)(CoordToOffset(ijk)); } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ ValueType getValue(__local__ const CoordT& ijk) const __global__ { return BASE(getValue)(CoordToOffset(ijk)); } ++ __hostdev__ ValueType getValue(__local__ const CoordT& ijk) const __local__ { return BASE(getValue)(CoordToOffset(ijk)); } ++#endif + + /// @brief Sets the value at the specified location and activate its state. + /// + /// @note This is safe since it does not change the topology of the tree (unlike setValue methods on the other nodes) +- __hostdev__ void setValue(const CoordT& ijk, const ValueType& v) { DataType::setValue(CoordToOffset(ijk), v); } ++ __hostdev__ void setValue(__global__ const CoordT& ijk, __global__ const ValueType& v) __global__ { DataType::setValue(CoordToOffset(ijk), v); } + + /// @brief Sets the value at the specified location but leaves its state unchanged. + /// + /// @note This is safe since it does not change the topology of the tree (unlike setValue methods on the other nodes) +- __hostdev__ void setValueOnly(uint32_t offset, const ValueType& v) { DataType::setValueOnly(offset, v); } +- __hostdev__ void setValueOnly(const CoordT& ijk, const ValueType& v) { DataType::setValueOnly(CoordToOffset(ijk), v); } ++ __hostdev__ void setValueOnly(uint32_t offset, __global__ const ValueType& v) __global__ { DataType::setValueOnly(offset, v); } ++ __hostdev__ void setValueOnly(__global__ const CoordT& ijk, __global__ const ValueType& v) __global__ { DataType::setValueOnly(CoordToOffset(ijk), v); } + + /// @brief Return @c true if the voxel value at the given coordinate is active. +- __hostdev__ bool isActive(const CoordT& ijk) const { return DataType::mValueMask.isOn(CoordToOffset(ijk)); } +- __hostdev__ bool isActive(uint32_t n) const { return DataType::mValueMask.isOn(n); } ++ __hostdev__ bool isActive(__global__ const CoordT& ijk) const __global__ { return BASE(mValueMask).isOn(CoordToOffset(ijk)); } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ bool isActive(__local__ const CoordT& ijk) const __global__ { return BASE(mValueMask).isOn(CoordToOffset(ijk)); } ++ __hostdev__ bool isActive(__local__ const CoordT& ijk) const __local__ { return BASE(mValueMask).isOn(CoordToOffset(ijk)); } ++#endif ++ ++ __hostdev__ bool isActive(uint32_t n) const __global__ { return BASE(mValueMask).isOn(n); } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ bool isActive(uint32_t n) const __local__ { return BASE(mValueMask).isOn(n); } ++#endif + + /// @brief Return @c true if any of the voxel value are active in this leaf node. +- __hostdev__ bool isActive() const ++ __hostdev__ bool isActive() const __global__ + { + //NANOVDB_ASSERT( bool(DataType::mFlags & uint8_t(2)) != DataType::mValueMask.isOff() ); + //return DataType::mFlags & uint8_t(2); + return !DataType::mValueMask.isOff(); + } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ bool isActive() const __local__ ++ { ++ NANOVDB_ASSERT( bool(DataType::mFlags & uint8_t(2)) != BASE(mValueMask).isOff() ); ++ return DataType::mFlags & uint8_t(2); ++ } ++#endif + + __hostdev__ bool hasBBox() const {return DataType::mFlags & uint8_t(2);} + + /// @brief Return @c true if the voxel value at the given coordinate is active and updates @c v with the value. +- __hostdev__ bool probeValue(const CoordT& ijk, ValueType& v) const ++ __hostdev__ bool probeValue(__global__ const CoordT& ijk, __global__ ValueType& v) const __global__ + { + const uint32_t n = CoordToOffset(ijk); + v = DataType::getValue(n); +- return DataType::mValueMask.isOn(n); ++ return BASE(mValueMask).isOn(n); + } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ bool probeValue(__local__ const CoordT& ijk, __local__ ValueType& v) const __global__ ++ { ++ const uint32_t n = CoordToOffset(ijk); ++ v = BASE(getValue)(n); ++ return BASE(mValueMask).isOn(n); ++ } ++#endif + +- __hostdev__ const LeafNode* probeLeaf(const CoordT&) const { return this; } ++ __hostdev__ __global__ const LeafNode* probeLeaf(__global__ const CoordT&) const __global__ { return this; } + + /// @brief Return the linear offset corresponding to the given coordinate +- __hostdev__ static uint32_t CoordToOffset(const CoordT& ijk) ++ __hostdev__ static uint32_t CoordToOffset(__global__ const CoordT& ijk) + { + #if 0 + return ((ijk[0] & MASK) << (2 * LOG2DIM)) + ((ijk[1] & MASK) << LOG2DIM) + (ijk[2] & MASK); +@@ -4454,6 +5301,16 @@ public: + return ((ijk[0] & MASK) << (2 * LOG2DIM)) | ((ijk[1] & MASK) << LOG2DIM) | (ijk[2] & MASK); + #endif + } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ static uint32_t CoordToOffset(__local__ const CoordT& ijk) ++ { ++ #if 0 ++ return ((ijk[0] & MASK) << (2 * LOG2DIM)) + ((ijk[1] & MASK) << LOG2DIM) + (ijk[2] & MASK); ++ #else ++ return ((ijk[0] & MASK) << (2 * LOG2DIM)) | ((ijk[1] & MASK) << LOG2DIM) | (ijk[2] & MASK); ++ #endif ++ } ++#endif + + /// @brief Updates the local bounding box of active voxels in this node. Return true if bbox was updated. + /// +@@ -4461,8 +5318,9 @@ public: + /// + /// @details This method is based on few (intrinsic) bit operations and hence is relatively fast. + /// However, it should only only be called of either the value mask has changed or if the ++ + /// active bounding box is still undefined. e.g. during construction of this node. +- __hostdev__ bool updateBBox(); ++ __hostdev__ bool updateBBox() __global__; + + private: + static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(LeafData) is misaligned"); +@@ -4478,49 +5336,77 @@ private: + + /// @brief Private method to return a voxel value and update a (dummy) ReadAccessor + template +- __hostdev__ ValueType getValueAndCache(const CoordT& ijk, const AccT&) const { return this->getValue(ijk); } ++ __hostdev__ ValueType getValueAndCache(__global__ const CoordT& ijk, __global__ const AccT&) const __global__ { return this->getValue(ijk); } ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ ValueType getValueAndCache(__local__ const CoordT& ijk, __local__ const AccT&) const __global__ { return this->getValue(ijk); } ++#endif + + /// @brief Return the node information. + template +- __hostdev__ typename AccT::NodeInfo getNodeInfoAndCache(const CoordType& /*ijk*/, const AccT& /*acc*/) const { ++ __hostdev__ typename AccT::NodeInfo getNodeInfoAndCache(__global__ const CoordType& /*ijk*/, __global__ const AccT& /*acc*/) const __global__ { + using NodeInfoT = typename AccT::NodeInfo; + return NodeInfoT{LEVEL, this->dim(), this->minimum(), this->maximum(), + this->average(), this->stdDeviation(), this->bbox()[0], this->bbox()[1]}; + } + + template +- __hostdev__ bool isActiveAndCache(const CoordT& ijk, const AccT&) const { return this->isActive(ijk); } ++ __hostdev__ bool isActiveAndCache(__global__ const CoordT& ijk, __global__ const AccT&) const __global__ { return this->isActive(ijk); } ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ bool isActiveAndCache(__local__ const CoordT& ijk, __local__ const AccT&) const __global__ { return this->isActive(ijk); } ++#endif + + template +- __hostdev__ bool probeValueAndCache(const CoordT& ijk, ValueType& v, const AccT&) const { return this->probeValue(ijk, v); } ++ __hostdev__ bool probeValueAndCache(__global__ const CoordT& ijk, __global__ ValueType& v, __global__ const AccT&) const __global__ { return this->probeValue(ijk, v); } + + template +- __hostdev__ const LeafNode* probeLeafAndCache(const CoordT&, const AccT&) const { return this; } ++ __hostdev__ __global__ const LeafNode* probeLeafAndCache(__global__ const CoordT&, __global__ const AccT&) const __global__ { return this; } + + template +- __hostdev__ uint32_t getDimAndCache(const CoordT&, const RayT& /*ray*/, const AccT&) const ++ __hostdev__ uint32_t getDimAndCache(__global__ const CoordT&, __global__ const RayT& /*ray*/, __global__ const AccT&) const __global__ + { + if (DataType::mFlags & uint8_t(1u)) return this->dim(); // skip this node if the 1st bit is set + + //if (!ray.intersects( this->bbox() )) return 1 << LOG2DIM; + return ChildNodeType::dim(); + } +- ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ uint32_t getDimAndCache(__local__ const CoordT&, __local__ const RayT& /*ray*/, __local__ const AccT&) const __global__ ++ { ++ if (BASE(mFlags) & uint8_t(1)) ++ return this->dim(); // skip this node if first bit is set ++ //if (!ray.intersects( this->bbox() )) return 1 << LOG2DIM; ++ return ChildNodeType::dim(); ++ } ++#endif ++#undef BASE + }; // LeafNode class + + template class MaskT, uint32_t LOG2DIM> +-__hostdev__ inline bool LeafNode::updateBBox() ++__hostdev__ inline bool LeafNode::updateBBox() __global__ + { + static_assert(LOG2DIM == 3, "LeafNode::updateBBox: only supports LOGDIM = 3!"); + if (DataType::mValueMask.isOff()) { + DataType::mFlags &= ~uint8_t(2);// set 2nd bit off, which indicates that this nodes has no bbox + return false; + } ++#if defined(__KERNEL_METAL__) ++ struct Update { ++ static void update(__global__ DataType &d, uint32_t min, uint32_t max, int axis) { ++ NANOVDB_ASSERT(min <= max && max < 8); ++ d.mBBoxMin[axis] = (d.mBBoxMin[axis] & ~MASK) + int(min); ++ d.mBBoxDif[axis] = uint8_t(max - min); ++ } ++ }; ++#else + auto update = [&](uint32_t min, uint32_t max, int axis) { + NANOVDB_ASSERT(min <= max && max < 8); + DataType::mBBoxMin[axis] = (DataType::mBBoxMin[axis] & ~MASK) + int(min); + DataType::mBBoxDif[axis] = uint8_t(max - min); + }; ++#endif + uint64_t word64 = DataType::mValueMask.template getWord(0); + uint32_t Xmin = word64 ? 0u : 8u; + uint32_t Xmax = Xmin; +@@ -4534,6 +5420,17 @@ __hostdev__ inline bool LeafNode::updateBBox() + } + } + NANOVDB_ASSERT(word64); ++#if defined(__KERNEL_METAL__) ++ Update::update(this, Xmin, Xmax, 0); ++ Update::update(this, FindLowestOn(word64) >> 3, FindHighestOn(word64) >> 3, 1); ++ __local__ const uint32_t *p = reinterpret_cast<__local__ const uint32_t*>(&word64), word32 = p[0] | p[1]; ++ __local__ const uint16_t *q = reinterpret_cast<__local__ const uint16_t*>(&word32), word16 = q[0] | q[1]; ++ __local__ const uint8_t *b = reinterpret_cast<__local__ const uint8_t* >(&word16), byte = b[0] | b[1]; ++ NANOVDB_ASSERT(byte); ++ Update::update(this, FindLowestOn(static_cast(byte)), FindHighestOn(static_cast(byte)), 2); ++ DataType::mFlags |= uint8_t(2);// set 2nd bit on, which indicates that this nodes has a bbox ++ return true; ++#else + update(Xmin, Xmax, 0); + update(FindLowestOn(word64) >> 3, FindHighestOn(word64) >> 3, 1); + const uint32_t *p = reinterpret_cast(&word64), word32 = p[0] | p[1]; +@@ -4541,8 +5438,9 @@ __hostdev__ inline bool LeafNode::updateBBox() + const uint8_t *b = reinterpret_cast(&word16), byte = b[0] | b[1]; + NANOVDB_ASSERT(byte); + update(FindLowestOn(static_cast(byte)), FindHighestOn(static_cast(byte)), 2); +- DataType::mFlags |= uint8_t(2);// set 2nd bit on, which indicates that this nodes has a bbox ++ DataType::mFlags |= uint8_t(2);// set 2nd bit on, which indicates that this nodes has a bbox + return true; ++#endif + } // LeafNode::updateBBox + + // --------------------------> Template specializations and traits <------------------------------------ +@@ -4651,12 +5549,12 @@ class ReadAccessor + using FloatType = typename RootT::FloatType; + using CoordValueType = typename RootT::CoordType::ValueType; + +- mutable const RootT* mRoot; // 8 bytes (mutable to allow for access methods to be const) ++ mutable __global__ const RootT* mRoot; // 8 bytes (mutable to allow for access methods to be const) + public: + using ValueType = typename RootT::ValueType; + using CoordType = typename RootT::CoordType; + +- static const int CacheLevels = 0; ++ static __constant__ const int CacheLevels = 0; + + struct NodeInfo { + uint32_t mLevel; // 4B +@@ -4670,60 +5568,77 @@ public: + }; + + /// @brief Constructor from a root node +- __hostdev__ ReadAccessor(const RootT& root) : mRoot{&root} {} ++ __hostdev__ ReadAccessor(__global__ const RootT& root) __local__ : mRoot{&root} {} + + /// @brief Constructor from a grid +- __hostdev__ ReadAccessor(const GridT& grid) : ReadAccessor(grid.tree().root()) {} ++ __hostdev__ ReadAccessor(__global__ const GridT& grid) __local__ : ReadAccessor(grid.tree().root()) {} + + /// @brief Constructor from a tree +- __hostdev__ ReadAccessor(const TreeT& tree) : ReadAccessor(tree.root()) {} ++ __hostdev__ ReadAccessor(__global__ const TreeT& tree) __local__ : ReadAccessor(tree.root()) {} + + /// @brief Reset this access to its initial state, i.e. with an empty cache + /// @node Noop since this template specialization has no cache + __hostdev__ void clear() {} + +- __hostdev__ const RootT& root() const { return *mRoot; } ++ __hostdev__ __global__ const RootT& root() const __global__ { return *mRoot; } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ __global__ const RootT& root() const __local__ { return *mRoot; } ++#endif + + /// @brief Defaults constructors +- ReadAccessor(const ReadAccessor&) = default; +- ~ReadAccessor() = default; +- ReadAccessor& operator=(const ReadAccessor&) = default; ++ ReadAccessor(__local__ const ReadAccessor&) __local__ = default; ++ ~ReadAccessor() __local__ = default; ++ __local__ ReadAccessor& operator=(__local__ const ReadAccessor&) __local__ = default; + +- __hostdev__ ValueType getValue(const CoordType& ijk) const ++ __hostdev__ ValueType getValue(__global__ const CoordType& ijk) const __local__ + { + return mRoot->getValueAndCache(ijk, *this); + } +- __hostdev__ ValueType operator()(const CoordType& ijk) const ++ ++#if defined(__KERNEL_METAL__) ++ __hostdev__ ValueType getValue(__local__ const CoordType& ijk) const __local__ ++ { ++ return mRoot->getValueAndCache(ijk, *this); ++ } ++#endif ++ ++ __hostdev__ ValueType operator()(__global__ const CoordType& ijk) const __local__ + { + return this->getValue(ijk); + } +- __hostdev__ ValueType operator()(int i, int j, int k) const ++ __hostdev__ ValueType operator()(int i, int j, int k) const __local__ + { + return this->getValue(CoordType(i,j,k)); + } + +- __hostdev__ NodeInfo getNodeInfo(const CoordType& ijk) const ++ __hostdev__ NodeInfo getNodeInfo(__global__ const CoordType& ijk) const __local__ + { + return mRoot->getNodeInfoAndCache(ijk, *this); + } + +- __hostdev__ bool isActive(const CoordType& ijk) const ++ __hostdev__ bool isActive(__global__ const CoordType& ijk) const __local__ + { + return mRoot->isActiveAndCache(ijk, *this); + } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ bool isActive(__local__ const CoordType& ijk) const __local__ ++ { ++ return mRoot->isActiveAndCache(ijk, *this); ++ } ++#endif + +- __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const ++ __hostdev__ bool probeValue(__global__ const CoordType& ijk, __global__ ValueType& v) const __local__ + { + return mRoot->probeValueAndCache(ijk, v, *this); + } + +- __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const ++ __hostdev__ __global__ const LeafT* probeLeaf(__global__ const CoordType& ijk) const __local__ + { + return mRoot->probeLeafAndCache(ijk, *this); + } + + template +- __hostdev__ uint32_t getDim(const CoordType& ijk, const RayT& ray) const ++ __hostdev__ uint32_t getDim(__global__ const CoordType& ijk, __global__ const RayT& ray) const __local__ + { + return mRoot->getDimAndCache(ijk, ray, *this); + } +@@ -4739,7 +5654,11 @@ private: + + /// @brief No-op + template +- __hostdev__ void insert(const CoordType&, const NodeT*) const {} ++ __hostdev__ void insert(__global__ const CoordType&, __global__ const NodeT*) const __local__ {} ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ void insert(__local__ const CoordType&, __global__ const NodeT*) const __local__ {} ++#endif + }; // ReadAccessor class + + /// @brief Node caching at a single tree level +@@ -4761,19 +5680,19 @@ class ReadAccessor//e.g. 0, 1, 2 + + // All member data are mutable to allow for access methods to be const + mutable CoordT mKey; // 3*4 = 12 bytes +- mutable const RootT* mRoot; // 8 bytes +- mutable const NodeT* mNode; // 8 bytes ++ mutable __global__ const RootT* mRoot; // 8 bytes ++ mutable __global__ const NodeT* mNode; // 8 bytes + + public: + using ValueType = ValueT; + using CoordType = CoordT; + +- static const int CacheLevels = 1; ++ static __constant__ const int CacheLevels = 1; + + using NodeInfo = typename ReadAccessor::NodeInfo; + + /// @brief Constructor from a root node +- __hostdev__ ReadAccessor(const RootT& root) ++ __hostdev__ ReadAccessor(__global__ const RootT& root) __local__ + : mKey(CoordType::max()) + , mRoot(&root) + , mNode(nullptr) +@@ -4781,10 +5700,10 @@ public: + } + + /// @brief Constructor from a grid +- __hostdev__ ReadAccessor(const GridT& grid) : ReadAccessor(grid.tree().root()) {} ++ __hostdev__ ReadAccessor(__global__ const GridT& grid) __local__ : ReadAccessor(grid.tree().root()) {} + + /// @brief Constructor from a tree +- __hostdev__ ReadAccessor(const TreeT& tree) : ReadAccessor(tree.root()) {} ++ __hostdev__ ReadAccessor(__global__ const TreeT& tree) __local__ : ReadAccessor(tree.root()) {} + + /// @brief Reset this access to its initial state, i.e. with an empty cache + __hostdev__ void clear() +@@ -4793,37 +5712,64 @@ public: + mNode = nullptr; + } + +- __hostdev__ const RootT& root() const { return *mRoot; } ++ __hostdev__ __global__ const RootT& root() const __global__ { return *mRoot; } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ __global__ const RootT& root() const __local__ { return *mRoot; } ++#endif + + /// @brief Defaults constructors +- ReadAccessor(const ReadAccessor&) = default; +- ~ReadAccessor() = default; +- ReadAccessor& operator=(const ReadAccessor&) = default; ++ ReadAccessor(__global__ const ReadAccessor&) __global__ = default; ++ ~ReadAccessor() __global__ = default; ++ __global__ ReadAccessor& operator=(__global__ const ReadAccessor&) __global__ = default; + +- __hostdev__ bool isCached(const CoordType& ijk) const ++ __hostdev__ bool isCached(__global__ const CoordType& ijk) const __global__ + { + return (ijk[0] & int32_t(~NodeT::MASK)) == mKey[0] && + (ijk[1] & int32_t(~NodeT::MASK)) == mKey[1] && + (ijk[2] & int32_t(~NodeT::MASK)) == mKey[2]; + } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ bool isCached(__local__ const CoordType& ijk) const __global__ ++ { ++ return (ijk[0] & int32_t(~NodeT::MASK)) == mKey[0] && ++ (ijk[1] & int32_t(~NodeT::MASK)) == mKey[1] && ++ (ijk[2] & int32_t(~NodeT::MASK)) == mKey[2]; ++ } ++ __hostdev__ bool isCached(__local__ const CoordType& ijk) const __local__ ++ { ++ return (ijk[0] & int32_t(~NodeT::MASK)) == mKey[0] && ++ (ijk[1] & int32_t(~NodeT::MASK)) == mKey[1] && ++ (ijk[2] & int32_t(~NodeT::MASK)) == mKey[2]; ++ } ++#endif + +- __hostdev__ ValueType getValue(const CoordType& ijk) const ++ __hostdev__ ValueType getValue(__global__ const CoordType& ijk) const __global__ + { + if (this->isCached(ijk)) { + return mNode->getValueAndCache(ijk, *this); + } + return mRoot->getValueAndCache(ijk, *this); + } +- __hostdev__ ValueType operator()(const CoordType& ijk) const ++#if defined(__KERNEL_METAL__) ++ __hostdev__ ValueType getValue(__local__ const CoordType& ijk) const __global__ ++ { ++ if (this->isCached(ijk)) { ++ return mNode->getValueAndCache(ijk, *this); ++ } ++ return mRoot->getValueAndCache(ijk, *this); ++ } ++#endif ++ ++ __hostdev__ ValueType operator()(__global__ const CoordType& ijk) const __global__ + { + return this->getValue(ijk); + } +- __hostdev__ ValueType operator()(int i, int j, int k) const ++ __hostdev__ ValueType operator()(int i, int j, int k) const __global__ + { + return this->getValue(CoordType(i,j,k)); + } + +- __hostdev__ NodeInfo getNodeInfo(const CoordType& ijk) const ++ __hostdev__ NodeInfo getNodeInfo(__global__ const CoordType& ijk) const __global__ + { + if (this->isCached(ijk)) { + return mNode->getNodeInfoAndCache(ijk, *this); +@@ -4831,15 +5777,24 @@ public: + return mRoot->getNodeInfoAndCache(ijk, *this); + } + +- __hostdev__ bool isActive(const CoordType& ijk) const ++ __hostdev__ bool isActive(__global__ const CoordType& ijk) const __global__ + { + if (this->isCached(ijk)) { + return mNode->isActiveAndCache(ijk, *this); + } + return mRoot->isActiveAndCache(ijk, *this); + } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ bool isActive(__global__ const CoordType& ijk) const __local__ ++ { ++ if (this->isCached(ijk)) { ++ return mNode->isActiveAndCache(ijk, *this); ++ } ++ return mRoot->isActiveAndCache(ijk, *this); ++ } ++#endif + +- __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const ++ __hostdev__ bool probeValue(__global__ const CoordType& ijk, __global__ ValueType& v) const __global__ + { + if (this->isCached(ijk)) { + return mNode->probeValueAndCache(ijk, v, *this); +@@ -4847,7 +5802,7 @@ public: + return mRoot->probeValueAndCache(ijk, v, *this); + } + +- __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const ++ __hostdev__ __global__ const LeafT* probeLeaf(__global__ const CoordType& ijk) const __global__ + { + if (this->isCached(ijk)) { + return mNode->probeLeafAndCache(ijk, *this); +@@ -4856,7 +5811,7 @@ public: + } + + template +- __hostdev__ uint32_t getDim(const CoordType& ijk, const RayT& ray) const ++ __hostdev__ uint32_t getDim(__global__ const CoordType& ijk, __global__ const RayT& ray) const __global__ + { + if (this->isCached(ijk)) { + return mNode->getDimAndCache(ijk, ray, *this); +@@ -4874,15 +5829,26 @@ private: + friend class LeafNode; + + /// @brief Inserts a leaf node and key pair into this ReadAccessor +- __hostdev__ void insert(const CoordType& ijk, const NodeT* node) const ++ __hostdev__ void insert(__global__ const CoordType& ijk, __global__ const NodeT* node) const __local__ + { + mKey = ijk & ~NodeT::MASK; + mNode = node; + } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ void insert(__local__ const CoordType& ijk, __global__ const NodeT* node) const __local__ ++ { ++ mKey = ijk & ~NodeT::MASK; ++ mNode = node; ++ } ++#endif + + // no-op + template +- __hostdev__ void insert(const CoordType&, const OtherNodeT*) const {} ++ __hostdev__ void insert(__global__ const CoordType&, __global__ const OtherNodeT*) const __local__ {} ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ void insert(__local__ const CoordType&, __global__ const OtherNodeT*) const __local__ {} ++#endif + + }; // ReadAccessor + +@@ -4909,20 +5875,20 @@ class ReadAccessor//e.g. (0,1), (1,2), (0,2) + #else // 68 bytes total + mutable CoordT mKeys[2]; // 2*3*4 = 24 bytes + #endif +- mutable const RootT* mRoot; +- mutable const Node1T* mNode1; +- mutable const Node2T* mNode2; ++ mutable __global__ const RootT* mRoot; ++ mutable __global__ const Node1T* mNode1; ++ mutable __global__ const Node2T* mNode2; + + public: + using ValueType = ValueT; + using CoordType = CoordT; + +- static const int CacheLevels = 2; ++ static __constant__ const int CacheLevels = 2; + + using NodeInfo = typename ReadAccessor::NodeInfo; + + /// @brief Constructor from a root node +- __hostdev__ ReadAccessor(const RootT& root) ++ __hostdev__ ReadAccessor(__global__ const RootT& root) __local__ + #ifdef USE_SINGLE_ACCESSOR_KEY + : mKey(CoordType::max()) + #else +@@ -4935,10 +5901,10 @@ public: + } + + /// @brief Constructor from a grid +- __hostdev__ ReadAccessor(const GridT& grid) : ReadAccessor(grid.tree().root()) {} ++ __hostdev__ ReadAccessor(__global__ const GridT& grid) __local__ : ReadAccessor(grid.tree().root()) {} + + /// @brief Constructor from a tree +- __hostdev__ ReadAccessor(const TreeT& tree) : ReadAccessor(tree.root()) {} ++ __hostdev__ ReadAccessor(__global__ const TreeT& tree) __local__ : ReadAccessor(tree.root()) {} + + /// @brief Reset this access to its initial state, i.e. with an empty cache + __hostdev__ void clear() +@@ -4952,15 +5918,18 @@ public: + mNode2 = nullptr; + } + +- __hostdev__ const RootT& root() const { return *mRoot; } ++ __hostdev__ __global__ const RootT& root() const __global__ { return *mRoot; } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ __global__ const RootT& root() const __local__ { return *mRoot; } ++#endif + + /// @brief Defaults constructors +- ReadAccessor(const ReadAccessor&) = default; ++ ReadAccessor(__global__ const ReadAccessor&) __global__ = default; + ~ReadAccessor() = default; +- ReadAccessor& operator=(const ReadAccessor&) = default; ++ __global__ ReadAccessor& operator=(__global__ const ReadAccessor&) __global__ = default; + + #ifdef USE_SINGLE_ACCESSOR_KEY +- __hostdev__ bool isCached1(CoordValueType dirty) const ++ __hostdev__ bool isCached1(CoordValueType dirty) const __global__ + { + if (!mNode1) + return false; +@@ -4970,7 +5939,7 @@ public: + } + return true; + } +- __hostdev__ bool isCached2(CoordValueType dirty) const ++ __hostdev__ bool isCached2(CoordValueType dirty) const __global__ + { + if (!mNode2) + return false; +@@ -4980,18 +5949,18 @@ public: + } + return true; + } +- __hostdev__ CoordValueType computeDirty(const CoordType& ijk) const ++ __hostdev__ CoordValueType computeDirty(__global__ const CoordType& ijk) const __global__ + { + return (ijk[0] ^ mKey[0]) | (ijk[1] ^ mKey[1]) | (ijk[2] ^ mKey[2]); + } + #else +- __hostdev__ bool isCached1(const CoordType& ijk) const ++ __hostdev__ bool isCached1(__global__ const CoordType& ijk) const __global__ + { + return (ijk[0] & int32_t(~Node1T::MASK)) == mKeys[0][0] && + (ijk[1] & int32_t(~Node1T::MASK)) == mKeys[0][1] && + (ijk[2] & int32_t(~Node1T::MASK)) == mKeys[0][2]; + } +- __hostdev__ bool isCached2(const CoordType& ijk) const ++ __hostdev__ bool isCached2(__global__ const CoordType& ijk) const __global__ + { + return (ijk[0] & int32_t(~Node2T::MASK)) == mKeys[1][0] && + (ijk[1] & int32_t(~Node2T::MASK)) == mKeys[1][1] && +@@ -4999,12 +5968,12 @@ public: + } + #endif + +- __hostdev__ ValueType getValue(const CoordType& ijk) const ++ __hostdev__ ValueType getValue(__global__ const CoordType& ijk) const __global__ + { + #ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); + #else +- auto&& dirty = ijk; ++ __global__ auto&& dirty = ijk; + #endif + if (this->isCached1(dirty)) { + return mNode1->getValueAndCache(ijk, *this); +@@ -5013,21 +5982,37 @@ public: + } + return mRoot->getValueAndCache(ijk, *this); + } +- __hostdev__ ValueType operator()(const CoordType& ijk) const +- { +- return this->getValue(ijk); +- } +- __hostdev__ ValueType operator()(int i, int j, int k) const +- { +- return this->getValue(CoordType(i,j,k)); +- } +- +- __hostdev__ NodeInfo getNodeInfo(const CoordType& ijk) const ++#if defined(__KERNEL_METAL__) ++ __hostdev__ ValueType getValue(__local__ const CoordType& ijk) const __global__ + { + #ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); + #else +- auto&& dirty = ijk; ++ __global__ auto&& dirty = ijk; ++#endif ++ if (this->isCached1(dirty)) { ++ return mNode1->getValueAndCache(ijk, *this); ++ } else if (this->isCached2(dirty)) { ++ return mNode2->getValueAndCache(ijk, *this); ++ } ++ return mRoot->getValueAndCache(ijk, *this); ++ } ++#endif ++ __hostdev__ ValueType operator()(__global__ const CoordType& ijk) const __global__ ++ { ++ return this->getValue(ijk); ++ } ++ __hostdev__ ValueType operator()(int i, int j, int k) const __global__ ++ { ++ return this->getValue(CoordType(i,j,k)); ++ } ++ ++ __hostdev__ NodeInfo getNodeInfo(__global__ const CoordType& ijk) const __global__ ++ { ++#ifdef USE_SINGLE_ACCESSOR_KEY ++ const CoordValueType dirty = this->computeDirty(ijk); ++#else ++ __global__ auto&& dirty = ijk; + #endif + if (this->isCached1(dirty)) { + return mNode1->getNodeInfoAndCache(ijk, *this); +@@ -5037,12 +6022,12 @@ public: + return mRoot->getNodeInfoAndCache(ijk, *this); + } + +- __hostdev__ bool isActive(const CoordType& ijk) const ++ __hostdev__ bool isActive(__global__ const CoordType& ijk) const __global__ + { + #ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); + #else +- auto&& dirty = ijk; ++ __global__ auto&& dirty = ijk; + #endif + if (this->isCached1(dirty)) { + return mNode1->isActiveAndCache(ijk, *this); +@@ -5052,12 +6037,12 @@ public: + return mRoot->isActiveAndCache(ijk, *this); + } + +- __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const ++ __hostdev__ bool probeValue(__global__ const CoordType& ijk, __global__ ValueType& v) const __global__ + { + #ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); + #else +- auto&& dirty = ijk; ++ __global__ auto&& dirty = ijk; + #endif + if (this->isCached1(dirty)) { + return mNode1->probeValueAndCache(ijk, v, *this); +@@ -5067,12 +6052,12 @@ public: + return mRoot->probeValueAndCache(ijk, v, *this); + } + +- __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const ++ __hostdev__ __global__ const LeafT* probeLeaf(__global__ const CoordType& ijk) const __global__ + { + #ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); + #else +- auto&& dirty = ijk; ++ __global__ auto&& dirty = ijk; + #endif + if (this->isCached1(dirty)) { + return mNode1->probeLeafAndCache(ijk, *this); +@@ -5083,12 +6068,12 @@ public: + } + + template +- __hostdev__ uint32_t getDim(const CoordType& ijk, const RayT& ray) const ++ __hostdev__ uint32_t getDim(__global__ const CoordType& ijk, __global__ const RayT& ray) const __global__ + { + #ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); + #else +- auto&& dirty = ijk; ++ __global__ auto&& dirty = ijk; + #endif + if (this->isCached1(dirty)) { + return mNode1->getDimAndCache(ijk, ray, *this); +@@ -5108,7 +6093,7 @@ private: + friend class LeafNode; + + /// @brief Inserts a leaf node and key pair into this ReadAccessor +- __hostdev__ void insert(const CoordType& ijk, const Node1T* node) const ++ __hostdev__ void insert(__global__ const CoordType& ijk, __global__ const Node1T* node) const __local__ + { + #ifdef USE_SINGLE_ACCESSOR_KEY + mKey = ijk; +@@ -5117,7 +6102,7 @@ private: + #endif + mNode1 = node; + } +- __hostdev__ void insert(const CoordType& ijk, const Node2T* node) const ++ __hostdev__ void insert(__local__ const CoordType& ijk, __global__ const Node2T* node) const __local__ + { + #ifdef USE_SINGLE_ACCESSOR_KEY + mKey = ijk; +@@ -5127,7 +6112,11 @@ private: + mNode2 = node; + } + template +- __hostdev__ void insert(const CoordType&, const OtherNodeT*) const {} ++ __hostdev__ void insert(__global__ const CoordType&, __global__ const OtherNodeT*) const __local__ {} ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ void insert(__local__ const CoordType&, __global__ const OtherNodeT*) const __local__ {} ++#endif + }; // ReadAccessor + + +@@ -5145,7 +6134,7 @@ class ReadAccessor + using ValueT = typename RootT::ValueType; + + using FloatType = typename RootT::FloatType; +- using CoordValueType = typename RootT::CoordT::ValueType; ++ using CoordValueType = typename RootT::CoordType::ValueType; + + // All member data are mutable to allow for access methods to be const + #ifdef USE_SINGLE_ACCESSOR_KEY // 44 bytes total +@@ -5153,19 +6142,19 @@ class ReadAccessor + #else // 68 bytes total + mutable CoordT mKeys[3]; // 3*3*4 = 36 bytes + #endif +- mutable const RootT* mRoot; +- mutable const void* mNode[3]; // 4*8 = 32 bytes ++ mutable __global__ const RootT* mRoot; ++ mutable __global__ const void* mNode[3]; // 4*8 = 32 bytes + + public: + using ValueType = ValueT; + using CoordType = CoordT; + +- static const int CacheLevels = 3; ++ static __constant__ const int CacheLevels = 3; + + using NodeInfo = typename ReadAccessor::NodeInfo; + + /// @brief Constructor from a root node +- __hostdev__ ReadAccessor(const RootT& root) ++ __hostdev__ ReadAccessor(__global__ const RootT& root) __local__ + #ifdef USE_SINGLE_ACCESSOR_KEY + : mKey(CoordType::max()) + #else +@@ -5177,35 +6166,38 @@ public: + } + + /// @brief Constructor from a grid +- __hostdev__ ReadAccessor(const GridT& grid) : ReadAccessor(grid.tree().root()) {} ++ __hostdev__ ReadAccessor(__global__ const GridT& grid) __local__ : ReadAccessor(grid.tree().root()) {} + + /// @brief Constructor from a tree +- __hostdev__ ReadAccessor(const TreeT& tree) : ReadAccessor(tree.root()) {} ++ __hostdev__ ReadAccessor(__global__ const TreeT& tree) __local__ : ReadAccessor(tree.root()) {} + +- __hostdev__ const RootT& root() const { return *mRoot; } ++ __hostdev__ __global__ const RootT& root() const __global__ { return *mRoot; } ++#if defined(__KERNEL_METAL__) ++ __hostdev__ __global__ const RootT& root() const __local__ { return *mRoot; } ++#endif + + /// @brief Defaults constructors +- ReadAccessor(const ReadAccessor&) = default; +- ~ReadAccessor() = default; +- ReadAccessor& operator=(const ReadAccessor&) = default; ++ ReadAccessor(__local__ const ReadAccessor&) __local__ = default; ++ ~ReadAccessor() __global__ = default; ++ __global__ ReadAccessor& operator=(__global__ const ReadAccessor&) __global__ = default; + + /// @brief Return a const point to the cached node of the specified type + /// + /// @warning The return value could be NULL. + template +- __hostdev__ const NodeT* getNode() const ++ __hostdev__ __global__ const NodeT* getNode() const __global__ + { + using T = typename NodeTrait::type; + static_assert(is_same::value, "ReadAccessor::getNode: Invalid node type"); +- return reinterpret_cast(mNode[NodeT::LEVEL]); ++ return reinterpret_cast<__global__ const T*>(mNode[NodeT::LEVEL]); + } + + template +- __hostdev__ const typename NodeTrait::type* getNode() const ++ __hostdev__ __global__ const typename NodeTrait::type* getNode() const + { + using T = typename NodeTrait::type; + static_assert(LEVEL>=0 && LEVEL<=2, "ReadAccessor::getNode: Invalid node type"); +- return reinterpret_cast(mNode[LEVEL]); ++ return reinterpret_cast<__global__ const T*>(mNode[LEVEL]); + } + + +@@ -5222,7 +6214,7 @@ public: + + #ifdef USE_SINGLE_ACCESSOR_KEY + template +- __hostdev__ bool isCached(CoordValueType dirty) const ++ __hostdev__ bool isCached(CoordValueType dirty) const __global__ + { + if (!mNode[NodeT::LEVEL]) + return false; +@@ -5233,128 +6225,229 @@ public: + return true; + } + +- __hostdev__ CoordValueType computeDirty(const CoordType& ijk) const ++ __hostdev__ CoordValueType computeDirty(const CoordType& ijk) const __global__ + { + return (ijk[0] ^ mKey[0]) | (ijk[1] ^ mKey[1]) | (ijk[2] ^ mKey[2]); + } + #else + template +- __hostdev__ bool isCached(const CoordType& ijk) const ++ __hostdev__ bool isCached(__global__ const CoordType& ijk) const __global__ + { + return (ijk[0] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][0] && (ijk[1] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][1] && (ijk[2] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][2]; + } ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ bool isCached(__local__ const CoordType& ijk) const __global__ ++ { ++ return (ijk[0] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][0] && (ijk[1] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][1] && (ijk[2] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][2]; ++ } ++ template ++ __hostdev__ bool isCached(__local__ const CoordType& ijk) const __local__ ++ { ++ return (ijk[0] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][0] && (ijk[1] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][1] && (ijk[2] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][2]; ++ } ++#endif // __KERNEL_METAL__ + #endif + +- __hostdev__ ValueType getValue(const CoordType& ijk) const ++ __hostdev__ ValueType getValue(__global__ const CoordType& ijk) const __global__ + { + #ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); + #else +- auto&& dirty = ijk; ++ __global__ auto&& dirty = ijk; + #endif + if (this->isCached(dirty)) { +- return ((LeafT*)mNode[0])->getValue(ijk); ++ return ((__global__ LeafT*)mNode[0])->getValue(ijk); + } else if (this->isCached(dirty)) { +- return ((NodeT1*)mNode[1])->getValueAndCache(ijk, *this); ++ return ((__global__ NodeT1*)mNode[1])->getValueAndCache(ijk, *this); + } else if (this->isCached(dirty)) { +- return ((NodeT2*)mNode[2])->getValueAndCache(ijk, *this); ++ return ((__global__ NodeT2*)mNode[2])->getValueAndCache(ijk, *this); + } + return mRoot->getValueAndCache(ijk, *this); + } +- __hostdev__ ValueType operator()(const CoordType& ijk) const ++#if defined(__KERNEL_METAL__) ++ __hostdev__ ValueType getValue(__local__ const CoordType& ijk) const __global__ ++ { ++#ifdef USE_SINGLE_ACCESSOR_KEY ++ const CoordValueType dirty = this->computeDirty(ijk); ++#else ++ __local__ auto&& dirty = ijk; ++#endif ++ if (this->isCached(dirty)) { ++ return ((__global__ LeafT*)mNode[0])->getValue(ijk); ++ } else if (this->isCached(dirty)) { ++ return ((__global__ NodeT1*)mNode[1])->getValueAndCache(ijk, *this); ++ } else if (this->isCached(dirty)) { ++ return ((__global__ NodeT2*)mNode[2])->getValueAndCache(ijk, *this); ++ } ++ return mRoot->getValueAndCache(ijk, *this); ++ } ++ __hostdev__ ValueType getValue(__local__ const CoordType& ijk) const __local__ ++ { ++#ifdef USE_SINGLE_ACCESSOR_KEY ++ const CoordValueType dirty = this->computeDirty(ijk); ++#else ++ __local__ auto&& dirty = ijk; ++#endif ++ if (this->isCached(dirty)) { ++ return ((__global__ LeafT*)mNode[0])->getValue(ijk); ++ } else if (this->isCached(dirty)) { ++ return ((__global__ NodeT1*)mNode[1])->getValueAndCache(ijk, *this); ++ } else if (this->isCached(dirty)) { ++ return ((__global__ NodeT2*)mNode[2])->getValueAndCache(ijk, *this); ++ } ++ return mRoot->getValueAndCache(ijk, *this); ++ } ++#endif // __KERNEL_METAL__ ++ ++ __hostdev__ ValueType operator()(__global__ const CoordType& ijk) const __global__ + { + return this->getValue(ijk); + } +- __hostdev__ ValueType operator()(int i, int j, int k) const ++ __hostdev__ ValueType operator()(int i, int j, int k) const __global__ + { + return this->getValue(CoordType(i,j,k)); + } + +- __hostdev__ NodeInfo getNodeInfo(const CoordType& ijk) const ++ __hostdev__ NodeInfo getNodeInfo(__global__ const CoordType& ijk) const __global__ + { + #ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); + #else +- auto&& dirty = ijk; ++ __global__ auto&& dirty = ijk; + #endif + if (this->isCached(dirty)) { +- return ((LeafT*)mNode[0])->getNodeInfoAndCache(ijk, *this); ++ return ((__global__ LeafT*)mNode[0])->getNodeInfoAndCache(ijk, *this); + } else if (this->isCached(dirty)) { +- return ((NodeT1*)mNode[1])->getNodeInfoAndCache(ijk, *this); ++ return ((__global__ NodeT1*)mNode[1])->getNodeInfoAndCache(ijk, *this); + } else if (this->isCached(dirty)) { +- return ((NodeT2*)mNode[2])->getNodeInfoAndCache(ijk, *this); ++ return ((__global__ NodeT2*)mNode[2])->getNodeInfoAndCache(ijk, *this); + } + return mRoot->getNodeInfoAndCache(ijk, *this); + } + +- __hostdev__ bool isActive(const CoordType& ijk) const ++ __hostdev__ bool isActive(__global__ const CoordType& ijk) const __global__ + { + #ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); + #else +- auto&& dirty = ijk; ++ __global__ auto&& dirty = ijk; + #endif + if (this->isCached(dirty)) { +- return ((LeafT*)mNode[0])->isActive(ijk); ++ return ((__global__ LeafT*)mNode[0])->isActive(ijk); + } else if (this->isCached(dirty)) { +- return ((NodeT1*)mNode[1])->isActiveAndCache(ijk, *this); ++ return ((__global__ NodeT1*)mNode[1])->isActiveAndCache(ijk, *this); + } else if (this->isCached(dirty)) { +- return ((NodeT2*)mNode[2])->isActiveAndCache(ijk, *this); ++ return ((__global__ NodeT2*)mNode[2])->isActiveAndCache(ijk, *this); + } + return mRoot->isActiveAndCache(ijk, *this); + } +- +- __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const ++#if defined(__KERNEL_METAL__) ++ __hostdev__ bool isActive(__local__ const CoordType& ijk) const __local__ + { + #ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); + #else +- auto&& dirty = ijk; ++ __local__ auto&& dirty = ijk; + #endif + if (this->isCached(dirty)) { +- return ((LeafT*)mNode[0])->probeValue(ijk, v); ++ return ((__global__ LeafT*)mNode[0])->isActive(ijk); + } else if (this->isCached(dirty)) { +- return ((NodeT1*)mNode[1])->probeValueAndCache(ijk, v, *this); ++ return ((__global__ NodeT1*)mNode[1])->isActiveAndCache(ijk, *this); + } else if (this->isCached(dirty)) { +- return ((NodeT2*)mNode[2])->probeValueAndCache(ijk, v, *this); ++ return ((__global__ NodeT2*)mNode[2])->isActiveAndCache(ijk, *this); ++ } ++ return mRoot->isActiveAndCache(ijk, *this); ++ } ++#endif ++ ++ __hostdev__ bool probeValue(__global__ const CoordType& ijk, __global__ ValueType& v) const __global__ ++ { ++#ifdef USE_SINGLE_ACCESSOR_KEY ++ const CoordValueType dirty = this->computeDirty(ijk); ++#else ++ __global__ auto&& dirty = ijk; ++#endif ++ if (this->isCached(dirty)) { ++ return ((__global__ LeafT*)mNode[0])->probeValue(ijk, v); ++ } else if (this->isCached(dirty)) { ++ return ((__global__ NodeT1*)mNode[1])->probeValueAndCache(ijk, v, *this); ++ } else if (this->isCached(dirty)) { ++ return ((__global__ NodeT2*)mNode[2])->probeValueAndCache(ijk, v, *this); + } + return mRoot->probeValueAndCache(ijk, v, *this); + } + +- __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const ++ __hostdev__ __global__ const LeafT* probeLeaf(__global__ const CoordType& ijk) const __global__ + { + #ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); + #else +- auto&& dirty = ijk; ++ __global__ auto&& dirty = ijk; + #endif + if (this->isCached(dirty)) { +- return ((LeafT*)mNode[0]); ++ return ((__global__ LeafT*)mNode[0]); + } else if (this->isCached(dirty)) { +- return ((NodeT1*)mNode[1])->probeLeafAndCache(ijk, *this); ++ return ((__global__ NodeT1*)mNode[1])->probeLeafAndCache(ijk, *this); + } else if (this->isCached(dirty)) { +- return ((NodeT2*)mNode[2])->probeLeafAndCache(ijk, *this); ++ return ((__global__ NodeT2*)mNode[2])->probeLeafAndCache(ijk, *this); + } + return mRoot->probeLeafAndCache(ijk, *this); + } + + template +- __hostdev__ uint32_t getDim(const CoordType& ijk, const RayT& ray) const ++ __hostdev__ uint32_t getDim(__global__ const CoordType& ijk, __global__ const RayT& ray) const __global__ + { + #ifdef USE_SINGLE_ACCESSOR_KEY + const CoordValueType dirty = this->computeDirty(ijk); + #else +- auto&& dirty = ijk; ++ __global__ auto&& dirty = ijk; + #endif + if (this->isCached(dirty)) { +- return ((LeafT*)mNode[0])->getDimAndCache(ijk, ray, *this); ++ return ((__global__ LeafT*)mNode[0])->getDimAndCache(ijk, ray, *this); + } else if (this->isCached(dirty)) { +- return ((NodeT1*)mNode[1])->getDimAndCache(ijk, ray, *this); ++ return ((__global__ NodeT1*)mNode[1])->getDimAndCache(ijk, ray, *this); + } else if (this->isCached(dirty)) { +- return ((NodeT2*)mNode[2])->getDimAndCache(ijk, ray, *this); ++ return ((__global__ NodeT2*)mNode[2])->getDimAndCache(ijk, ray, *this); + } + return mRoot->getDimAndCache(ijk, ray, *this); + } ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ uint32_t getDim(__global__ const CoordType& ijk, __local__ const RayT& ray) const __global__ ++ { ++#ifdef USE_SINGLE_ACCESSOR_KEY ++ const CoordValueType dirty = this->computeDirty(ijk); ++#else ++ __global__ auto&& dirty = ijk; ++#endif ++ if (this->isCached(dirty)) { ++ return ((__global__ LeafT*)mNode[0])->getDimAndCache(ijk, ray, *this); ++ } else if (this->isCached(dirty)) { ++ return ((__global__ NodeT1*)mNode[1])->getDimAndCache(ijk, ray, *this); ++ } else if (this->isCached(dirty)) { ++ return ((__global__ NodeT2*)mNode[2])->getDimAndCache(ijk, ray, *this); ++ } ++ return mRoot->getDimAndCache(ijk, ray, *this); ++ } ++ template ++ __hostdev__ uint32_t getDim(__local__ const CoordType& ijk, __local__ const RayT& ray) const __local__ ++ { ++#ifdef USE_SINGLE_ACCESSOR_KEY ++ const CoordValueType dirty = this->computeDirty(ijk); ++#else ++ __local__ auto&& dirty = ijk; ++#endif ++ if (this->isCached(dirty)) { ++ return ((__global__ LeafT*)mNode[0])->getDimAndCache(ijk, ray, *this); ++ } else if (this->isCached(dirty)) { ++ return ((__global__ NodeT1*)mNode[1])->getDimAndCache(ijk, ray, *this); ++ } else if (this->isCached(dirty)) { ++ return ((__global__ NodeT2*)mNode[2])->getDimAndCache(ijk, ray, *this); ++ } ++ return mRoot->getDimAndCache(ijk, ray, *this); ++ } ++#endif // __KERNEL_METAL__ + + private: + /// @brief Allow nodes to insert themselves into the cache. +@@ -5367,7 +6460,7 @@ private: + + /// @brief Inserts a leaf node and key pair into this ReadAccessor + template +- __hostdev__ void insert(const CoordType& ijk, const NodeT* node) const ++ __hostdev__ void insert(__global__ const CoordType& ijk, __global__ const NodeT* node) const __local__ + { + #ifdef USE_SINGLE_ACCESSOR_KEY + mKey = ijk; +@@ -5376,6 +6469,28 @@ private: + #endif + mNode[NodeT::LEVEL] = node; + } ++#if defined(__KERNEL_METAL__) ++ template ++ __hostdev__ void insert(__local__ const CoordType& ijk, __global__ const NodeT* node) const __local__ ++ { ++#ifdef USE_SINGLE_ACCESSOR_KEY ++ mKey = ijk; ++#else ++ mKeys[NodeT::LEVEL] = ijk & ~NodeT::MASK; ++#endif ++ mNode[NodeT::LEVEL] = node; ++ } ++ template ++ __hostdev__ void insert(__local__ const CoordType& ijk, __global__ const NodeT* node) const __global__ ++ { ++#ifdef USE_SINGLE_ACCESSOR_KEY ++ mKey = ijk; ++#else ++ mKeys[NodeT::LEVEL] = ijk & ~NodeT::MASK; ++#endif ++ mNode[NodeT::LEVEL] = node; ++ } ++#endif // __KERNEL_METAL__ + }; // ReadAccessor + + ////////////////////////////////////////////////// +@@ -5393,19 +6508,19 @@ private: + /// createAccessor<0,1,2>(grid): Caching of all nodes at all tree levels + + template +-ReadAccessor createAccessor(const NanoGrid &grid) ++ReadAccessor createAccessor(__global__ const NanoGrid &grid) + { + return ReadAccessor(grid); + } + + template +-ReadAccessor createAccessor(const NanoTree &tree) ++ReadAccessor createAccessor(__global__ const NanoTree &tree) + { + return ReadAccessor(tree); + } + + template +-ReadAccessor createAccessor(const NanoRoot &root) ++ReadAccessor createAccessor(__global__ const NanoRoot &root) + { + return ReadAccessor(root); + } +@@ -5424,52 +6539,59 @@ class GridMetaData + // memory-layout of the data structure and the reasons why certain methods are safe + // to call and others are not! + using GridT = NanoGrid; +- __hostdev__ const GridT& grid() const { return *reinterpret_cast(this); } ++ __hostdev__ __global__ const GridT& grid() const __global__ { return *reinterpret_cast<__global__ const GridT*>(this); } + + public: +- __hostdev__ bool isValid() const { return this->grid().isValid(); } +- __hostdev__ uint64_t gridSize() const { return this->grid().gridSize(); } +- __hostdev__ uint32_t gridIndex() const { return this->grid().gridIndex(); } +- __hostdev__ uint32_t gridCount() const { return this->grid().gridCount(); } +- __hostdev__ const char* shortGridName() const { return this->grid().shortGridName(); } +- __hostdev__ GridType gridType() const { return this->grid().gridType(); } +- __hostdev__ GridClass gridClass() const { return this->grid().gridClass(); } +- __hostdev__ bool isLevelSet() const { return this->grid().isLevelSet(); } +- __hostdev__ bool isFogVolume() const { return this->grid().isFogVolume(); } +- __hostdev__ bool isPointIndex() const { return this->grid().isPointIndex(); } +- __hostdev__ bool isPointData() const { return this->grid().isPointData(); } +- __hostdev__ bool isMask() const { return this->grid().isMask(); } +- __hostdev__ bool isStaggered() const { return this->grid().isStaggered(); } +- __hostdev__ bool isUnknown() const { return this->grid().isUnknown(); } +- __hostdev__ const Map& map() const { return this->grid().map(); } +- __hostdev__ const BBox& worldBBox() const { return this->grid().worldBBox(); } +- __hostdev__ const BBox& indexBBox() const { return this->grid().indexBBox(); } +- __hostdev__ Vec3R voxelSize() const { return this->grid().voxelSize(); } +- __hostdev__ int blindDataCount() const { return this->grid().blindDataCount(); } +- __hostdev__ const GridBlindMetaData& blindMetaData(uint32_t n) const { return this->grid().blindMetaData(n); } +- __hostdev__ uint64_t activeVoxelCount() const { return this->grid().activeVoxelCount(); } +- __hostdev__ const uint32_t& activeTileCount(uint32_t level) const { return this->grid().tree().activeTileCount(level); } +- __hostdev__ uint32_t nodeCount(uint32_t level) const { return this->grid().tree().nodeCount(level); } +- __hostdev__ uint64_t checksum() const { return this->grid().checksum(); } +- __hostdev__ bool isEmpty() const { return this->grid().isEmpty(); } +- __hostdev__ Version version() const { return this->grid().version(); } ++ __hostdev__ bool isValid() const __global__ { return this->grid().isValid(); } ++ __hostdev__ uint64_t gridSize() const __global__ { return this->grid().gridSize(); } ++ __hostdev__ uint32_t gridIndex() const __global__ { return this->grid().gridIndex(); } ++ __hostdev__ uint32_t gridCount() const __global__ { return this->grid().gridCount(); } ++ __hostdev__ __global__ const char* shortGridName() const __global__ { return this->grid().shortGridName(); } ++ __hostdev__ GridType gridType() const __global__ { return this->grid().gridType(); } ++ __hostdev__ GridClass gridClass() const __global__ { return this->grid().gridClass(); } ++ __hostdev__ bool isLevelSet() const __global__ { return this->grid().isLevelSet(); } ++ __hostdev__ bool isFogVolume() const __global__ { return this->grid().isFogVolume(); } ++ __hostdev__ bool isPointIndex() const __global__ { return this->grid().isPointIndex(); } ++ __hostdev__ bool isPointData() const __global__ { return this->grid().isPointData(); } ++ __hostdev__ bool isMask() const __global__ { return this->grid().isMask(); } ++ __hostdev__ bool isStaggered() const __global__ { return this->grid().isStaggered(); } ++ __hostdev__ bool isUnknown() const __global__ { return this->grid().isUnknown(); } ++ __hostdev__ __global__ const Map& map() const __global__ { return this->grid().map(); } ++ __hostdev__ __global__ const BBox& worldBBox() const __global__ { return this->grid().worldBBox(); } ++ __hostdev__ __global__ const BBox& indexBBox() const __global__ { return this->grid().indexBBox(); } ++ __hostdev__ Vec3R voxelSize() const __global__ { return this->grid().voxelSize(); } ++ __hostdev__ int blindDataCount() const __global__ { return this->grid().blindDataCount(); } ++ __hostdev__ __global__ const GridBlindMetaData& blindMetaData(uint32_t n) const __global__ { return this->grid().blindMetaData(n); } ++ __hostdev__ uint64_t activeVoxelCount() const __global__ { return this->grid().activeVoxelCount(); } ++ __hostdev__ __global__ const uint32_t& activeTileCount(uint32_t level) const __global__ { return this->grid().tree().activeTileCount(level); } ++ __hostdev__ uint32_t nodeCount(uint32_t level) const __global__ { return this->grid().tree().nodeCount(level); } ++ __hostdev__ uint64_t checksum() const __global__ { return this->grid().checksum(); } ++ __hostdev__ bool isEmpty() const __global__ { return this->grid().isEmpty(); } ++ __hostdev__ Version version() const __global__ { return this->grid().version(); } + }; // GridMetaData + + /// @brief Class to access points at a specific voxel location + template +-class PointAccessor : public DefaultReadAccessor ++class PointAccessor ++#if !defined(__KERNEL_METAL__) ++ : public DefaultReadAccessor ++#endif + { ++#if defined(__KERNEL_METAL__) ++ DefaultReadAccessor AccT; ++#else + using AccT = DefaultReadAccessor; +- const UInt32Grid* mGrid; +- const AttT* mData; ++#endif ++ const __global__ UInt32Grid* mGrid; ++ const __global__ AttT* mData; + + public: + using LeafNodeType = typename NanoRoot::LeafNodeType; + +- PointAccessor(const UInt32Grid& grid) ++ PointAccessor(__global__ const UInt32Grid& grid) __local__ + : AccT(grid.tree().root()) + , mGrid(&grid) +- , mData(reinterpret_cast(grid.blindData(0))) ++ , mData(reinterpret_cast<__global__ const AttT*>(grid.blindData(0))) + { + NANOVDB_ASSERT(grid.gridType() == GridType::UInt32); + NANOVDB_ASSERT((grid.gridClass() == GridClass::PointIndex && is_same::value) || +@@ -5478,7 +6600,7 @@ public: + } + /// @brief Return the total number of point in the grid and set the + /// iterators to the complete range of points. +- __hostdev__ uint64_t gridPoints(const AttT*& begin, const AttT*& end) const ++ __hostdev__ uint64_t gridPoints(__global__ const AttT*& begin, __global__ const AttT*& end) const __global__ + { + const uint64_t count = mGrid->blindMetaData(0u).mElementCount; + begin = mData; +@@ -5488,9 +6610,9 @@ public: + /// @brief Return the number of points in the leaf node containing the coordinate @a ijk. + /// If this return value is larger than zero then the iterators @a begin and @a end + /// will point to all the attributes contained within that leaf node. +- __hostdev__ uint64_t leafPoints(const Coord& ijk, const AttT*& begin, const AttT*& end) const ++ __hostdev__ uint64_t leafPoints(__global__ const Coord& ijk, __global__ const AttT*& begin, __global__ const AttT*& end) const __global__ + { +- auto* leaf = this->probeLeaf(ijk); ++ __global__ auto* leaf = this->probeLeaf(ijk); + if (leaf == nullptr) { + return 0; + } +@@ -5500,14 +6622,14 @@ public: + } + + /// @brief get iterators over offsets to points at a specific voxel location +- __hostdev__ uint64_t voxelPoints(const Coord& ijk, const AttT*& begin, const AttT*& end) const ++ __hostdev__ uint64_t voxelPoints(__global__ const Coord& ijk, __global__ const AttT*& begin, __global__ const AttT*& end) const __global__ + { +- auto* leaf = this->probeLeaf(ijk); ++ __global__ auto* leaf = this->probeLeaf(ijk); + if (leaf == nullptr) + return 0; + const uint32_t offset = LeafNodeType::CoordToOffset(ijk); + if (leaf->isActive(offset)) { +- auto* p = mData + leaf->minimum(); ++ __global__ auto* p = mData + leaf->minimum(); + begin = p + (offset == 0 ? 0 : leaf->getValue(offset - 1)); + end = p + leaf->getValue(offset); + return end - begin; +@@ -5520,11 +6642,20 @@ public: + /// + /// @note The ChannelT template parameter can be either const and non-const. + template +-class ChannelAccessor : public DefaultReadAccessor ++class ChannelAccessor ++#if !defined (__KERNEL_METAL__) ++ : public DefaultReadAccessor ++#endif + { ++#if defined (__KERNEL_METAL__) ++ DefaultReadAccessor BaseT; ++#define BASE(v) BaseT.v ++#else + using BaseT = DefaultReadAccessor; +- const IndexGrid &mGrid; +- ChannelT *mChannel; ++#define BASE(v) BaseT::v ++#endif ++ __global__ const IndexGrid &mGrid; ++ __global__ ChannelT *mChannel; + + public: + using ValueType = ChannelT; +@@ -5533,7 +6664,7 @@ public: + + /// @brief Ctor from an IndexGrid and an integer ID of an internal channel + /// that is assumed to exist as blind data in the IndexGrid. +- __hostdev__ ChannelAccessor(const IndexGrid& grid, uint32_t channelID = 0u) ++ __hostdev__ ChannelAccessor(__global__ const IndexGrid& grid, uint32_t channelID = 0u) + : BaseT(grid.tree().root()) + , mGrid(grid) + , mChannel(nullptr) +@@ -5544,7 +6675,7 @@ public: + } + + /// @brief Ctor from an IndexGrid and an external channel +- __hostdev__ ChannelAccessor(const IndexGrid& grid, ChannelT *channelPtr) ++ __hostdev__ ChannelAccessor(__global__ const IndexGrid& grid, __global__ ChannelT *channelPtr) + : BaseT(grid.tree().root()) + , mGrid(grid) + , mChannel(channelPtr) +@@ -5555,19 +6686,19 @@ public: + } + + /// @brief Return a const reference to the IndexGrid +- __hostdev__ const IndexGrid &grid() const {return mGrid;} ++ __hostdev__ __global__ const IndexGrid &grid() const {return mGrid;} + + /// @brief Return a const reference to the tree of the IndexGrid +- __hostdev__ const IndexTree &tree() const {return mGrid.tree();} ++ __hostdev__ __global__ const IndexTree &tree() const {return mGrid.tree();} + + /// @brief Return a vector of the axial voxel sizes +- __hostdev__ const Vec3R& voxelSize() const { return mGrid.voxelSize(); } ++ __hostdev__ __global__ const Vec3R& voxelSize() const { return mGrid.voxelSize(); } + + /// @brief Return total number of values indexed by the IndexGrid +- __hostdev__ const uint64_t& valueCount() const { return mGrid.valueCount(); } ++ __hostdev__ uint64_t valueCount() const { return mGrid.valueCount(); } + + /// @brief Change to an external channel +- __hostdev__ void setChannel(ChannelT *channelPtr) ++ __hostdev__ void setChannel(__global__ ChannelT *channelPtr) + { + mChannel = channelPtr; + NANOVDB_ASSERT(mChannel); +@@ -5577,23 +6708,24 @@ public: + /// in the IndexGrid. + __hostdev__ void setChannel(uint32_t channelID) + { +- this->setChannel(reinterpret_cast(const_cast(mGrid.blindData(channelID)))); ++ this->setChannel(reinterpret_cast<__global__ ChannelT*>(const_cast<__global__ void*>(mGrid.blindData(channelID)))); + } + + /// @brief Return the linear offset into a channel that maps to the specified coordinate +- __hostdev__ uint64_t getIndex(const Coord& ijk) const {return BaseT::getValue(ijk);} +- __hostdev__ uint64_t idx(int i, int j, int k) const {return BaseT::getValue(Coord(i,j,k));} ++ __hostdev__ uint64_t getIndex(__global__ const Coord& ijk) const {return BASE(getValue)(ijk);} ++ __hostdev__ uint64_t idx(int i, int j, int k) const {return BASE(getValue)(Coord(i,j,k));} + + /// @brief Return the value from a cached channel that maps to the specified coordinate +- __hostdev__ ChannelT& getValue(const Coord& ijk) const {return mChannel[BaseT::getValue(ijk)];} +- __hostdev__ ChannelT& operator()(const Coord& ijk) const {return this->getValue(ijk);} +- __hostdev__ ChannelT& operator()(int i, int j, int k) const {return this->getValue(Coord(i,j,k));} ++ __hostdev__ __global__ ChannelT& getValue(__global__ const Coord& ijk) const {return mChannel[BASE(getValue)(ijk)];} ++ __hostdev__ __global__ ChannelT& operator()(__global__ const Coord& ijk) const {return this->getValue(ijk);} ++ __hostdev__ __global__ ChannelT& operator()(int i, int j, int k) const {return this->getValue(Coord(i,j,k));} + + /// @brief return the state and updates the value of the specified voxel +- __hostdev__ bool probeValue(const CoordType& ijk, typename remove_const::type &v) const ++ using CoordType = DefaultReadAccessor::CoordType; ++ __hostdev__ bool probeValue(__global__ const CoordType& ijk, __global__ typename remove_const::type &v) const + { + uint64_t idx; +- const bool isActive = BaseT::probeValue(ijk, idx); ++ const bool isActive = BASE(probeValue)(ijk, idx); + v = mChannel[idx]; + return isActive; + } +@@ -5601,7 +6733,7 @@ public: + /// + /// @note The template parameter can be either const or non-const + template +- __hostdev__ T& getValue(const Coord& ijk, T* channelPtr) const {return channelPtr[BaseT::getValue(ijk)];} ++ __hostdev__ __global__ T& getValue(__global__ const Coord& ijk, __global__ T* channelPtr) const {return channelPtr[BASE(getValue)(ijk)];} + + }; // ChannelAccessor + +@@ -5643,6 +6775,7 @@ namespace io { + /// @throw std::invalid_argument if buffer does not point to a valid NanoVDB grid. + /// + /// @warning This is pretty ugly code that involves lots of pointer and bit manipulations - not for the faint of heart :) ++#if !defined(__KERNEL_METAL__) + template // StreamT class must support: "void write(char*, size_t)" + void writeUncompressedGrid(StreamT &os, const void *buffer) + { +@@ -5768,7 +6901,7 @@ VecT readUncompressedGrids(const char *fileName, const typename Gri + } + return readUncompressedGrids(is, buffer); + }// readUncompressedGrids +- ++#endif // #if !defined(__KERNEL_METAL__) + } // namespace io + + #endif// if !defined(__CUDA_ARCH__) && !defined(__HIP__) +diff --git a/nanovdb/nanovdb/util/SampleFromVoxels.h b/nanovdb/nanovdb/util/SampleFromVoxels.h +index e779d66..e2f9283 100644 +--- a/nanovdb/nanovdb/util/SampleFromVoxels.h ++++ b/nanovdb/nanovdb/util/SampleFromVoxels.h +@@ -1,983 +1,1120 @@ +-// Copyright Contributors to the OpenVDB Project +-// SPDX-License-Identifier: MPL-2.0 +- +-////////////////////////////////////////////////////////////////////////// +-/// +-/// @file SampleFromVoxels.h +-/// +-/// @brief NearestNeighborSampler, TrilinearSampler, TriquadraticSampler and TricubicSampler +-/// +-/// @note These interpolators employ internal caching for better performance when used repeatedly +-/// in the same voxel location, so try to reuse an instance of these classes more than once. +-/// +-/// @warning While all the interpolators defined below work with both scalars and vectors +-/// values (e.g. float and Vec3) TrilinarSampler::zeroCrossing and +-/// Trilinear::gradient will only compile with floating point value types. +-/// +-/// @author Ken Museth +-/// +-/////////////////////////////////////////////////////////////////////////// +- +-#ifndef NANOVDB_SAMPLE_FROM_VOXELS_H_HAS_BEEN_INCLUDED +-#define NANOVDB_SAMPLE_FROM_VOXELS_H_HAS_BEEN_INCLUDED +- +-// Only define __hostdev__ when compiling as NVIDIA CUDA +-#if defined(__CUDACC__) || defined(__HIP__) +-#define __hostdev__ __host__ __device__ +-#else +-#include // for floor +-#define __hostdev__ +-#endif +- +-namespace nanovdb { +- +-// Forward declaration of sampler with specific polynomial orders +-template +-class SampleFromVoxels; +- +-/// @brief Factory free-function for a sampler of specific polynomial orders +-/// +-/// @details This allows for the compact syntax: +-/// @code +-/// auto acc = grid.getAccessor(); +-/// auto smp = nanovdb::createSampler<1>( acc ); +-/// @endcode +-template +-__hostdev__ SampleFromVoxels createSampler(const TreeOrAccT& acc) +-{ +- return SampleFromVoxels(acc); +-} +- +-/// @brief Utility function that returns the Coord of the round-down of @a xyz +-/// and redefined @xyz as the fractional part, ie xyz-in = return-value + xyz-out +-template class Vec3T> +-__hostdev__ inline CoordT Floor(Vec3T& xyz); +- +-/// @brief Template specialization of Floor for Vec3 +-template class Vec3T> +-__hostdev__ inline CoordT Floor(Vec3T& xyz) +-{ +- const float ijk[3] = {floorf(xyz[0]), floorf(xyz[1]), floorf(xyz[2])}; +- xyz[0] -= ijk[0]; +- xyz[1] -= ijk[1]; +- xyz[2] -= ijk[2]; +- return CoordT(int32_t(ijk[0]), int32_t(ijk[1]), int32_t(ijk[2])); +-} +- +-/// @brief Template specialization of Floor for Vec3 +-template class Vec3T> +-__hostdev__ inline CoordT Floor(Vec3T& xyz) +-{ +- const double ijk[3] = {floor(xyz[0]), floor(xyz[1]), floor(xyz[2])}; +- xyz[0] -= ijk[0]; +- xyz[1] -= ijk[1]; +- xyz[2] -= ijk[2]; +- return CoordT(int32_t(ijk[0]), int32_t(ijk[1]), int32_t(ijk[2])); +-} +- +-// ------------------------------> NearestNeighborSampler <-------------------------------------- +- +-/// @brief Nearest neighbor, i.e. zero order, interpolator with caching +-template +-class SampleFromVoxels +-{ +-public: +- using ValueT = typename TreeOrAccT::ValueType; +- using CoordT = typename TreeOrAccT::CoordType; +- +- static const int ORDER = 0; +- /// @brief Construction from a Tree or ReadAccessor +- __hostdev__ SampleFromVoxels(const TreeOrAccT& acc) +- : mAcc(acc) +- , mPos(CoordT::max()) +- { +- } +- +- __hostdev__ const TreeOrAccT& accessor() const { return mAcc; } +- +- /// @note xyz is in index space space +- template +- inline __hostdev__ ValueT operator()(const Vec3T& xyz) const; +- +- inline __hostdev__ ValueT operator()(const CoordT& ijk) const; +- +-private: +- const TreeOrAccT& mAcc; +- mutable CoordT mPos; +- mutable ValueT mVal; // private cache +-}; // SampleFromVoxels +- +-/// @brief Nearest neighbor, i.e. zero order, interpolator without caching +-template +-class SampleFromVoxels +-{ +-public: +- using ValueT = typename TreeOrAccT::ValueType; +- using CoordT = typename TreeOrAccT::CoordType; +- static const int ORDER = 0; +- +- /// @brief Construction from a Tree or ReadAccessor +- __hostdev__ SampleFromVoxels(const TreeOrAccT& acc) +- : mAcc(acc) +- { +- } +- +- __hostdev__ const TreeOrAccT& accessor() const { return mAcc; } +- +- /// @note xyz is in index space space +- template +- inline __hostdev__ ValueT operator()(const Vec3T& xyz) const; +- +- inline __hostdev__ ValueT operator()(const CoordT& ijk) const { return mAcc.getValue(ijk);} +- +-private: +- const TreeOrAccT& mAcc; +-}; // SampleFromVoxels +- +-template +-template +-__hostdev__ typename TreeOrAccT::ValueType SampleFromVoxels::operator()(const Vec3T& xyz) const +-{ +- const CoordT ijk = Round(xyz); +- if (ijk != mPos) { +- mPos = ijk; +- mVal = mAcc.getValue(mPos); +- } +- return mVal; +-} +- +-template +-__hostdev__ typename TreeOrAccT::ValueType SampleFromVoxels::operator()(const CoordT& ijk) const +-{ +- if (ijk != mPos) { +- mPos = ijk; +- mVal = mAcc.getValue(mPos); +- } +- return mVal; +-} +- +-template +-template +-__hostdev__ typename TreeOrAccT::ValueType SampleFromVoxels::operator()(const Vec3T& xyz) const +-{ +- return mAcc.getValue(Round(xyz)); +-} +- +-// ------------------------------> TrilinearSampler <-------------------------------------- +- +-/// @brief Tri-linear sampler, i.e. first order, interpolator +-template +-class TrilinearSampler +-{ +-protected: +- const TreeOrAccT& mAcc; +- +-public: +- using ValueT = typename TreeOrAccT::ValueType; +- using CoordT = typename TreeOrAccT::CoordType; +- static const int ORDER = 1; +- +- /// @brief Protected constructor from a Tree or ReadAccessor +- __hostdev__ TrilinearSampler(const TreeOrAccT& acc) : mAcc(acc) {} +- +- __hostdev__ const TreeOrAccT& accessor() const { return mAcc; } +- +- /// @brief Extract the stencil of 8 values +- inline __hostdev__ void stencil(CoordT& ijk, ValueT (&v)[2][2][2]) const; +- +- template class Vec3T> +- static inline __hostdev__ ValueT sample(const Vec3T &uvw, const ValueT (&v)[2][2][2]); +- +- template class Vec3T> +- static inline __hostdev__ Vec3T gradient(const Vec3T &uvw, const ValueT (&v)[2][2][2]); +- +- static inline __hostdev__ bool zeroCrossing(const ValueT (&v)[2][2][2]); +-}; // TrilinearSamplerBase +- +-template +-__hostdev__ void TrilinearSampler::stencil(CoordT& ijk, ValueT (&v)[2][2][2]) const +-{ +- v[0][0][0] = mAcc.getValue(ijk); // i, j, k +- +- ijk[2] += 1; +- v[0][0][1] = mAcc.getValue(ijk); // i, j, k + 1 +- +- ijk[1] += 1; +- v[0][1][1] = mAcc.getValue(ijk); // i, j+1, k + 1 +- +- ijk[2] -= 1; +- v[0][1][0] = mAcc.getValue(ijk); // i, j+1, k +- +- ijk[0] += 1; +- ijk[1] -= 1; +- v[1][0][0] = mAcc.getValue(ijk); // i+1, j, k +- +- ijk[2] += 1; +- v[1][0][1] = mAcc.getValue(ijk); // i+1, j, k + 1 +- +- ijk[1] += 1; +- v[1][1][1] = mAcc.getValue(ijk); // i+1, j+1, k + 1 +- +- ijk[2] -= 1; +- v[1][1][0] = mAcc.getValue(ijk); // i+1, j+1, k +-} +- +-template +-template class Vec3T> +-__hostdev__ typename TreeOrAccT::ValueType TrilinearSampler::sample(const Vec3T &uvw, const ValueT (&v)[2][2][2]) +-{ +-#if 0 +- auto lerp = [](ValueT a, ValueT b, ValueT w){ return fma(w, b-a, a); };// = w*(b-a) + a +- //auto lerp = [](ValueT a, ValueT b, ValueT w){ return fma(w, b, fma(-w, a, a));};// = (1-w)*a + w*b +-#else +- auto lerp = [](ValueT a, ValueT b, RealT w) { return a + ValueT(w) * (b - a); }; +-#endif +- return lerp(lerp(lerp(v[0][0][0], v[0][0][1], uvw[2]), lerp(v[0][1][0], v[0][1][1], uvw[2]), uvw[1]), +- lerp(lerp(v[1][0][0], v[1][0][1], uvw[2]), lerp(v[1][1][0], v[1][1][1], uvw[2]), uvw[1]), +- uvw[0]); +-} +- +-template +-template class Vec3T> +-__hostdev__ Vec3T TrilinearSampler::gradient(const Vec3T &uvw, const ValueT (&v)[2][2][2]) +-{ +- static_assert(is_floating_point::value, "TrilinearSampler::gradient requires a floating-point type"); +-#if 0 +- auto lerp = [](ValueT a, ValueT b, ValueT w){ return fma(w, b-a, a); };// = w*(b-a) + a +- //auto lerp = [](ValueT a, ValueT b, ValueT w){ return fma(w, b, fma(-w, a, a));};// = (1-w)*a + w*b +-#else +- auto lerp = [](ValueT a, ValueT b, RealT w) { return a + ValueT(w) * (b - a); }; +-#endif +- +- ValueT D[4] = {v[0][0][1] - v[0][0][0], v[0][1][1] - v[0][1][0], v[1][0][1] - v[1][0][0], v[1][1][1] - v[1][1][0]}; +- +- // Z component +- Vec3T grad(0, 0, lerp(lerp(D[0], D[1], uvw[1]), lerp(D[2], D[3], uvw[1]), uvw[0])); +- +- const ValueT w = ValueT(uvw[2]); +- D[0] = v[0][0][0] + D[0] * w; +- D[1] = v[0][1][0] + D[1] * w; +- D[2] = v[1][0][0] + D[2] * w; +- D[3] = v[1][1][0] + D[3] * w; +- +- // X component +- grad[0] = lerp(D[2], D[3], uvw[1]) - lerp(D[0], D[1], uvw[1]); +- +- // Y component +- grad[1] = lerp(D[1] - D[0], D[3] - D[2], uvw[0]); +- +- return grad; +-} +- +-template +-__hostdev__ bool TrilinearSampler::zeroCrossing(const ValueT (&v)[2][2][2]) +-{ +- static_assert(is_floating_point::value, "TrilinearSampler::zeroCrossing requires a floating-point type"); +- const bool less = v[0][0][0] < ValueT(0); +- return (less ^ (v[0][0][1] < ValueT(0))) || +- (less ^ (v[0][1][1] < ValueT(0))) || +- (less ^ (v[0][1][0] < ValueT(0))) || +- (less ^ (v[1][0][0] < ValueT(0))) || +- (less ^ (v[1][0][1] < ValueT(0))) || +- (less ^ (v[1][1][1] < ValueT(0))) || +- (less ^ (v[1][1][0] < ValueT(0))); +-} +- +-/// @brief Template specialization that does not use caching of stencil points +-template +-class SampleFromVoxels : public TrilinearSampler +-{ +- using BaseT = TrilinearSampler; +- using ValueT = typename TreeOrAccT::ValueType; +- using CoordT = typename TreeOrAccT::CoordType; +- +-public: +- +- /// @brief Construction from a Tree or ReadAccessor +- __hostdev__ SampleFromVoxels(const TreeOrAccT& acc) : BaseT(acc) {} +- +- /// @note xyz is in index space space +- template class Vec3T> +- inline __hostdev__ ValueT operator()(Vec3T xyz) const; +- +- /// @note ijk is in index space space +- __hostdev__ ValueT operator()(const CoordT &ijk) const {return BaseT::mAcc.getValue(ijk);} +- +- /// @brief Return the gradient in index space. +- /// +- /// @warning Will only compile with floating point value types +- template class Vec3T> +- inline __hostdev__ Vec3T gradient(Vec3T xyz) const; +- +- /// @brief Return true if the tr-linear stencil has a zero crossing at the specified index position. +- /// +- /// @warning Will only compile with floating point value types +- template class Vec3T> +- inline __hostdev__ bool zeroCrossing(Vec3T xyz) const; +- +-}; // SampleFromVoxels +- +-/// @brief Template specialization with caching of stencil values +-template +-class SampleFromVoxels : public TrilinearSampler +-{ +- using BaseT = TrilinearSampler; +- using ValueT = typename TreeOrAccT::ValueType; +- using CoordT = typename TreeOrAccT::CoordType; +- +- mutable CoordT mPos; +- mutable ValueT mVal[2][2][2]; +- +- template class Vec3T> +- __hostdev__ void cache(Vec3T& xyz) const; +-public: +- +- /// @brief Construction from a Tree or ReadAccessor +- __hostdev__ SampleFromVoxels(const TreeOrAccT& acc) : BaseT(acc), mPos(CoordT::max()){} +- +- /// @note xyz is in index space space +- template class Vec3T> +- inline __hostdev__ ValueT operator()(Vec3T xyz) const; +- +- // @note ijk is in index space space +- __hostdev__ ValueT operator()(const CoordT &ijk) const; +- +- /// @brief Return the gradient in index space. +- /// +- /// @warning Will only compile with floating point value types +- template class Vec3T> +- inline __hostdev__ Vec3T gradient(Vec3T xyz) const; +- +- /// @brief Return true if the tr-linear stencil has a zero crossing at the specified index position. +- /// +- /// @warning Will only compile with floating point value types +- template class Vec3T> +- inline __hostdev__ bool zeroCrossing(Vec3T xyz) const; +- +- /// @brief Return true if the cached tri-linear stencil has a zero crossing. +- /// +- /// @warning Will only compile with floating point value types +- __hostdev__ bool zeroCrossing() const { return BaseT::zeroCrossing(mVal); } +- +-}; // SampleFromVoxels +- +-template +-template class Vec3T> +-__hostdev__ typename TreeOrAccT::ValueType SampleFromVoxels::operator()(Vec3T xyz) const +-{ +- this->cache(xyz); +- return BaseT::sample(xyz, mVal); +-} +- +-template +-__hostdev__ typename TreeOrAccT::ValueType SampleFromVoxels::operator()(const CoordT &ijk) const +-{ +- return ijk == mPos ? mVal[0][0][0] : BaseT::mAcc.getValue(ijk); +-} +- +-template +-template class Vec3T> +-__hostdev__ Vec3T SampleFromVoxels::gradient(Vec3T xyz) const +-{ +- this->cache(xyz); +- return BaseT::gradient(xyz, mVal); +-} +- +-template +-template class Vec3T> +-__hostdev__ bool SampleFromVoxels::zeroCrossing(Vec3T xyz) const +-{ +- this->cache(xyz); +- return BaseT::zeroCrossing(mVal); +-} +- +-template +-template class Vec3T> +-__hostdev__ void SampleFromVoxels::cache(Vec3T& xyz) const +-{ +- CoordT ijk = Floor(xyz); +- if (ijk != mPos) { +- mPos = ijk; +- BaseT::stencil(ijk, mVal); +- } +-} +- +-#if 0 +- +-template +-template class Vec3T> +-__hostdev__ typename TreeOrAccT::ValueType SampleFromVoxels::operator()(Vec3T xyz) const +-{ +- ValueT val[2][2][2]; +- CoordT ijk = Floor(xyz); +- BaseT::stencil(ijk, val); +- return BaseT::sample(xyz, val); +-} +- +-#else +- +-template +-template class Vec3T> +-__hostdev__ typename TreeOrAccT::ValueType SampleFromVoxels::operator()(Vec3T xyz) const +-{ +- auto lerp = [](ValueT a, ValueT b, RealT w) { return a + ValueT(w) * (b - a); }; +- +- CoordT coord = Floor(xyz); +- +- ValueT vx, vx1, vy, vy1, vz, vz1; +- +- vz = BaseT::mAcc.getValue(coord); +- coord[2] += 1; +- vz1 = BaseT::mAcc.getValue(coord); +- vy = lerp(vz, vz1, xyz[2]); +- +- coord[1] += 1; +- +- vz1 = BaseT::mAcc.getValue(coord); +- coord[2] -= 1; +- vz = BaseT::mAcc.getValue(coord); +- vy1 = lerp(vz, vz1, xyz[2]); +- +- vx = lerp(vy, vy1, xyz[1]); +- +- coord[0] += 1; +- +- vz = BaseT::mAcc.getValue(coord); +- coord[2] += 1; +- vz1 = BaseT::mAcc.getValue(coord); +- vy1 = lerp(vz, vz1, xyz[2]); +- +- coord[1] -= 1; +- +- vz1 = BaseT::mAcc.getValue(coord); +- coord[2] -= 1; +- vz = BaseT::mAcc.getValue(coord); +- vy = lerp(vz, vz1, xyz[2]); +- +- vx1 = lerp(vy, vy1, xyz[1]); +- +- return lerp(vx, vx1, xyz[0]); +-} +-#endif +- +- +-template +-template class Vec3T> +-__hostdev__ inline Vec3T SampleFromVoxels::gradient(Vec3T xyz) const +-{ +- ValueT val[2][2][2]; +- CoordT ijk = Floor(xyz); +- BaseT::stencil(ijk, val); +- return BaseT::gradient(xyz, val); +-} +- +-template +-template class Vec3T> +-__hostdev__ bool SampleFromVoxels::zeroCrossing(Vec3T xyz) const +-{ +- ValueT val[2][2][2]; +- CoordT ijk = Floor(xyz); +- BaseT::stencil(ijk, val); +- return BaseT::zeroCrossing(val); +-} +- +-// ------------------------------> TriquadraticSampler <-------------------------------------- +- +-/// @brief Tri-quadratic sampler, i.e. second order, interpolator +-template +-class TriquadraticSampler +-{ +-protected: +- const TreeOrAccT& mAcc; +- +-public: +- using ValueT = typename TreeOrAccT::ValueType; +- using CoordT = typename TreeOrAccT::CoordType; +- static const int ORDER = 1; +- +- /// @brief Protected constructor from a Tree or ReadAccessor +- __hostdev__ TriquadraticSampler(const TreeOrAccT& acc) : mAcc(acc) {} +- +- __hostdev__ const TreeOrAccT& accessor() const { return mAcc; } +- +- /// @brief Extract the stencil of 27 values +- inline __hostdev__ void stencil(const CoordT &ijk, ValueT (&v)[3][3][3]) const; +- +- template class Vec3T> +- static inline __hostdev__ ValueT sample(const Vec3T &uvw, const ValueT (&v)[3][3][3]); +- +- static inline __hostdev__ bool zeroCrossing(const ValueT (&v)[3][3][3]); +-}; // TriquadraticSamplerBase +- +-template +-__hostdev__ void TriquadraticSampler::stencil(const CoordT &ijk, ValueT (&v)[3][3][3]) const +-{ +- CoordT p(ijk[0] - 1, 0, 0); +- for (int dx = 0; dx < 3; ++dx, ++p[0]) { +- p[1] = ijk[1] - 1; +- for (int dy = 0; dy < 3; ++dy, ++p[1]) { +- p[2] = ijk[2] - 1; +- for (int dz = 0; dz < 3; ++dz, ++p[2]) { +- v[dx][dy][dz] = mAcc.getValue(p);// extract the stencil of 27 values +- } +- } +- } +-} +- +-template +-template class Vec3T> +-__hostdev__ typename TreeOrAccT::ValueType TriquadraticSampler::sample(const Vec3T &uvw, const ValueT (&v)[3][3][3]) +-{ +- auto kernel = [](const ValueT* value, double weight)->ValueT { +- return weight * (weight * (0.5f * (value[0] + value[2]) - value[1]) + +- 0.5f * (value[2] - value[0])) + value[1]; +- }; +- +- ValueT vx[3]; +- for (int dx = 0; dx < 3; ++dx) { +- ValueT vy[3]; +- for (int dy = 0; dy < 3; ++dy) { +- vy[dy] = kernel(&v[dx][dy][0], uvw[2]); +- }//loop over y +- vx[dx] = kernel(vy, uvw[1]); +- }//loop over x +- return kernel(vx, uvw[0]); +-} +- +-template +-__hostdev__ bool TriquadraticSampler::zeroCrossing(const ValueT (&v)[3][3][3]) +-{ +- static_assert(is_floating_point::value, "TrilinearSampler::zeroCrossing requires a floating-point type"); +- const bool less = v[0][0][0] < ValueT(0); +- for (int dx = 0; dx < 3; ++dx) { +- for (int dy = 0; dy < 3; ++dy) { +- for (int dz = 0; dz < 3; ++dz) { +- if (less ^ (v[dx][dy][dz] < ValueT(0))) return true; +- } +- } +- } +- return false; +-} +- +-/// @brief Template specialization that does not use caching of stencil points +-template +-class SampleFromVoxels : public TriquadraticSampler +-{ +- using BaseT = TriquadraticSampler; +- using ValueT = typename TreeOrAccT::ValueType; +- using CoordT = typename TreeOrAccT::CoordType; +-public: +- +- /// @brief Construction from a Tree or ReadAccessor +- __hostdev__ SampleFromVoxels(const TreeOrAccT& acc) : BaseT(acc) {} +- +- /// @note xyz is in index space space +- template class Vec3T> +- inline __hostdev__ ValueT operator()(Vec3T xyz) const; +- +- __hostdev__ ValueT operator()(const CoordT &ijk) const {return BaseT::mAcc.getValue(ijk);} +- +- /// @brief Return true if the tr-linear stencil has a zero crossing at the specified index position. +- /// +- /// @warning Will only compile with floating point value types +- template class Vec3T> +- inline __hostdev__ bool zeroCrossing(Vec3T xyz) const; +- +-}; // SampleFromVoxels +- +-/// @brief Template specialization with caching of stencil values +-template +-class SampleFromVoxels : public TriquadraticSampler +-{ +- using BaseT = TriquadraticSampler; +- using ValueT = typename TreeOrAccT::ValueType; +- using CoordT = typename TreeOrAccT::CoordType; +- +- mutable CoordT mPos; +- mutable ValueT mVal[3][3][3]; +- +- template class Vec3T> +- __hostdev__ void cache(Vec3T& xyz) const; +-public: +- +- /// @brief Construction from a Tree or ReadAccessor +- __hostdev__ SampleFromVoxels(const TreeOrAccT& acc) : BaseT(acc), mPos(CoordT::max()){} +- +- /// @note xyz is in index space space +- template class Vec3T> +- inline __hostdev__ ValueT operator()(Vec3T xyz) const; +- +- inline __hostdev__ ValueT operator()(const CoordT &ijk) const; +- +- /// @brief Return true if the tr-linear stencil has a zero crossing at the specified index position. +- /// +- /// @warning Will only compile with floating point value types +- template class Vec3T> +- inline __hostdev__ bool zeroCrossing(Vec3T xyz) const; +- +- /// @brief Return true if the cached tri-linear stencil has a zero crossing. +- /// +- /// @warning Will only compile with floating point value types +- __hostdev__ bool zeroCrossing() const { return BaseT::zeroCrossing(mVal); } +- +-}; // SampleFromVoxels +- +-template +-template class Vec3T> +-__hostdev__ typename TreeOrAccT::ValueType SampleFromVoxels::operator()(Vec3T xyz) const +-{ +- this->cache(xyz); +- return BaseT::sample(xyz, mVal); +-} +- +-template +-__hostdev__ typename TreeOrAccT::ValueType SampleFromVoxels::operator()(const CoordT &ijk) const +-{ +- return ijk == mPos ? mVal[1][1][1] : BaseT::mAcc.getValue(ijk); +-} +- +-template +-template class Vec3T> +-__hostdev__ bool SampleFromVoxels::zeroCrossing(Vec3T xyz) const +-{ +- this->cache(xyz); +- return BaseT::zeroCrossing(mVal); +-} +- +-template +-template class Vec3T> +-__hostdev__ void SampleFromVoxels::cache(Vec3T& xyz) const +-{ +- CoordT ijk = Floor(xyz); +- if (ijk != mPos) { +- mPos = ijk; +- BaseT::stencil(ijk, mVal); +- } +-} +- +-template +-template class Vec3T> +-__hostdev__ typename TreeOrAccT::ValueType SampleFromVoxels::operator()(Vec3T xyz) const +-{ +- ValueT val[3][3][3]; +- CoordT ijk = Floor(xyz); +- BaseT::stencil(ijk, val); +- return BaseT::sample(xyz, val); +-} +- +-template +-template class Vec3T> +-__hostdev__ bool SampleFromVoxels::zeroCrossing(Vec3T xyz) const +-{ +- ValueT val[3][3][3]; +- CoordT ijk = Floor(xyz); +- BaseT::stencil(ijk, val); +- return BaseT::zeroCrossing(val); +-} +- +-// ------------------------------> TricubicSampler <-------------------------------------- +- +-/// @brief Tri-cubic sampler, i.e. third order, interpolator. +-/// +-/// @details See the following paper for implementation details: +-/// Lekien, F. and Marsden, J.: Tricubic interpolation in three dimensions. +-/// In: International Journal for Numerical Methods +-/// in Engineering (2005), No. 63, p. 455-471 +- +-template +-class TricubicSampler +-{ +-protected: +- using ValueT = typename TreeOrAccT::ValueType; +- using CoordT = typename TreeOrAccT::CoordType; +- +- const TreeOrAccT& mAcc; +- +-public: +- /// @brief Construction from a Tree or ReadAccessor +- __hostdev__ TricubicSampler(const TreeOrAccT& acc) +- : mAcc(acc) +- { +- } +- +- __hostdev__ const TreeOrAccT& accessor() const { return mAcc; } +- +- /// @brief Extract the stencil of 8 values +- inline __hostdev__ void stencil(const CoordT& ijk, ValueT (&c)[64]) const; +- +- template class Vec3T> +- static inline __hostdev__ ValueT sample(const Vec3T &uvw, const ValueT (&c)[64]); +-}; // TricubicSampler +- +-template +-__hostdev__ void TricubicSampler::stencil(const CoordT& ijk, ValueT (&C)[64]) const +-{ +- auto fetch = [&](int i, int j, int k) -> ValueT& { return C[((i + 1) << 4) + ((j + 1) << 2) + k + 1]; }; +- +- // fetch 64 point stencil values +- for (int i = -1; i < 3; ++i) { +- for (int j = -1; j < 3; ++j) { +- fetch(i, j, -1) = mAcc.getValue(ijk + CoordT(i, j, -1)); +- fetch(i, j, 0) = mAcc.getValue(ijk + CoordT(i, j, 0)); +- fetch(i, j, 1) = mAcc.getValue(ijk + CoordT(i, j, 1)); +- fetch(i, j, 2) = mAcc.getValue(ijk + CoordT(i, j, 2)); +- } +- } +- const ValueT half(0.5), quarter(0.25), eighth(0.125); +- const ValueT X[64] = {// values of f(x,y,z) at the 8 corners (each from 1 stencil value). +- fetch(0, 0, 0), +- fetch(1, 0, 0), +- fetch(0, 1, 0), +- fetch(1, 1, 0), +- fetch(0, 0, 1), +- fetch(1, 0, 1), +- fetch(0, 1, 1), +- fetch(1, 1, 1), +- // values of df/dx at the 8 corners (each from 2 stencil values). +- half * (fetch(1, 0, 0) - fetch(-1, 0, 0)), +- half * (fetch(2, 0, 0) - fetch(0, 0, 0)), +- half * (fetch(1, 1, 0) - fetch(-1, 1, 0)), +- half * (fetch(2, 1, 0) - fetch(0, 1, 0)), +- half * (fetch(1, 0, 1) - fetch(-1, 0, 1)), +- half * (fetch(2, 0, 1) - fetch(0, 0, 1)), +- half * (fetch(1, 1, 1) - fetch(-1, 1, 1)), +- half * (fetch(2, 1, 1) - fetch(0, 1, 1)), +- // values of df/dy at the 8 corners (each from 2 stencil values). +- half * (fetch(0, 1, 0) - fetch(0, -1, 0)), +- half * (fetch(1, 1, 0) - fetch(1, -1, 0)), +- half * (fetch(0, 2, 0) - fetch(0, 0, 0)), +- half * (fetch(1, 2, 0) - fetch(1, 0, 0)), +- half * (fetch(0, 1, 1) - fetch(0, -1, 1)), +- half * (fetch(1, 1, 1) - fetch(1, -1, 1)), +- half * (fetch(0, 2, 1) - fetch(0, 0, 1)), +- half * (fetch(1, 2, 1) - fetch(1, 0, 1)), +- // values of df/dz at the 8 corners (each from 2 stencil values). +- half * (fetch(0, 0, 1) - fetch(0, 0, -1)), +- half * (fetch(1, 0, 1) - fetch(1, 0, -1)), +- half * (fetch(0, 1, 1) - fetch(0, 1, -1)), +- half * (fetch(1, 1, 1) - fetch(1, 1, -1)), +- half * (fetch(0, 0, 2) - fetch(0, 0, 0)), +- half * (fetch(1, 0, 2) - fetch(1, 0, 0)), +- half * (fetch(0, 1, 2) - fetch(0, 1, 0)), +- half * (fetch(1, 1, 2) - fetch(1, 1, 0)), +- // values of d2f/dxdy at the 8 corners (each from 4 stencil values). +- quarter * (fetch(1, 1, 0) - fetch(-1, 1, 0) - fetch(1, -1, 0) + fetch(-1, -1, 0)), +- quarter * (fetch(2, 1, 0) - fetch(0, 1, 0) - fetch(2, -1, 0) + fetch(0, -1, 0)), +- quarter * (fetch(1, 2, 0) - fetch(-1, 2, 0) - fetch(1, 0, 0) + fetch(-1, 0, 0)), +- quarter * (fetch(2, 2, 0) - fetch(0, 2, 0) - fetch(2, 0, 0) + fetch(0, 0, 0)), +- quarter * (fetch(1, 1, 1) - fetch(-1, 1, 1) - fetch(1, -1, 1) + fetch(-1, -1, 1)), +- quarter * (fetch(2, 1, 1) - fetch(0, 1, 1) - fetch(2, -1, 1) + fetch(0, -1, 1)), +- quarter * (fetch(1, 2, 1) - fetch(-1, 2, 1) - fetch(1, 0, 1) + fetch(-1, 0, 1)), +- quarter * (fetch(2, 2, 1) - fetch(0, 2, 1) - fetch(2, 0, 1) + fetch(0, 0, 1)), +- // values of d2f/dxdz at the 8 corners (each from 4 stencil values). +- quarter * (fetch(1, 0, 1) - fetch(-1, 0, 1) - fetch(1, 0, -1) + fetch(-1, 0, -1)), +- quarter * (fetch(2, 0, 1) - fetch(0, 0, 1) - fetch(2, 0, -1) + fetch(0, 0, -1)), +- quarter * (fetch(1, 1, 1) - fetch(-1, 1, 1) - fetch(1, 1, -1) + fetch(-1, 1, -1)), +- quarter * (fetch(2, 1, 1) - fetch(0, 1, 1) - fetch(2, 1, -1) + fetch(0, 1, -1)), +- quarter * (fetch(1, 0, 2) - fetch(-1, 0, 2) - fetch(1, 0, 0) + fetch(-1, 0, 0)), +- quarter * (fetch(2, 0, 2) - fetch(0, 0, 2) - fetch(2, 0, 0) + fetch(0, 0, 0)), +- quarter * (fetch(1, 1, 2) - fetch(-1, 1, 2) - fetch(1, 1, 0) + fetch(-1, 1, 0)), +- quarter * (fetch(2, 1, 2) - fetch(0, 1, 2) - fetch(2, 1, 0) + fetch(0, 1, 0)), +- // values of d2f/dydz at the 8 corners (each from 4 stencil values). +- quarter * (fetch(0, 1, 1) - fetch(0, -1, 1) - fetch(0, 1, -1) + fetch(0, -1, -1)), +- quarter * (fetch(1, 1, 1) - fetch(1, -1, 1) - fetch(1, 1, -1) + fetch(1, -1, -1)), +- quarter * (fetch(0, 2, 1) - fetch(0, 0, 1) - fetch(0, 2, -1) + fetch(0, 0, -1)), +- quarter * (fetch(1, 2, 1) - fetch(1, 0, 1) - fetch(1, 2, -1) + fetch(1, 0, -1)), +- quarter * (fetch(0, 1, 2) - fetch(0, -1, 2) - fetch(0, 1, 0) + fetch(0, -1, 0)), +- quarter * (fetch(1, 1, 2) - fetch(1, -1, 2) - fetch(1, 1, 0) + fetch(1, -1, 0)), +- quarter * (fetch(0, 2, 2) - fetch(0, 0, 2) - fetch(0, 2, 0) + fetch(0, 0, 0)), +- quarter * (fetch(1, 2, 2) - fetch(1, 0, 2) - fetch(1, 2, 0) + fetch(1, 0, 0)), +- // values of d3f/dxdydz at the 8 corners (each from 8 stencil values). +- eighth * (fetch(1, 1, 1) - fetch(-1, 1, 1) - fetch(1, -1, 1) + fetch(-1, -1, 1) - fetch(1, 1, -1) + fetch(-1, 1, -1) + fetch(1, -1, -1) - fetch(-1, -1, -1)), +- eighth * (fetch(2, 1, 1) - fetch(0, 1, 1) - fetch(2, -1, 1) + fetch(0, -1, 1) - fetch(2, 1, -1) + fetch(0, 1, -1) + fetch(2, -1, -1) - fetch(0, -1, -1)), +- eighth * (fetch(1, 2, 1) - fetch(-1, 2, 1) - fetch(1, 0, 1) + fetch(-1, 0, 1) - fetch(1, 2, -1) + fetch(-1, 2, -1) + fetch(1, 0, -1) - fetch(-1, 0, -1)), +- eighth * (fetch(2, 2, 1) - fetch(0, 2, 1) - fetch(2, 0, 1) + fetch(0, 0, 1) - fetch(2, 2, -1) + fetch(0, 2, -1) + fetch(2, 0, -1) - fetch(0, 0, -1)), +- eighth * (fetch(1, 1, 2) - fetch(-1, 1, 2) - fetch(1, -1, 2) + fetch(-1, -1, 2) - fetch(1, 1, 0) + fetch(-1, 1, 0) + fetch(1, -1, 0) - fetch(-1, -1, 0)), +- eighth * (fetch(2, 1, 2) - fetch(0, 1, 2) - fetch(2, -1, 2) + fetch(0, -1, 2) - fetch(2, 1, 0) + fetch(0, 1, 0) + fetch(2, -1, 0) - fetch(0, -1, 0)), +- eighth * (fetch(1, 2, 2) - fetch(-1, 2, 2) - fetch(1, 0, 2) + fetch(-1, 0, 2) - fetch(1, 2, 0) + fetch(-1, 2, 0) + fetch(1, 0, 0) - fetch(-1, 0, 0)), +- eighth * (fetch(2, 2, 2) - fetch(0, 2, 2) - fetch(2, 0, 2) + fetch(0, 0, 2) - fetch(2, 2, 0) + fetch(0, 2, 0) + fetch(2, 0, 0) - fetch(0, 0, 0))}; +- +- // 4Kb of static table (int8_t has a range of -127 -> 127 which suffices) +- static const int8_t A[64][64] = { +- {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {-3, 3, 0, 0, 0, 0, 0, 0, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {2, -2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {9, -9, -9, 9, 0, 0, 0, 0, 6, 3, -6, -3, 0, 0, 0, 0, 6, -6, 3, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {-6, 6, 6, -6, 0, 0, 0, 0, -3, -3, 3, 3, 0, 0, 0, 0, -4, 4, -2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {-6, 6, 6, -6, 0, 0, 0, 0, -4, -2, 4, 2, 0, 0, 0, 0, -3, 3, -3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {4, -4, -4, 4, 0, 0, 0, 0, 2, 2, -2, -2, 0, 0, 0, 0, 2, -2, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0, -2, -1, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, -9, -9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3, -6, -3, 0, 0, 0, 0, 6, -6, 3, -3, 0, 0, 0, 0, 4, 2, 2, 1, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 6, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, -3, 3, 3, 0, 0, 0, 0, -4, 4, -2, 2, 0, 0, 0, 0, -2, -2, -1, -1, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 6, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, -2, 4, 2, 0, 0, 0, 0, -3, 3, -3, 3, 0, 0, 0, 0, -2, -1, -2, -1, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, -4, -4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, -2, -2, 0, 0, 0, 0, 2, -2, 2, -2, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0}, +- {-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {9, -9, 0, 0, -9, 9, 0, 0, 6, 3, 0, 0, -6, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, -6, 0, 0, 3, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {-6, 6, 0, 0, 6, -6, 0, 0, -3, -3, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 4, 0, 0, -2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -2, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, -1, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, -9, 0, 0, -9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3, 0, 0, -6, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, -6, 0, 0, 3, -3, 0, 0, 4, 2, 0, 0, 2, 1, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 6, 0, 0, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, -3, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 4, 0, 0, -2, 2, 0, 0, -2, -2, 0, 0, -1, -1, 0, 0}, +- {9, 0, -9, 0, -9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, 0, -6, 0, -3, 0, 6, 0, -6, 0, 3, 0, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 9, 0, -9, 0, -9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, 0, -6, 0, -3, 0, 6, 0, -6, 0, 3, 0, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 0, 2, 0, 1, 0}, +- {-27, 27, 27, -27, 27, -27, -27, 27, -18, -9, 18, 9, 18, 9, -18, -9, -18, 18, -9, 9, 18, -18, 9, -9, -18, 18, 18, -18, -9, 9, 9, -9, -12, -6, -6, -3, 12, 6, 6, 3, -12, -6, 12, 6, -6, -3, 6, 3, -12, 12, -6, 6, -6, 6, -3, 3, -8, -4, -4, -2, -4, -2, -2, -1}, +- {18, -18, -18, 18, -18, 18, 18, -18, 9, 9, -9, -9, -9, -9, 9, 9, 12, -12, 6, -6, -12, 12, -6, 6, 12, -12, -12, 12, 6, -6, -6, 6, 6, 6, 3, 3, -6, -6, -3, -3, 6, 6, -6, -6, 3, 3, -3, -3, 8, -8, 4, -4, 4, -4, 2, -2, 4, 4, 2, 2, 2, 2, 1, 1}, +- {-6, 0, 6, 0, 6, 0, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, -3, 0, 3, 0, 3, 0, -4, 0, 4, 0, -2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -2, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, -6, 0, 6, 0, 6, 0, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, -3, 0, 3, 0, 3, 0, -4, 0, 4, 0, -2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -2, 0, -1, 0, -1, 0}, +- {18, -18, -18, 18, -18, 18, 18, -18, 12, 6, -12, -6, -12, -6, 12, 6, 9, -9, 9, -9, -9, 9, -9, 9, 12, -12, -12, 12, 6, -6, -6, 6, 6, 3, 6, 3, -6, -3, -6, -3, 8, 4, -8, -4, 4, 2, -4, -2, 6, -6, 6, -6, 3, -3, 3, -3, 4, 2, 4, 2, 2, 1, 2, 1}, +- {-12, 12, 12, -12, 12, -12, -12, 12, -6, -6, 6, 6, 6, 6, -6, -6, -6, 6, -6, 6, 6, -6, 6, -6, -8, 8, 8, -8, -4, 4, 4, -4, -3, -3, -3, -3, 3, 3, 3, 3, -4, -4, 4, 4, -2, -2, 2, 2, -4, 4, -4, 4, -2, 2, -2, 2, -2, -2, -2, -2, -1, -1, -1, -1}, +- {2, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {-6, 6, 0, 0, 6, -6, 0, 0, -4, -2, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, 0, 0, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {4, -4, 0, 0, -4, 4, 0, 0, 2, 2, 0, 0, -2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 6, 0, 0, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, -2, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, -3, 3, 0, 0, -2, -1, 0, 0, -2, -1, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, -4, 0, 0, -4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, -2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 2, -2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0}, +- {-6, 0, 6, 0, 6, 0, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 0, -2, 0, 4, 0, 2, 0, -3, 0, 3, 0, -3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, 0, -2, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, -6, 0, 6, 0, 6, 0, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 0, -2, 0, 4, 0, 2, 0, -3, 0, 3, 0, -3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, 0, -2, 0, -1, 0}, +- {18, -18, -18, 18, -18, 18, 18, -18, 12, 6, -12, -6, -12, -6, 12, 6, 12, -12, 6, -6, -12, 12, -6, 6, 9, -9, -9, 9, 9, -9, -9, 9, 8, 4, 4, 2, -8, -4, -4, -2, 6, 3, -6, -3, 6, 3, -6, -3, 6, -6, 3, -3, 6, -6, 3, -3, 4, 2, 2, 1, 4, 2, 2, 1}, +- {-12, 12, 12, -12, 12, -12, -12, 12, -6, -6, 6, 6, 6, 6, -6, -6, -8, 8, -4, 4, 8, -8, 4, -4, -6, 6, 6, -6, -6, 6, 6, -6, -4, -4, -2, -2, 4, 4, 2, 2, -3, -3, 3, 3, -3, -3, 3, 3, -4, 4, -2, 2, -4, 4, -2, 2, -2, -2, -1, -1, -2, -2, -1, -1}, +- {4, 0, -4, 0, -4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, -2, 0, -2, 0, 2, 0, -2, 0, 2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +- {0, 0, 0, 0, 0, 0, 0, 0, 4, 0, -4, 0, -4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, -2, 0, -2, 0, 2, 0, -2, 0, 2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0}, +- {-12, 12, 12, -12, 12, -12, -12, 12, -8, -4, 8, 4, 8, 4, -8, -4, -6, 6, -6, 6, 6, -6, 6, -6, -6, 6, 6, -6, -6, 6, 6, -6, -4, -2, -4, -2, 4, 2, 4, 2, -4, -2, 4, 2, -4, -2, 4, 2, -3, 3, -3, 3, -3, 3, -3, 3, -2, -1, -2, -1, -2, -1, -2, -1}, +- {8, -8, -8, 8, -8, 8, 8, -8, 4, 4, -4, -4, -4, -4, 4, 4, 4, -4, 4, -4, -4, 4, -4, 4, 4, -4, -4, 4, 4, -4, -4, 4, 2, 2, 2, 2, -2, -2, -2, -2, 2, 2, -2, -2, 2, 2, -2, -2, 2, -2, 2, -2, 2, -2, 2, -2, 1, 1, 1, 1, 1, 1, 1, 1}}; +- +- for (int i = 0; i < 64; ++i) { // C = A * X +- C[i] = ValueT(0); +-#if 0 +- for (int j = 0; j < 64; j += 4) { +- C[i] = fma(A[i][j], X[j], fma(A[i][j+1], X[j+1], fma(A[i][j+2], X[j+2], fma(A[i][j+3], X[j+3], C[i])))); +- } +-#else +- for (int j = 0; j < 64; j += 4) { +- C[i] += A[i][j] * X[j] + A[i][j + 1] * X[j + 1] + A[i][j + 2] * X[j + 2] + A[i][j + 3] * X[j + 3]; +- } +-#endif +- } +-} +- +-template +-template class Vec3T> +-__hostdev__ typename TreeOrAccT::ValueType TricubicSampler::sample(const Vec3T &xyz, const ValueT (&C)[64]) +-{ +- ValueT zPow(1), sum(0); +- for (int k = 0, n = 0; k < 4; ++k) { +- ValueT yPow(1); +- for (int j = 0; j < 4; ++j, n += 4) { +-#if 0 +- sum = fma( yPow, zPow * fma(xyz[0], fma(xyz[0], fma(xyz[0], C[n + 3], C[n + 2]), C[n + 1]), C[n]), sum); +-#else +- sum += yPow * zPow * (C[n] + xyz[0] * (C[n + 1] + xyz[0] * (C[n + 2] + xyz[0] * C[n + 3]))); +-#endif +- yPow *= xyz[1]; +- } +- zPow *= xyz[2]; +- } +- return sum; +-} +- +-template +-class SampleFromVoxels : public TricubicSampler +-{ +- using BaseT = TricubicSampler; +- using ValueT = typename TreeOrAccT::ValueType; +- using CoordT = typename TreeOrAccT::CoordType; +- +- mutable CoordT mPos; +- mutable ValueT mC[64]; +- +- template class Vec3T> +- __hostdev__ void cache(Vec3T& xyz) const; +- +-public: +- /// @brief Construction from a Tree or ReadAccessor +- __hostdev__ SampleFromVoxels(const TreeOrAccT& acc) +- : BaseT(acc) +- { +- } +- +- /// @note xyz is in index space space +- template class Vec3T> +- inline __hostdev__ ValueT operator()(Vec3T xyz) const; +- +- // @brief Return value at the coordinate @a ijk in index space space +- __hostdev__ ValueT operator()(const CoordT &ijk) const {return BaseT::mAcc.getValue(ijk);} +- +-}; // SampleFromVoxels +- +-template +-template class Vec3T> +-__hostdev__ typename TreeOrAccT::ValueType SampleFromVoxels::operator()(Vec3T xyz) const +-{ +- this->cache(xyz); +- return BaseT::sample(xyz, mC); +-} +- +-template +-template class Vec3T> +-__hostdev__ void SampleFromVoxels::cache(Vec3T& xyz) const +-{ +- CoordT ijk = Floor(xyz); +- if (ijk != mPos) { +- mPos = ijk; +- BaseT::stencil(ijk, mC); +- } +-} +- +-template +-class SampleFromVoxels : public TricubicSampler +-{ +- using BaseT = TricubicSampler; +- using ValueT = typename TreeOrAccT::ValueType; +- using CoordT = typename TreeOrAccT::CoordType; +- +-public: +- /// @brief Construction from a Tree or ReadAccessor +- __hostdev__ SampleFromVoxels(const TreeOrAccT& acc) +- : BaseT(acc) +- { +- } +- +- /// @note xyz is in index space space +- template class Vec3T> +- inline __hostdev__ ValueT operator()(Vec3T xyz) const; +- +- __hostdev__ ValueT operator()(const CoordT &ijk) const {return BaseT::mAcc.getValue(ijk);} +- +-}; // SampleFromVoxels +- +-template +-template class Vec3T> +-__hostdev__ typename TreeOrAccT::ValueType SampleFromVoxels::operator()(Vec3T xyz) const +-{ +- ValueT C[64]; +- CoordT ijk = Floor(xyz); +- BaseT::stencil(ijk, C); +- return BaseT::sample(xyz, C); +-} +- +-} // namespace nanovdb +- +-#endif // NANOVDB_SAMPLE_FROM_VOXELS_H_HAS_BEEN_INCLUDED ++// SampleFromVoxels.h ++// Copyright Contributors to the OpenVDB Project ++// SPDX-License-Identifier: MPL-2.0 ++ ++////////////////////////////////////////////////////////////////////////// ++/// ++/// @file SampleFromVoxels.h ++/// ++/// @brief NearestNeighborSampler, TrilinearSampler, TriquadraticSampler and TricubicSampler ++/// ++/// @note These interpolators employ internal caching for better performance when used repeatedly ++/// in the same voxel location, so try to reuse an instance of these classes more than once. ++/// ++/// @warning While all the interpolators defined below work with both scalars and vectors ++/// values (e.g. float and Vec3) TrilinarSampler::zeroCrossing and ++/// Trilinear::gradient will only compile with floating point value types. ++/// ++/// @author Ken Museth ++/// ++/////////////////////////////////////////////////////////////////////////// ++ ++#ifndef NANOVDB_SAMPLE_FROM_VOXELS_H_HAS_BEEN_INCLUDED ++#define NANOVDB_SAMPLE_FROM_VOXELS_H_HAS_BEEN_INCLUDED ++ ++// Only define __hostdev__ when compiling as NVIDIA CUDA ++#ifdef __CUDACC__ ++#define __hostdev__ __host__ __device__ ++#elif defined(__KERNEL_METAL__) ++#else ++#include // for floor ++#define __hostdev__ ++#endif ++ ++namespace nanovdb { ++ ++// Forward declaration of sampler with specific polynomial orders ++template ++class SampleFromVoxels; ++ ++/// @brief Factory free-function for a sampler of specific polynomial orders ++/// ++/// @details This allows for the compact syntax: ++/// @code ++/// auto acc = grid.getAccessor(); ++/// auto smp = nanovdb::createSampler<1>( acc ); ++/// @endcode ++template ++__hostdev__ SampleFromVoxels createSampler(__global__ const TreeOrAccT& acc) ++{ ++ return SampleFromVoxels(acc); ++} ++ ++/// @brief Utility function that returns the Coord of the round-down of @a xyz ++/// and redefined @xyz as the fractional part, ie xyz-in = return-value + xyz-out ++template class Vec3T> ++__hostdev__ inline CoordT Floor(__global__ Vec3T& xyz); ++ ++/// @brief Template specialization of Floor for Vec3 ++template class Vec3T> ++__hostdev__ inline CoordT Floor(__global__ Vec3T& xyz) ++{ ++ const float ijk[3] = {floorf(xyz[0]), floorf(xyz[1]), floorf(xyz[2])}; ++ xyz[0] -= ijk[0]; ++ xyz[1] -= ijk[1]; ++ xyz[2] -= ijk[2]; ++ return CoordT(int32_t(ijk[0]), int32_t(ijk[1]), int32_t(ijk[2])); ++} ++ ++/// @brief Template specialization of Floor for Vec3 ++template class Vec3T> ++__hostdev__ inline CoordT Floor(__global__ Vec3T& xyz) ++{ ++ const double ijk[3] = {floor(xyz[0]), floor(xyz[1]), floor(xyz[2])}; ++ xyz[0] -= ijk[0]; ++ xyz[1] -= ijk[1]; ++ xyz[2] -= ijk[2]; ++ return CoordT(int32_t(ijk[0]), int32_t(ijk[1]), int32_t(ijk[2])); ++} ++ ++#if defined(__KERNEL_METAL__) ++/// @brief Template specialization of Floor for Vec3 ++template class Vec3T> ++__hostdev__ inline CoordT Floor(__local__ Vec3T& xyz) ++{ ++ const float ijk[3] = {floorf(xyz[0]), floorf(xyz[1]), floorf(xyz[2])}; ++ xyz[0] -= ijk[0]; ++ xyz[1] -= ijk[1]; ++ xyz[2] -= ijk[2]; ++ return CoordT(int32_t(ijk[0]), int32_t(ijk[1]), int32_t(ijk[2])); ++} ++ ++/// @brief Template specialization of Floor for Vec3 ++template class Vec3T> ++__hostdev__ inline CoordT Floor(__local__ Vec3T& xyz) ++{ ++ const double ijk[3] = {floor(xyz[0]), floor(xyz[1]), floor(xyz[2])}; ++ xyz[0] -= ijk[0]; ++ xyz[1] -= ijk[1]; ++ xyz[2] -= ijk[2]; ++ return CoordT(int32_t(ijk[0]), int32_t(ijk[1]), int32_t(ijk[2])); ++} ++#endif ++ ++// ------------------------------> NearestNeighborSampler <-------------------------------------- ++ ++/// @brief Nearest neighbor, i.e. zero order, interpolator with caching ++template ++class SampleFromVoxels ++{ ++public: ++ using ValueT = typename TreeOrAccT::ValueType; ++ using CoordT = typename TreeOrAccT::CoordType; ++ ++ static __constant__ const int ORDER = 0; ++ /// @brief Construction from a Tree or ReadAccessor ++ __hostdev__ SampleFromVoxels(__local__ const TreeOrAccT& acc) ++ : mAcc(acc) ++ , mPos(CoordT::max()) ++ { ++ } ++ ++ __hostdev__ __global__ const TreeOrAccT& accessor() const { return mAcc; } ++ ++ /// @note xyz is in index space space ++ template ++ inline __hostdev__ ValueT operator()(__global__ const Vec3T& xyz) const __local__; ++#if defined(__KERNEL_METAL__) ++ template ++ inline __hostdev__ ValueT operator()(__local__ const Vec3T& xyz) const __local__; ++#endif ++ ++ inline __hostdev__ ValueT operator()(__global__ const CoordT& ijk) const __local__; ++ ++ inline __hostdev__ ValueT operator()() const; ++ ++private: ++ __global__ const TreeOrAccT& mAcc; ++ mutable CoordT mPos; ++ mutable ValueT mVal; // private cache ++}; // SampleFromVoxels ++ ++/// @brief Nearest neighbor, i.e. zero order, interpolator without caching ++template ++class SampleFromVoxels ++{ ++public: ++ using ValueT = typename TreeOrAccT::ValueType; ++ using CoordT = typename TreeOrAccT::CoordType; ++ static __constant__ const int ORDER = 0; ++ ++ /// @brief Construction from a Tree or ReadAccessor ++ __hostdev__ SampleFromVoxels(__local__ const TreeOrAccT& acc) ++ : mAcc(acc) ++ { ++ } ++ ++ __hostdev__ __global__ const TreeOrAccT& accessor() const __local__ { return mAcc; } ++ ++ /// @note xyz is in index space space ++ template ++ inline __hostdev__ ValueT operator()(__global__ const Vec3T& xyz) const __local__; ++#if defined(__KERNEL_METAL__) ++ template ++ inline __hostdev__ ValueT operator()(__local__ const Vec3T& xyz) const __local__; ++#endif ++ ++ inline __hostdev__ ValueT operator()(__global__ const CoordT& ijk) const __local__ { return mAcc.getValue(ijk);} ++ ++private: ++ __local__ const TreeOrAccT& mAcc; ++}; // SampleFromVoxels ++ ++template ++template ++typename TreeOrAccT::ValueType SampleFromVoxels::operator()(__global__ const Vec3T& xyz) const __local__ ++{ ++ const CoordT ijk = Round(xyz); ++ if (ijk != mPos) { ++ mPos = ijk; ++ mVal = mAcc.getValue(mPos); ++ } ++ return mVal; ++} ++#if defined(__KERNEL_METAL__) ++template ++template ++typename TreeOrAccT::ValueType SampleFromVoxels::operator()(__local__ const Vec3T& xyz) const __local__ ++{ ++ const CoordT ijk = Round(xyz); ++ if (ijk != mPos) { ++ mPos = ijk; ++ mVal = mAcc.getValue(mPos); ++ } ++ return mVal; ++} ++#endif ++ ++template ++typename TreeOrAccT::ValueType SampleFromVoxels::operator()(__global__ const CoordT& ijk) const __local__ ++{ ++ if (ijk != mPos) { ++ mPos = ijk; ++ mVal = mAcc.getValue(mPos); ++ } ++ return mVal; ++} ++ ++template ++template ++typename TreeOrAccT::ValueType SampleFromVoxels::operator()(__global__ const Vec3T& xyz) const __local__ ++{ ++ return mAcc.getValue(Round(xyz)); ++} ++ ++#if defined(__KERNEL_METAL__) ++template ++template ++typename TreeOrAccT::ValueType SampleFromVoxels::operator()(__local__ const Vec3T& xyz) const __local__ ++{ ++ return mAcc.getValue(Round(xyz)); ++} ++#endif ++ ++// ------------------------------> TrilinearSampler <-------------------------------------- ++ ++/// @brief Tri-linear sampler, i.e. first order, interpolator ++template ++class TrilinearSampler ++{ ++#if defined(__KERNEL_METAL__) ++public: ++#else ++protected: ++#endif ++ __local__ const TreeOrAccT& mAcc; ++ ++public: ++ using ValueT = typename TreeOrAccT::ValueType; ++ using CoordT = typename TreeOrAccT::CoordType; ++ static __constant__ const int ORDER = 1; ++ ++ /// @brief Protected constructor from a Tree or ReadAccessor ++ __hostdev__ TrilinearSampler(__local__ const TreeOrAccT& acc) : mAcc(acc) {} ++ ++ __hostdev__ __global__ const TreeOrAccT& accessor() const { return mAcc; } ++ ++ /// @brief Extract the stencil of 8 values ++ inline __hostdev__ void stencil(__global__ CoordT& ijk, __global__ ValueT (&v)[2][2][2]) const; ++ ++ template class Vec3T> ++ static inline __hostdev__ ValueT sample(__global__ const Vec3T &uvw, __global__ const ValueT (&v)[2][2][2]); ++ ++ template class Vec3T> ++ static inline __hostdev__ Vec3T gradient(__global__ const Vec3T &uvw, __global__ const ValueT (&v)[2][2][2]); ++ ++ static inline __hostdev__ bool zeroCrossing(__global__ const ValueT (&v)[2][2][2]); ++}; // TrilinearSamplerBase ++ ++template ++void TrilinearSampler::stencil(__global__ CoordT& ijk, __global__ ValueT (&v)[2][2][2]) const ++{ ++ v[0][0][0] = mAcc.getValue(ijk); // i, j, k ++ ++ ijk[2] += 1; ++ v[0][0][1] = mAcc.getValue(ijk); // i, j, k + 1 ++ ++ ijk[1] += 1; ++ v[0][1][1] = mAcc.getValue(ijk); // i, j+1, k + 1 ++ ++ ijk[2] -= 1; ++ v[0][1][0] = mAcc.getValue(ijk); // i, j+1, k ++ ++ ijk[0] += 1; ++ ijk[1] -= 1; ++ v[1][0][0] = mAcc.getValue(ijk); // i+1, j, k ++ ++ ijk[2] += 1; ++ v[1][0][1] = mAcc.getValue(ijk); // i+1, j, k + 1 ++ ++ ijk[1] += 1; ++ v[1][1][1] = mAcc.getValue(ijk); // i+1, j+1, k + 1 ++ ++ ijk[2] -= 1; ++ v[1][1][0] = mAcc.getValue(ijk); // i+1, j+1, k ++} ++ ++template ++template class Vec3T> ++typename TreeOrAccT::ValueType TrilinearSampler::sample(__global__ const Vec3T &uvw, __global__ const ValueT (&v)[2][2][2]) ++{ ++#if 0 ++ auto lerp = [](ValueT a, ValueT b, ValueT w){ return fma(w, b-a, a); };// = w*(b-a) + a ++ //auto lerp = [](ValueT a, ValueT b, ValueT w){ return fma(w, b, fma(-w, a, a));};// = (1-w)*a + w*b ++#else ++ struct Lerp { ++ static ValueT lerp(ValueT a, ValueT b, RealT w) { return a + ValueT(w) * (b - a); } ++ }; ++#endif ++ return Lerp::lerp(Lerp::lerp(Lerp::lerp(v[0][0][0], v[0][0][1], uvw[2]), Lerp::lerp(v[0][1][0], v[0][1][1], uvw[2]), uvw[1]), ++ Lerp::lerp(Lerp::lerp(v[1][0][0], v[1][0][1], uvw[2]), Lerp::lerp(v[1][1][0], v[1][1][1], uvw[2]), uvw[1]), ++ uvw[0]); ++} ++ ++template ++template class Vec3T> ++Vec3T TrilinearSampler::gradient(__global__ const Vec3T &uvw, __global__ const ValueT (&v)[2][2][2]) ++{ ++ static_assert(is_floating_point::value, "TrilinearSampler::gradient requires a floating-point type"); ++#if 0 ++ auto lerp = [](ValueT a, ValueT b, ValueT w){ return fma(w, b-a, a); };// = w*(b-a) + a ++ //auto lerp = [](ValueT a, ValueT b, ValueT w){ return fma(w, b, fma(-w, a, a));};// = (1-w)*a + w*b ++#else ++ struct Lerp { ++ static ValueT lerp(ValueT a, ValueT b, RealT w) { return a + ValueT(w) * (b - a); } ++ }; ++#endif ++ ++ ValueT D[4] = {v[0][0][1] - v[0][0][0], v[0][1][1] - v[0][1][0], v[1][0][1] - v[1][0][0], v[1][1][1] - v[1][1][0]}; ++ ++ // Z component ++ Vec3T grad(0, 0, Lerp::lerp(Lerp::lerp(D[0], D[1], uvw[1]), lerp(D[2], D[3], uvw[1]), uvw[0])); ++ ++ const ValueT w = ValueT(uvw[2]); ++ D[0] = v[0][0][0] + D[0] * w; ++ D[1] = v[0][1][0] + D[1] * w; ++ D[2] = v[1][0][0] + D[2] * w; ++ D[3] = v[1][1][0] + D[3] * w; ++ ++ // X component ++ grad[0] = Lerp::lerp(D[2], D[3], uvw[1]) - Lerp::lerp(D[0], D[1], uvw[1]); ++ ++ // Y component ++ grad[1] = Lerp::lerp(D[1] - D[0], D[3] - D[2], uvw[0]); ++ ++ return grad; ++} ++ ++template ++bool TrilinearSampler::zeroCrossing(__global__ const ValueT (&v)[2][2][2]) ++{ ++ static_assert(is_floating_point::value, "TrilinearSampler::zeroCrossing requires a floating-point type"); ++ const bool less = v[0][0][0] < ValueT(0); ++ return (less ^ (v[0][0][1] < ValueT(0))) || ++ (less ^ (v[0][1][1] < ValueT(0))) || ++ (less ^ (v[0][1][0] < ValueT(0))) || ++ (less ^ (v[1][0][0] < ValueT(0))) || ++ (less ^ (v[1][0][1] < ValueT(0))) || ++ (less ^ (v[1][1][1] < ValueT(0))) || ++ (less ^ (v[1][1][0] < ValueT(0))); ++} ++ ++/// @brief Template specialization that does not use caching of stencil points ++template ++class SampleFromVoxels ++#if !defined(__KERNEL_METAL__) ++ : public TrilinearSampler ++#endif ++{ ++#if defined(__KERNEL_METAL__) ++ ++ TrilinearSampler _base; ++#define BASE(v) _base.v ++#else ++#define BASE(v) BaseT::v ++ ++#endif ++ using BaseT = TrilinearSampler; ++ using ValueT = typename TreeOrAccT::ValueType; ++ using CoordT = typename TreeOrAccT::CoordType; ++ ++public: ++ ++ /// @brief Construction from a Tree or ReadAccessor ++#if defined(__KERNEL_METAL__) ++ __hostdev__ SampleFromVoxels(__local__ const TreeOrAccT& acc) : _base(acc) {} ++#else ++ __hostdev__ SampleFromVoxels(__local__ const TreeOrAccT& acc) : BaseT(acc) {} ++#endif ++ ++ /// @note xyz is in index space space ++ template class Vec3T> ++ inline __hostdev__ ValueT operator()(Vec3T xyz) const; ++ ++ /// @note ijk is in index space space ++ __hostdev__ ValueT operator()(__global__ const CoordT &ijk) const {return BaseT::mAcc.getValue(ijk);} ++ ++ /// @brief Return the gradient in index space. ++ /// ++ /// @warning Will only compile with floating point value types ++ template class Vec3T> ++ inline __hostdev__ Vec3T gradient(Vec3T xyz) const; ++ ++ /// @brief Return true if the tr-linear stencil has a zero crossing at the specified index position. ++ /// ++ /// @warning Will only compile with floating point value types ++ template class Vec3T> ++ inline __hostdev__ bool zeroCrossing(Vec3T xyz) const; ++ ++}; // SampleFromVoxels ++ ++/// @brief Template specialization with caching of stencil values ++template ++class SampleFromVoxels ++#if !defined(__KERNEL_METAL__) ++ : public TrilinearSampler ++#endif ++{ ++#if defined(__KERNEL_METAL__) ++ TrilinearSampler _base; ++#endif ++ using BaseT = TrilinearSampler; ++ using ValueT = typename TreeOrAccT::ValueType; ++ using CoordT = typename TreeOrAccT::CoordType; ++ ++ mutable CoordT mPos; ++ mutable ValueT mVal[2][2][2]; ++ ++ template class Vec3T> ++ __hostdev__ void cache(__global__ Vec3T& xyz) const; ++public: ++ ++ /// @brief Construction from a Tree or ReadAccessor ++ __hostdev__ SampleFromVoxels(__local__ const TreeOrAccT& acc) : BaseT(acc), mPos(CoordT::max()){} ++ ++ /// @note xyz is in index space space ++ template class Vec3T> ++ inline __hostdev__ ValueT operator()(Vec3T xyz) const; ++ ++ // @note ijk is in index space space ++ __hostdev__ ValueT operator()(__global__ const CoordT &ijk) const; ++ ++ /// @brief Return the gradient in index space. ++ /// ++ /// @warning Will only compile with floating point value types ++ template class Vec3T> ++ inline __hostdev__ Vec3T gradient(Vec3T xyz) const; ++ ++ /// @brief Return true if the tr-linear stencil has a zero crossing at the specified index position. ++ /// ++ /// @warning Will only compile with floating point value types ++ template class Vec3T> ++ inline __hostdev__ bool zeroCrossing(Vec3T xyz) const; ++ ++ /// @brief Return true if the cached tri-linear stencil has a zero crossing. ++ /// ++ /// @warning Will only compile with floating point value types ++ __hostdev__ bool zeroCrossing() const { return BaseT::zeroCrossing(mVal); } ++ ++}; // SampleFromVoxels ++ ++template ++template class Vec3T> ++typename TreeOrAccT::ValueType SampleFromVoxels::operator()(Vec3T xyz) const ++{ ++ this->cache(xyz); ++ return BaseT::sample(xyz, mVal); ++} ++ ++template ++typename TreeOrAccT::ValueType SampleFromVoxels::operator()(__global__ const CoordT &ijk) const ++{ ++ return ijk == mPos ? mVal[0][0][0] : BaseT::mAcc.getValue(ijk); ++} ++ ++template ++template class Vec3T> ++Vec3T SampleFromVoxels::gradient(Vec3T xyz) const ++{ ++ this->cache(xyz); ++ return BaseT::gradient(xyz, mVal); ++} ++ ++template ++template class Vec3T> ++__hostdev__ bool SampleFromVoxels::zeroCrossing(Vec3T xyz) const ++{ ++ this->cache(xyz); ++ return BaseT::zeroCrossing(mVal); ++} ++ ++template ++template class Vec3T> ++void SampleFromVoxels::cache(__global__ Vec3T& xyz) const ++{ ++ CoordT ijk = Floor(xyz); ++ if (ijk != mPos) { ++ mPos = ijk; ++ BaseT::stencil(ijk, mVal); ++ } ++} ++ ++#if 0 ++ ++template ++template class Vec3T> ++typename TreeOrAccT::ValueType SampleFromVoxels::operator()(Vec3T xyz) const ++{ ++ ValueT val[2][2][2]; ++ CoordT ijk = Floor(xyz); ++ BaseT::stencil(ijk, val); ++ return BaseT::sample(xyz, val); ++} ++ ++#else ++ ++template ++template class Vec3T> ++typename TreeOrAccT::ValueType SampleFromVoxels::operator()(Vec3T xyz) const ++{ ++ struct Lerp { ++ static ValueT lerp(ValueT a, ValueT b, RealT w) { return a + ValueT(w) * (b - a); } ++ }; ++ ++ CoordT coord = Floor(xyz); ++ ++ ValueT vx, vx1, vy, vy1, vz, vz1; ++ ++ vz = BASE(mAcc).getValue(coord); ++ coord[2] += 1; ++ vz1 = BASE(mAcc).getValue(coord); ++ vy = Lerp::lerp(vz, vz1, xyz[2]); ++ ++ coord[1] += 1; ++ ++ vz1 = BASE(mAcc).getValue(coord); ++ coord[2] -= 1; ++ vz = BASE(mAcc).getValue(coord); ++ vy1 = Lerp::lerp(vz, vz1, xyz[2]); ++ ++ vx = Lerp::lerp(vy, vy1, xyz[1]); ++ ++ coord[0] += 1; ++ ++ vz = BASE(mAcc).getValue(coord); ++ coord[2] += 1; ++ vz1 = BASE(mAcc).getValue(coord); ++ vy1 = Lerp::lerp(vz, vz1, xyz[2]); ++ ++ coord[1] -= 1; ++ ++ vz1 = BASE(mAcc).getValue(coord); ++ coord[2] -= 1; ++ vz = BASE(mAcc).getValue(coord); ++ vy = Lerp::lerp(vz, vz1, xyz[2]); ++ ++ vx1 = Lerp::lerp(vy, vy1, xyz[1]); ++ ++ return Lerp::lerp(vx, vx1, xyz[0]); ++} ++#endif ++ ++ ++template ++template class Vec3T> ++inline Vec3T SampleFromVoxels::gradient(Vec3T xyz) const ++{ ++ ValueT val[2][2][2]; ++ CoordT ijk = Floor(xyz); ++ BaseT::stencil(ijk, val); ++ return BaseT::gradient(xyz, val); ++} ++ ++template ++template class Vec3T> ++bool SampleFromVoxels::zeroCrossing(Vec3T xyz) const ++{ ++ ValueT val[2][2][2]; ++ CoordT ijk = Floor(xyz); ++ BaseT::stencil(ijk, val); ++ return BaseT::zeroCrossing(val); ++} ++ ++// ------------------------------> TriquadraticSampler <-------------------------------------- ++ ++/// @brief Tri-quadratic sampler, i.e. second order, interpolator ++template ++class TriquadraticSampler ++{ ++protected: ++ __local__ const TreeOrAccT& mAcc; ++ ++public: ++ using ValueT = typename TreeOrAccT::ValueType; ++ using CoordT = typename TreeOrAccT::CoordType; ++ static __constant__ const int ORDER = 1; ++ ++ /// @brief Protected constructor from a Tree or ReadAccessor ++ __hostdev__ TriquadraticSampler(__local__ const TreeOrAccT& acc) : mAcc(acc) {} ++ ++ __hostdev__ __global__ const TreeOrAccT& accessor() const { return mAcc; } ++ ++ /// @brief Extract the stencil of 27 values ++ inline __hostdev__ void stencil(__local__ const CoordT &ijk, __local__ ValueT (&v)[3][3][3]) const; ++ ++ template class Vec3T> ++ static inline __hostdev__ ValueT sample(__local__ const Vec3T &uvw, __local__ const ValueT (&v)[3][3][3]); ++ ++ static inline __hostdev__ bool zeroCrossing(__global__ const ValueT (&v)[3][3][3]); ++}; // TriquadraticSamplerBase ++ ++template ++void TriquadraticSampler::stencil(__local__ const CoordT &ijk, __local__ ValueT (&v)[3][3][3]) const ++{ ++ CoordT p(ijk[0] - 1, 0, 0); ++ for (int dx = 0; dx < 3; ++dx, ++p[0]) { ++ p[1] = ijk[1] - 1; ++ for (int dy = 0; dy < 3; ++dy, ++p[1]) { ++ p[2] = ijk[2] - 1; ++ for (int dz = 0; dz < 3; ++dz, ++p[2]) { ++ v[dx][dy][dz] = mAcc.getValue(p);// extract the stencil of 27 values ++ } ++ } ++ } ++} ++ ++template ++template class Vec3T> ++typename TreeOrAccT::ValueType TriquadraticSampler::sample(__local__ const Vec3T &uvw, __local__ const ValueT (&v)[3][3][3]) ++{ ++ struct Kernel { ++ static ValueT _kernel(__local__ const ValueT* value, double weight) { ++ return weight * (weight * (0.5f * (value[0] + value[2]) - value[1]) + 0.5f * (value[2] - value[0])) + value[1]; ++ } ++ }; ++ ++ ValueT vx[3]; ++ for (int dx = 0; dx < 3; ++dx) { ++ ValueT vy[3]; ++ for (int dy = 0; dy < 3; ++dy) { ++ vy[dy] = Kernel::_kernel(&v[dx][dy][0], uvw[2]); ++ }//loop over y ++ vx[dx] = Kernel::_kernel(vy, uvw[1]); ++ }//loop over x ++ return Kernel::_kernel(vx, uvw[0]); ++} ++ ++template ++bool TriquadraticSampler::zeroCrossing(__global__ const ValueT (&v)[3][3][3]) ++{ ++ static_assert(is_floating_point::value, "TrilinearSampler::zeroCrossing requires a floating-point type"); ++ const bool less = v[0][0][0] < ValueT(0); ++ for (int dx = 0; dx < 3; ++dx) { ++ for (int dy = 0; dy < 3; ++dy) { ++ for (int dz = 0; dz < 3; ++dz) { ++ if (less ^ (v[dx][dy][dz] < ValueT(0))) return true; ++ } ++ } ++ } ++ return false; ++} ++ ++/// @brief Template specialization that does not use caching of stencil points ++template ++class SampleFromVoxels ++#if !defined(__KERNEL_METAL__) ++ : public TriquadraticSampler ++#endif ++{ ++#if defined(__KERNEL_METAL__) ++ TriquadraticSampler _base; ++#define BASE(v) _base.v ++#else ++#define BASE(v) BaseT::v ++#endif ++ using BaseT = TriquadraticSampler; ++ using ValueT = typename TreeOrAccT::ValueType; ++ using CoordT = typename TreeOrAccT::CoordType; ++public: ++ ++ /// @brief Construction from a Tree or ReadAccessor ++#if defined(__KERNEL_METAL__) ++ __hostdev__ SampleFromVoxels(__local__ const TreeOrAccT& acc) : _base(acc) {} ++#else ++ __hostdev__ SampleFromVoxels(__local__ const TreeOrAccT& acc) : BaseT(acc) {} ++#endif ++ ++ /// @note xyz is in index space space ++ template class Vec3T> ++ inline __hostdev__ ValueT operator()(Vec3T xyz) const; ++ ++ __hostdev__ ValueT operator()(__global__ const CoordT &ijk) const {return BaseT::mAcc.getValue(ijk);} ++ ++ /// @brief Return true if the tr-linear stencil has a zero crossing at the specified index position. ++ /// ++ /// @warning Will only compile with floating point value types ++ template class Vec3T> ++ inline __hostdev__ bool zeroCrossing(Vec3T xyz) const; ++ ++}; // SampleFromVoxels ++ ++/// @brief Template specialization with caching of stencil values ++template ++class SampleFromVoxels ++#if !defined(__KERNEL_METAL__) ++ : public TriquadraticSampler ++#endif ++{ ++#if defined(__KERNEL_METAL__) ++ TriquadraticSampler _base; ++#define BASE(v) _base.v ++#else ++#define BASE(v) BaseT::v ++#endif ++ using BaseT = TriquadraticSampler; ++ using ValueT = typename TreeOrAccT::ValueType; ++ using CoordT = typename TreeOrAccT::CoordType; ++ ++ mutable CoordT mPos; ++ mutable ValueT mVal[3][3][3]; ++ ++ template class Vec3T> ++ __hostdev__ void cache(__global__ Vec3T& xyz) const; ++public: ++ ++ /// @brief Construction from a Tree or ReadAccessor ++ __hostdev__ SampleFromVoxels(__local__ const TreeOrAccT& acc) : BaseT(acc), mPos(CoordT::max()){} ++ ++ /// @note xyz is in index space space ++ template class Vec3T> ++ inline __hostdev__ ValueT operator()(Vec3T xyz) const; ++ ++ inline __hostdev__ ValueT operator()(__global__ const CoordT &ijk) const; ++ ++ /// @brief Return true if the tr-linear stencil has a zero crossing at the specified index position. ++ /// ++ /// @warning Will only compile with floating point value types ++ template class Vec3T> ++ inline __hostdev__ bool zeroCrossing(Vec3T xyz) const; ++ ++ /// @brief Return true if the cached tri-linear stencil has a zero crossing. ++ /// ++ /// @warning Will only compile with floating point value types ++ __hostdev__ bool zeroCrossing() const { return BaseT::zeroCrossing(mVal); } ++ ++}; // SampleFromVoxels ++ ++template ++template class Vec3T> ++typename TreeOrAccT::ValueType SampleFromVoxels::operator()(Vec3T xyz) const ++{ ++ this->cache(xyz); ++ return BaseT::sample(xyz, mVal); ++} ++ ++template ++typename TreeOrAccT::ValueType SampleFromVoxels::operator()(__global__ const CoordT &ijk) const ++{ ++ return ijk == mPos ? mVal[1][1][1] : BaseT::mAcc.getValue(ijk); ++} ++ ++template ++template class Vec3T> ++__hostdev__ bool SampleFromVoxels::zeroCrossing(Vec3T xyz) const ++{ ++ this->cache(xyz); ++ return BaseT::zeroCrossing(mVal); ++} ++ ++template ++template class Vec3T> ++void SampleFromVoxels::cache(__global__ Vec3T& xyz) const ++{ ++ CoordT ijk = Floor(xyz); ++ if (ijk != mPos) { ++ mPos = ijk; ++ BaseT::stencil(ijk, mVal); ++ } ++} ++ ++template ++template class Vec3T> ++typename TreeOrAccT::ValueType SampleFromVoxels::operator()(Vec3T xyz) const ++{ ++ ValueT val[3][3][3]; ++ CoordT ijk = Floor(xyz); ++ BASE(stencil)(ijk, val); ++ return BaseT::sample(xyz, val); ++} ++ ++template ++template class Vec3T> ++bool SampleFromVoxels::zeroCrossing(Vec3T xyz) const ++{ ++ ValueT val[3][3][3]; ++ CoordT ijk = Floor(xyz); ++ BaseT::stencil(ijk, val); ++ return BaseT::zeroCrossing(val); ++} ++ ++// ------------------------------> TricubicSampler <-------------------------------------- ++ ++/// @brief Tri-cubic sampler, i.e. third order, interpolator. ++/// ++/// @details See the following paper for implementation details: ++/// Lekien, F. and Marsden, J.: Tricubic interpolation in three dimensions. ++/// In: International Journal for Numerical Methods ++/// in Engineering (2005), No. 63, p. 455-471 ++ ++template ++class TricubicSampler ++{ ++protected: ++ using ValueT = typename TreeOrAccT::ValueType; ++ using CoordT = typename TreeOrAccT::CoordType; ++ ++ __global__ const TreeOrAccT& mAcc; ++ ++public: ++ /// @brief Construction from a Tree or ReadAccessor ++ __hostdev__ TricubicSampler(__global__ const TreeOrAccT& acc) ++ : mAcc(acc) ++ { ++ } ++ ++ __hostdev__ __global__ const TreeOrAccT& accessor() const { return mAcc; } ++ ++ /// @brief Extract the stencil of 8 values ++ inline __hostdev__ void stencil(__global__ const CoordT& ijk, __global__ ValueT (&c)[64]) const; ++ ++ template class Vec3T> ++ static inline __hostdev__ ValueT sample(__global__ const Vec3T &uvw, __global__ const ValueT (&c)[64]); ++}; // TricubicSampler ++ ++// 4Kb of static table (int8_t has a range of -127 -> 127 which suffices) ++static __constant__ const int8_t TricubicSampler_A[64][64] = { ++ {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {-3, 3, 0, 0, 0, 0, 0, 0, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {2, -2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {9, -9, -9, 9, 0, 0, 0, 0, 6, 3, -6, -3, 0, 0, 0, 0, 6, -6, 3, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {-6, 6, 6, -6, 0, 0, 0, 0, -3, -3, 3, 3, 0, 0, 0, 0, -4, 4, -2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {-6, 6, 6, -6, 0, 0, 0, 0, -4, -2, 4, 2, 0, 0, 0, 0, -3, 3, -3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {4, -4, -4, 4, 0, 0, 0, 0, 2, 2, -2, -2, 0, 0, 0, 0, 2, -2, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0, -2, -1, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, -9, -9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3, -6, -3, 0, 0, 0, 0, 6, -6, 3, -3, 0, 0, 0, 0, 4, 2, 2, 1, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 6, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, -3, 3, 3, 0, 0, 0, 0, -4, 4, -2, 2, 0, 0, 0, 0, -2, -2, -1, -1, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 6, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, -2, 4, 2, 0, 0, 0, 0, -3, 3, -3, 3, 0, 0, 0, 0, -2, -1, -2, -1, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, -4, -4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, -2, -2, 0, 0, 0, 0, 2, -2, 2, -2, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0}, ++ {-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {9, -9, 0, 0, -9, 9, 0, 0, 6, 3, 0, 0, -6, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, -6, 0, 0, 3, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {-6, 6, 0, 0, 6, -6, 0, 0, -3, -3, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 4, 0, 0, -2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -2, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, -1, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, -9, 0, 0, -9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3, 0, 0, -6, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, -6, 0, 0, 3, -3, 0, 0, 4, 2, 0, 0, 2, 1, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 6, 0, 0, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, -3, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 4, 0, 0, -2, 2, 0, 0, -2, -2, 0, 0, -1, -1, 0, 0}, ++ {9, 0, -9, 0, -9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, 0, -6, 0, -3, 0, 6, 0, -6, 0, 3, 0, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 9, 0, -9, 0, -9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, 0, -6, 0, -3, 0, 6, 0, -6, 0, 3, 0, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 0, 2, 0, 1, 0}, ++ {-27, 27, 27, -27, 27, -27, -27, 27, -18, -9, 18, 9, 18, 9, -18, -9, -18, 18, -9, 9, 18, -18, 9, -9, -18, 18, 18, -18, -9, 9, 9, -9, -12, -6, -6, -3, 12, 6, 6, 3, -12, -6, 12, 6, -6, -3, 6, 3, -12, 12, -6, 6, -6, 6, -3, 3, -8, -4, -4, -2, -4, -2, -2, -1}, ++ {18, -18, -18, 18, -18, 18, 18, -18, 9, 9, -9, -9, -9, -9, 9, 9, 12, -12, 6, -6, -12, 12, -6, 6, 12, -12, -12, 12, 6, -6, -6, 6, 6, 6, 3, 3, -6, -6, -3, -3, 6, 6, -6, -6, 3, 3, -3, -3, 8, -8, 4, -4, 4, -4, 2, -2, 4, 4, 2, 2, 2, 2, 1, 1}, ++ {-6, 0, 6, 0, 6, 0, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, -3, 0, 3, 0, 3, 0, -4, 0, 4, 0, -2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -2, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, -6, 0, 6, 0, 6, 0, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, -3, 0, 3, 0, 3, 0, -4, 0, 4, 0, -2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -2, 0, -1, 0, -1, 0}, ++ {18, -18, -18, 18, -18, 18, 18, -18, 12, 6, -12, -6, -12, -6, 12, 6, 9, -9, 9, -9, -9, 9, -9, 9, 12, -12, -12, 12, 6, -6, -6, 6, 6, 3, 6, 3, -6, -3, -6, -3, 8, 4, -8, -4, 4, 2, -4, -2, 6, -6, 6, -6, 3, -3, 3, -3, 4, 2, 4, 2, 2, 1, 2, 1}, ++ {-12, 12, 12, -12, 12, -12, -12, 12, -6, -6, 6, 6, 6, 6, -6, -6, -6, 6, -6, 6, 6, -6, 6, -6, -8, 8, 8, -8, -4, 4, 4, -4, -3, -3, -3, -3, 3, 3, 3, 3, -4, -4, 4, 4, -2, -2, 2, 2, -4, 4, -4, 4, -2, 2, -2, 2, -2, -2, -2, -2, -1, -1, -1, -1}, ++ {2, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {-6, 6, 0, 0, 6, -6, 0, 0, -4, -2, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, 0, 0, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {4, -4, 0, 0, -4, 4, 0, 0, 2, 2, 0, 0, -2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 6, 0, 0, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, -2, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, -3, 3, 0, 0, -2, -1, 0, 0, -2, -1, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, -4, 0, 0, -4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, -2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 2, -2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0}, ++ {-6, 0, 6, 0, 6, 0, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 0, -2, 0, 4, 0, 2, 0, -3, 0, 3, 0, -3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, 0, -2, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, -6, 0, 6, 0, 6, 0, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 0, -2, 0, 4, 0, 2, 0, -3, 0, 3, 0, -3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, 0, -2, 0, -1, 0}, ++ {18, -18, -18, 18, -18, 18, 18, -18, 12, 6, -12, -6, -12, -6, 12, 6, 12, -12, 6, -6, -12, 12, -6, 6, 9, -9, -9, 9, 9, -9, -9, 9, 8, 4, 4, 2, -8, -4, -4, -2, 6, 3, -6, -3, 6, 3, -6, -3, 6, -6, 3, -3, 6, -6, 3, -3, 4, 2, 2, 1, 4, 2, 2, 1}, ++ {-12, 12, 12, -12, 12, -12, -12, 12, -6, -6, 6, 6, 6, 6, -6, -6, -8, 8, -4, 4, 8, -8, 4, -4, -6, 6, 6, -6, -6, 6, 6, -6, -4, -4, -2, -2, 4, 4, 2, 2, -3, -3, 3, 3, -3, -3, 3, 3, -4, 4, -2, 2, -4, 4, -2, 2, -2, -2, -1, -1, -2, -2, -1, -1}, ++ {4, 0, -4, 0, -4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, -2, 0, -2, 0, 2, 0, -2, 0, 2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 4, 0, -4, 0, -4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, -2, 0, -2, 0, 2, 0, -2, 0, 2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0}, ++ {-12, 12, 12, -12, 12, -12, -12, 12, -8, -4, 8, 4, 8, 4, -8, -4, -6, 6, -6, 6, 6, -6, 6, -6, -6, 6, 6, -6, -6, 6, 6, -6, -4, -2, -4, -2, 4, 2, 4, 2, -4, -2, 4, 2, -4, -2, 4, 2, -3, 3, -3, 3, -3, 3, -3, 3, -2, -1, -2, -1, -2, -1, -2, -1}, ++ {8, -8, -8, 8, -8, 8, 8, -8, 4, 4, -4, -4, -4, -4, 4, 4, 4, -4, 4, -4, -4, 4, -4, 4, 4, -4, -4, 4, 4, -4, -4, 4, 2, 2, 2, 2, -2, -2, -2, -2, 2, 2, -2, -2, 2, 2, -2, -2, 2, -2, 2, -2, 2, -2, 2, -2, 1, 1, 1, 1, 1, 1, 1, 1}}; ++ ++template ++void TricubicSampler::stencil(__global__ const CoordT& ijk, __global__ ValueT (&C)[64]) const ++{ ++ struct Fetch { ++ Fetch(__global__ ValueT (&_C)[64]):C(_C) {} ++ __global__ ValueT& fetch(int i, int j, int k) { return C[((i + 1) << 4) + ((j + 1) << 2) + k + 1]; } ++ ++ __global__ ValueT (&C)[64]; ++ }; ++ Fetch f(C); ++ ++ // fetch 64 point stencil values ++ for (int i = -1; i < 3; ++i) { ++ for (int j = -1; j < 3; ++j) { ++ Fetch::fetch(i, j, -1) = mAcc.getValue(ijk + CoordT(i, j, -1)); ++ Fetch::fetch(i, j, 0) = mAcc.getValue(ijk + CoordT(i, j, 0)); ++ Fetch::fetch(i, j, 1) = mAcc.getValue(ijk + CoordT(i, j, 1)); ++ Fetch::fetch(i, j, 2) = mAcc.getValue(ijk + CoordT(i, j, 2)); ++ } ++ } ++ const ValueT _half(0.5), quarter(0.25), eighth(0.125); ++ const ValueT X[64] = {// values of f(x,y,z) at the 8 corners (each from 1 stencil value). ++ f.fetch(0, 0, 0), ++ f.fetch(1, 0, 0), ++ f.fetch(0, 1, 0), ++ f.fetch(1, 1, 0), ++ f.fetch(0, 0, 1), ++ f.fetch(1, 0, 1), ++ f.fetch(0, 1, 1), ++ f.fetch(1, 1, 1), ++ // values of df/dx at the 8 corners (each from 2 stencil values). ++ _half * (f.fetch(1, 0, 0) - f.fetch(-1, 0, 0)), ++ _half * (f.fetch(2, 0, 0) - f.fetch(0, 0, 0)), ++ _half * (f.fetch(1, 1, 0) - f.fetch(-1, 1, 0)), ++ _half * (f.fetch(2, 1, 0) - f.fetch(0, 1, 0)), ++ _half * (f.fetch(1, 0, 1) - f.fetch(-1, 0, 1)), ++ _half * (f.fetch(2, 0, 1) - f.fetch(0, 0, 1)), ++ _half * (f.fetch(1, 1, 1) - f.fetch(-1, 1, 1)), ++ _half * (f.fetch(2, 1, 1) - f.fetch(0, 1, 1)), ++ // values of df/dy at the 8 corners (each from 2 stencil values). ++ _half * (f.fetch(0, 1, 0) - f.fetch(0, -1, 0)), ++ _half * (f.fetch(1, 1, 0) - f.fetch(1, -1, 0)), ++ _half * (f.fetch(0, 2, 0) - f.fetch(0, 0, 0)), ++ _half * (f.fetch(1, 2, 0) - f.fetch(1, 0, 0)), ++ _half * (f.fetch(0, 1, 1) - f.fetch(0, -1, 1)), ++ _half * (f.fetch(1, 1, 1) - f.fetch(1, -1, 1)), ++ _half * (f.fetch(0, 2, 1) - f.fetch(0, 0, 1)), ++ _half * (f.fetch(1, 2, 1) - f.fetch(1, 0, 1)), ++ // values of df/dz at the 8 corners (each from 2 stencil values). ++ _half * (f.fetch(0, 0, 1) - f.fetch(0, 0, -1)), ++ _half * (f.fetch(1, 0, 1) - f.fetch(1, 0, -1)), ++ _half * (f.fetch(0, 1, 1) - f.fetch(0, 1, -1)), ++ _half * (f.fetch(1, 1, 1) - f.fetch(1, 1, -1)), ++ _half * (f.fetch(0, 0, 2) - f.fetch(0, 0, 0)), ++ _half * (f.fetch(1, 0, 2) - f.fetch(1, 0, 0)), ++ _half * (f.fetch(0, 1, 2) - f.fetch(0, 1, 0)), ++ _half * (f.fetch(1, 1, 2) - f.fetch(1, 1, 0)), ++ // values of d2f/dxdy at the 8 corners (each from 4 stencil values). ++ quarter * (f.fetch(1, 1, 0) - f.fetch(-1, 1, 0) - f.fetch(1, -1, 0) + f.fetch(-1, -1, 0)), ++ quarter * (f.fetch(2, 1, 0) - f.fetch(0, 1, 0) - f.fetch(2, -1, 0) + f.fetch(0, -1, 0)), ++ quarter * (f.fetch(1, 2, 0) - f.fetch(-1, 2, 0) - f.fetch(1, 0, 0) + f.fetch(-1, 0, 0)), ++ quarter * (f.fetch(2, 2, 0) - f.fetch(0, 2, 0) - f.fetch(2, 0, 0) + f.fetch(0, 0, 0)), ++ quarter * (f.fetch(1, 1, 1) - f.fetch(-1, 1, 1) - f.fetch(1, -1, 1) + f.fetch(-1, -1, 1)), ++ quarter * (f.fetch(2, 1, 1) - f.fetch(0, 1, 1) - f.fetch(2, -1, 1) + f.fetch(0, -1, 1)), ++ quarter * (f.fetch(1, 2, 1) - f.fetch(-1, 2, 1) - f.fetch(1, 0, 1) + f.fetch(-1, 0, 1)), ++ quarter * (f.fetch(2, 2, 1) - f.fetch(0, 2, 1) - f.fetch(2, 0, 1) + f.fetch(0, 0, 1)), ++ // values of d2f/dxdz at the 8 corners (each from 4 stencil values). ++ quarter * (f.fetch(1, 0, 1) - f.fetch(-1, 0, 1) - f.fetch(1, 0, -1) + f.fetch(-1, 0, -1)), ++ quarter * (f.fetch(2, 0, 1) - f.fetch(0, 0, 1) - f.fetch(2, 0, -1) + f.fetch(0, 0, -1)), ++ quarter * (f.fetch(1, 1, 1) - f.fetch(-1, 1, 1) - f.fetch(1, 1, -1) + f.fetch(-1, 1, -1)), ++ quarter * (f.fetch(2, 1, 1) - f.fetch(0, 1, 1) - f.fetch(2, 1, -1) + f.fetch(0, 1, -1)), ++ quarter * (f.fetch(1, 0, 2) - f.fetch(-1, 0, 2) - f.fetch(1, 0, 0) + f.fetch(-1, 0, 0)), ++ quarter * (f.fetch(2, 0, 2) - f.fetch(0, 0, 2) - f.fetch(2, 0, 0) + f.fetch(0, 0, 0)), ++ quarter * (f.fetch(1, 1, 2) - f.fetch(-1, 1, 2) - f.fetch(1, 1, 0) + f.fetch(-1, 1, 0)), ++ quarter * (f.fetch(2, 1, 2) - f.fetch(0, 1, 2) - f.fetch(2, 1, 0) + f.fetch(0, 1, 0)), ++ // values of d2f/dydz at the 8 corners (each from 4 stencil values). ++ quarter * (f.fetch(0, 1, 1) - f.fetch(0, -1, 1) - f.fetch(0, 1, -1) + f.fetch(0, -1, -1)), ++ quarter * (f.fetch(1, 1, 1) - f.fetch(1, -1, 1) - f.fetch(1, 1, -1) + f.fetch(1, -1, -1)), ++ quarter * (f.fetch(0, 2, 1) - f.fetch(0, 0, 1) - f.fetch(0, 2, -1) + f.fetch(0, 0, -1)), ++ quarter * (f.fetch(1, 2, 1) - f.fetch(1, 0, 1) - f.fetch(1, 2, -1) + f.fetch(1, 0, -1)), ++ quarter * (f.fetch(0, 1, 2) - f.fetch(0, -1, 2) - f.fetch(0, 1, 0) + f.fetch(0, -1, 0)), ++ quarter * (f.fetch(1, 1, 2) - f.fetch(1, -1, 2) - f.fetch(1, 1, 0) + f.fetch(1, -1, 0)), ++ quarter * (f.fetch(0, 2, 2) - f.fetch(0, 0, 2) - f.fetch(0, 2, 0) + f.fetch(0, 0, 0)), ++ quarter * (f.fetch(1, 2, 2) - f.fetch(1, 0, 2) - f.fetch(1, 2, 0) + f.fetch(1, 0, 0)), ++ // values of d3f/dxdydz at the 8 corners (each from 8 stencil values). ++ eighth * (f.fetch(1, 1, 1) - f.fetch(-1, 1, 1) - f.fetch(1, -1, 1) + f.fetch(-1, -1, 1) - f.fetch(1, 1, -1) + f.fetch(-1, 1, -1) + f.fetch(1, -1, -1) - f.fetch(-1, -1, -1)), ++ eighth * (f.fetch(2, 1, 1) - f.fetch(0, 1, 1) - f.fetch(2, -1, 1) + f.fetch(0, -1, 1) - f.fetch(2, 1, -1) + f.fetch(0, 1, -1) + f.fetch(2, -1, -1) - f.fetch(0, -1, -1)), ++ eighth * (f.fetch(1, 2, 1) - f.fetch(-1, 2, 1) - f.fetch(1, 0, 1) + f.fetch(-1, 0, 1) - f.fetch(1, 2, -1) + f.fetch(-1, 2, -1) + f.fetch(1, 0, -1) - f.fetch(-1, 0, -1)), ++ eighth * (f.fetch(2, 2, 1) - f.fetch(0, 2, 1) - f.fetch(2, 0, 1) + f.fetch(0, 0, 1) - f.fetch(2, 2, -1) + f.fetch(0, 2, -1) + f.fetch(2, 0, -1) - f.fetch(0, 0, -1)), ++ eighth * (f.fetch(1, 1, 2) - f.fetch(-1, 1, 2) - f.fetch(1, -1, 2) + f.fetch(-1, -1, 2) - f.fetch(1, 1, 0) + f.fetch(-1, 1, 0) + f.fetch(1, -1, 0) - f.fetch(-1, -1, 0)), ++ eighth * (f.fetch(2, 1, 2) - f.fetch(0, 1, 2) - f.fetch(2, -1, 2) + f.fetch(0, -1, 2) - f.fetch(2, 1, 0) + f.fetch(0, 1, 0) + f.fetch(2, -1, 0) - f.fetch(0, -1, 0)), ++ eighth * (f.fetch(1, 2, 2) - f.fetch(-1, 2, 2) - f.fetch(1, 0, 2) + f.fetch(-1, 0, 2) - f.fetch(1, 2, 0) + f.fetch(-1, 2, 0) + f.fetch(1, 0, 0) - f.fetch(-1, 0, 0)), ++ eighth * (f.fetch(2, 2, 2) - f.fetch(0, 2, 2) - f.fetch(2, 0, 2) + f.fetch(0, 0, 2) - f.fetch(2, 2, 0) + f.fetch(0, 2, 0) + f.fetch(2, 0, 0) - f.fetch(0, 0, 0))}; ++ ++ for (int i = 0; i < 64; ++i) { // C = A * X ++ C[i] = ValueT(0); ++#if 0 ++ for (int j = 0; j < 64; j += 4) { ++ C[i] = fma(A[i][j], X[j], fma(A[i][j+1], X[j+1], fma(A[i][j+2], X[j+2], fma(A[i][j+3], X[j+3], C[i])))); ++ } ++#else ++ for (int j = 0; j < 64; j += 4) { ++ C[i] += TricubicSampler_A[i][j] * X[j] + TricubicSampler_A[i][j + 1] * X[j + 1] + ++ TricubicSampler_A[i][j + 2] * X[j + 2] + TricubicSampler_A[i][j + 3] * X[j + 3]; ++ } ++#endif ++ } ++} ++ ++template ++template class Vec3T> ++__hostdev__ typename TreeOrAccT::ValueType TricubicSampler::sample(__global__ const Vec3T &xyz, __global__ const ValueT (&C)[64]) ++{ ++ ValueT zPow(1), sum(0); ++ for (int k = 0, n = 0; k < 4; ++k) { ++ ValueT yPow(1); ++ for (int j = 0; j < 4; ++j, n += 4) { ++#if 0 ++ sum = fma( yPow, zPow * fma(xyz[0], fma(xyz[0], fma(xyz[0], C[n + 3], C[n + 2]), C[n + 1]), C[n]), sum); ++#else ++ sum += yPow * zPow * (C[n] + xyz[0] * (C[n + 1] + xyz[0] * (C[n + 2] + xyz[0] * C[n + 3]))); ++#endif ++ yPow *= xyz[1]; ++ } ++ zPow *= xyz[2]; ++ } ++ return sum; ++} ++ ++template ++class SampleFromVoxels ++#if !defined(__KERNEL_METAL__) ++ : public TricubicSampler ++#endif ++{ ++#if defined(__KERNEL_METAL__) ++ TricubicSampler _base; ++#define BASE(v) _base.v ++#else ++#define BASE(v) BaseT::v ++#endif ++ using BaseT = TricubicSampler; ++ using ValueT = typename TreeOrAccT::ValueType; ++ using CoordT = typename TreeOrAccT::CoordType; ++ ++ mutable CoordT mPos; ++ mutable ValueT mC[64]; ++ ++ template class Vec3T> ++ __hostdev__ void cache(__global__ Vec3T& xyz) const; ++ ++public: ++ /// @brief Construction from a Tree or ReadAccessor ++ __hostdev__ SampleFromVoxels(__local__ const TreeOrAccT& acc) ++ : BaseT(acc) ++ { ++ } ++ ++ /// @note xyz is in index space space ++ template class Vec3T> ++ inline __hostdev__ ValueT operator()(Vec3T xyz) const; ++ ++ // @brief Return value at the coordinate @a ijk in index space space ++ __hostdev__ ValueT operator()(__global__ const CoordT &ijk) const {return BaseT::mAcc.getValue(ijk);} ++ ++}; // SampleFromVoxels ++ ++template ++template class Vec3T> ++typename TreeOrAccT::ValueType SampleFromVoxels::operator()(Vec3T xyz) const ++{ ++ this->cache(xyz); ++ return BaseT::sample(xyz, mC); ++} ++ ++template ++template class Vec3T> ++void SampleFromVoxels::cache(__global__ Vec3T& xyz) const ++{ ++ CoordT ijk = Floor(xyz); ++ if (ijk != mPos) { ++ mPos = ijk; ++ BaseT::stencil(ijk, mC); ++ } ++} ++ ++template ++class SampleFromVoxels ++#if !defined(__KERNEL_METAL__) ++ : public TricubicSampler ++#endif ++{ ++#if defined(__KERNEL_METAL__) ++ TricubicSampler _base; ++#define BASE(v) _base.v ++#else ++#define BASE(v) BaseT::v ++#endif ++ using BaseT = TricubicSampler; ++ using ValueT = typename TreeOrAccT::ValueType; ++ using CoordT = typename TreeOrAccT::CoordType; ++ ++public: ++ /// @brief Construction from a Tree or ReadAccessor ++ __hostdev__ SampleFromVoxels(__local__ const TreeOrAccT& acc) ++ : BaseT(acc) ++ { ++ } ++ ++ /// @note xyz is in index space space ++ template class Vec3T> ++ inline __hostdev__ ValueT operator()(Vec3T xyz) const; ++ ++ __hostdev__ ValueT operator()(__global__ const CoordT &ijk) const {return BaseT::mAcc.getValue(ijk);} ++ ++}; // SampleFromVoxels ++ ++template ++template class Vec3T> ++__hostdev__ typename TreeOrAccT::ValueType SampleFromVoxels::operator()(Vec3T xyz) const ++{ ++ ValueT C[64]; ++ CoordT ijk = Floor(xyz); ++ BaseT::stencil(ijk, C); ++ return BaseT::sample(xyz, C); ++} ++ ++} // namespace nanovdb ++ ++#endif // NANOVDB_SAMPLE_FROM_VOXELS_H_HAS_BEEN_INCLUDED diff --git a/blender-build/build_environment/patches/osl.diff b/blender-build/build_environment/patches/osl.diff new file mode 100644 index 0000000..46539a7 --- /dev/null +++ b/blender-build/build_environment/patches/osl.diff @@ -0,0 +1,113 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index d527232..5ad6eaa 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -99,6 +99,11 @@ set (OSL_PTX_INSTALL_DIR "${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT_NAME}/ptx" + CACHE STRING "Directory where OptiX PTX files will be installed") + set (CMAKE_DEBUG_POSTFIX "" CACHE STRING "Library naming postfix for Debug builds (e.g., '_debug')") + ++set (USE_OIIO_STATIC ON CACHE BOOL "If OIIO is built static") ++if (USE_OIIO_STATIC) ++ add_definitions ("-DOIIO_STATIC_BUILD=1") ++ add_definitions ("-DOIIO_STATIC_DEFINE=1") ++endif () + + set (OSL_NO_DEFAULT_TEXTURESYSTEM OFF CACHE BOOL "Do not use create a raw OIIO::TextureSystem") + if (OSL_NO_DEFAULT_TEXTURESYSTEM) +diff --git a/src/cmake/externalpackages.cmake b/src/cmake/externalpackages.cmake +index a7e098b..dad11d0 100644 +--- a/src/cmake/externalpackages.cmake ++++ b/src/cmake/externalpackages.cmake +@@ -77,6 +77,7 @@ link_directories ("${Boost_LIBRARY_DIRS}") + + + checked_find_package (ZLIB REQUIRED) # Needed by several packages ++checked_find_package (PNG REQUIRED) # Needed since OIIO needs it + + # IlmBase & OpenEXR + checked_find_package (OpenEXR REQUIRED +diff --git a/src/liboslcomp/oslcomp.cpp b/src/liboslcomp/oslcomp.cpp +index 8c2e77b..211b8a7 100644 +--- a/src/liboslcomp/oslcomp.cpp ++++ b/src/liboslcomp/oslcomp.cpp +@@ -21,6 +21,13 @@ + #if !defined(__STDC_CONSTANT_MACROS) + # define __STDC_CONSTANT_MACROS 1 + #endif ++ ++// clang uses CALLBACK in its templates which causes issues if it is already defined ++#ifdef _WIN32 && defined(CALLBACK) ++# undef CALLBACK ++#endif ++ ++// + #include + #include + #include +diff --git a/src/liboslexec/llvm_instance.cpp b/src/liboslexec/llvm_instance.cpp +index 8f52546..8c2d0c7 100644 +--- a/src/liboslexec/llvm_instance.cpp ++++ b/src/liboslexec/llvm_instance.cpp +@@ -1363,6 +1363,10 @@ BackendLLVM::run() + #ifdef OSL_LLVM_NO_BITCODE + OSL_ASSERT(!use_rs_bitcode()); + ll.module(ll.new_module("llvm_ops")); ++ if (use_optix()) { ++ ll.module()->setDataLayout("e-i64:64-i128:128-v16:16-v32:32-n16:32:64"); ++ ll.module()->setTargetTriple("nvptx64-nvidia-cuda"); ++ } + #else + if (!use_optix()) { + if (use_rs_bitcode()) { +diff --git a/src/liboslexec/shadingsys.cpp b/src/liboslexec/shadingsys.cpp +index 46e4529..8e86486 100644 +--- a/src/liboslexec/shadingsys.cpp ++++ b/src/liboslexec/shadingsys.cpp +@@ -2121,6 +2121,11 @@ ShadingSystemImpl::getattribute(ShaderGroup* group, string_view name, + return true; + } + ++ if (name == "groupdata_size" && type == TypeDesc::TypeInt) { ++ *(int*)val = (int)group->m_llvm_groupdata_size; ++ return true; ++ } ++ + return false; + } + +diff --git a/src/liboslexec/CMakeLists.txt b/src/liboslexec/CMakeLists.txt +index 6bb0d175..19f13513 100644 +--- a/src/liboslexec/CMakeLists.txt ++++ b/src/liboslexec/CMakeLists.txt +@@ -148,7 +148,9 @@ file (GLOB exec_headers "*.h") + file (GLOB compiler_headers "../liboslcomp/*.h") + + FLEX_BISON ( osolex.l osogram.y oso lib_src exec_headers ) +-FLEX_BISON ( ../liboslcomp/osllex.l ../liboslcomp/oslgram.y osl lib_src compiler_headers ) ++if (BUILD_SHARED_LIBS) ++ FLEX_BISON ( ../liboslcomp/osllex.l ../liboslcomp/oslgram.y osl lib_src compiler_headers ) ++endif() + + set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS" ) + +diff --git a/src/include/OSL/mask.h b/src/include/OSL/mask.h +index 24197af..b9275f6 100644 +--- a/src/include/OSL/mask.h ++++ b/src/include/OSL/mask.h +@@ -4,7 +4,6 @@ + + #pragma once + +-#include + #include + + #include +@@ -23,6 +22,8 @@ using std::countr_zero; + + #elif OSL_INTEL_CLASSIC_COMPILER_VERSION + ++#include ++ + OSL_FORCEINLINE int popcount(uint32_t x) noexcept { return _mm_popcnt_u32(x);} + OSL_FORCEINLINE int popcount(uint64_t x) noexcept { return _mm_popcnt_u64(x); } + OSL_FORCEINLINE int countr_zero(uint32_t x) noexcept { return _bit_scan_forward(x); } diff --git a/blender-build/build_environment/patches/pthreads.diff b/blender-build/build_environment/patches/pthreads.diff new file mode 100644 index 0000000..4b6c976 --- /dev/null +++ b/blender-build/build_environment/patches/pthreads.diff @@ -0,0 +1,12 @@ +diff -Naur orig/Makefile external_pthreads/Makefile +--- orig/Makefile 2018-08-08 04:47:40 -0600 ++++ external_pthreads/Makefile 2020-05-09 11:20:28 -0600 +@@ -185,7 +185,7 @@ + @ $(MAKE) /E /nologo XCFLAGS="/MTd" EHFLAGS="$(VSEFLAGSD) /D__PTW32_STATIC_LIB /D__PTW32_BUILD_INLINED" CLEANUP=__PTW32_CLEANUP_SEH pthreadVSE$(PTW32_VER_DEBUG).inlined_static_stamp + + VC-static: +- @ $(MAKE) /E /nologo XCFLAGS="/MT" EHFLAGS="$(VCFLAGS) /D__PTW32_STATIC_LIB /D__PTW32_BUILD_INLINED" CLEANUP=__PTW32_CLEANUP_C pthreadVC$(PTW32_VER).inlined_static_stamp ++ @ $(MAKE) /E /nologo XCFLAGS="/MD" EHFLAGS="$(VCFLAGS) /D__PTW32_STATIC_LIB /D__PTW32_BUILD_INLINED" CLEANUP=__PTW32_CLEANUP_C pthreadVC$(PTW32_VER).inlined_static_stamp + + VC-static-debug: + @ $(MAKE) /E /nologo XCFLAGS="/MTd" EHFLAGS="$(VCFLAGSD) /D__PTW32_STATIC_LIB /D__PTW32_BUILD_INLINED" CLEANUP=__PTW32_CLEANUP_C pthreadVC$(PTW32_VER_DEBUG).inlined_static_stamp diff --git a/blender-build/build_environment/patches/python_unix.diff b/blender-build/build_environment/patches/python_unix.diff new file mode 100644 index 0000000..3969c70 --- /dev/null +++ b/blender-build/build_environment/patches/python_unix.diff @@ -0,0 +1,74 @@ +diff --git a/setup.py.orig b/setup.py +index a97a755..07ce853 100644 +--- a/setup.py.orig ++++ b/setup.py +@@ -1603,13 +1603,13 @@ + version = line.split()[2] + break + if version >= version_req: +- if (self.compiler.find_library_file(self.lib_dirs, 'z')): ++ if (self.compiler.find_library_file(self.lib_dirs, 'z_pic')): + if MACOS: + zlib_extra_link_args = ('-Wl,-search_paths_first',) + else: + zlib_extra_link_args = () + self.add(Extension('zlib', ['zlibmodule.c'], +- libraries=['z'], ++ libraries=['z_pic'], + extra_link_args=zlib_extra_link_args)) + have_zlib = True + else: +@@ -1623,7 +1623,7 @@ + # crc32 if we have it. Otherwise binascii uses its own. + if have_zlib: + extra_compile_args = ['-DUSE_ZLIB_CRC32'] +- libraries = ['z'] ++ libraries = ['z_pic'] + extra_link_args = zlib_extra_link_args + else: + extra_compile_args = [] +@@ -2168,7 +2168,7 @@ + ffi_inc = None + print('Header file {} does not exist'.format(ffi_h)) + if ffi_lib is None and ffi_inc: +- for lib_name in ('ffi', 'ffi_pic'): ++ for lib_name in ('ffi_pic', ): + if (self.compiler.find_library_file(self.lib_dirs, lib_name)): + ffi_lib = lib_name + break +--- a/Modules/posixmodule.c 2022-12-09 21:44:03 ++++ b/Modules/posixmodule.c 2022-12-09 21:39:46 +@@ -10564,10 +10564,15 @@ + Py_BEGIN_ALLOW_THREADS + #ifdef HAVE_MKFIFOAT + if (dir_fd != DEFAULT_DIR_FD) { ++// BLENDER: disable also at compile time for compatibility when linking with older Xcode. ++// https://github.com/python/cpython/issues/97897 ++#ifndef __APPLE__ + if (HAVE_MKFIFOAT_RUNTIME) { + result = mkfifoat(dir_fd, path->narrow, mode); + ++ } else ++#endif ++ { +- } else { + mkfifoat_unavailable = 1; + result = 0; + } +@@ -10638,10 +10633,15 @@ + Py_BEGIN_ALLOW_THREADS + #ifdef HAVE_MKNODAT + if (dir_fd != DEFAULT_DIR_FD) { ++// BLENDER: disable also at compile time for compatibility when linking with older Xcode. ++// https://github.com/python/cpython/issues/97897 ++#ifndef __APPLE__ + if (HAVE_MKNODAT_RUNTIME) { + result = mknodat(dir_fd, path->narrow, mode, device); + ++ } else ++#endif ++ { +- } else { + mknodat_unavailable = 1; + result = 0; + } diff --git a/blender-build/build_environment/patches/python_windows.diff b/blender-build/build_environment/patches/python_windows.diff new file mode 100644 index 0000000..ea9d501 --- /dev/null +++ b/blender-build/build_environment/patches/python_windows.diff @@ -0,0 +1,59 @@ +--- a/PCbuild/prepare_ssl.bat 2022-10-30 11:48:14 -0600 ++++ b/PCbuild/prepare_ssl.bat 2022-10-30 11:53:16 -0600 +@@ -47,12 +47,13 @@ + if "%PERL%" == "" where perl > "%TEMP%\perl.loc" 2> nul && set /P PERL= <"%TEMP%\perl.loc" & del "%TEMP%\perl.loc" + if "%PERL%" == "" (echo Cannot locate perl.exe on PATH or as PERL variable & exit /b 4) + +-%MSBUILD% "%PCBUILD%\openssl.vcxproj" /p:Configuration=Release /p:Platform=Win32 +-if errorlevel 1 exit /b ++REM Blender: we only need x64, ssl is kind of a long build, so just build what we need ++REM %MSBUILD% "%PCBUILD%\openssl.vcxproj" /p:Configuration=Release /p:Platform=Win32 ++REM if errorlevel 1 exit /b + %MSBUILD% "%PCBUILD%\openssl.vcxproj" /p:Configuration=Release /p:Platform=x64 + if errorlevel 1 exit /b +-%MSBUILD% "%PCBUILD%\openssl.vcxproj" /p:Configuration=Release /p:Platform=ARM +-if errorlevel 1 exit /b +-%MSBUILD% "%PCBUILD%\openssl.vcxproj" /p:Configuration=Release /p:Platform=ARM64 +-if errorlevel 1 exit /b ++REM %MSBUILD% "%PCBUILD%\openssl.vcxproj" /p:Configuration=Release /p:Platform=ARM ++REM if errorlevel 1 exit /b ++REM %MSBUILD% "%PCBUILD%\openssl.vcxproj" /p:Configuration=Release /p:Platform=ARM64 ++REM if errorlevel 1 exit /b + +diff -aurw Python-3.10.12/PCbuild/openssl.props external_python/PCbuild/openssl.props +--- Python-3.10.12/PCbuild/openssl.props 2023-06-06 16:30:33 -0600 ++++ external_python/PCbuild/openssl.props 2023-06-20 09:58:57 -0600 +@@ -10,7 +10,7 @@ + + + +- <_DLLSuffix>-1_1 ++ <_DLLSuffix>-3 + <_DLLSuffix Condition="$(Platform) == 'ARM'">$(_DLLSuffix)-arm + <_DLLSuffix Condition="$(Platform) == 'ARM64'">$(_DLLSuffix)-arm64 + +diff -aurw Python-3.10.12/PCbuild/openssl.vcxproj external_python/PCbuild/openssl.vcxproj +--- Python-3.10.12/PCbuild/openssl.vcxproj 2023-06-06 16:30:33 -0600 ++++ external_python/PCbuild/openssl.vcxproj 2023-06-20 08:50:43 -0600 +@@ -98,7 +98,7 @@ + + + +- <_Built Include="$(opensslDir)\LICENSE" /> ++ <_Built Include="$(opensslDir)\LICENSE.txt" /> + <_Built Include="$(IntDir)\libcrypto.lib;$(IntDir)\libcrypto-*.dll;$(IntDir)\libcrypto-*.pdb" /> + <_Built Include="$(IntDir)\libssl.lib;$(IntDir)\libssl-*.dll;$(IntDir)\libssl-*.pdb" /> + <_AppLink Include="$(opensslDir)\ms\applink.c" /> +diff -aurw Python-3.10.12/PCbuild/regen.targets external_python/PCbuild/regen.targets +--- Python-3.10.12/PCbuild/regen.targets 2023-06-06 16:30:33 -0600 ++++ external_python/PCbuild/regen.targets 2023-06-20 09:37:17 -0600 +@@ -89,7 +89,7 @@ + <_LicenseSources Include="$(PySourcePath)LICENSE; + $(PySourcePath)PC\crtlicense.txt; + $(bz2Dir)LICENSE; +- $(opensslOutDir)LICENSE; ++ $(opensslOutDir)LICENSE.txt; + $(libffiDir)LICENSE;" /> + <_LicenseSources Include="$(tcltkDir)tcllicense.terms; + $(tcltkDir)tklicense.terms; + diff --git a/blender-build/build_environment/patches/sdl.diff b/blender-build/build_environment/patches/sdl.diff new file mode 100644 index 0000000..6caa98f --- /dev/null +++ b/blender-build/build_environment/patches/sdl.diff @@ -0,0 +1,48 @@ +diff -ru ./src/video/SDL_video.c ./src/video/SDL_video.c +--- CMakeLists.txt.old 2016-01-02 12:56:31 -0700 ++++ CMakeLists.txt 2016-10-03 11:24:24 -0600 +@@ -609,7 +609,7 @@ + list(APPEND EXTRA_LIBS m) + endif() + +- check_library_exists(iconv iconv_open "" HAVE_LIBICONV) ++ #check_library_exists(iconv iconv_open "" HAVE_LIBICONV) + if(HAVE_LIBICONV) + list(APPEND EXTRA_LIBS iconv) + set(HAVE_ICONV 1) +--- src/video/SDL_video.c 2018-09-10 23:27:57.000000000 +0200 ++++ src/video/SDL_video.c 2018-09-10 23:28:09.000000000 +0200 +@@ -1176,7 +1176,7 @@ + return 0; + } + +-#ifdef __MACOSX__ ++#if defined(__MACOSX__) && SDL_VIDEO_DRIVER_COCOA + /* if the window is going away and no resolution change is necessary, + do nothing, or else we may trigger an ugly double-transition + */ +@@ -2563,7 +2563,7 @@ + return SDL_FALSE; + } + +-#ifdef __MACOSX__ ++#if defined(__MACOSX__) && SDL_VIDEO_DRIVER_COCOA + if (SDL_strcmp(_this->name, "cocoa") == 0) { /* don't do this for X11, etc */ + if (Cocoa_IsWindowInFullscreenSpace(window)) { + return SDL_FALSE; +--- CMakeLists.txt 2022-12-09 20:40:00 ++++ CMakeLists.txt 2022-12-09 20:40:00 +@@ -526,6 +526,13 @@ + list(APPEND EXTRA_CFLAGS "-fno-strict-aliasing") + endif() + ++ # BLENDER: make libs compatible with older Xcode. ++ # https://github.com/KhronosGroup/MoltenVK/issues/1756 ++ check_c_compiler_flag(-fno-objc-msgsend-selector-stubs HAVE_GCC_NO_OBJC_MSGSEND_SELECTOR_STUBS) ++ if(HAVE_GCC_NO_OBJC_MSGSEND_SELECTOR_STUBS) ++ list(APPEND EXTRA_CFLAGS "-fno-objc-msgsend-selector-stubs") ++ endif() ++ + check_c_compiler_flag(-Wdeclaration-after-statement HAVE_GCC_WDECLARATION_AFTER_STATEMENT) + if(HAVE_GCC_WDECLARATION_AFTER_STATEMENT) + check_c_compiler_flag(-Werror=declaration-after-statement HAVE_GCC_WERROR_DECLARATION_AFTER_STATEMENT) diff --git a/blender-build/build_environment/patches/semi.txt b/blender-build/build_environment/patches/semi.txt new file mode 100644 index 0000000..092bc2b --- /dev/null +++ b/blender-build/build_environment/patches/semi.txt @@ -0,0 +1 @@ +; diff --git a/blender-build/build_environment/patches/ssl.diff b/blender-build/build_environment/patches/ssl.diff new file mode 100644 index 0000000..7bb4413 --- /dev/null +++ b/blender-build/build_environment/patches/ssl.diff @@ -0,0 +1,10 @@ +--- ./test/v3ext.c 2022-07-05 11:08:33.000000000 +0200 ++++ ./test/v3ext.c 2022-10-18 13:58:05.000000000 +0200 +@@ -8,6 +8,7 @@ + */ + + #include ++#include + #include + #include + #include diff --git a/blender-build/build_environment/patches/tbb.diff b/blender-build/build_environment/patches/tbb.diff new file mode 100644 index 0000000..07f70aa --- /dev/null +++ b/blender-build/build_environment/patches/tbb.diff @@ -0,0 +1,24 @@ +diff --git a/include/tbb/tbb_config.h b/include/tbb/tbb_config.h +index 7a8d06a0..886699d8 100644 +--- a/include/tbb/tbb_config.h ++++ b/include/tbb/tbb_config.h +@@ -620,7 +620,7 @@ There are four cases that are supported: + // instantiation site, which is too late for suppression of the corresponding messages for internal + // stuff. + #if !defined(__INTEL_COMPILER) && (!defined(TBB_SUPPRESS_DEPRECATED_MESSAGES) || (TBB_SUPPRESS_DEPRECATED_MESSAGES == 0)) +- #if (__cplusplus >= 201402L) ++ #if (__cplusplus >= 201402L && (!defined(_MSC_VER) || _MSC_VER >= 1920)) + #define __TBB_DEPRECATED [[deprecated]] + #define __TBB_DEPRECATED_MSG(msg) [[deprecated(msg)]] + #elif _MSC_VER +--- a/src/tbb/tools_api/ittnotify_config.h ++++ b/src/tbb/tools_api/ittnotify_config.h +@@ -162,7 +162,7 @@ + # define ITT_ARCH ITT_ARCH_IA32E + # elif defined _M_IA64 || defined __ia64__ + # define ITT_ARCH ITT_ARCH_IA64 +-# elif defined _M_ARM || defined __arm__ ++# elif defined _M_ARM || defined __arm__ || defined __aarch64__ + # define ITT_ARCH ITT_ARCH_ARM + # elif defined __powerpc64__ + # define ITT_ARCH ITT_ARCH_PPC64 diff --git a/blender-build/build_environment/patches/theora.diff b/blender-build/build_environment/patches/theora.diff new file mode 100644 index 0000000..4436577 --- /dev/null +++ b/blender-build/build_environment/patches/theora.diff @@ -0,0 +1,18 @@ +--- config.sub ++++ config.sub +@@ -226,6 +226,7 @@ + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ ++ | aarch64 \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ +@@ -286,6 +287,7 @@ + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ ++ | aarch64-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ diff --git a/blender-build/build_environment/patches/tinyxml.diff b/blender-build/build_environment/patches/tinyxml.diff new file mode 100644 index 0000000..9965f3e --- /dev/null +++ b/blender-build/build_environment/patches/tinyxml.diff @@ -0,0 +1,34 @@ +diff -Naur tinyxml.orig/CMakeLists.txt tinyxml/CMakeLists.txt +--- tinyxml.orig/CMakeLists.txt 1969-12-31 16:00:00.000000000 -0800 ++++ tinyxml/CMakeLists.txt 2013-06-18 17:10:59.000000000 -0700 +@@ -0,0 +1,30 @@ ++project(tinyxml) ++ ++cmake_minimum_required(VERSION 2.8) ++ ++add_library(tinyxml ++ STATIC ++ tinystr.cpp ++ tinyxml.cpp ++ tinyxmlerror.cpp ++ tinyxmlparser.cpp) ++ ++set(TINYXML_COMPILE_FLAGS "-DTIXML_USE_STL") ++ ++if(UNIX) ++ set(TINYXML_COMPILE_FLAGS "${TINYXML_COMPILE_FLAGS} -fPIC -fvisibility=hidden") ++endif() ++ ++if(OCIO_INLINES_HIDDEN AND UNIX) ++ set(TINYXML_COMPILE_FLAGS "${TINYXML_COMPILE_FLAGS} -fvisibility-inlines-hidden") ++endif() ++ ++set_target_properties(tinyxml PROPERTIES ++ COMPILE_FLAGS "${TINYXML_COMPILE_FLAGS}") ++ ++install(TARGETS ++ tinyxml ++ DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) ++install(FILES ++ tinyxml.h tinystr.h ++ DESTINATION ${CMAKE_INSTALL_PREFIX}/include) diff --git a/blender-build/build_environment/patches/usd.diff b/blender-build/build_environment/patches/usd.diff new file mode 100644 index 0000000..39d3416 --- /dev/null +++ b/blender-build/build_environment/patches/usd.diff @@ -0,0 +1,116 @@ +diff -Naur orig/cmake/defaults/Packages.cmake external_usd/cmake/defaults/Packages.cmake +--- orig/cmake/defaults/Packages.cmake 2022-10-27 12:56:33 -0600 ++++ external_usd/cmake/defaults/Packages.cmake 2022-10-27 13:05:08 -0600 +@@ -129,7 +129,7 @@ + endif() + + # --TBB +-find_package(TBB REQUIRED COMPONENTS tbb) ++find_package(TBB) + add_definitions(${TBB_DEFINITIONS}) + + # --math +diff -Naur orig/cmake/defaults/msvcdefaults.cmake external_usd/cmake/defaults/msvcdefaults.cmake +--- orig/cmake/defaults/msvcdefaults.cmake 2022-10-27 12:56:33 -0600 ++++ external_usd/cmake/defaults/msvcdefaults.cmake 2022-10-27 13:05:08 -0600 +@@ -120,9 +120,6 @@ + # for all translation units. + set(_PXR_CXX_FLAGS "${_PXR_CXX_FLAGS} /bigobj") + +-# Enable PDB generation. +-set(_PXR_CXX_FLAGS "${_PXR_CXX_FLAGS} /Zi") +- + # Enable multiprocessor builds. + set(_PXR_CXX_FLAGS "${_PXR_CXX_FLAGS} /MP") + set(_PXR_CXX_FLAGS "${_PXR_CXX_FLAGS} /Gm-") +diff -Naur orig/pxr/base/arch/timing.h external_usd/pxr/base/arch/timing.h +--- orig/pxr/base/arch/timing.h 2022-10-27 12:56:34 -0600 ++++ external_usd/pxr/base/arch/timing.h 2022-10-27 13:05:08 -0600 +@@ -84,6 +84,10 @@ + inline uint64_t + ArchGetStartTickTime() + { ++ // BLENDER: avoid using rdtsc instruction that is not supported on older CPUs. ++ return ArchGetTickTime(); ++ ++#if 0 + uint64_t t; + #if defined (ARCH_OS_DARWIN) + return ArchGetTickTime(); +@@ -116,6 +120,7 @@ + #error "Unsupported architecture." + #endif + return t; ++#endif + } + + /// Get a "stop" tick time for measuring an interval of time. See +@@ -125,6 +130,10 @@ + inline uint64_t + ArchGetStopTickTime() + { ++ // BLENDER: avoid using rdtsc instruction that is not supported on older CPUs. ++ return ArchGetTickTime(); ++ ++#if 0 + uint64_t t; + #if defined (ARCH_OS_DARWIN) + return ArchGetTickTime(); +@@ -155,11 +164,11 @@ + #error "Unsupported architecture." + #endif + return t; ++#endif + } + +-#if defined (doxygen) || \ +- (!defined(ARCH_OS_DARWIN) && defined(ARCH_CPU_INTEL) && \ +- (defined(ARCH_COMPILER_CLANG) || defined(ARCH_COMPILER_GCC))) ++// BLENDER: avoid using rdtsc instruction that is not supported on older CPUs. ++#if 0 + + /// A simple timer class for measuring an interval of time using the + /// ArchTickTimer facilities. +diff -Naur orig/pxr/imaging/hioOpenVDB/CMakeLists.txt external_usd/pxr/imaging/hioOpenVDB/CMakeLists.txt +--- orig/pxr/imaging/hioOpenVDB/CMakeLists.txt 2022-10-27 12:56:35 -0600 ++++ external_usd/pxr/imaging/hioOpenVDB/CMakeLists.txt 2022-10-27 13:05:08 -0600 +@@ -20,6 +20,12 @@ + LIST(APPEND __VDB_IMATH_LIBS ${OPENEXR_Half_LIBRARY}) + endif() + ++if (WIN32) ++ # OpenVDB uses constants from that aren't available on ++ # Windows unless this is defined. ++ add_definitions(-D_USE_MATH_DEFINES) ++endif() ++ + pxr_library(hioOpenVDB + LIBRARIES + ar +diff -Naur orig/pxr/usdImaging/CMakeLists.txt external_usd/pxr/usdImaging/CMakeLists.txt +--- orig/pxr/usdImaging/CMakeLists.txt 2022-10-27 12:56:37 -0600 ++++ external_usd/pxr/usdImaging/CMakeLists.txt 2022-10-27 13:05:08 -0600 +@@ -7,7 +7,7 @@ + usdVolImaging + usdAppUtils + usdviewq +- bin ++# bin + plugin + ) + +diff -Naur orig/cmake/macros/Private.cmake external_usd/cmake/macros/Private.cmake +--- orig/cmake/macros/Private.cmake 2022-02-18 14:49:09 -0700 ++++ external_usd/cmake/macros/Private.cmake 2022-08-05 10:42:03 -0600 +@@ -900,8 +900,10 @@ + return() + endif() + +- if (WIN32 AND PXR_USE_DEBUG_PYTHON) ++ if (WIN32 AND PXR_USE_DEBUG_PYTHON AND NOT CMAKE_DEBUG_POSTFIX) + # On Windows when compiling with debug python the library must be named with _d. ++ # Blender: but this can be skipped if CMAKE_DEBUG_POSTFIX is set, it knows ++ # what it is doing and we don't want libraries ending in _d_d.pyd + set(LIBRARY_NAME "_${NAME}_d") + else() + set(LIBRARY_NAME "_${NAME}") diff --git a/blender-build/build_environment/patches/usd_hydra.diff b/blender-build/build_environment/patches/usd_hydra.diff new file mode 100644 index 0000000..04dacaf --- /dev/null +++ b/blender-build/build_environment/patches/usd_hydra.diff @@ -0,0 +1,37 @@ +diff --git a/pxr/usd/usdMtlx/reader.cpp b/pxr/usd/usdMtlx/reader.cpp +index 29e901816..e6fc68b20 100644 +--- a/pxr/usd/usdMtlx/reader.cpp ++++ b/pxr/usd/usdMtlx/reader.cpp +@@ -797,6 +797,15 @@ _NodeGraphBuilder::_CreateInterfaceInputs( + // We deliberately ignore tokens here. + } + ++mx::StringSet _GetStdlibIncludes() { ++ mx::StringSet stdlibIncludes = UsdMtlxGetDocument("")->getReferencedSourceUris(); ++ mx::StringSet normStdlibIncludes; ++ for (std::string const& entry : stdlibIncludes) { ++ normStdlibIncludes.insert(TfNormPath(entry)); ++ } ++ return normStdlibIncludes; ++} ++ + // Returns True if the mtlxNodeDef corresponds to a locally defined custom node + // with an associated nodegraph. + // XXX Locally defined custom nodes without nodegraphs are not supported +@@ -818,13 +827,14 @@ _NodeGraphBuilder::_IsLocalCustomNode(const mx::ConstNodeDefPtr &mtlxNodeDef) + } + // Combine with the nodeDef relative path + nodeDefUri = TfNormPath(fullMtlxPath + nodeDefUri); ++ } else { ++ nodeDefUri = TfNormPath(nodeDefUri); + } + + // This is a locally defined custom node if the absolute path to the + // nodedef is not included in the stdlibDoc. + static mx::StringSet customNodeDefNames; +- static const mx::StringSet stdlibIncludes = +- UsdMtlxGetDocument("")->getReferencedSourceUris(); ++ static const mx::StringSet stdlibIncludes = _GetStdlibIncludes(); + if (stdlibIncludes.find(nodeDefUri) == stdlibIncludes.end()) { + // Check if we already used this custom node + if (std::find(customNodeDefNames.begin(), customNodeDefNames.end(), diff --git a/blender-build/build_environment/patches/usd_pull_1965.diff b/blender-build/build_environment/patches/usd_pull_1965.diff new file mode 100644 index 0000000..308ee6c --- /dev/null +++ b/blender-build/build_environment/patches/usd_pull_1965.diff @@ -0,0 +1,106 @@ +diff --git a/build_scripts/build_usd.py b/build_scripts/build_usd.py +index cfe243effb..a4bb94eee1 100644 +--- a/build_scripts/build_usd.py ++++ b/build_scripts/build_usd.py +@@ -1415,7 +1415,7 @@ def InstallDraco(context, force, buildArgs): + ############################################################ + # MaterialX + +-MATERIALX_URL = "https://github.com/materialx/MaterialX/archive/v1.38.4.zip" ++MATERIALX_URL = "https://github.com/materialx/MaterialX/archive/v1.38.5.zip" + + def InstallMaterialX(context, force, buildArgs): + with CurrentWorkingDirectory(DownloadURL(MATERIALX_URL, context, force)): +diff --git a/pxr/imaging/hdSt/materialXShaderGen.cpp b/pxr/imaging/hdSt/materialXShaderGen.cpp +index df80ff119f..e4b5f04a73 100644 +--- a/pxr/imaging/hdSt/materialXShaderGen.cpp ++++ b/pxr/imaging/hdSt/materialXShaderGen.cpp +@@ -136,8 +136,7 @@ HdStMaterialXShaderGen::HdStMaterialXShaderGen( + "st" : mxHdInfo.defaultTexcoordName; + + // Register the customized version of the Surface node generator +- registerImplementation("IM_surface_" + GlslShaderGenerator::TARGET, +- HdStMaterialXSurfaceNodeGen::create); ++ registerImplementation("IM_surface_genglsl", HdStMaterialXSurfaceNodeGen::create); + } + + // Based on GlslShaderGenerator::generate() +@@ -273,8 +272,7 @@ HdStMaterialXShaderGen::_EmitMxFunctions( + mx::ShaderStage& mxStage) const + { + // Add global constants and type definitions +- emitLibraryInclude("stdlib/" + mx::GlslShaderGenerator::TARGET +- + "/lib/mx_math.glsl", mxContext, mxStage); ++ emitLibraryInclude("stdlib/genglsl/lib/mx_math.glsl", mxContext, mxStage); + emitLine("#if NUM_LIGHTS > 0", mxStage, false); + emitLine("#define MAX_LIGHT_SOURCES NUM_LIGHTS", mxStage, false); + emitLine("#else", mxStage, false); +@@ -394,16 +392,24 @@ HdStMaterialXShaderGen::_EmitMxFunctions( + emitSpecularEnvironment(mxContext, mxStage); + } + if (shadowing) { +- emitLibraryInclude("pbrlib/" + mx::GlslShaderGenerator::TARGET +- + "/lib/mx_shadow.glsl", mxContext, mxStage); ++ emitLibraryInclude("pbrlib/genglsl/lib/mx_shadow.glsl", mxContext, mxStage); + } + ++#if MATERIALX_MAJOR_VERSION > 1 || \ ++ (MATERIALX_MAJOR_VERSION == 1 && MATERIALX_MINOR_VERSION > 38) || \ ++ (MATERIALX_MAJOR_VERSION == 1 && MATERIALX_MINOR_VERSION == 38 && MATERIALX_BUILD_VERSION > 4) ++ // MaterialX 1.38.5 changes the default transmission method to "refraction". ++ mxContext.getOptions().hwTransmissionRenderMethod = mx::TRANSMISSION_OPACITY; ++ ++ // Emit transmission code ++ emitTransmissionRender(mxContext, mxStage); ++#endif ++ + // Emit directional albedo table code. + if (mxContext.getOptions().hwDirectionalAlbedoMethod == + mx::HwDirectionalAlbedoMethod::DIRECTIONAL_ALBEDO_TABLE || + mxContext.getOptions().hwWriteAlbedoTable) { +- emitLibraryInclude("pbrlib/" + mx::GlslShaderGenerator::TARGET +- + "/lib/mx_table.glsl", mxContext, mxStage); ++ emitLibraryInclude("pbrlib/genglsl/lib/mx_table.glsl", mxContext, mxStage); + emitLineBreak(mxStage); + } + +@@ -421,7 +427,7 @@ HdStMaterialXShaderGen::_EmitMxFunctions( + // Emit uv transform code globally if needed. + if (mxContext.getOptions().hwAmbientOcclusion) { + emitLibraryInclude( +- "stdlib/" + mx::GlslShaderGenerator::TARGET + "/lib/" + ++ "stdlib/genglsl/lib/" + + _tokenSubstitutions[ShaderGenerator::T_FILE_TRANSFORM_UV], + mxContext, mxStage); + } +@@ -490,10 +496,30 @@ HdStMaterialXShaderGen::_EmitMxSurfaceShader( + // closure/shader nodes and need to be emitted first. + emitFunctionCalls(mxGraph, mxContext, mxStage, mx::ShaderNode::Classification::TEXTURE); + ++#if MATERIALX_MAJOR_VERSION == 1 && \ ++ MATERIALX_MINOR_VERSION == 38 && \ ++ MATERIALX_BUILD_VERSION <= 4 + // Emit function calls for all surface shader nodes. + // These will internally emit their closure function calls. + emitFunctionCalls(mxGraph, mxContext, mxStage, mx::ShaderNode::Classification::SHADER | + mx::ShaderNode::Classification::SURFACE); ++#else ++ // Emit function calls for "root" closure/shader nodes. ++ // These will internally emit function calls for any dependent closure nodes upstream. ++ for (mx::ShaderGraphOutputSocket* socket : mxGraph.getOutputSockets()) ++ { ++ if (socket->getConnection()) ++ { ++ const mx::ShaderNode* upstream = socket->getConnection()->getNode(); ++ if (upstream->getParent() == &mxGraph && ++ (upstream->hasClassification(mx::ShaderNode::Classification::CLOSURE) || ++ upstream->hasClassification(mx::ShaderNode::Classification::SHADER))) ++ { ++ emitFunctionCall(*upstream, mxContext, mxStage); ++ } ++ } ++ } ++#endif + } + else + { diff --git a/blender-build/build_environment/patches/vpx_windows.diff b/blender-build/build_environment/patches/vpx_windows.diff new file mode 100644 index 0000000..13e3b06 --- /dev/null +++ b/blender-build/build_environment/patches/vpx_windows.diff @@ -0,0 +1,11 @@ +diff -Naur orig/configure external_vpx/configure +--- orig/configure 2022-07-06 09:22:04 -0600 ++++ external_vpx/configure 2022-07-06 09:24:12 -0600 +@@ -270,7 +270,6 @@ + HAVE_LIST=" + ${ARCH_EXT_LIST} + vpx_ports +- pthread_h + unistd_h + " + EXPERIMENT_LIST=" diff --git a/blender-build/build_environment/windows/build_deps.cmd b/blender-build/build_environment/windows/build_deps.cmd new file mode 100644 index 0000000..0c3bf85 --- /dev/null +++ b/blender-build/build_environment/windows/build_deps.cmd @@ -0,0 +1,140 @@ +@echo off +if NOT "%1" == "" ( + if "%1" == "2017" ( + echo "Building for VS2017" + set VSVER=15.0 + set VSVER_SHORT=15 + set BuildDir=VS15 + goto par2 + ) + if "%1" == "2019" ( + echo "Building for VS2019" + set VSVER=15.0 + set VSVER_SHORT=15 + set BuildDir=VS15 + goto par2 + ) + +) +:usage + +Echo Usage build_deps 2017/2019 x64 +goto exit +:par2 +if NOT "%2" == "" ( + if "%2" == "x64" ( + echo "Building for x64" + set HARVESTROOT=Win64_vc + set ARCH=64 + if "%1" == "2019" ( + set CMAKE_BUILDER=Visual Studio 16 2019 + set CMAKE_BUILD_ARCH=-A x64 + ) + if "%1" == "2017" ( + set CMAKE_BUILDER=Visual Studio 15 2017 Win64 + set CMAKE_BUILD_ARCH= + ) + goto start + ) +) +goto usage + +:start +setlocal ENABLEEXTENSIONS +set CMAKE_DEBUG_OPTIONS=-DWITH_OPTIMIZED_DEBUG=On +if "%3" == "debug" set CMAKE_DEBUG_OPTIONS=-DWITH_OPTIMIZED_DEBUG=Off +set dobuild=1 +if "%4" == "nobuild" set dobuild=0 + +REM If Python is be available certain deps may try to +REM to use this over the version we build, to prevent that +REM make sure pythonw is NOT in the path. We look for pythonw.exe +REM since windows apparently ships a python.exe that just opens up +REM the windows store but does not ship any actual python files that +REM could cause issues. +for %%X in (pythonw.exe) do (set PYTHONW=%%~$PATH:X) +if EXIST "%PYTHONW%" ( + echo PYTHON found at %PYTHONW% dependencies cannot be build with python available in the path + goto exit +) + +set SOURCE_DIR=%~dp0\.. +set BUILD_DIR=%cd%\build +set HARVEST_DIR=%BUILD_DIR%\output +set STAGING=%BUILD_DIR%\S + +rem for python module build +set MSSdk=1 +set DISTUTILS_USE_SDK=1 +rem if you let pip pick its own build dirs, it'll stick it somewhere deep inside the user profile +rem and cython will refuse to link due to a path that gets too long. +set TMPDIR=c:\t\ +rem for python externals source to be shared between the various archs and compilers +mkdir %BUILD_DIR%\downloads\externals + +REM Detect MSVC Installation +if DEFINED VisualStudioVersion goto msvc_detect_finally +set VALUE_NAME=ProductDir +REM Check 64 bits +set KEY_NAME="HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\%VSVER%\Setup\VC" +for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY %KEY_NAME% /v %VALUE_NAME% 2^>nul`) DO set MSVC_VC_DIR=%%C +if DEFINED MSVC_VC_DIR goto msvc_detect_finally +REM Check 32 bits +set KEY_NAME="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\%VSVER%\Setup\VC" +for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY %KEY_NAME% /v %VALUE_NAME% 2^>nul`) DO set MSVC_VC_DIR=%%C +if DEFINED MSVC_VC_DIR goto msvc_detect_finally +:msvc_detect_finally +if DEFINED MSVC_VC_DIR call "%MSVC_VC_DIR%\vcvarsall.bat" +echo on + +REM Sanity Checks +where /Q msbuild +if %ERRORLEVEL% NEQ 0 ( + echo Error: "MSBuild" command not in the PATH. + echo You must have MSVC installed and run this from the "Developer Command Prompt" + echo ^(available from Visual Studio's Start menu entry^), aborting! + goto EOF +) +where /Q cmake +if %ERRORLEVEL% NEQ 0 ( + echo Error: "CMake" command not in the PATH. + echo You must have CMake installed and added to your PATH, aborting! + goto EOF +) + +set StatusFile=%BUILD_DIR%\%1_%2.log +set original_path=%path% +set oiio_paths=%Staging%\%BuildDir%%ARCH%R\Release\openimageio\bin;%Staging%\%BuildDir%%ARCH%D\Debug\openimageio\bin +set boost_paths=%Staging%\%BuildDir%%ARCH%R\Release\boost\lib;%Staging%\%BuildDir%%ARCH%D\Debug\boost\lib +set openexr_paths=%Staging%\%BuildDir%%ARCH%R\Release\openexr\bin;%Staging%\%BuildDir%%ARCH%D\Debug\openexr\bin +set imath_paths=%Staging%\%BuildDir%%ARCH%R\Release\imath\bin;%Staging%\%BuildDir%%ARCH%D\Debug\imath\bin +set tbb_paths=%Staging%\%BuildDir%%ARCH%R\Release\tbb\bin;%Staging%\%BuildDir%%ARCH%D\Debug\tbb\bin +set path=%BUILD_DIR%\downloads\mingw\mingw64\msys\1.0\bin\;%BUILD_DIR%\downloads\nasm-2.12.01\;%path%;%boost_paths%;%oiio_paths%;%openexr_paths%;%imath_paths%;%tbb_paths% +mkdir %STAGING%\%BuildDir%%ARCH%R +cd %Staging%\%BuildDir%%ARCH%R +echo %DATE% %TIME% : Start > %StatusFile% +cmake -G "%CMAKE_BUILDER%" %CMAKE_BUILD_ARCH% -Thost=x64 %SOURCE_DIR% -DPACKAGE_DIR=%BUILD_DIR%/packages -DDOWNLOAD_DIR=%BUILD_DIR%/downloads -DBUILD_MODE=Release -DHARVEST_TARGET=%HARVEST_DIR%/%HARVESTROOT%%VSVER_SHORT%/ +echo %DATE% %TIME% : Release Configuration done >> %StatusFile% +if "%dobuild%" == "1" ( + msbuild -maxcpucount:1 "BlenderDependencies.sln" /p:Configuration=Release /fl /flp:logfile=BlenderDeps.log;Verbosity=minimal /verbosity:minimal + echo %DATE% %TIME% : Release Build done >> %StatusFile% + cmake --build . --target Harvest_Release_Results > Harvest_Release.txt +) +echo %DATE% %TIME% : Release Harvest done >> %StatusFile% +if "%NODEBUG%" == "1" goto exit +cd %BUILD_DIR% +mkdir %STAGING%\%BuildDir%%ARCH%D +cd %Staging%\%BuildDir%%ARCH%D +cmake -G "%CMAKE_BUILDER%" %CMAKE_BUILD_ARCH% -Thost=x64 %SOURCE_DIR% -DPACKAGE_DIR=%BUILD_DIR%/packages -DDOWNLOAD_DIR=%BUILD_DIR%/downloads -DCMAKE_BUILD_TYPE=Debug -DBUILD_MODE=Debug -DHARVEST_TARGET=%HARVEST_DIR%/%HARVESTROOT%%VSVER_SHORT%/ %CMAKE_DEBUG_OPTIONS% +echo %DATE% %TIME% : Debug Configuration done >> %StatusFile% +if "%dobuild%" == "1" ( + msbuild -maxcpucount:1 "BlenderDependencies.sln" /p:Configuration=Debug /verbosity:n /fl /flp:logfile=BlenderDeps.log;;Verbosity=normal + echo %DATE% %TIME% : Debug Build done >> %StatusFile% + cmake --build . --target Harvest_Debug_Results> Harvest_Debug.txt +) +echo %DATE% %TIME% : Debug Harvest done >> %StatusFile% +cd %BUILD_DIR% + +:exit +set path=%original_path% +Echo . diff --git a/blender-build/build_environment/windows/buildall.cmd b/blender-build/build_environment/windows/buildall.cmd new file mode 100644 index 0000000..480be8c --- /dev/null +++ b/blender-build/build_environment/windows/buildall.cmd @@ -0,0 +1,10 @@ +title building 1_4 - x86_2013 +call build_deps 2013 x86 +title building 2_4 - x86_2015 +call build_deps 2015 x86 +title building 3_4 - x64_2013 +call build_deps 2013 x64 +title building 4_4 - x64_2015 +call build_deps 2015 x64 +title done! +echo done! \ No newline at end of file diff --git a/blender-build/build_environment/windows/nuke.cmd b/blender-build/build_environment/windows/nuke.cmd new file mode 100644 index 0000000..68dbc8d --- /dev/null +++ b/blender-build/build_environment/windows/nuke.cmd @@ -0,0 +1,52 @@ +@echo off +if "%1"=="" goto EOF: +set ROOT=%~dp0\..\..\..\..\build_windows\deps + +set CurPath=%ROOT%\s\vs1264D\debug\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1264D\build\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1264R\release\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1264R\build\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\output\win64_vc12\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) + +set CurPath=%ROOT%\s\vs1464D\debug\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1464D\build\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1464R\release\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1464R\build\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\output\win64_vc14\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) + +set CurPath=%ROOT%\s\vs1286D\debug\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1286D\build\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1286R\release\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1286R\build\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\output\windows_vc12\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) + +set CurPath=%ROOT%\s\vs1486D\debug\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1486D\build\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1486R\release\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\s\vs1486R\build\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) +set CurPath=%ROOT%\output\windows_vc14\%1\ +if EXIST %CurPath%\nul ( echo removing "%CurPath%" && rd /s /q "%CurPath%" ) + + +:EOF + + diff --git a/build-blender.sh b/build-blender.sh new file mode 100755 index 0000000..95d00fc --- /dev/null +++ b/build-blender.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +set -e +BASE_PATH=$(pwd) +CPU=$(uname -m) + +BLENDER_DIR=${BASE_PATH}/blender +DEPS_BUILD=${BASE_PATH}/build_linux_${CPU}_deps +DEPS_SRC=${BASE_PATH}/blender-build/build_environment +DEPS_INSTALL=${BASE_PATH}/lib/lib_${CPU} +BLENDER_SRC=${BLENDER_DIR} +BLENDER_BUILD=${BASE_PATH}/build_linux_${CPU} + +cd ${BASE_PATH}/blender +#sed -e 's/set(OPENAL_HASH .*/set(OPENAL_HASH a4922a79526c590b6cac0c10f3f1bef8)/g' -i build_files/build_environment/cmake/versions.cmake +## sed -e 's/set(LIBGLU_HASH .*/set(LIBGLU_HASH d41d8cd98f00b204e9800998ecf8427e)/g' -i build_files/build_environment/cmake/versions.cmake +#sed -e 's@set(OPENAL_URI .*@set(OPENAL_URI https://github.com/kcat/openal-soft/archive/refs/tags/${OPENAL_VERSION}.tar.gz)@g' -i build_files/build_environment/cmake/versions.cmake +#sed -e 's@set(OPENAL_FILE .*@set(OPENAL_FILE openal-soft-${OPENAL_VERSION}.tar.gz)@g' -i build_files/build_environment/cmake/versions.cmake +#sed -e 's@set(LIBGLU_URI .*@set(LIBGLU_URI https://archive.mesa3d.org/glu/glu-${LIBGLU_VERSION}.tar.xz)@g' -i build_files/build_environment/cmake/versions.cmake +#sed -e 's@set(MESA_URI .*@set(MESA_URI https://archive.mesa3d.org/older-versions/21.x/mesa-${MESA_VERSION}.tar.xz)@g' -i build_files/build_environment/cmake/versions.cmake +#sed -e 's@set(FRIBIDI_URI .*@set(FRIBIDI_URI https://github.com/fribidi/fribidi/archive/refs/tags/${FRIBIDI_VERSION}.tar.gz)@g' -i build_files/build_environment/cmake/versions.cmake +#sed -e 's@set(FRIBIDI_FILE .*@set(FRIBIDI_FILE fribidi-${FRIBIDI_VERSION}.tar.gz)@g' -i build_files/build_environment/cmake/versions.cmake +if [ x$CPU = xaarch64 ]; then +python3 ./build_files/utils/make_update.py --architecture arm64 +else +python3 ./build_files/utils/make_update.py +fi +cd ${BASE_PATH} + + +cmake -S ${DEPS_SRC} -B ${DEPS_BUILD} \ + -DHARVEST_TARGET=${DEPS_INSTALL} \ + -DBLENDER_PLATFORM_ARM=ON +cd ${DEPS_BUILD} && make install && cd ${BASE_PATH} + +cmake -S ${BLENDER_SRC} -B ${BLENDER_BUILD} \ + -C${BLENDER_DIR}/build_files/cmake/config/blender_release.cmake \ + -DBLENDER_PLATFORM_ARM=ON \ + -DWITH_CYCLES_EMBREE=OFF \ + -DLIBDIR=${BASE_PATH}/lib/lib_${CPU} +cd ${BLENDER_BUILD} && make && make install && make package_archive +mkdir prebuilts +cp ./build_linux_${CPU}/release/Blender-3.6-unknown-linux-${CPU}.tar.xz ./prebuilts +git add ./prebuilts/Blender-3.6-unknown-linux-${CPU}.tar.xz +git lfs track --filename ./prebuilts/Blender-3.6-unknown-linux-${CPU}.tar.xz +