pax_global_header00006660000000000000000000000064141723475070014524gustar00rootroot0000000000000052 comment=3a92a3f95b86b7babeed7403a330334758e1d644 Halide-13.0.4/000077500000000000000000000000001417234750700127775ustar00rootroot00000000000000Halide-13.0.4/.clang-format000066400000000000000000000026631417234750700153610ustar00rootroot00000000000000--- AccessModifierOffset: -4 AlignEscapedNewlines: Left AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: Empty AllowShortFunctionsOnASingleLine: None AllowShortIfStatementsOnASingleLine: Always AllowShortLoopsOnASingleLine: false AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: Yes BinPackParameters: true BreakBeforeBinaryOperators: None BreakBeforeBraces: Attach BreakBeforeTernaryOperators: false BreakConstructorInitializersBeforeComma: false ColumnLimit: 0 ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 Cpp11BracedListStyle: true DerivePointerAlignment: false ExperimentalAutoDetectBinPacking: false IndentCaseLabels: false IndentWrappedFunctionNames: false IndentWidth: 4 MaxEmptyLinesToKeep: 1 NamespaceIndentation: None ObjCSpaceBeforeProtocolList: true PenaltyBreakBeforeFirstCallParameter: 19 PenaltyBreakComment: 60 PenaltyBreakFirstLessLess: 120 PenaltyBreakString: 1000 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 60 PointerAlignment: Right SpaceBeforeParens: ControlStatements SpaceAfterCStyleCast: false SpaceAfterTemplateKeyword: false SpaceBeforeAssignmentOperators: true SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 2 SpacesInAngles: false SpacesInCStyleCastParentheses: false SpacesInParentheses: false Standard: c++17 TabWidth: 8 UseTab: Never ... Halide-13.0.4/.clang-format-ignore000066400000000000000000000004111417234750700166270ustar00rootroot00000000000000# .clang-format-ignore ./bin ./build ./cmake_build ./cmake_build_static ./cmake_build_shared ./distrib ./doc ./include ./lib # Our tutorials have special formatting: skip them ./tutorial # hexagon_remote/bin/src is also special ./src/runtime/hexagon_remote/bin/src Halide-13.0.4/.clang-tidy000066400000000000000000000034661417234750700150440ustar00rootroot00000000000000# TODO: some of the blocklisted bugprone checks can/should be re-enabled # one at a time (with careful code fixes made as necessary). --- Checks: > -*, bugprone-*, -bugprone-branch-clone, -bugprone-exception-escape, -bugprone-integer-division, -bugprone-narrowing-conversions, -bugprone-reserved-identifier, -bugprone-signed-char-misuse, misc-*, -misc-no-recursion, -misc-non-private-member-variables-in-classes, -misc-unconventional-assign-operator, -misc-unused-parameters, modernize-deprecated-headers, modernize-loop-convert, modernize-make-shared, modernize-make-unique, modernize-redundant-void-arg, modernize-use-bool-literals, modernize-use-default-member-init, modernize-use-emplace, modernize-use-equals-default, modernize-use-equals-delete, modernize-use-nullptr, modernize-use-override, performance-*, -performance-inefficient-string-concatenation, -performance-inefficient-vector-operation, -performance-no-int-to-ptr, readability-avoid-const-params-in-decls, readability-braces-around-statements, readability-const-return-type, readability-container-size-empty, readability-misplaced-array-index, readability-qualified-auto, readability-redundant-access-specifiers, readability-redundant-control-flow, readability-redundant-function-ptr-dereference, readability-redundant-preprocessor, readability-redundant-smartptr-get, readability-redundant-string-cstr, readability-simplify-subscript-expr, readability-static-accessed-through-instance, readability-static-definition-in-anonymous-namespace, WarningsAsErrors: '*' HeaderFilterRegex: '.*' FormatStyle: 'file' CheckOptions: - key: modernize-use-default-member-init.UseAssignment value: 1 ... Halide-13.0.4/.gitattributes000066400000000000000000000005261417234750700156750ustar00rootroot00000000000000# Set the default behavior, in case people don't have core.autocrlf set. * text=auto # Explicitly declare text files you want to always be normalized and converted # to native line endings on checkout. *.cpp text *.c text *.h text # Denote all files that are truly binary and should not be modified. *.png binary *.jpg binary *.tiff binary Halide-13.0.4/.github/000077500000000000000000000000001417234750700143375ustar00rootroot00000000000000Halide-13.0.4/.github/workflows/000077500000000000000000000000001417234750700163745ustar00rootroot00000000000000Halide-13.0.4/.github/workflows/packaging.yml000066400000000000000000000036541417234750700210530ustar00rootroot00000000000000name: Packaging on: [ 'pull_request' ] jobs: package-ubuntu: name: Package for Ubuntu runs-on: ubuntu-20.04 env: CMAKE_CXX_COMPILER_LAUNCHER: ccache CMAKE_C_COMPILER_LAUNCHER: ccache LLVM_ROOT: /usr/lib/llvm-11 steps: - name: Install dependencies run: | wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null \ | gpg --dearmor - | sudo tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null sudo apt-add-repository 'deb https://apt.kitware.com/ubuntu/ focal main' sudo apt update sudo apt install cmake ninja-build doxygen ccache sudo apt install llvm-11-dev liblld-11-dev clang-11 libclang-11-dev libjpeg-dev libpng-dev sudo apt install lintian dpkg-dev - name: Check out sources uses: actions/checkout@v2 - name: Set up ccache uses: hendrikmuhs/ccache-action@v1 - name: Run Ubuntu packaging script run: ./packaging/ubuntu/package.sh . ubuntu - name: Upload packages uses: actions/upload-artifact@v2 with: name: packages path: ubuntu/*.deb test-ubuntu: name: Test Ubuntu package needs: package-ubuntu runs-on: ubuntu-20.04 steps: # Specifically use the CMake version that comes with Ubuntu. - name: Install dependencies run: | sudo apt update sudo apt install cmake ninja-build libc6-dev-arm64-cross gcc-aarch64-linux-gnu g++-aarch64-linux-gnu qemu-user - name: Check out sources uses: actions/checkout@v2 - name: Download Halide Ubuntu packages uses: actions/download-artifact@v2 with: name: packages - name: Install Halide Ubuntu packages run: sudo apt install ./*.deb - name: Test integration run: | cmake -S test/integration -B build cd build && ctest -j$(nproc) --output-on-failure Halide-13.0.4/.github/workflows/presubmit.yml000066400000000000000000000051541417234750700211360ustar00rootroot00000000000000name: Halide Presubmit Checks on: # We don't want 'edited' (that's basically just the description, title, etc) # We don't want 'review_requested' (that's redundant to the ones below for our purposes) pull_request: types: [opened, synchronize, reopened] paths: - '**.h' - '**.c' - '**.cpp' jobs: check_clang_format: name: Check clang-format runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - uses: DoozyX/clang-format-lint-action@v0.12 with: source: '.' extensions: 'h,c,cpp' clangFormatVersion: 12 check_clang_tidy: name: Check clang-tidy runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - name: Install clang-tidy run: | sudo apt-get update sudo apt-get install llvm-12 clang-12 liblld-12-dev libclang-12-dev clang-tidy-12 ninja-build - name: Run clang-tidy run: | export CC=clang-12 export CXX=clang++-12 export CLANG_TIDY_LLVM_INSTALL_DIR=/usr/lib/llvm-12 ./run-clang-tidy.sh check_cmake_file_lists: name: Check CMake file lists runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - name: Run test sources check run: | shopt -s nullglob (cd test/auto_schedule && comm -23 <(ls *.{c,cpp} | sort) <(grep -P '^\s*#?\s*[A-Za-z0-9_.]+$' CMakeLists.txt | tr -d '# ' | sort) | tee missing_files && [ ! -s missing_files ]) (cd test/correctness && comm -23 <(ls *.{c,cpp} | sort) <(grep -P '^\s*#?\s*[A-Za-z0-9_.]+$' CMakeLists.txt | tr -d '# ' | sort) | tee missing_files && [ ! -s missing_files ]) (cd test/error && comm -23 <(ls *.{c,cpp} | sort) <(grep -P '^\s*#?\s*[A-Za-z0-9_.]+$' CMakeLists.txt | tr -d '# ' | sort) | tee missing_files && [ ! -s missing_files ]) (cd test/generator && comm -23 <(ls *.{c,cpp} | sort) <(grep -P '^\s*#?\s*[A-Za-z0-9_.]+$' CMakeLists.txt | tr -d '# ' | sort) | tee missing_files && [ ! -s missing_files ]) (cd test/failing_with_issue && comm -23 <(ls *.{c,cpp} | sort) <(grep -P '^\s*#?\s*[A-Za-z0-9_.]+$' CMakeLists.txt | tr -d '# ' | sort) | tee missing_files && [ ! -s missing_files ]) (cd test/performance && comm -23 <(ls *.{c,cpp} | sort) <(grep -P '^\s*#?\s*[A-Za-z0-9_.]+$' CMakeLists.txt | tr -d '# ' | sort) | tee missing_files && [ ! -s missing_files ]) (cd test/warning && comm -23 <(ls *.{c,cpp} | sort) <(grep -P '^\s*#?\s*[A-Za-z0-9_.]+$' CMakeLists.txt | tr -d '# ' | sort) | tee missing_files && [ ! -s missing_files ]) Halide-13.0.4/.github/workflows/test.yml000066400000000000000000000425441417234750700201070ustar00rootroot00000000000000# TODO (known issues) # - no GPU tests are attempted (probably not possible) # - cmake static builds aren't handled yet. # - arm32 and arm64 is build-only, no testing (qemu is too slow). # Perhaps some limited testing instead of none? # - python is built+tested for x86-64 targets only (no arm or 32-bit) # - apps are skipped for x86-32, arm-32, arm-64 # # TODO (stuff that could be usefully added, perhaps) # - build + test of WASM # - build + test of PyTorch # # TODO (GHA issues) # - GHA is occasionally flaky and some VMs just fail, but there isn't a way # to restart just one of the jobs (it's currently all-or-none) name: Halide Presubmit Build + Test on: workflow_dispatch: # inputs: # logLevel: # description: 'Log level' # required: true # default: 'warning' # tags: # description: 'Test scenario tags' # pull_request: # # We don't want 'edited' (that's basically just the description, title, etc) # # We don't want 'review_requested' (that's redundant to the ones below for our purposes) # types: [opened, synchronize, reopened] # # TODO: do we want to limit this to certain filetypes? # # paths: # # - '**.h' # # - '**.c' # # - '**.cpp' jobs: test_halide: name: HL-${{matrix.llvm_version}}-${{matrix.target_arch}}-${{matrix.target_bits}}-${{matrix.target_os}}-${{matrix.build_tool}} runs-on: ${{matrix.host_os}} env: CC: ${{matrix.cc}} CXX: ${{matrix.cxx}} LD: ${{matrix.ld}} strategy: fail-fast: false # Keep running other jobs even if one fails # free-tier projects (like Halide) get 20 concurrent tasks. # The build matrix here has only 7 tasks -- should we limit it to fewer # than that? Need to experiment. # max-parallel: TBD TODO matrix: # TODO: this matrix is probably overkill; we don't need to build every combination. # (Some combinations are nonsensical and excluded via the 'exclude:' section below.) target_arch: [x86, arm] target_bits: [32, 64] target_os: [linux, osx, windows] llvm_version: [12] build_tool: [cmake_shared] # llvm_version: [10, 11, 12] # TODO # build_tool: [cmake_shared, make] # TODO # This section basically allows us to define additional values for # each matrix entry, e.g. to map an llvm version number to the specific # git branch that is needed. include: # - llvm_version: 10 # llvm_branch: release/10.x # - llvm_version: 11 # llvm_branch: release/11.x - llvm_version: 12 llvm_branch: master # map things to the necessary host cross-compiler host - target_os: osx host_os: macos-10.15 cc: clang cxx: clang++ ld: ld - target_os: linux host_os: ubuntu-18.04 # GHA has clang 6, 8, and 9 and GCC 7.4, 8.3, 9.2 preinstalled. # We will explicitly choose gcc 7.x (even though the default is gcc 7.4) # to ensure we match gcc versions with the arm crosscompiler. cc: gcc-7 cxx: g++-7 ld: ld - target_os: windows host_os: windows-2019 cc: cl.exe cxx: cl.exe ld: ld.exe - target_arch: x86 python_version: '3.7' uses_python: true run_tests: true - target_bits: 32 # We don't build/test Python bindings on any 32-bit targets uses_python: false - target_arch: arm # We don't build/test Python bindings on any ARM targets uses_python: false # Running our test suite (via e.g. QEMU) is too slow to be useful # at present (> 5 hours on current GHA VMs). That said, we'll leave # in the relevant code for now (disabled via this flag) in case # it proves useful later. run_tests: false exclude: - target_os: osx target_arch: arm # OSX is x86-only - target_os: osx target_bits: 32 # OSX is 64-bit only - target_os: windows target_arch: arm # OSX is x86-only - target_os: windows build_tool: make # Windows is CMake-only - target_arch: arm build_tool: make # In this setup, all ARM builds require CMake steps: - uses: actions/checkout@v2 with: path: 'halide' - name: Configure Python if: matrix.uses_python uses: actions/setup-python@v1 with: python-version: '${{matrix.python_version}}' architecture: 'x64' - name: Configure Ubuntu Host if: startsWith(matrix.host_os, 'ubuntu') shell: bash run: | sudo apt-get update sudo apt-get install \ doxygen \ libjpeg-dev \ libpng-dev \ ninja-build - name: Configure MacOS Host if: startsWith(matrix.host_os, 'macos') shell: bash run: | # coreutils is for gtimeout brew install \ coreutils \ doxygen \ jpeg \ libpng \ ninja - name: Configure Windows Host if: startsWith(matrix.host_os, 'windows') shell: bash run: | if [[ ${{matrix.target_bits}} == 32 ]]; then export VCPKG_DEFAULT_TRIPLET=x86-windows else export VCPKG_DEFAULT_TRIPLET=x64-windows fi vcpkg install \ libjpeg-turbo \ libpng \ zlib - name: Configure x86-32 Crosscompilation if: matrix.target_os == 'linux' && matrix.target_arch == 'x86' && matrix.target_bits == 32 shell: bash run: | sudo dpkg --add-architecture i386 sudo apt-get update sudo apt-get install \ ${{matrix.cc}}-multilib \ ${{matrix.cxx}}-multilib \ libjpeg-dev:i386 \ libpng-dev:i386 \ - name: Configure Arm32 Crosscompilation if: matrix.target_os == 'linux' && matrix.target_arch == 'arm' && matrix.target_bits == 32 shell: bash run: | # Note that we are configuring this for user-mode emulation: # syscalls will be native, only user-mode code will be emulated. # This is not 100% perfect (there are various corner cases that # can bite us), but is *much* faster than full machine emulation. sudo apt-get update sudo apt-get install --install-suggests \ ${{matrix.cc}}-arm-linux-gnueabihf \ ${{matrix.cxx}}-arm-linux-gnueabihf # TODO: figure out how to install libjpeg and libpng for armhf; # the standard apt repository for GHA VMs barfs on these. # sudo apt-get install \ # libjpeg-dev:armhf \ # libpng-dev:armhf # Note that we need QEMU even if not running tests, as Generators # will be built for arm by default, and we need to be able to run them. sudo apt-get install --install-suggests \ qemu-user \ qemu-user-binfmt qemu-arm --version echo ::set-env name=QEMU_LD_PREFIX::"/usr/arm-linux-gnueabihf" - name: Configure AArch64 Crosscompilation if: matrix.target_os == 'linux' && matrix.target_arch == 'arm' && matrix.target_bits == 64 shell: bash run: | sudo apt-get update sudo apt-get install --install-suggests \ ${{matrix.cc}}-aarch64-linux-gnu \ ${{matrix.cxx}}-aarch64-linux-gnu # TODO: figure out how to install libjpeg and libpng for armhf; # the standard apt repository for GHA VMs barfs on these. # sudo apt-get install \ # libjpeg-dev:aarch64 \ # libpng-dev:aarch64 # Note that we need QEMU even if not running tests, as Generators # will be built for arm by default, and we need to be able to run them. sudo apt-get install --install-suggests \ qemu-user \ qemu-user-binfmt qemu-arm --version echo ::set-env name=QEMU_LD_PREFIX::"/usr/aarch64-linux-gnu" - name: Configure Env Vars shell: bash run: | echo "github.event_name is ${{github.event_name}}" # should always be "pull_request" echo "github.event.action is ${{github.event.action}}" # Demangle Windows names, to simplify CMake stuff later _ROOT=${GITHUB_WORKSPACE//\\//} _TEMP_RAW="${{runner.temp}}" _TEMP=${_TEMP_RAW//\\//} # This is the trick GitHub Actions uses to allow us to set env vars across all subsequent job steps echo ::set-env name=BUILD_TYPE::"Release" echo ::set-env name=LLVM_INSTALL_DIR::"${_ROOT}/llvm" echo ::set-env name=LLVM_CONFIG::"${_ROOT}/llvm/bin/llvm-config" echo ::set-env name=HALIDE_SOURCE_DIR::"${_ROOT}/halide" echo ::set-env name=HALIDE_BUILD_DIR::"${_ROOT}/halide_build" echo ::set-env name=HALIDE_TEMP_DIR::"${_TEMP}" echo ::set-env name=PARALLEL_JOBS::"4" if [[ ${{matrix.host_os}} == windows* ]]; then # On Windows, it's just 'python', apparently echo ::set-env name=PYTHON::"python" else echo ::set-env name=PYTHON::"python${{matrix.python_version}}" fi - name: Install Python Dependencies if: matrix.uses_python shell: bash run: | ${PYTHON} -m pip --version ${PYTHON} -m pip install --upgrade pip ${PYTHON} -m pip install -r ${HALIDE_SOURCE_DIR}/python_bindings/requirements.txt echo ::set-env name=PYTHON::"${PYTHON}" - name: Install LLVM shell: bash run: | LLVM_ID="llvm-${{matrix.llvm_version}}-${{matrix.target_arch}}-${{matrix.target_bits}}-${{matrix.target_os}}" curl \ --user llvm_user:${{secrets.LLVM_USER_PASSWORD}} \ --output ${HALIDE_TEMP_DIR}/llvm-prebuilt.tgz \ https://buildbot.halide-lang.org/llvm/${LLVM_ID}.tgz TAR_CMD="tar" if [[ ${{matrix.host_os}} == windows* ]]; then # Must use --force-local to avoid tar misinterpreting the : in # a Windows pathname as a hostname. TAR_CMD="tar --force-local" fi mkdir ${LLVM_INSTALL_DIR} ${TAR_CMD} -xf ${HALIDE_TEMP_DIR}/llvm-prebuilt.tgz -C ${LLVM_INSTALL_DIR} rm -rf ${HALIDE_TEMP_DIR}/llvm-prebuilt.tgz LLVM_COMMIT_HASH=`cat ${LLVM_INSTALL_DIR}/.halide_builder_llvm_commit` echo "Using LLVM v${{matrix.llvm_version}} commit=${LLVM_COMMIT_HASH}" - name: Configure Halide (Make) if: startsWith(matrix.build_tool, 'make') shell: bash run: | # Configure Make mkdir ${HALIDE_BUILD_DIR} if [[ ${{matrix.target_arch}} == x86 && \ ${{matrix.target_os}} == linux && \ ${{matrix.target_bits}} == 32 ]]; then echo ::set-env name=CC::"${CC} -m32" echo ::set-env name=CXX::"${CXX} -m32" echo ::set-env name=LD::"${LD} -melf_i386" fi - name: Configure Halide (CMake) if: startsWith(matrix.build_tool, 'cmake') shell: bash run: | # Configure CMake echo `cmake --version` mkdir ${HALIDE_BUILD_DIR} CMAKE_GEN="Ninja" EXTRA_CMAKE_FLAGS= if [[ ${{matrix.host_os}} == windows* ]]; then CMAKE_GEN="Visual Studio 16 2019" # CMAKE_TOOLCHAIN_FILE is necessary for CMake to find things installed by vcpkg EXTRA_CMAKE_FLAGS="${EXTRA_CMAKE_FLAGS} \ -D CMAKE_TOOLCHAIN_FILE=${VCPKG_INSTALLATION_ROOT//\\//}/scripts/buildsystems/vcpkg.cmake \ -T host=x64" if [[ ${{matrix.target_bits}} == 32 ]]; then EXTRA_CMAKE_FLAGS="${EXTRA_CMAKE_FLAGS} -A Win32" else EXTRA_CMAKE_FLAGS="${EXTRA_CMAKE_FLAGS} -A x64" fi fi if [[ ${{matrix.target_arch}} == x86 && \ ${{matrix.target_os}} == linux && \ ${{matrix.target_bits}} == 32 ]]; then # Assume host_os is ubuntu* EXTRA_CMAKE_FLAGS="${EXTRA_CMAKE_FLAGS} \ -D CMAKE_TOOLCHAIN_FILE=${HALIDE_SOURCE_DIR}/cmake/toolchain.linux-i386.cmake" fi if [[ ${{matrix.target_os}} == osx ]]; then # LLVM_ENABLE_SUPPORT_XCODE_SIGNPOSTS=OFF is needed for compatibility with older XCode versions EXTRA_CMAKE_FLAGS="${EXTRA_CMAKE_FLAGS} \ -D LLVM_ENABLE_SUPPORT_XCODE_SIGNPOSTS=FORCE_OFF" fi if [[ ${{matrix.target_arch}} == arm ]]; then # The arm toolchain files default to "gcc"/"g++" with no version appended, # but we installed specific versions, so be sure it can find those specific versions. if [[ ${{matrix.target_bits}} == 32 ]]; then export ARCH_FOR_TESTS=armv7-a EXTRA_CMAKE_FLAGS="${EXTRA_CMAKE_FLAGS} \ -D CMAKE_C_COMPILER=arm-linux-gnueabihf-${{matrix.cc}} \ -D CMAKE_CXX_COMPILER=arm-linux-gnueabihf-${{matrix.cxx}} \ -D CMAKE_TOOLCHAIN_FILE=${HALIDE_SOURCE_DIR}/cmake/toolchain.linux-arm32.cmake" else export ARCH_FOR_TESTS=armv8-a EXTRA_CMAKE_FLAGS="${EXTRA_CMAKE_FLAGS} \ -D CMAKE_C_COMPILER=aarch64-linux-gnu-${{matrix.cc}} \ -D CMAKE_CXX_COMPILER=aarch64-linux-gnu-${{matrix.cxx}} \ -D CMAKE_TOOLCHAIN_FILE=${HALIDE_SOURCE_DIR}/cmake/toolchain.linux-aarch64.cmake" fi fi REQUIRE_LLVM_VERSION="${{matrix.llvm_version}}0" SHARED_LIBRARY=$([ ${{matrix.build_tool}} == "cmake_shared" ] && echo "ON" || echo "OFF") if [[ "${{matrix.uses_python}}" == "true" ]]; then EXTRA_CMAKE_FLAGS="${EXTRA_CMAKE_FLAGS} \ -D WITH_PYTHON_BINDINGS=ON" else EXTRA_CMAKE_FLAGS="${EXTRA_CMAKE_FLAGS} \ -D WITH_PYTHON_BINDINGS=OFF" fi cmake \ -D CMAKE_BUILD_TYPE=${BUILD_TYPE} \ -D LLVM_DIR="${LLVM_INSTALL_DIR}/lib/cmake/llvm" \ -D HALIDE_REQUIRE_LLVM_VERSION="${REQUIRE_LLVM_VERSION}" \ -D HALIDE_SHARED_LIBRARY=${SHARED_LIBRARY} \ -G "${CMAKE_GEN}" \ ${EXTRA_CMAKE_FLAGS} \ -S "${HALIDE_SOURCE_DIR}" \ -B "${HALIDE_BUILD_DIR}" - name: Build Halide (Make) if: startsWith(matrix.build_tool, 'make') shell: bash run: | # Build Halide cd ${HALIDE_BUILD_DIR} BUILD_TARGETS="distrib build_tests" if [[ "${{matrix.uses_python}}" == "true" ]]; then # build_apps requires the python bindings BUILD_TARGETS="${BUILD_TARGETS} build_apps build_python_bindings" fi make -f ${HALIDE_SOURCE_DIR}/Makefile -j ${PARALLEL_JOBS} ${BUILD_TARGETS} - name: Build Halide (CMake) if: startsWith(matrix.build_tool, 'cmake') shell: bash run: | # Build Halide cd ${HALIDE_BUILD_DIR} cmake \ --build ${HALIDE_BUILD_DIR} \ --config ${BUILD_TYPE} \ -j ${PARALLEL_JOBS} - name: Run Tests (Make) if: matrix.run_tests && startsWith(matrix.build_tool, 'make') shell: bash run: | # Test Halide export TEST_TMPDIR="${HALIDE_TEMP_DIR}" cd ${HALIDE_BUILD_DIR} TEST_GROUPS_PARALLEL="internal correctness error warning generator" if [[ "${{matrix.uses_python}}" == "true" ]]; then TEST_GROUPS_PARALLEL="${TEST_GROUPS_PARALLEL} python" fi # tutorial has some performance measurements that can be flaky if we run them in parallel TEST_GROUPS_SERIAL="tutorial" # performance is never going to be reliable on VMs. # auto_schedule is just flaky. TEST_GROUPS_BROKEN="performance auto_schedule" if [[ ${{matrix.target_bits}} == 32 ]]; then # TODO: Skip testing apps on 32-bit systems for now; # in particular, apps/autoscheduler can time out, and also has build # issues on ubuntu-32 at the moment (__udivdi3). TEST_GROUPS_BROKEN="${TEST_GROUPS_BROKEN} apps" else TEST_GROUPS_PARALLEL="${TEST_GROUPS_PARALLEL} apps" fi # Parallel for t in ${TEST_GROUPS_PARALLEL}; do make -f ${HALIDE_SOURCE_DIR}/Makefile -j ${PARALLEL_JOBS} test_${t} done # Serial for t in ${TEST_GROUPS_SERIAL}; do make -f ${HALIDE_SOURCE_DIR}/Makefile test_$t done - name: Run Tests (CMake) if: matrix.run_tests && startsWith(matrix.build_tool, 'cmake') shell: bash run: | # Test Halide TEST_GROUPS_PARALLEL="internal|correctness|error|warning|generator" if [[ "${{matrix.uses_python}}" == "true" ]]; then TEST_GROUPS_PARALLEL="${TEST_GROUPS_PARALLEL}|python" fi # tutorial has some performance measurements that can be flaky if we run them in parallel TEST_GROUPS_SERIAL="tutorial" # performance is never going to be reliable on VMs. # auto_schedule is just flaky. TEST_GROUPS_BROKEN="performance|auto_schedule" export TEST_TMPDIR="${HALIDE_TEMP_DIR}" cd ${HALIDE_BUILD_DIR} # Parallel ctest \ -C ${BUILD_TYPE} \ -j ${PARALLEL_JOBS} \ -L "${TEST_GROUPS_PARALLEL}" \ --output-on-failure # Serial ctest \ -C ${BUILD_TYPE} \ -L "${TEST_GROUPS_SERIAL}" \ -E "${TEST_GROUPS_BROKEN}" \ --output-on-failure Halide-13.0.4/.gitignore000066400000000000000000000021611417234750700147670ustar00rootroot00000000000000CMakeUserPresets.json /tutorial/figures/tmp/trace.bin /apps/*/bin /apps/*/cmake_build /apps/HelloMatlab/blurred.png /apps/HelloMatlab/iir_blur.mex bin/* build/* share/* python_bindings/bin/* build-64/* build-ios/* build-osx/* build_wasm*/* cmake_build*/* */build/* tmp/* include/* distrib/* testing/* msvc/*/Win32/* msvc/*/x64/* \#*\# .\#* *~ *.o *.a *.so *.dot .DS_Store *.log generated.obj hello-fimage test.s testX64 xcuserdata in.png _build a.out *.bc *.cubin tags src/*.top llvm_svn llvm/* cpp/* *.h.gch src/test_*.ll src/test_*.s .clang_complete *.guru *.dSYM .*.swp tools/objc/BUILD tools/objc/*.mobileprovision *.xcworkspacedata *.txt.user* .idea/ # jrk editor settings .tm_properties *.sublime-project *.sublime-workspace apps/patchmatch # app intermediates apps/*/*out*.png apps/*/*.lowered apps/*/*.def apps/*/*.ptx apps/*/passes.txt apps/*/*.ll apps/*/*.sass apps/*/filter apps/HelloAndroidGL/jni/halide_gl_filter.h # tutorial intermediates tutorial/lesson_10_halide.h # test intermediates log.txt err.txt test/*.lowered *.pyc src/.tags src/.tags_sorted_by_file /.vs /out /CMakeSettings.json /venv/ /cmake-build-*/ Halide-13.0.4/.gitmodules000066400000000000000000000000001417234750700151420ustar00rootroot00000000000000Halide-13.0.4/CMakeLists.txt000066400000000000000000000131151417234750700155400ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.16...3.20) project(Halide VERSION 13.0.4 DESCRIPTION "Halide compiler and libraries" HOMEPAGE_URL "https://halide-lang.org") enable_testing() ## # Set up project-wide properties ## # Make our custom helpers available throughout the project via include(). list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake) include(HalideGeneratorHelpers) include(MakeShellPath) include(CMakeDependentOption) # Build Halide as a shared lib by default, but still honor command-line settings. option(BUILD_SHARED_LIBS "Build shared libraries" ON) # Warn if the user did not set a build type and is using a single-configuration generator. get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if (NOT IS_MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE) message(WARNING "Single-configuration generators require CMAKE_BUILD_TYPE to be set.") endif () # Windows has file name length restrictions and lacks an RPATH mechanism. # We work around this by setting a path max and putting all exes / dlls in # the same output directory. if (CMAKE_SYSTEM_NAME MATCHES "Windows") set(CMAKE_OBJECT_PATH_MAX 260) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin") message(STATUS "Windows: setting CMAKE_OBJECT_PATH_MAX to ${CMAKE_OBJECT_PATH_MAX}") endif () # Export all symbols on Windows to match GCC/Clang behavior on Linux/macOS set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) # Require standard C++17 if(NOT CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) elseif(CMAKE_CXX_STANDARD LESS 17) message(FATAL_ERROR "Halide requires C++17 or newer") endif() # Build Halide with ccache if the package is present option(Halide_CCACHE_BUILD "Set to ON for a ccache enabled build" OFF) mark_as_advanced(Halide_CCACHE_BUILD) if (Halide_CCACHE_BUILD) find_program(CCACHE_PROGRAM ccache) if (CCACHE_PROGRAM) # TODO: ccache recommends setting CCACHE_SLOPPINESS=pch_defines,time_macros to # enable precompiled header caching. Our timing found it slightly faster with # just CCACHE_SLOPPINESS=pch_defines, so that's what we're using. Maybe revisit # if issues occur (but we don't use any of the time macros so should be irrelevant). set(Halide_CCACHE_PARAMS CCACHE_CPP2=yes CCACHE_HASHDIR=yes CCACHE_SLOPPINESS=pch_defines CACHE STRING "Parameters to pass through to ccache") mark_as_advanced(Halide_CCACHE_PARAMS) set(CMAKE_C_COMPILER_LAUNCHER ${CMAKE_COMMAND} -E env ${Halide_CCACHE_PARAMS} ${CCACHE_PROGRAM}) set(CMAKE_CXX_COMPILER_LAUNCHER ${CMAKE_COMMAND} -E env ${Halide_CCACHE_PARAMS} ${CCACHE_PROGRAM}) message(STATUS "Enabling ccache usage for building.") else () message(FATAL_ERROR "Unable to find the program ccache. Set Halide_CCACHE_BUILD to OFF") endif () endif () ## # Import dependencies ## add_subdirectory(dependencies) ## # Add source directories ## add_subdirectory(src) add_subdirectory(tools) ## # Add tests, tutorials, etc. if we're not being imported into another CMake project. ## if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) option(WITH_TESTS "Build tests" ON) if (WITH_TESTS) message(STATUS "Building tests enabled") add_subdirectory(test) else () message(STATUS "Building tests disabled") endif () option(WITH_PYTHON_BINDINGS "Build Python bindings" ON) if (WITH_PYTHON_BINDINGS) if (Halide_ENABLE_RTTI AND Halide_ENABLE_EXCEPTIONS) message(STATUS "Building Python bindings enabled") add_subdirectory(python_bindings) else () if (NOT Halide_ENABLE_RTTI) message(WARNING "Building Python bindings disabled: must compile with RTTI") endif () if (NOT Halide_ENABLE_EXCEPTIONS) message(WARNING "Building Python bindings disabled: must compile with exceptions") endif () set(WITH_PYTHON_BINDINGS OFF CACHE BOOL "Build Python bindings" FORCE) endif () else () message(STATUS "Building Python bindings disabled") endif () option(WITH_TUTORIALS "Build tutorials" ON) if (WITH_TUTORIALS) message(STATUS "Building tutorials enabled") add_subdirectory(tutorial) else () message(STATUS "Building tutorials disabled") endif () option(WITH_DOCS "Build documentation" OFF) if (WITH_DOCS) message(STATUS "Building docs enabled") add_subdirectory(doc) else () message(STATUS "Building docs disabled") endif () option(WITH_UTILS "Build utils" ON) if (WITH_UTILS) message(STATUS "Building utils enabled") add_subdirectory(util) else () message(STATUS "Building utils disabled") endif () add_subdirectory(packaging) add_custom_target(distrib COMMAND ${CMAKE_COMMAND} -E echo "\\'distrib\\' is not available under CMake. Use \\'package\\' instead.") if (TARGET clang-format AND NOT WIN32) add_custom_target(format COMMAND find "${Halide_SOURCE_DIR}/apps" "${Halide_SOURCE_DIR}/src" "${Halide_SOURCE_DIR}/tools" "${Halide_SOURCE_DIR}/test" "${Halide_SOURCE_DIR}/util" "${Halide_SOURCE_DIR}/python_bindings" -name *.cpp -o -name *.h -o -name *.c | xargs $ -i -style=file) endif () endif () Halide-13.0.4/CMakePresets.json000066400000000000000000000122611417234750700162220ustar00rootroot00000000000000{ "version": 1, "cmakeMinimumRequired": { "major": 3, "minor": 16, "patch": 0 }, "configurePresets": [ { "name": "gcc-debug", "displayName": "GCC (Debug)", "description": "Debug build using Ninja generator and GCC-compatible compiler", "generator": "Ninja", "binaryDir": "${sourceDir}/build", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" } }, { "name": "gcc-release", "inherits": "gcc-debug", "displayName": "GCC (Release)", "description": "Release build using Ninja generator and GCC-compatible compiler", "cacheVariables": { "CMAKE_BUILD_TYPE": "Release" } }, { "name": "msvc-debug", "displayName": "MSVC (Debug)", "description": "Debug build using Ninja generator and MSVC with vcpkg dependencies.", "generator": "Ninja", "binaryDir": "${sourceDir}/build", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug", "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" } }, { "name": "msvc-release", "inherits": "msvc-debug", "displayName": "MSVC (Release)", "description": "Release build using Ninja generator and MSVC with vcpkg dependencies.", "cacheVariables": { "CMAKE_BUILD_TYPE": "Release" } }, { "name": "win32", "displayName": "Win32 (Visual Studio)", "description": "Visual Studio-based Win32 build with vcpkg dependencies.", "generator": "Visual Studio 16 2019", "architecture": "Win32", "toolset": "host=x64", "binaryDir": "${sourceDir}/build", "cacheVariables": { "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" } }, { "name": "win64", "displayName": "Win64 (Visual Studio)", "description": "Visual Studio-based Win64 build with vcpkg dependencies.", "generator": "Visual Studio 16 2019", "architecture": "x64", "toolset": "host=x64", "binaryDir": "${sourceDir}/build", "cacheVariables": { "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" } }, { "name": "package", "hidden": true, "cacheVariables": { "CMAKE_BUILD_TYPE": "Release", "LLVM_DIR": "$env{LLVM_DIR}", "Clang_DIR": "$env{Clang_DIR}", "LLD_DIR": "$env{LLD_DIR}", "WITH_TESTS": "NO", "WITH_TUTORIALS": "NO", "WITH_DOCS": "YES", "WITH_UTILS": "NO", "WITH_PYTHON_BINDINGS": "NO", "CMAKE_INSTALL_DATADIR": "share/Halide" } }, { "name": "package-windows", "inherits": "package", "displayName": "Package ZIP for Windows", "description": "Build for packaging Windows shared libraries.", "binaryDir": "${sourceDir}/build", "generator": "Visual Studio 16 2019", "toolset": "host=x64", "cacheVariables": { "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", "BUILD_SHARED_LIBS": "YES", "CMAKE_INSTALL_BINDIR": "bin/$", "CMAKE_INSTALL_LIBDIR": "lib/$", "Halide_INSTALL_CMAKEDIR": "lib/cmake/Halide", "Halide_INSTALL_HELPERSDIR": "lib/cmake/HalideHelpers" } }, { "name": "package-unix", "hidden": true, "inherits": "package", "generator": "Ninja" }, { "name": "package-unix-shared", "inherits": "package-unix", "displayName": "Package UNIX shared libs", "description": "Build for packaging UNIX shared libraries.", "binaryDir": "shared-Release", "cacheVariables": { "BUILD_SHARED_LIBS": "YES" } }, { "name": "package-unix-static", "inherits": "package-unix", "displayName": "Package UNIX static libs", "description": "Build for packaging UNIX static libraries.", "binaryDir": "static-Release", "cacheVariables": { "BUILD_SHARED_LIBS": "NO", "Halide_BUNDLE_LLVM": "YES" } }, { "name": "package-ubuntu-shared", "inherits": "package-unix-shared", "displayName": "Package shared Halide for Ubuntu", "description": "Package shared Halide for Ubuntu, using system packages.", "binaryDir": "shared-release", "cacheVariables": { "Halide_SHARED_LLVM": "YES", "LLVM_DIR": "$env{LLVM_ROOT}/lib/cmake/llvm", "Clang_DIR": "$env{LLVM_ROOT}/lib/cmake/clang", "LLD_DIR": "$env{LLVM_ROOT}/lib/cmake/lld", "CMAKE_INSTALL_INCLUDEDIR": "include/Halide", "CMAKE_INSTALL_LIBDIR": "lib/x86_64-linux-gnu", "Halide_INSTALL_PLUGINDIR": "lib/x86_64-linux-gnu/Halide", "Halide_INSTALL_HELPERSDIR": "lib/cmake/HalideHelpers", "CMAKE_STRIP": "${sourceDir}/packaging/ubuntu/extra-strip.sh" } }, { "name": "package-ubuntu-static", "inherits": "package-ubuntu-shared", "displayName": "Package static Halide for Ubuntu", "description": "Package static Halide for Ubuntu, using system packages.", "binaryDir": "static-release", "cacheVariables": { "BUILD_SHARED_LIBS": "NO", "WITH_DOCS": "NO" } } ] } Halide-13.0.4/CODE_OF_CONDUCT.md000066400000000000000000000067501417234750700156060ustar00rootroot00000000000000The Halide community has always worked to be a welcoming and respectful community, and we want to ensure that doesn’t change as we grow and evolve. To that end, we have a few ground rules that we ask people to adhere to: - **Be friendly and patient.** - **Be welcoming.** We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, colour, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability. - **Be considerate.** Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary language. - **Be respectful.** Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It’s important to remember that a community where people feel uncomfortable or threatened is not a productive one. Members of the Halide community should be respectful when dealing with other members as well as with people outside the Halide community. - **Be careful in the words that you choose.** We are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behavior aren't acceptable. This includes, but is not limited to: - Violent threats or language directed against another person. - Discriminatory jokes and language. - Posting sexually explicit or violent material. - Posting (or threatening to post) other people's personally identifying information ("doxing"). - Personal insults, especially those using racist or sexist terms. - Unwelcome sexual attention. - Advocating for, or encouraging, any of the above behavior. - Repeated harassment of others. In general, if someone asks you to stop, then stop. - **When we disagree, try to understand why.** Disagreements, both social and technical, happen all the time and Halide is no exception. It is important that we resolve disagreements and differing views constructively. Being unable to understand why someone holds a viewpoint doesn't mean that they’re wrong. Don’t forget that it is human to err and blaming each other doesn't get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes. - **Give credit where it's due.** If you use code or ideas from other people, projects, or publications, say so. Add a comment in the source code at the point where the idea is used. If adapting code, this requirement is above and beyond any requirements placed on you by the license of the original code. We all like recognition for our work. To that end... **Acknowledgements.** This code of conduct is a mix of [LLVM's](https://llvm.org/docs/CodeOfConduct.html) and [Django's](https://www.djangoproject.com/conduct/), which both ultimately derive from the code of conduct from the [Speak Up!](http://web.archive.org/web/20141109123859/http://speakup.io/coc.html) project. Halide-13.0.4/LICENSE.txt000066400000000000000000000063011417234750700146220ustar00rootroot00000000000000Copyright (c) 2012-2020 MIT CSAIL, Google, Facebook, Adobe, NVIDIA CORPORATION, and other contributors. Developed by: The Halide team http://halide-lang.org Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- apps/bgu is Copyright 2016 Google Inc. and is Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http ://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ----- apps/support/cmdline.h is Copyright (c) 2009, Hideyuki Tanaka and is licensed under the BSD 3-Clause license. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Halide-13.0.4/Makefile000066400000000000000000003117321417234750700144460ustar00rootroot00000000000000# 'make' builds libHalide.a, the internal test suite, and runs the internal test suite # 'make run_tests' builds and runs all the end-to-end tests in the test subdirectory # 'make {error,performance}_foo' builds and runs test/{...}/foo.cpp for any # c_source file in the corresponding subdirectory of the test folder # 'make correctness_foo' builds and runs test/correctness/foo.cpp for any # c_source file in the correctness/ subdirectory of the test folder # 'make test_apps' checks some of the apps build and run (but does not check their output) # 'make time_compilation_tests' records the compile time for each test module into a csv file. # For correctness and performance tests this include halide build time and run time. For # the tests in test/generator/ this times only the halide build time. # Disable built-in makefile rules for all apps to avoid pointless file-system # scanning and general weirdness resulting from implicit rules. MAKEFLAGS += --no-builtin-rules .SUFFIXES: UNAME = $(shell uname) ifeq ($(OS), Windows_NT) $(error Halide no longer supports the MinGW environment. Please use MSVC through CMake instead.) else # let's assume "normal" UNIX such as linux COMMON_LD_FLAGS=$(LDFLAGS) -ldl -lpthread -lz FPIC=-fPIC ifeq ($(UNAME), Darwin) SHARED_EXT=dylib else SHARED_EXT=so endif endif ifeq ($(UNAME), Darwin) # Anything that we us install_name_tool on needs these linker flags # to ensure there is enough padding for install_name_tool to use INSTALL_NAME_TOOL_LD_FLAGS=-Wl,-headerpad_max_install_names else INSTALL_NAME_TOOL_LD_FLAGS= endif ifeq ($(UNAME), Darwin) define alwayslink -Wl,-force_load,$(1) endef else define alwayslink -Wl,--whole-archive $(1) -Wl,-no-whole-archive endef endif SHELL = bash CXX ?= g++ PREFIX ?= /usr/local LLVM_CONFIG ?= llvm-config LLVM_COMPONENTS= $(shell $(LLVM_CONFIG) --components) LLVM_VERSION = $(shell $(LLVM_CONFIG) --version | sed 's/\([0-9][0-9]*\)\.\([0-9]\).*/\1.\2/') LLVM_FULL_VERSION = $(shell $(LLVM_CONFIG) --version) LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir | sed -e 's/\\/\//g' -e 's/\([a-zA-Z]\):/\/\1/g') LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir | sed -e 's/\\/\//g' -e 's/\([a-zA-Z]\):/\/\1/g') # Apparently there is no llvm_config flag to get canonical paths to tools, # so we'll just construct one relative to --src-root and hope that is stable everywhere. LLVM_GIT_LLD_INCLUDE_DIR = $(shell $(LLVM_CONFIG) --src-root | sed -e 's/\\/\//g' -e 's/\([a-zA-Z]\):/\/\1/g')/../lld/include LLVM_SYSTEM_LIBS=$(shell ${LLVM_CONFIG} --system-libs --link-static | sed -e 's/[\/&]/\\&/g' | sed 's/-llibxml2.tbd/-lxml2/') LLVM_AS = $(LLVM_BINDIR)/llvm-as LLVM_NM = $(LLVM_BINDIR)/llvm-nm LLVM_CXX_FLAGS = -std=c++17 $(filter-out -O% -g -fomit-frame-pointer -pedantic -W% -W, $(shell $(LLVM_CONFIG) --cxxflags | sed -e 's/\\/\//g' -e 's/\([a-zA-Z]\):/\/\1/g;s/-D/ -D/g;s/-O/ -O/;s/c++14/c++17/g')) -I$(LLVM_GIT_LLD_INCLUDE_DIR) OPTIMIZE ?= -O3 OPTIMIZE_FOR_BUILD_TIME ?= -O0 PYTHON ?= python3 CLANG ?= $(LLVM_BINDIR)/clang CLANG_VERSION = $(shell $(CLANG) --version) SANITIZER_FLAGS ?= # TODO: this is suboptimal hackery; we should really add the relevant # support libs for the sanitizer(s) as weak symbols in Codegen_LLVM. # (Note also that, in general, most Sanitizers work most reliably with an all-Clang # build system.) ifneq (,$(findstring tsan,$(HL_TARGET)$(HL_JIT_TARGET))) # Note that attempting to use TSAN with the JIT can produce false positives # if libHalide is not also compiled with TSAN enabled; we tack the relevant # flag onto OPTIMIZE here, but that's really only effective if you ensure # to do a clean build before testing. (In general, most of the Sanitizers # only work well when used in a completely clean environment.) OPTIMIZE += -fsanitize=thread SANITIZER_FLAGS += -fsanitize=thread endif ifneq (,$(findstring asan,$(HL_TARGET)$(HL_JIT_TARGET))) OPTIMIZE += -fsanitize=address SANITIZER_FLAGS += -fsanitize=address endif COMMON_LD_FLAGS += $(SANITIZER_FLAGS) LLVM_VERSION_TIMES_10 = $(shell $(LLVM_CONFIG) --version | sed 's/\([0-9][0-9]*\)\.\([0-9]\).*/\1\2/') LLVM_CXX_FLAGS += -DLLVM_VERSION=$(LLVM_VERSION_TIMES_10) # All WITH_* flags are either empty or not-empty. They do not behave # like true/false values in most languages. To turn one off, either # edit this file, add "WITH_FOO=" (no assigned value) to the make # line, or define an environment variable WITH_FOO that has an empty # value. WITH_X86 ?= $(findstring x86, $(LLVM_COMPONENTS)) WITH_ARM ?= $(findstring arm, $(LLVM_COMPONENTS)) WITH_HEXAGON ?= $(findstring hexagon, $(LLVM_COMPONENTS)) WITH_MIPS ?= $(findstring mips, $(LLVM_COMPONENTS)) WITH_RISCV ?= $(findstring riscv, $(LLVM_COMPONENTS)) WITH_AARCH64 ?= $(findstring aarch64, $(LLVM_COMPONENTS)) WITH_POWERPC ?= $(findstring powerpc, $(LLVM_COMPONENTS)) WITH_NVPTX ?= $(findstring nvptx, $(LLVM_COMPONENTS)) WITH_WEBASSEMBLY ?= $(findstring webassembly, $(LLVM_COMPONENTS)) # AMDGPU target is WIP WITH_AMDGPU ?= $(findstring amdgpu, $(LLVM_COMPONENTS)) WITH_OPENCL ?= not-empty WITH_METAL ?= not-empty WITH_OPENGLCOMPUTE ?= not-empty WITH_D3D12 ?= not-empty WITH_INTROSPECTION ?= not-empty WITH_EXCEPTIONS ?= WITH_LLVM_INSIDE_SHARED_LIBHALIDE ?= not-empty # If HL_TARGET or HL_JIT_TARGET aren't set, use host HL_TARGET ?= host HL_JIT_TARGET ?= host X86_CXX_FLAGS=$(if $(WITH_X86), -DWITH_X86, ) X86_LLVM_CONFIG_LIB=$(if $(WITH_X86), x86, ) ARM_CXX_FLAGS=$(if $(WITH_ARM), -DWITH_ARM, ) ARM_LLVM_CONFIG_LIB=$(if $(WITH_ARM), arm, ) MIPS_CXX_FLAGS=$(if $(WITH_MIPS), -DWITH_MIPS, ) MIPS_LLVM_CONFIG_LIB=$(if $(WITH_MIPS), mips, ) POWERPC_CXX_FLAGS=$(if $(WITH_POWERPC), -DWITH_POWERPC, ) POWERPC_LLVM_CONFIG_LIB=$(if $(WITH_POWERPC), powerpc, ) PTX_CXX_FLAGS=$(if $(WITH_NVPTX), -DWITH_NVPTX, ) PTX_LLVM_CONFIG_LIB=$(if $(WITH_NVPTX), nvptx, ) PTX_DEVICE_INITIAL_MODULES=$(if $(WITH_NVPTX), libdevice.compute_20.10.bc libdevice.compute_30.10.bc libdevice.compute_35.10.bc, ) AMDGPU_CXX_FLAGS=$(if $(WITH_AMDGPU), -DWITH_AMDGPU, ) AMDGPU_LLVM_CONFIG_LIB=$(if $(WITH_AMDGPU), amdgpu, ) # TODO add bitcode files OPENCL_CXX_FLAGS=$(if $(WITH_OPENCL), -DWITH_OPENCL, ) OPENCL_LLVM_CONFIG_LIB=$(if $(WITH_OPENCL), , ) METAL_CXX_FLAGS=$(if $(WITH_METAL), -DWITH_METAL, ) METAL_LLVM_CONFIG_LIB=$(if $(WITH_METAL), , ) OPENGLCOMPUTE_CXX_FLAGS=$(if $(WITH_OPENGLCOMPUTE), -DWITH_OPENGLCOMPUTE, ) D3D12_CXX_FLAGS=$(if $(WITH_D3D12), -DWITH_D3D12, ) D3D12_LLVM_CONFIG_LIB=$(if $(WITH_D3D12), , ) AARCH64_CXX_FLAGS=$(if $(WITH_AARCH64), -DWITH_AARCH64, ) AARCH64_LLVM_CONFIG_LIB=$(if $(WITH_AARCH64), aarch64, ) RISCV_CXX_FLAGS=$(if $(WITH_RISCV), -DWITH_RISCV, ) RISCV_LLVM_CONFIG_LIB=$(if $(WITH_RISCV), riscv, ) INTROSPECTION_CXX_FLAGS=$(if $(WITH_INTROSPECTION), -DWITH_INTROSPECTION, ) EXCEPTIONS_CXX_FLAGS=$(if $(WITH_EXCEPTIONS), -DHALIDE_WITH_EXCEPTIONS -fexceptions, ) HEXAGON_CXX_FLAGS=$(if $(WITH_HEXAGON), -DWITH_HEXAGON, ) HEXAGON_LLVM_CONFIG_LIB=$(if $(WITH_HEXAGON), hexagon, ) WEBASSEMBLY_CXX_FLAGS=$(if $(WITH_WEBASSEMBLY), -DWITH_WEBASSEMBLY, ) WEBASSEMBLY_LLVM_CONFIG_LIB=$(if $(WITH_WEBASSEMBLY), webassembly, ) LLVM_HAS_NO_RTTI = $(findstring -fno-rtti, $(LLVM_CXX_FLAGS)) WITH_RTTI ?= $(if $(LLVM_HAS_NO_RTTI),, not-empty) RTTI_CXX_FLAGS=$(if $(WITH_RTTI), , -fno-rtti ) CXX_VERSION = $(shell $(CXX) --version | head -n1) CXX_WARNING_FLAGS = -Wall -Werror -Wno-unused-function -Wcast-qual -Wignored-qualifiers -Wno-comment -Wsign-compare -Wno-unknown-warning-option -Wno-psabi ifneq (,$(findstring g++,$(CXX_VERSION))) GCC_MAJOR_VERSION := $(shell $(CXX) -dumpfullversion -dumpversion | cut -f1 -d.) GCC_MINOR_VERSION := $(shell $(CXX) -dumpfullversion -dumpversion | cut -f2 -d.) ifeq (1,$(shell expr $(GCC_MAJOR_VERSION) \> 5 \| $(GCC_MAJOR_VERSION) = 5 \& $(GCC_MINOR_VERSION) \>= 1)) CXX_WARNING_FLAGS += -Wsuggest-override endif endif ifneq (,$(findstring clang,$(CXX_VERSION))) LLVM_CXX_FLAGS_LIBCPP := $(findstring -stdlib=libc++, $(LLVM_CXX_FLAGS)) endif CXX_FLAGS = $(CXXFLAGS) $(CXX_WARNING_FLAGS) $(RTTI_CXX_FLAGS) -Woverloaded-virtual $(FPIC) $(OPTIMIZE) -fno-omit-frame-pointer -DCOMPILING_HALIDE CXX_FLAGS += $(LLVM_CXX_FLAGS) CXX_FLAGS += $(PTX_CXX_FLAGS) CXX_FLAGS += $(ARM_CXX_FLAGS) CXX_FLAGS += $(HEXAGON_CXX_FLAGS) CXX_FLAGS += $(AARCH64_CXX_FLAGS) CXX_FLAGS += $(X86_CXX_FLAGS) CXX_FLAGS += $(OPENCL_CXX_FLAGS) CXX_FLAGS += $(METAL_CXX_FLAGS) CXX_FLAGS += $(OPENGLCOMPUTE_CXX_FLAGS) CXX_FLAGS += $(D3D12_CXX_FLAGS) CXX_FLAGS += $(MIPS_CXX_FLAGS) CXX_FLAGS += $(POWERPC_CXX_FLAGS) CXX_FLAGS += $(INTROSPECTION_CXX_FLAGS) CXX_FLAGS += $(EXCEPTIONS_CXX_FLAGS) CXX_FLAGS += $(AMDGPU_CXX_FLAGS) CXX_FLAGS += $(RISCV_CXX_FLAGS) CXX_FLAGS += $(WEBASSEMBLY_CXX_FLAGS) # This is required on some hosts like powerpc64le-linux-gnu because we may build # everything with -fno-exceptions. Without -funwind-tables, libHalide.so fails # to propagate exceptions and causes a test failure. CXX_FLAGS += -funwind-tables print-%: @echo '$*=$($*)' LLVM_STATIC_LIBFILES = \ bitwriter \ bitreader \ linker \ ipo \ passes \ mcjit \ $(X86_LLVM_CONFIG_LIB) \ $(ARM_LLVM_CONFIG_LIB) \ $(OPENCL_LLVM_CONFIG_LIB) \ $(METAL_LLVM_CONFIG_LIB) \ $(PTX_LLVM_CONFIG_LIB) \ $(AARCH64_LLVM_CONFIG_LIB) \ $(MIPS_LLVM_CONFIG_LIB) \ $(POWERPC_LLVM_CONFIG_LIB) \ $(HEXAGON_LLVM_CONFIG_LIB) \ $(AMDGPU_LLVM_CONFIG_LIB) \ $(WEBASSEMBLY_LLVM_CONFIG_LIB) \ $(RISCV_LLVM_CONFIG_LIB) LLVM_STATIC_LIBS = -L $(LLVM_LIBDIR) $(shell $(LLVM_CONFIG) --link-static --libfiles $(LLVM_STATIC_LIBFILES) | sed -e 's/\\/\//g' -e 's/\([a-zA-Z]\):/\/\1/g') # Add a rpath to the llvm used for linking, in case multiple llvms are # installed. Bakes a path on the build system into the .so, so don't # use this config for distributions. LLVM_SHARED_LIBS = -Wl,-rpath=$(LLVM_LIBDIR) -L $(LLVM_LIBDIR) -lLLVM LLVM_LIBS_FOR_SHARED_LIBHALIDE=$(if $(WITH_LLVM_INSIDE_SHARED_LIBHALIDE),$(LLVM_STATIC_LIBS),$(LLVM_SHARED_LIBS)) TUTORIAL_CXX_FLAGS ?= -std=c++17 -g -fno-omit-frame-pointer $(RTTI_CXX_FLAGS) -I $(ROOT_DIR)/tools $(SANITIZER_FLAGS) $(LLVM_CXX_FLAGS_LIBCPP) # The tutorials contain example code with warnings that we don't want # to be flagged as errors, so the test flags are the tutorial flags # plus our warning flags. # Also allow tests, via conditional compilation, to use the entire # capability of the CPU being compiled on via -march=native. This # presumes tests are run on the same machine they are compiled on. TEST_CXX_FLAGS ?= $(TUTORIAL_CXX_FLAGS) $(CXX_WARNING_FLAGS) TEST_LD_FLAGS = -L$(BIN_DIR) -lHalide $(COMMON_LD_FLAGS) # In the tests, some of our expectations change depending on the llvm version TEST_CXX_FLAGS += -DLLVM_VERSION=$(LLVM_VERSION_TIMES_10) # gcc 4.8 fires a bogus warning on old versions of png.h ifneq (,$(findstring g++,$(CXX_VERSION))) ifneq (,$(findstring 4.8,$(CXX_VERSION))) TEST_CXX_FLAGS += -Wno-literal-suffix endif endif ifeq ($(UNAME), Linux) TEST_LD_FLAGS += -rdynamic -Wl,--rpath=$(CURDIR)/$(BIN_DIR) endif ifeq ($(WITH_LLVM_INSIDE_SHARED_LIBHALIDE), ) TEST_LD_FLAGS += -Wl,--rpath=$(LLVM_LIBDIR) endif ifneq ($(WITH_NVPTX), ) ifneq (,$(findstring ptx,$(HL_TARGET))) TEST_CUDA = 1 endif ifneq (,$(findstring cuda,$(HL_TARGET))) TEST_CUDA = 1 endif endif ifneq ($(WITH_OPENCL), ) ifneq (,$(findstring opencl,$(HL_TARGET))) TEST_OPENCL = 1 endif endif ifneq ($(WITH_METAL), ) ifneq (,$(findstring metal,$(HL_TARGET))) TEST_METAL = 1 endif endif ifeq ($(UNAME), Linux) ifneq ($(TEST_CUDA), ) CUDA_LD_FLAGS ?= -L/usr/lib/nvidia-current -lcuda endif ifneq ($(TEST_OPENCL), ) OPENCL_LD_FLAGS ?= -lOpenCL endif OPENGL_LD_FLAGS ?= -lGL HOST_OS=linux endif ifeq ($(UNAME), Darwin) # Someone with an osx box with cuda installed please fix the line below ifneq ($(TEST_CUDA), ) CUDA_LD_FLAGS ?= -L/usr/local/cuda/lib -lcuda endif ifneq ($(TEST_OPENCL), ) OPENCL_LD_FLAGS ?= -framework OpenCL endif ifneq ($(TEST_METAL), ) METAL_LD_FLAGS ?= -framework Metal -framework Foundation endif OPENGL_LD_FLAGS ?= -framework OpenGL HOST_OS=os_x endif ifneq ($(TEST_OPENCL), ) TEST_CXX_FLAGS += -DTEST_OPENCL endif ifneq ($(TEST_METAL), ) # Using Metal APIs requires writing Objective-C++ (or Swift). Add ObjC++ # to allow tests to create and destroy Metal contexts, etc. This requires # tests to be valid Objective-C++, e.g. avoiding using the identifier "id" # in certain ways. In practice this is not enough of a problem to justify # the work to limit which files are compiled this way. TEST_CXX_FLAGS += -DTEST_METAL -ObjC++ endif ifneq ($(TEST_CUDA), ) TEST_CXX_FLAGS += -DTEST_CUDA TEST_CXX_FLAGS += -I/usr/local/cuda/include endif # Compiling the tutorials requires libpng LIBPNG_LIBS_DEFAULT = $(shell libpng-config --ldflags) LIBPNG_CXX_FLAGS ?= $(shell libpng-config --cflags) # Workaround for libpng-config pointing to 64-bit versions on linux even when we're building for 32-bit ifneq (,$(findstring -m32,$(CXX))) ifneq (,$(findstring x86_64,$(LIBPNG_LIBS_DEFAULT))) LIBPNG_LIBS ?= -lpng endif endif LIBPNG_LIBS ?= $(LIBPNG_LIBS_DEFAULT) # Workaround brew Cellar path for libpng-config output. LIBJPEG_LINKER_PATH ?= $(shell echo $(LIBPNG_LIBS_DEFAULT) | sed -e'/-L.*[/][Cc]ellar[/]libpng/!d;s=\(.*\)/[Cc]ellar/libpng/.*=\1/lib=') LIBJPEG_LIBS ?= $(LIBJPEG_LINKER_PATH) -ljpeg # There's no libjpeg-config, unfortunately. We should look for # jpeglib.h one directory level up from png.h . Also handle # Mac OS brew installs where libpng-config returns paths # into the PNG cellar. LIBPNG_INCLUDE_DIRS = $(filter -I%,$(LIBPNG_CXX_FLAGS)) LIBJPEG_CXX_FLAGS ?= $(shell echo $(LIBPNG_INCLUDE_DIRS) | sed -e'/[Cc]ellar[/]libpng/!s=\(.*\)=\1/..=;s=\(.*\)/[Cc]ellar/libpng/.*=\1/include=') IMAGE_IO_LIBS = $(LIBPNG_LIBS) $(LIBJPEG_LIBS) IMAGE_IO_CXX_FLAGS = $(LIBPNG_CXX_FLAGS) $(LIBJPEG_CXX_FLAGS) # We're building into the current directory $(CURDIR). Find the Halide # repo root directory (the location of the makefile) THIS_MAKEFILE = $(realpath $(filter %Makefile, $(MAKEFILE_LIST))) ROOT_DIR = $(strip $(shell dirname $(THIS_MAKEFILE))) SRC_DIR = $(ROOT_DIR)/src TARGET=$(if $(HL_TARGET),$(HL_TARGET),host) # The following directories are all relative to the output directory (i.e. $(CURDIR), not $(SRC_DIR)) LIB_DIR = lib BIN_DIR = bin DISTRIB_DIR = distrib INCLUDE_DIR = include SHARE_DIR = share DOC_DIR = $(SHARE_DIR)/doc/Halide BUILD_DIR = $(BIN_DIR)/build FILTERS_DIR = $(BIN_DIR)/$(TARGET)/build TMP_DIR = $(BUILD_DIR)/tmp HEXAGON_RUNTIME_LIBS_DIR = src/runtime/hexagon_remote/bin HEXAGON_RUNTIME_LIBS = \ $(HEXAGON_RUNTIME_LIBS_DIR)/arm-32-android/libhalide_hexagon_host.so \ $(HEXAGON_RUNTIME_LIBS_DIR)/arm-64-android/libhalide_hexagon_host.so \ $(HEXAGON_RUNTIME_LIBS_DIR)/host/libhalide_hexagon_host.so \ $(HEXAGON_RUNTIME_LIBS_DIR)/v65/hexagon_sim_remote \ $(HEXAGON_RUNTIME_LIBS_DIR)/v65/libhalide_hexagon_remote_skel.so \ $(HEXAGON_RUNTIME_LIBS_DIR)/v65/signed_by_debug/libhalide_hexagon_remote_skel.so # Keep this list sorted in alphabetical order. SOURCE_FILES = \ AddAtomicMutex.cpp \ AddImageChecks.cpp \ AddParameterChecks.cpp \ AlignLoads.cpp \ AllocationBoundsInference.cpp \ ApplySplit.cpp \ Argument.cpp \ AssociativeOpsTable.cpp \ Associativity.cpp \ AsyncProducers.cpp \ AutoScheduleUtils.cpp \ BoundaryConditions.cpp \ Bounds.cpp \ BoundsInference.cpp \ BoundSmallAllocations.cpp \ Buffer.cpp \ CanonicalizeGPUVars.cpp \ Closure.cpp \ ClampUnsafeAccesses.cpp \ CodeGen_ARM.cpp \ CodeGen_C.cpp \ CodeGen_D3D12Compute_Dev.cpp \ CodeGen_GPU_Dev.cpp \ CodeGen_Hexagon.cpp \ CodeGen_Internal.cpp \ CodeGen_LLVM.cpp \ CodeGen_Metal_Dev.cpp \ CodeGen_MIPS.cpp \ CodeGen_OpenCL_Dev.cpp \ CodeGen_OpenGLCompute_Dev.cpp \ CodeGen_Posix.cpp \ CodeGen_PowerPC.cpp \ CodeGen_PTX_Dev.cpp \ CodeGen_PyTorch.cpp \ CodeGen_RISCV.cpp \ CodeGen_WebAssembly.cpp \ CodeGen_X86.cpp \ CompilerLogger.cpp \ CPlusPlusMangle.cpp \ CSE.cpp \ Debug.cpp \ DebugArguments.cpp \ DebugToFile.cpp \ Definition.cpp \ Deinterleave.cpp \ Derivative.cpp \ DerivativeUtils.cpp \ DeviceArgument.cpp \ DeviceInterface.cpp \ Dimension.cpp \ EarlyFree.cpp \ Elf.cpp \ EliminateBoolVectors.cpp \ EmulateFloat16Math.cpp \ Error.cpp \ Expr.cpp \ FastIntegerDivide.cpp \ FindCalls.cpp \ FindIntrinsics.cpp \ FlattenNestedRamps.cpp \ Float16.cpp \ Func.cpp \ Function.cpp \ FuseGPUThreadLoops.cpp \ FuzzFloatStores.cpp \ Generator.cpp \ HexagonOffload.cpp \ HexagonOptimize.cpp \ ImageParam.cpp \ InferArguments.cpp \ InjectHostDevBufferCopies.cpp \ Inline.cpp \ InlineReductions.cpp \ IntegerDivisionTable.cpp \ Interval.cpp \ Introspection.cpp \ IR.cpp \ IREquality.cpp \ IRMatch.cpp \ IRMutator.cpp \ IROperator.cpp \ IRPrinter.cpp \ IRVisitor.cpp \ JITModule.cpp \ Lambda.cpp \ Lerp.cpp \ LICM.cpp \ LLVM_Output.cpp \ LLVM_Runtime_Linker.cpp \ LoopCarry.cpp \ Lower.cpp \ LowerWarpShuffles.cpp \ MatlabWrapper.cpp \ Memoization.cpp \ Module.cpp \ ModulusRemainder.cpp \ Monotonic.cpp \ ObjectInstanceRegistry.cpp \ OffloadGPULoops.cpp \ OutputImageParam.cpp \ ParallelRVar.cpp \ Parameter.cpp \ ParamMap.cpp \ PartitionLoops.cpp \ Pipeline.cpp \ Prefetch.cpp \ PrintLoopNest.cpp \ Profiling.cpp \ PurifyIndexMath.cpp \ PythonExtensionGen.cpp \ Qualify.cpp \ Random.cpp \ RDom.cpp \ Realization.cpp \ RealizationOrder.cpp \ RebaseLoopsToZero.cpp \ Reduction.cpp \ RegionCosts.cpp \ RemoveDeadAllocations.cpp \ RemoveExternLoops.cpp \ RemoveUndef.cpp \ Schedule.cpp \ ScheduleFunctions.cpp \ SelectGPUAPI.cpp \ Simplify.cpp \ Simplify_Add.cpp \ Simplify_And.cpp \ Simplify_Call.cpp \ Simplify_Cast.cpp \ Simplify_Div.cpp \ Simplify_EQ.cpp \ Simplify_Exprs.cpp \ Simplify_Let.cpp \ Simplify_LT.cpp \ Simplify_Max.cpp \ Simplify_Min.cpp \ Simplify_Mod.cpp \ Simplify_Mul.cpp \ Simplify_Not.cpp \ Simplify_Or.cpp \ Simplify_Select.cpp \ Simplify_Shuffle.cpp \ Simplify_Stmts.cpp \ Simplify_Sub.cpp \ SimplifyCorrelatedDifferences.cpp \ SimplifySpecializations.cpp \ SkipStages.cpp \ SlidingWindow.cpp \ Solve.cpp \ SplitTuples.cpp \ StmtToHtml.cpp \ StorageFlattening.cpp \ StorageFolding.cpp \ StrictifyFloat.cpp \ Substitute.cpp \ Target.cpp \ Tracing.cpp \ TrimNoOps.cpp \ Tuple.cpp \ Type.cpp \ UnifyDuplicateLets.cpp \ UniquifyVariableNames.cpp \ UnpackBuffers.cpp \ UnrollLoops.cpp \ UnsafePromises.cpp \ Util.cpp \ Var.cpp \ VectorizeLoops.cpp \ WasmExecutor.cpp \ WrapCalls.cpp # The externally-visible header files that go into making Halide.h. # Don't include anything here that includes llvm headers. # Keep this list sorted in alphabetical order. HEADER_FILES = \ AddAtomicMutex.h \ AddImageChecks.h \ AddParameterChecks.h \ AlignLoads.h \ AllocationBoundsInference.h \ ApplySplit.h \ Argument.h \ AssociativeOpsTable.h \ Associativity.h \ AsyncProducers.h \ AutoScheduleUtils.h \ BoundaryConditions.h \ Bounds.h \ BoundsInference.h \ BoundSmallAllocations.h \ Buffer.h \ CanonicalizeGPUVars.h \ ClampUnsafeAccesses.h \ Closure.h \ CodeGen_C.h \ CodeGen_D3D12Compute_Dev.h \ CodeGen_GPU_Dev.h \ CodeGen_Internal.h \ CodeGen_LLVM.h \ CodeGen_Metal_Dev.h \ CodeGen_OpenCL_Dev.h \ CodeGen_OpenGLCompute_Dev.h \ CodeGen_Posix.h \ CodeGen_PTX_Dev.h \ CodeGen_PyTorch.h \ CodeGen_Targets.h \ CompilerLogger.h \ ConciseCasts.h \ CPlusPlusMangle.h \ CSE.h \ Debug.h \ DebugArguments.h \ DebugToFile.h \ Definition.h \ Deinterleave.h \ Derivative.h \ DerivativeUtils.h \ DeviceAPI.h \ DeviceArgument.h \ DeviceInterface.h \ Dimension.h \ EarlyFree.h \ Elf.h \ EliminateBoolVectors.h \ EmulateFloat16Math.h \ Error.h \ Expr.h \ ExprUsesVar.h \ Extern.h \ ExternFuncArgument.h \ FastIntegerDivide.h \ FindCalls.h \ FindIntrinsics.h \ FlattenNestedRamps.h \ Float16.h \ Func.h \ Function.h \ FunctionPtr.h \ FuseGPUThreadLoops.h \ FuzzFloatStores.h \ Generator.h \ HexagonOffload.h \ HexagonOptimize.h \ ImageParam.h \ InferArguments.h \ InjectHostDevBufferCopies.h \ Inline.h \ InlineReductions.h \ IntegerDivisionTable.h \ Interval.h \ Introspection.h \ IntrusivePtr.h \ IR.h \ IREquality.h \ IRMatch.h \ IRMutator.h \ IROperator.h \ IRPrinter.h \ IRVisitor.h \ WasmExecutor.h \ JITModule.h \ Lambda.h \ Lerp.h \ LICM.h \ LLVM_Output.h \ LLVM_Runtime_Linker.h \ LoopCarry.h \ Lower.h \ LowerWarpShuffles.h \ MainPage.h \ MatlabWrapper.h \ Memoization.h \ Module.h \ ModulusRemainder.h \ Monotonic.h \ ObjectInstanceRegistry.h \ OffloadGPULoops.h \ OutputImageParam.h \ ParallelRVar.h \ Param.h \ Parameter.h \ ParamMap.h \ PartitionLoops.h \ Pipeline.h \ Prefetch.h \ Profiling.h \ PurifyIndexMath.h \ PythonExtensionGen.h \ Qualify.h \ Random.h \ Realization.h \ RDom.h \ RealizationOrder.h \ RebaseLoopsToZero.h \ Reduction.h \ RegionCosts.h \ RemoveDeadAllocations.h \ RemoveExternLoops.h \ RemoveUndef.h \ runtime/HalideBuffer.h \ runtime/HalideRuntime.h \ Schedule.h \ ScheduleFunctions.h \ Scope.h \ SelectGPUAPI.h \ Simplify.h \ SimplifyCorrelatedDifferences.h \ SimplifySpecializations.h \ SkipStages.h \ SlidingWindow.h \ Solve.h \ SplitTuples.h \ StmtToHtml.h \ StorageFlattening.h \ StorageFolding.h \ StrictifyFloat.h \ Substitute.h \ Target.h \ ThreadPool.h \ Tracing.h \ TrimNoOps.h \ Tuple.h \ Type.h \ UnifyDuplicateLets.h \ UniquifyVariableNames.h \ UnpackBuffers.h \ UnrollLoops.h \ UnsafePromises.h \ Util.h \ Var.h \ VectorizeLoops.h \ WrapCalls.h OBJECTS = $(SOURCE_FILES:%.cpp=$(BUILD_DIR)/%.o) HEADERS = $(HEADER_FILES:%.h=$(SRC_DIR)/%.h) RUNTIME_CPP_COMPONENTS = \ aarch64_cpu_features \ alignment_128 \ alignment_32 \ allocation_cache \ alignment_64 \ android_clock \ android_host_cpu_count \ android_io \ arm_cpu_features \ cache \ can_use_target \ cuda \ destructors \ device_interface \ errors \ fake_get_symbol \ fake_thread_pool \ float16_t \ fuchsia_clock \ fuchsia_host_cpu_count \ fuchsia_yield \ gpu_device_selection \ halide_buffer_t \ hexagon_cache_allocator \ hexagon_cpu_features \ hexagon_dma_pool \ hexagon_dma \ hexagon_host \ ios_io \ linux_clock \ linux_host_cpu_count \ linux_yield \ matlab \ metadata \ metal \ metal_objc_arm \ metal_objc_x86 \ mips_cpu_features \ module_aot_ref_count \ module_jit_ref_count \ msan \ msan_stubs \ opencl \ openglcompute \ opengl_egl_context \ opengl_glx_context \ osx_clock \ osx_get_symbol \ osx_host_cpu_count \ osx_opengl_context \ osx_yield \ posix_allocator \ posix_clock \ posix_error_handler \ posix_get_symbol \ posix_io \ posix_print \ posix_threads \ posix_threads_tsan \ powerpc_cpu_features \ prefetch \ profiler \ profiler_inlined \ pseudostack \ qurt_allocator \ qurt_hvx \ qurt_hvx_vtcm \ qurt_threads \ qurt_threads_tsan \ qurt_yield \ riscv_cpu_features \ runtime_api \ to_string \ trace_helper \ tracing \ wasm_cpu_features \ windows_clock \ windows_cuda \ windows_d3d12compute_arm \ windows_d3d12compute_x86 \ windows_get_symbol \ windows_io \ windows_opencl \ windows_profiler \ windows_threads \ windows_threads_tsan \ windows_yield \ write_debug_image \ x86_cpu_features \ RUNTIME_LL_COMPONENTS = \ aarch64 \ arm \ arm_no_neon \ hvx_128 \ mips \ posix_math \ powerpc \ ptx_dev \ wasm_math \ win32_math \ x86 \ x86_avx \ x86_avx2 \ x86_avx512 \ x86_sse41 RUNTIME_EXPORTED_INCLUDES = $(INCLUDE_DIR)/HalideRuntime.h \ $(INCLUDE_DIR)/HalideRuntimeD3D12Compute.h \ $(INCLUDE_DIR)/HalideRuntimeCuda.h \ $(INCLUDE_DIR)/HalideRuntimeHexagonDma.h \ $(INCLUDE_DIR)/HalideRuntimeHexagonHost.h \ $(INCLUDE_DIR)/HalideRuntimeOpenCL.h \ $(INCLUDE_DIR)/HalideRuntimeOpenGLCompute.h \ $(INCLUDE_DIR)/HalideRuntimeMetal.h \ $(INCLUDE_DIR)/HalideRuntimeQurt.h \ $(INCLUDE_DIR)/HalideBuffer.h \ $(INCLUDE_DIR)/HalidePyTorchHelpers.h \ $(INCLUDE_DIR)/HalidePyTorchCudaHelpers.h INITIAL_MODULES = $(RUNTIME_CPP_COMPONENTS:%=$(BUILD_DIR)/initmod.%_32.o) \ $(RUNTIME_CPP_COMPONENTS:%=$(BUILD_DIR)/initmod.%_64.o) \ $(RUNTIME_CPP_COMPONENTS:%=$(BUILD_DIR)/initmod.%_32_debug.o) \ $(RUNTIME_CPP_COMPONENTS:%=$(BUILD_DIR)/initmod.%_64_debug.o) \ $(RUNTIME_EXPORTED_INCLUDES:$(INCLUDE_DIR)/%.h=$(BUILD_DIR)/initmod.%_h.o) \ $(BUILD_DIR)/initmod.inlined_c.o \ $(RUNTIME_LL_COMPONENTS:%=$(BUILD_DIR)/initmod.%_ll.o) \ $(PTX_DEVICE_INITIAL_MODULES:libdevice.%.bc=$(BUILD_DIR)/initmod_ptx.%_ll.o) # Add the Hexagon simulator to the rpath on Linux. (Not supported elsewhere, so no else cases.) ifeq ($(UNAME), Linux) ifneq (,$(WITH_HEXAGON)) ifneq (,$(HL_HEXAGON_TOOLS)) TEST_LD_FLAGS += -Wl,--rpath=$(ROOT_DIR)/src/runtime/hexagon_remote/bin/host TEST_LD_FLAGS += -Wl,--rpath=$(HL_HEXAGON_TOOLS)/lib/iss endif endif endif .PHONY: all all: distrib test_internal # Depending on which linker we're using, # we need a different invocation to get the # linker map file. ifeq ($(UNAME), Darwin) MAP_FLAGS= -Wl,-map -Wl,$(BUILD_DIR)/llvm_objects/list.all else MAP_FLAGS= -Wl,-Map=$(BUILD_DIR)/llvm_objects/list.all endif $(BUILD_DIR)/llvm_objects/list: $(OBJECTS) $(INITIAL_MODULES) # Determine the relevant object files from llvm with a dummy # compilation. Passing -map to the linker gets it to list, as # part of the linker map file, the object files in which archives it uses to # resolve symbols. We only care about the libLLVM ones, which we will filter below. @mkdir -p $(@D) $(CXX) -o /dev/null -shared $(MAP_FLAGS) $(OBJECTS) $(INITIAL_MODULES) $(LLVM_STATIC_LIBS) $(LLVM_SYSTEM_LIBS) $(COMMON_LD_FLAGS) > /dev/null # if the list has changed since the previous build, or there # is no list from a previous build, then delete any old object # files and re-extract the required object files cd $(BUILD_DIR)/llvm_objects; \ cat list.all | LANG=C sed -n 's/^[^\/]*\(\/[^ ()]*libLLVM.*[.]a\)[^a-zA-Z]*\([^ ()]*[.]o\).*$$/\1 \2/p' | sort | uniq > list.new; \ rm list.all; \ if cmp -s list.new list; \ then \ echo "No changes in LLVM deps"; \ touch list; \ else \ rm -f llvm_*.o*; \ cat list.new | sed = | sed "N;s/\n /\n/;s/\([0-9]*\)\n\([^ ]*\) \([^ ]*\)/ar x \2 \3; mv \3 llvm_\1_\3/" | bash - ; \ mv list.new list; \ fi $(LIB_DIR)/libHalide.a: $(OBJECTS) $(INITIAL_MODULES) $(BUILD_DIR)/llvm_objects/list # Archive together all the halide and llvm object files @mkdir -p $(@D) @rm -f $(LIB_DIR)/libHalide.a ar q $(LIB_DIR)/libHalide.a $(OBJECTS) $(INITIAL_MODULES) $(BUILD_DIR)/llvm_objects/llvm_*.o* ranlib $(LIB_DIR)/libHalide.a ifeq ($(UNAME), Linux) LIBHALIDE_SONAME_FLAGS=-Wl,-soname,libHalide.so else LIBHALIDE_SONAME_FLAGS= endif ifeq ($(UNAME), Linux) LIBHALIDE_EXPORTS=-Wl,--version-script=$(ROOT_DIR)/src/exported_symbols.ldscript else LIBHALIDE_EXPORTS=-Wl,-exported_symbols_list $(ROOT_DIR)/src/exported_symbols.osx endif $(BIN_DIR)/libHalide.$(SHARED_EXT): $(OBJECTS) $(INITIAL_MODULES) @mkdir -p $(@D) $(CXX) -shared $(LIBHALIDE_EXPORTS) $(OBJECTS) $(INITIAL_MODULES) $(LLVM_LIBS_FOR_SHARED_LIBHALIDE) $(LLVM_SYSTEM_LIBS) $(COMMON_LD_FLAGS) $(INSTALL_NAME_TOOL_LD_FLAGS) $(LIBHALIDE_SONAME_FLAGS) -o $(BIN_DIR)/libHalide.$(SHARED_EXT) ifeq ($(UNAME), Darwin) install_name_tool -id $(CURDIR)/$(BIN_DIR)/libHalide.$(SHARED_EXT) $(BIN_DIR)/libHalide.$(SHARED_EXT) endif $(INCLUDE_DIR)/Halide.h: $(SRC_DIR)/../LICENSE.txt $(HEADERS) $(BIN_DIR)/build_halide_h @mkdir -p $(@D) $(BIN_DIR)/build_halide_h $(SRC_DIR)/../LICENSE.txt $(HEADERS) > $(INCLUDE_DIR)/Halide.h # Also generate a precompiled version in the same folder so that anything compiled with a compatible set of flags can use it @mkdir -p $(INCLUDE_DIR)/Halide.h.gch $(CXX) -std=c++17 $(TEST_CXX_FLAGS) -I$(ROOT_DIR) $(OPTIMIZE) -x c++-header $(INCLUDE_DIR)/Halide.h -o $(INCLUDE_DIR)/Halide.h.gch/Halide.default.gch $(CXX) -std=c++17 $(TEST_CXX_FLAGS) -I$(ROOT_DIR) $(OPTIMIZE_FOR_BUILD_TIME) -x c++-header $(INCLUDE_DIR)/Halide.h -o $(INCLUDE_DIR)/Halide.h.gch/Halide.test.gch $(INCLUDE_DIR)/HalideRuntime%: $(SRC_DIR)/runtime/HalideRuntime% echo Copying $< @mkdir -p $(@D) cp $< $(INCLUDE_DIR)/ $(INCLUDE_DIR)/HalideBuffer.h: $(SRC_DIR)/runtime/HalideBuffer.h echo Copying $< @mkdir -p $(@D) cp $< $(INCLUDE_DIR)/ $(INCLUDE_DIR)/HalidePyTorchHelpers.h: $(SRC_DIR)/runtime/HalidePyTorchHelpers.h echo Copying $< @mkdir -p $(@D) cp $< $(INCLUDE_DIR)/ $(INCLUDE_DIR)/HalidePyTorchCudaHelpers.h: $(SRC_DIR)/runtime/HalidePyTorchCudaHelpers.h echo Copying $< @mkdir -p $(@D) cp $< $(INCLUDE_DIR)/ $(BIN_DIR)/build_halide_h: $(ROOT_DIR)/tools/build_halide_h.cpp @-mkdir -p $(@D) $(CXX) -std=c++17 $< -o $@ -include $(OBJECTS:.o=.d) -include $(INITIAL_MODULES:.o=.d) # Compile generic 32- or 64-bit code # (The 'nacl' is a red herring. This is just a generic 32-bit little-endian target.) RUNTIME_TRIPLE_32 = "le32-unknown-nacl-unknown" RUNTIME_TRIPLE_64 = "le64-unknown-unknown-unknown" # Windows requires special handling. The generic windows_* modules must have -fpic elided # and (for 64 bit) must set wchar to be 2 bytes. The windows_*_x86 and windows_*_arm # modules need to interact with specific calling conventions related to D3D12. # # TODO(marcos): generic code won't hold for ARM32... If ARM32 support becomes necessary, # all windows-related runtime modules will have to be wrapped in windows_*_arm.cpp files # for now, generic Windows 32bit code just assumes x86 (i386) RUNTIME_TRIPLE_WIN_X86_32 = "i386-unknown-windows-unknown" RUNTIME_TRIPLE_WIN_X86_64 = "x86_64-unknown-windows-unknown" RUNTIME_TRIPLE_WIN_ARM_32 = "arm-unknown-windows-unknown" RUNTIME_TRIPLE_WIN_ARM_64 = "aarch64-unknown-windows-unknown" RUNTIME_TRIPLE_WIN_GENERIC_64 = "le64-unknown-windows-unknown" # `-fno-threadsafe-statics` is very important here (note that it allows us to use a 'modern' C++ # standard but still skip threadsafe guards for static initialization in our runtime code) # # `-fno-rtti` is necessary to allow us to use classes with virtual functions in the runtime code RUNTIME_CXX_FLAGS = -std=c++17 -O3 -fno-vectorize -ffreestanding -fno-blocks -fno-exceptions -fno-unwind-tables -fno-threadsafe-statics -fno-rtti $(BUILD_DIR)/initmod.windows_%_x86_32.ll: $(SRC_DIR)/runtime/windows_%_x86.cpp $(BUILD_DIR)/clang_ok @mkdir -p $(@D) $(CLANG) $(CXX_WARNING_FLAGS) $(RUNTIME_CXX_FLAGS) -m32 -target $(RUNTIME_TRIPLE_WIN_X86_32) -DCOMPILING_HALIDE_RUNTIME -DBITS_32 -emit-llvm -S $(SRC_DIR)/runtime/windows_$*_x86.cpp -o $@ -MMD -MP -MF $(BUILD_DIR)/initmod.windows_$*_x86_32.d $(BUILD_DIR)/initmod.windows_%_x86_64.ll: $(SRC_DIR)/runtime/windows_%_x86.cpp $(BUILD_DIR)/clang_ok @mkdir -p $(@D) $(CLANG) $(CXX_WARNING_FLAGS) $(RUNTIME_CXX_FLAGS) -m64 -target $(RUNTIME_TRIPLE_WIN_X86_64) -DCOMPILING_HALIDE_RUNTIME -DBITS_64 -emit-llvm -S $(SRC_DIR)/runtime/windows_$*_x86.cpp -o $@ -MMD -MP -MF $(BUILD_DIR)/initmod.windows_$*_x86_64.d $(BUILD_DIR)/initmod.windows_%_arm_32.ll: $(SRC_DIR)/runtime/windows_%_arm.cpp $(BUILD_DIR)/clang_ok @mkdir -p $(@D) $(CLANG) $(CXX_WARNING_FLAGS) $(RUNTIME_CXX_FLAGS) -m32 -target $(RUNTIME_TRIPLE_WIN_ARM_32) -DCOMPILING_HALIDE_RUNTIME -DBITS_32 -emit-llvm -S $(SRC_DIR)/runtime/windows_$*_arm.cpp -o $@ -MMD -MP -MF $(BUILD_DIR)/initmod.windows_$*_arm_32.d $(BUILD_DIR)/initmod.windows_%_arm_64.ll: $(SRC_DIR)/runtime/windows_%_arm.cpp $(BUILD_DIR)/clang_ok @mkdir -p $(@D) $(CLANG) $(CXX_WARNING_FLAGS) $(RUNTIME_CXX_FLAGS) -m64 -target $(RUNTIME_TRIPLE_WIN_ARM_64) -DCOMPILING_HALIDE_RUNTIME -DBITS_64 -emit-llvm -S $(SRC_DIR)/runtime/windows_$*_arm.cpp -o $@ -MMD -MP -MF $(BUILD_DIR)/initmod.windows_$*_arm_64.d $(BUILD_DIR)/initmod.windows_%_32.ll: $(SRC_DIR)/runtime/windows_%.cpp $(BUILD_DIR)/clang_ok @mkdir -p $(@D) $(CLANG) $(CXX_WARNING_FLAGS) $(RUNTIME_CXX_FLAGS) -m32 -target $(RUNTIME_TRIPLE_WIN_X86_32) -DCOMPILING_HALIDE_RUNTIME -DBITS_32 -emit-llvm -S $(SRC_DIR)/runtime/windows_$*.cpp -o $@ -MMD -MP -MF $(BUILD_DIR)/initmod.windows_$*_32.d $(BUILD_DIR)/initmod.windows_%_64.ll: $(SRC_DIR)/runtime/windows_%.cpp $(BUILD_DIR)/clang_ok @mkdir -p $(@D) $(CLANG) $(CXX_WARNING_FLAGS) $(RUNTIME_CXX_FLAGS) -m64 -target $(RUNTIME_TRIPLE_WIN_GENERIC_64) -fshort-wchar -DCOMPILING_HALIDE_RUNTIME -DBITS_64 -emit-llvm -S $(SRC_DIR)/runtime/windows_$*.cpp -o $@ -MMD -MP -MF $(BUILD_DIR)/initmod.windows_$*_64.d $(BUILD_DIR)/initmod.%_64.ll: $(SRC_DIR)/runtime/%.cpp $(BUILD_DIR)/clang_ok @mkdir -p $(@D) $(CLANG) $(CXX_WARNING_FLAGS) $(RUNTIME_CXX_FLAGS) -fpic -m64 -target $(RUNTIME_TRIPLE_64) -DCOMPILING_HALIDE_RUNTIME -DBITS_64 -emit-llvm -S $(SRC_DIR)/runtime/$*.cpp -o $@ -MMD -MP -MF $(BUILD_DIR)/initmod.$*_64.d $(BUILD_DIR)/initmod.%_32.ll: $(SRC_DIR)/runtime/%.cpp $(BUILD_DIR)/clang_ok @mkdir -p $(@D) $(CLANG) $(CXX_WARNING_FLAGS) $(RUNTIME_CXX_FLAGS) -fpic -m32 -target $(RUNTIME_TRIPLE_32) -DCOMPILING_HALIDE_RUNTIME -DBITS_32 -emit-llvm -S $(SRC_DIR)/runtime/$*.cpp -o $@ -MMD -MP -MF $(BUILD_DIR)/initmod.$*_32.d $(BUILD_DIR)/initmod.windows_%_x86_32_debug.ll: $(SRC_DIR)/runtime/windows_%_x86.cpp $(BUILD_DIR)/clang_ok @mkdir -p $(@D) $(CLANG) $(CXX_WARNING_FLAGS) -g -DDEBUG_RUNTIME $(RUNTIME_CXX_FLAGS) -m32 -target $(RUNTIME_TRIPLE_WIN_X86_32) -DCOMPILING_HALIDE_RUNTIME -DBITS_32 -emit-llvm -S $(SRC_DIR)/runtime/windows_$*_x86.cpp -o $@ -MMD -MP -MF $(BUILD_DIR)/initmod.windows_$*_x86_32_debug.d $(BUILD_DIR)/initmod.windows_%_x86_64_debug.ll: $(SRC_DIR)/runtime/windows_%_x86.cpp $(BUILD_DIR)/clang_ok @mkdir -p $(@D) $(CLANG) $(CXX_WARNING_FLAGS) -g -DDEBUG_RUNTIME $(RUNTIME_CXX_FLAGS) -m64 -target $(RUNTIME_TRIPLE_WIN_X86_64) -DCOMPILING_HALIDE_RUNTIME -DBITS_64 -emit-llvm -S $(SRC_DIR)/runtime/windows_$*_x86.cpp -o $@ -MMD -MP -MF $(BUILD_DIR)/initmod.windows_$*_x86_64_debug.d $(BUILD_DIR)/initmod.windows_%_arm_32_debug.ll: $(SRC_DIR)/runtime/windows_%_arm.cpp $(BUILD_DIR)/clang_ok @mkdir -p $(@D) $(CLANG) $(CXX_WARNING_FLAGS) -g -DDEBUG_RUNTIME $(RUNTIME_CXX_FLAGS) -m32 -target $(RUNTIME_TRIPLE_WIN_ARM_32) -DCOMPILING_HALIDE_RUNTIME -DBITS_32 -emit-llvm -S $(SRC_DIR)/runtime/windows_$*_arm.cpp -o $@ -MMD -MP -MF $(BUILD_DIR)/initmod.windows_$*_arm_32_debug.d $(BUILD_DIR)/initmod.windows_%_arm_64_debug.ll: $(SRC_DIR)/runtime/windows_%_arm.cpp $(BUILD_DIR)/clang_ok @mkdir -p $(@D) $(CLANG) $(CXX_WARNING_FLAGS) -g -DDEBUG_RUNTIME $(RUNTIME_CXX_FLAGS) -m64 -target $(RUNTIME_TRIPLE_WIN_ARM_64) -DCOMPILING_HALIDE_RUNTIME -DBITS_64 -emit-llvm -S $(SRC_DIR)/runtime/windows_$*_arm.cpp -o $@ -MMD -MP -MF $(BUILD_DIR)/initmod.windows_$*_arm_64_debug.d $(BUILD_DIR)/initmod.windows_%_64_debug.ll: $(SRC_DIR)/runtime/windows_%.cpp $(BUILD_DIR)/clang_ok @mkdir -p $(@D) $(CLANG) $(CXX_WARNING_FLAGS) -g -DDEBUG_RUNTIME $(RUNTIME_CXX_FLAGS) -m64 -target $(RUNTIME_TRIPLE_WIN_GENERIC_64) -DCOMPILING_HALIDE_RUNTIME -DBITS_64 -emit-llvm -S $(SRC_DIR)/runtime/windows_$*.cpp -o $@ -MMD -MP -MF $(BUILD_DIR)/initmod.windows_$*_64_debug.d $(BUILD_DIR)/initmod.%_64_debug.ll: $(SRC_DIR)/runtime/%.cpp $(BUILD_DIR)/clang_ok @mkdir -p $(@D) $(CLANG) $(CXX_WARNING_FLAGS) -g -DDEBUG_RUNTIME $(RUNTIME_CXX_FLAGS) -fpic -m64 -target $(RUNTIME_TRIPLE_64) -DCOMPILING_HALIDE_RUNTIME -DBITS_64 -emit-llvm -S $(SRC_DIR)/runtime/$*.cpp -o $@ -MMD -MP -MF $(BUILD_DIR)/initmod.$*_64_debug.d $(BUILD_DIR)/initmod.windows_%_32_debug.ll: $(SRC_DIR)/runtime/windows_%.cpp $(BUILD_DIR)/clang_ok @mkdir -p $(@D) $(CLANG) $(CXX_WARNING_FLAGS) -g -DDEBUG_RUNTIME $(RUNTIME_CXX_FLAGS) -m32 -target $(RUNTIME_TRIPLE_WIN_X86_32) -DCOMPILING_HALIDE_RUNTIME -DBITS_32 -emit-llvm -S $(SRC_DIR)/runtime/windows_$*.cpp -o $@ -MMD -MP -MF $(BUILD_DIR)/initmod.windows_$*_32_debug.d $(BUILD_DIR)/initmod.%_32_debug.ll: $(SRC_DIR)/runtime/%.cpp $(BUILD_DIR)/clang_ok @mkdir -p $(@D) $(CLANG) $(CXX_WARNING_FLAGS) -g -DDEBUG_RUNTIME -O3 $(RUNTIME_CXX_FLAGS) -fpic -m32 -target $(RUNTIME_TRIPLE_32) -DCOMPILING_HALIDE_RUNTIME -DBITS_32 -emit-llvm -S $(SRC_DIR)/runtime/$*.cpp -o $@ -MMD -MP -MF $(BUILD_DIR)/initmod.$*_32_debug.d $(BUILD_DIR)/initmod.%_ll.ll: $(SRC_DIR)/runtime/%.ll @mkdir -p $(@D) cp $(SRC_DIR)/runtime/$*.ll $(BUILD_DIR)/initmod.$*_ll.ll $(BUILD_DIR)/initmod.%.bc: $(BUILD_DIR)/initmod.%.ll $(BUILD_DIR)/llvm_ok $(LLVM_AS) $(BUILD_DIR)/initmod.$*.ll -o $(BUILD_DIR)/initmod.$*.bc $(BUILD_DIR)/initmod.%.cpp: $(BIN_DIR)/binary2cpp $(BUILD_DIR)/initmod.%.bc ./$(BIN_DIR)/binary2cpp halide_internal_initmod_$* < $(BUILD_DIR)/initmod.$*.bc > $@ $(BUILD_DIR)/initmod.%_h.cpp: $(BIN_DIR)/binary2cpp $(SRC_DIR)/runtime/%.h ./$(BIN_DIR)/binary2cpp halide_internal_runtime_header_$*_h < $(SRC_DIR)/runtime/$*.h > $@ # Any c in the runtime that must be inlined needs to be copy-pasted into the output for the C backend. $(BUILD_DIR)/initmod.inlined_c.cpp: $(BIN_DIR)/binary2cpp $(SRC_DIR)/runtime/halide_buffer_t.cpp ./$(BIN_DIR)/binary2cpp halide_internal_initmod_inlined_c < $(SRC_DIR)/runtime/halide_buffer_t.cpp > $@ $(BUILD_DIR)/initmod_ptx.%_ll.cpp: $(BIN_DIR)/binary2cpp $(SRC_DIR)/runtime/nvidia_libdevice_bitcode/libdevice.%.bc ./$(BIN_DIR)/binary2cpp halide_internal_initmod_ptx_$(basename $*)_ll < $(SRC_DIR)/runtime/nvidia_libdevice_bitcode/libdevice.$*.bc > $@ $(BIN_DIR)/binary2cpp: $(ROOT_DIR)/tools/binary2cpp.cpp @mkdir -p $(@D) $(CXX) $< -o $@ $(BUILD_DIR)/initmod_ptx.%_ll.o: $(BUILD_DIR)/initmod_ptx.%_ll.cpp $(CXX) -c $< -o $@ -MMD -MP -MF $(BUILD_DIR)/$*.d -MT $(BUILD_DIR)/$*.o $(BUILD_DIR)/initmod.%.o: $(BUILD_DIR)/initmod.%.cpp $(CXX) -c $< -o $@ -MMD -MP -MF $(BUILD_DIR)/$*.d -MT $(BUILD_DIR)/$*.o $(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp $(BUILD_DIR)/llvm_ok @mkdir -p $(@D) $(CXX) $(CXX_FLAGS) -c $< -o $@ -MMD -MP -MF $(BUILD_DIR)/$*.d -MT $(BUILD_DIR)/$*.o $(BUILD_DIR)/Simplify_%.o: $(SRC_DIR)/Simplify_%.cpp $(SRC_DIR)/Simplify_Internal.h $(BUILD_DIR)/llvm_ok @mkdir -p $(@D) $(CXX) $(CXX_FLAGS) -c $< -o $@ -MMD -MP -MF $(BUILD_DIR)/Simplify_$*.d -MT $@ .PHONY: clean clean: rm -rf $(LIB_DIR) rm -rf $(BIN_DIR) rm -rf $(BUILD_DIR) rm -rf $(TMP_DIR) rm -rf $(FILTERS_DIR) rm -rf $(INCLUDE_DIR) rm -rf $(SHARE_DIR) rm -rf $(DISTRIB_DIR) rm -rf $(ROOT_DIR)/apps/*/bin .SECONDARY: CORRECTNESS_TESTS = $(shell ls $(ROOT_DIR)/test/correctness/*.cpp) $(shell ls $(ROOT_DIR)/test/correctness/*.c) PERFORMANCE_TESTS = $(shell ls $(ROOT_DIR)/test/performance/*.cpp) ERROR_TESTS = $(shell ls $(ROOT_DIR)/test/error/*.cpp) WARNING_TESTS = $(shell ls $(ROOT_DIR)/test/warning/*.cpp) GENERATOR_EXTERNAL_TESTS := $(shell ls $(ROOT_DIR)/test/generator/*test.cpp) GENERATOR_EXTERNAL_TEST_GENERATOR := $(shell ls $(ROOT_DIR)/test/generator/*_generator.cpp) TUTORIALS = $(filter-out %_generate.cpp, $(shell ls $(ROOT_DIR)/tutorial/*.cpp)) AUTO_SCHEDULE_TESTS = $(shell ls $(ROOT_DIR)/test/auto_schedule/*.cpp) test_correctness: $(CORRECTNESS_TESTS:$(ROOT_DIR)/test/correctness/%.cpp=quiet_correctness_%) $(CORRECTNESS_TESTS:$(ROOT_DIR)/test/correctness/%.c=quiet_correctness_%) test_performance: $(PERFORMANCE_TESTS:$(ROOT_DIR)/test/performance/%.cpp=performance_%) test_error: $(ERROR_TESTS:$(ROOT_DIR)/test/error/%.cpp=error_%) test_warning: $(WARNING_TESTS:$(ROOT_DIR)/test/warning/%.cpp=warning_%) test_tutorial: $(TUTORIALS:$(ROOT_DIR)/tutorial/%.cpp=tutorial_%) test_valgrind: $(CORRECTNESS_TESTS:$(ROOT_DIR)/test/correctness/%.cpp=valgrind_%) test_avx512: $(CORRECTNESS_TESTS:$(ROOT_DIR)/test/correctness/%.cpp=avx512_%) test_auto_schedule: test_mullapudi2016 test_li2018 test_adams2019 .PHONY: test_correctness_multi_gpu test_correctness_multi_gpu: correctness_gpu_multi_device # There are 3 types of tests for generators: # 1) Externally-written aot-based tests # 2) Externally-written aot-based tests (compiled using C++ backend) # 3) Externally-written JIT-based tests GENERATOR_AOT_TESTS = $(GENERATOR_EXTERNAL_TESTS:$(ROOT_DIR)/test/generator/%_aottest.cpp=generator_aot_%) GENERATOR_AOTCPP_TESTS = $(GENERATOR_EXTERNAL_TESTS:$(ROOT_DIR)/test/generator/%_aottest.cpp=generator_aotcpp_%) GENERATOR_JIT_TESTS = $(GENERATOR_EXTERNAL_TESTS:$(ROOT_DIR)/test/generator/%_jittest.cpp=generator_jit_%) # multitarget test doesn't make any sense for the CPP backend; just skip it. GENERATOR_AOTCPP_TESTS := $(filter-out generator_aotcpp_multitarget,$(GENERATOR_AOTCPP_TESTS)) # Note that many of the AOT-CPP tests are broken right now; # remove AOT-CPP tests that don't (yet) work for C++ backend # (each tagged with the *known* blocking issue(s)) # https://github.com/halide/Halide/issues/2084 (only if opencl enabled) GENERATOR_AOTCPP_TESTS := $(filter-out generator_aotcpp_gpu_texture,$(GENERATOR_AOTCPP_TESTS)) # https://github.com/halide/Halide/issues/2084 (only if opencl enabled) GENERATOR_AOTCPP_TESTS := $(filter-out generator_aotcpp_acquire_release,$(GENERATOR_AOTCPP_TESTS)) # https://github.com/halide/Halide/issues/2084 (only if opencl enabled) GENERATOR_AOTCPP_TESTS := $(filter-out generator_aotcpp_define_extern_opencl,$(GENERATOR_AOTCPP_TESTS)) # https://github.com/halide/Halide/issues/2084 (only if opencl enabled) GENERATOR_AOTCPP_TESTS := $(filter-out generator_aotcpp_gpu_object_lifetime,$(GENERATOR_AOTCPP_TESTS)) # https://github.com/halide/Halide/issues/2084 (only if opencl enabled) GENERATOR_AOTCPP_TESTS := $(filter-out generator_aotcpp_gpu_only,$(GENERATOR_AOTCPP_TESTS)) # https://github.com/halide/Halide/issues/2084 (only if opencl enabled)) GENERATOR_AOTCPP_TESTS := $(filter-out generator_aotcpp_cleanup_on_error,$(GENERATOR_AOTCPP_TESTS)) # https://github.com/halide/Halide/issues/2084 (only if opencl enabled) GENERATOR_AOTCPP_TESTS := $(filter-out generator_aotcpp_buffer_copy,$(GENERATOR_AOTCPP_TESTS)) # https://github.com/halide/Halide/issues/2075 GENERATOR_AOTCPP_TESTS := $(filter-out generator_aotcpp_msan,$(GENERATOR_AOTCPP_TESTS)) # https://github.com/halide/Halide/issues/2075 GENERATOR_AOTCPP_TESTS := $(filter-out generator_aotcpp_memory_profiler_mandelbrot,$(GENERATOR_AOTCPP_TESTS)) # https://github.com/halide/Halide/issues/2082 GENERATOR_AOTCPP_TESTS := $(filter-out generator_aotcpp_matlab,$(GENERATOR_AOTCPP_TESTS)) # https://github.com/halide/Halide/issues/2093 GENERATOR_AOTCPP_TESTS := $(filter-out generator_aotcpp_async_parallel,$(GENERATOR_AOTCPP_TESTS)) # https://github.com/halide/Halide/issues/4916 GENERATOR_AOTCPP_TESTS := $(filter-out generator_aotcpp_stubtest,$(GENERATOR_AOTCPP_TESTS)) GENERATOR_AOTCPP_TESTS := $(filter-out generator_aotcpp_stubuser,$(GENERATOR_AOTCPP_TESTS)) GENERATOR_AOTCPP_TESTS := $(filter-out generator_aotcpp_gpu_multi_context_threaded,$(GENERATOR_AOTCPP_TESTS)) test_aotcpp_generator: $(GENERATOR_AOTCPP_TESTS) # This is just a test to ensure than RunGen builds and links for a critical mass of Generators; # not all will work directly (e.g. due to missing define_externs at link time), so we disable # those known to be broken for plausible reasons. GENERATOR_BUILD_RUNGEN_TESTS = $(GENERATOR_EXTERNAL_TEST_GENERATOR:$(ROOT_DIR)/test/generator/%_generator.cpp=$(FILTERS_DIR)/%.rungen) GENERATOR_BUILD_RUNGEN_TESTS := $(filter-out $(FILTERS_DIR)/async_parallel.rungen,$(GENERATOR_BUILD_RUNGEN_TESTS)) GENERATOR_BUILD_RUNGEN_TESTS := $(filter-out $(FILTERS_DIR)/cxx_mangling_define_extern.rungen,$(GENERATOR_BUILD_RUNGEN_TESTS)) GENERATOR_BUILD_RUNGEN_TESTS := $(filter-out $(FILTERS_DIR)/define_extern_opencl.rungen,$(GENERATOR_BUILD_RUNGEN_TESTS)) GENERATOR_BUILD_RUNGEN_TESTS := $(filter-out $(FILTERS_DIR)/matlab.rungen,$(GENERATOR_BUILD_RUNGEN_TESTS)) GENERATOR_BUILD_RUNGEN_TESTS := $(filter-out $(FILTERS_DIR)/msan.rungen,$(GENERATOR_BUILD_RUNGEN_TESTS)) GENERATOR_BUILD_RUNGEN_TESTS := $(filter-out $(FILTERS_DIR)/multitarget.rungen,$(GENERATOR_BUILD_RUNGEN_TESTS)) GENERATOR_BUILD_RUNGEN_TESTS := $(filter-out $(FILTERS_DIR)/nested_externs.rungen,$(GENERATOR_BUILD_RUNGEN_TESTS)) GENERATOR_BUILD_RUNGEN_TESTS := $(filter-out $(FILTERS_DIR)/tiled_blur.rungen,$(GENERATOR_BUILD_RUNGEN_TESTS)) GENERATOR_BUILD_RUNGEN_TESTS := $(filter-out $(FILTERS_DIR)/extern_output.rungen,$(GENERATOR_BUILD_RUNGEN_TESTS)) GENERATOR_BUILD_RUNGEN_TESTS := $(filter-out $(FILTERS_DIR)/gpu_multi_context_threaded.rungen,$(GENERATOR_BUILD_RUNGEN_TESTS)) GENERATOR_BUILD_RUNGEN_TESTS := $(GENERATOR_BUILD_RUNGEN_TESTS) \ $(FILTERS_DIR)/multi_rungen \ $(FILTERS_DIR)/multi_rungen2 \ $(FILTERS_DIR)/rungen_test \ $(FILTERS_DIR)/registration_test test_rungen: $(GENERATOR_BUILD_RUNGEN_TESTS) $(FILTERS_DIR)/rungen_test $(FILTERS_DIR)/registration_test test_generator: $(GENERATOR_AOT_TESTS) $(GENERATOR_AOTCPP_TESTS) $(GENERATOR_JIT_TESTS) $(GENERATOR_BUILD_RUNGEN_TESTS) $(FILTERS_DIR)/rungen_test $(FILTERS_DIR)/registration_test ALL_TESTS = test_internal test_correctness test_error test_tutorial test_warning test_generator # These targets perform timings of each test. For most tests this includes Halide JIT compile times, and run times. # For generator tests they time the compile time only. The times are recorded in CSV files. time_compilation_correctness: init_time_compilation_correctness $(CORRECTNESS_TESTS:$(ROOT_DIR)/test/correctness/%.cpp=time_compilation_test_%) time_compilation_performance: init_time_compilation_performance $(PERFORMANCE_TESTS:$(ROOT_DIR)/test/performance/%.cpp=time_compilation_performance_%) time_compilation_generator: init_time_compilation_generator $(GENERATOR_TESTS:$(ROOT_DIR)/test/generator/%_aottest.cpp=time_compilation_generator_%) init_time_compilation_%: echo "TEST,User (s),System (s),Real" > $(@:init_time_compilation_%=compile_times_%.csv) TIME_COMPILATION ?= /usr/bin/time -a -f "$@,%U,%S,%E" -o run_tests: $(ALL_TESTS) make -f $(THIS_MAKEFILE) test_performance test_auto_schedule .PHONY: build_tests build_tests: $(CORRECTNESS_TESTS:$(ROOT_DIR)/test/correctness/%.cpp=$(BIN_DIR)/correctness_%) \ $(PERFORMANCE_TESTS:$(ROOT_DIR)/test/performance/%.cpp=$(BIN_DIR)/performance_%) \ $(ERROR_TESTS:$(ROOT_DIR)/test/error/%.cpp=$(BIN_DIR)/error_%) \ $(WARNING_TESTS:$(ROOT_DIR)/test/warning/%.cpp=$(BIN_DIR)/warning_%) \ $(GENERATOR_EXTERNAL_TESTS:$(ROOT_DIR)/test/generator/%_aottest.cpp=$(BIN_DIR)/$(TARGET)/generator_aot_%) \ $(GENERATOR_EXTERNAL_TESTS:$(ROOT_DIR)/test/generator/%_jittest.cpp=$(BIN_DIR)/generator_jit_%) \ $(AUTO_SCHEDULE_TESTS:$(ROOT_DIR)/test/auto_schedule/%.cpp=$(BIN_DIR)/auto_schedule_%) clean_generator: rm -rf $(BIN_DIR)/*.generator rm -rf $(BIN_DIR)/*/runtime.a rm -rf $(FILTERS_DIR) rm -rf $(BIN_DIR)/*/generator_* rm -rf $(BUILD_DIR)/*_generator.o rm -f $(BUILD_DIR)/GenGen.o rm -f $(BUILD_DIR)/RunGenMain.o time_compilation_tests: time_compilation_correctness time_compilation_performance time_compilation_generator $(BUILD_DIR)/GenGen.o: $(ROOT_DIR)/tools/GenGen.cpp $(INCLUDE_DIR)/Halide.h @mkdir -p $(@D) $(CXX) -c $< $(TEST_CXX_FLAGS) -I$(INCLUDE_DIR) -o $@ # Make an empty generator for generating runtimes. $(BIN_DIR)/runtime.generator: $(BUILD_DIR)/GenGen.o $(BIN_DIR)/libHalide.$(SHARED_EXT) @mkdir -p $(@D) $(CXX) $< $(TEST_LD_FLAGS) -o $@ # Generate a standalone runtime for a given target string $(BIN_DIR)/%/runtime.a: $(BIN_DIR)/runtime.generator @mkdir -p $(@D) $(CURDIR)/$< -r runtime -o $(CURDIR)/$(BIN_DIR)/$* target=$* $(BIN_DIR)/test_internal: $(ROOT_DIR)/test/internal.cpp $(BIN_DIR)/libHalide.$(SHARED_EXT) @mkdir -p $(@D) $(CXX) $(TEST_CXX_FLAGS) $< -I$(SRC_DIR) $(TEST_LD_FLAGS) -o $@ # Correctness test that link against libHalide $(BIN_DIR)/correctness_%: $(ROOT_DIR)/test/correctness/%.cpp $(BIN_DIR)/libHalide.$(SHARED_EXT) $(INCLUDE_DIR)/Halide.h $(RUNTIME_EXPORTED_INCLUDES) @mkdir -p $(@D) $(CXX) $(TEST_CXX_FLAGS) -I$(ROOT_DIR)/src/runtime -I$(ROOT_DIR)/test/common $(OPTIMIZE_FOR_BUILD_TIME) $< -I$(INCLUDE_DIR) $(TEST_LD_FLAGS) -o $@ # Correctness tests that do NOT link against libHalide $(BIN_DIR)/correctness_plain_c_includes: $(ROOT_DIR)/test/correctness/plain_c_includes.c $(RUNTIME_EXPORTED_INCLUDES) $(CXX) -x c -Wall -Werror -I$(ROOT_DIR)/src/runtime $(OPTIMIZE_FOR_BUILD_TIME) $< -I$(ROOT_DIR)/src/runtime -o $@ # Note that this test must *not* link in either libHalide, or a Halide runtime; # this test should be usable without either. $(BIN_DIR)/correctness_halide_buffer: $(ROOT_DIR)/test/correctness/halide_buffer.cpp $(INCLUDE_DIR)/HalideBuffer.h $(RUNTIME_EXPORTED_INCLUDES) $(CXX) $(TEST_CXX_FLAGS) $(OPTIMIZE_FOR_BUILD_TIME) $< -I$(INCLUDE_DIR) -o $@ # The image_io test additionally needs to link to libpng and # libjpeg. $(BIN_DIR)/correctness_image_io: $(ROOT_DIR)/test/correctness/image_io.cpp $(BIN_DIR)/libHalide.$(SHARED_EXT) $(INCLUDE_DIR)/Halide.h $(RUNTIME_EXPORTED_INCLUDES) $(CXX) $(TEST_CXX_FLAGS) $(IMAGE_IO_CXX_FLAGS) -I$(ROOT_DIR)/src/runtime -I$(ROOT_DIR)/test/common $(OPTIMIZE_FOR_BUILD_TIME) $< -I$(INCLUDE_DIR) $(TEST_LD_FLAGS) $(IMAGE_IO_LIBS) -o $@ # OpenCL runtime correctness test requires runtime.a to be linked. $(BIN_DIR)/$(TARGET)/correctness_opencl_runtime: $(ROOT_DIR)/test/correctness/opencl_runtime.cpp $(RUNTIME_EXPORTED_INCLUDES) $(BIN_DIR)/$(TARGET)/runtime.a @mkdir -p $(@D) $(CXX) $(BIN_DIR)/$(TARGET)/runtime.a $(TEST_CXX_FLAGS) -I$(ROOT_DIR)/src/runtime $(OPTIMIZE_FOR_BUILD_TIME) $< -I$(INCLUDE_DIR) $(TEST_LD_FLAGS) -o $@ $(BIN_DIR)/performance_%: $(ROOT_DIR)/test/performance/%.cpp $(BIN_DIR)/libHalide.$(SHARED_EXT) $(INCLUDE_DIR)/Halide.h $(CXX) $(TEST_CXX_FLAGS) $(OPTIMIZE) $< -I$(INCLUDE_DIR) -I$(ROOT_DIR)/src/runtime -I$(ROOT_DIR)/test/common $(TEST_LD_FLAGS) -o $@ # Error tests that link against libHalide $(BIN_DIR)/error_%: $(ROOT_DIR)/test/error/%.cpp $(BIN_DIR)/libHalide.$(SHARED_EXT) $(INCLUDE_DIR)/Halide.h $(CXX) $(TEST_CXX_FLAGS) -I$(ROOT_DIR)/src/runtime -I$(ROOT_DIR)/test/common $(OPTIMIZE_FOR_BUILD_TIME) $< -I$(INCLUDE_DIR) $(TEST_LD_FLAGS) -o $@ $(BIN_DIR)/warning_%: $(ROOT_DIR)/test/warning/%.cpp $(BIN_DIR)/libHalide.$(SHARED_EXT) $(INCLUDE_DIR)/Halide.h $(CXX) $(TEST_CXX_FLAGS) $(OPTIMIZE_FOR_BUILD_TIME) $< -I$(INCLUDE_DIR) $(TEST_LD_FLAGS) -o $@ # Auto schedule tests that link against libHalide $(BIN_DIR)/auto_schedule_%: $(ROOT_DIR)/test/auto_schedule/%.cpp $(BIN_DIR)/libHalide.$(SHARED_EXT) $(INCLUDE_DIR)/Halide.h $(CXX) $(TEST_CXX_FLAGS) $(OPTIMIZE_FOR_BUILD_TIME) $< -I$(INCLUDE_DIR) $(TEST_LD_FLAGS) -o $@ # TODO(srj): this doesn't auto-delete, why not? .INTERMEDIATE: $(BIN_DIR)/%.generator # By default, %.generator is produced by building %_generator.cpp # Note that the rule includes all _generator.cpp files, so that generator with define_extern # usage can just add deps later. $(BUILD_DIR)/%_generator.o: $(ROOT_DIR)/test/generator/%_generator.cpp $(INCLUDE_DIR)/Halide.h @mkdir -p $(@D) $(CXX) $(TEST_CXX_FLAGS) -I$(INCLUDE_DIR) -I$(CURDIR)/$(FILTERS_DIR) -c $< -o $@ $(BIN_DIR)/%.generator: $(BUILD_DIR)/GenGen.o $(BIN_DIR)/libHalide.$(SHARED_EXT) $(BUILD_DIR)/%_generator.o @mkdir -p $(@D) $(CXX) $(filter %.cpp %.o %.a,$^) $(TEST_LD_FLAGS) -o $@ # It is not always possible to cross compile between 32-bit and 64-bit via the clang build as part of llvm # These next two rules can fail the compilationa nd produce zero length bitcode blobs. # If the zero length blob is actually used, the test will fail anyway, but usually only the bitness # of the target is used. $(BUILD_DIR)/external_code_extern_bitcode_32.cpp : $(ROOT_DIR)/test/generator/external_code_extern.cpp $(BIN_DIR)/binary2cpp @mkdir -p $(@D) $(CLANG) $(CXX_WARNING_FLAGS) -O3 -c -m32 -target $(RUNTIME_TRIPLE_32) -emit-llvm $< -o $(BUILD_DIR)/external_code_extern_32.bc || echo -n > $(BUILD_DIR)/external_code_extern_32.bc ./$(BIN_DIR)/binary2cpp external_code_extern_bitcode_32 < $(BUILD_DIR)/external_code_extern_32.bc > $@ $(BUILD_DIR)/external_code_extern_bitcode_64.cpp : $(ROOT_DIR)/test/generator/external_code_extern.cpp $(BIN_DIR)/binary2cpp @mkdir -p $(@D) $(CLANG) $(CXX_WARNING_FLAGS) -O3 -c -m64 -target $(RUNTIME_TRIPLE_64) -emit-llvm $< -o $(BUILD_DIR)/external_code_extern_64.bc || echo -n > $(BUILD_DIR)/external_code_extern_64.bc ./$(BIN_DIR)/binary2cpp external_code_extern_bitcode_64 < $(BUILD_DIR)/external_code_extern_64.bc > $@ $(BUILD_DIR)/external_code_extern_cpp_source.cpp : $(ROOT_DIR)/test/generator/external_code_extern.cpp $(BIN_DIR)/binary2cpp @mkdir -p $(@D) ./$(BIN_DIR)/binary2cpp external_code_extern_cpp_source < $(ROOT_DIR)/test/generator/external_code_extern.cpp > $@ $(BIN_DIR)/external_code.generator: $(BUILD_DIR)/GenGen.o $(BIN_DIR)/libHalide.$(SHARED_EXT) $(BUILD_DIR)/external_code_generator.o $(BUILD_DIR)/external_code_extern_bitcode_32.cpp $(BUILD_DIR)/external_code_extern_bitcode_64.cpp $(BUILD_DIR)/external_code_extern_cpp_source.cpp @mkdir -p $(@D) $(CXX) $(filter %.cpp %.o %.a,$^) $(TEST_LD_FLAGS) -o $@ NAME_MANGLING_TARGET=$(NON_EMPTY_TARGET)-c_plus_plus_name_mangling GEN_AOT_OUTPUTS=-e static_library,c_header,c_source,registration # By default, %.a/.h are produced by executing %.generator. Runtimes are not included in these. # (We explicitly also generate .cpp output here as well, as additional test surface for the C++ backend.) $(FILTERS_DIR)/%.a: $(BIN_DIR)/%.generator @mkdir -p $(@D) $(CURDIR)/$< -g $* $(GEN_AOT_OUTPUTS) -o $(CURDIR)/$(FILTERS_DIR) target=$(TARGET)-no_runtime $(FILTERS_DIR)/%.h: $(FILTERS_DIR)/%.a @echo $@ produced implicitly by $^ $(FILTERS_DIR)/%.halide_generated.cpp: $(FILTERS_DIR)/%.a @echo $@ produced implicitly by $^ $(FILTERS_DIR)/%.registration.cpp: $(FILTERS_DIR)/%.a @echo $@ produced implicitly by $^ $(FILTERS_DIR)/%.stub.h: $(BIN_DIR)/%.generator @mkdir -p $(@D) $(CURDIR)/$< -g $* -n $* -o $(CURDIR)/$(FILTERS_DIR) -e cpp_stub $(FILTERS_DIR)/cxx_mangling_externs.o: $(ROOT_DIR)/test/generator/cxx_mangling_externs.cpp @mkdir -p $(@D) $(CXX) $(GEN_AOT_CXX_FLAGS) -c $(filter-out %.h,$^) $(GEN_AOT_INCLUDES) -o $@ # If we want to use a Generator with custom GeneratorParams, we need to write # custom rules: to pass the GeneratorParams, and to give a unique function and file name. $(FILTERS_DIR)/cxx_mangling.a: $(BIN_DIR)/cxx_mangling.generator $(FILTERS_DIR)/cxx_mangling_externs.o @mkdir -p $(@D) $(CURDIR)/$< -g cxx_mangling $(GEN_AOT_OUTPUTS) -o $(CURDIR)/$(FILTERS_DIR) target=$(TARGET)-no_runtime-c_plus_plus_name_mangling -f "HalideTest::AnotherNamespace::cxx_mangling" $(ROOT_DIR)/tools/makelib.sh $@ $@ $(FILTERS_DIR)/cxx_mangling_externs.o ifneq ($(TEST_CUDA), ) # Also build with a gpu target to ensure that the GPU-Host generation # code handles name mangling properly. (Note that we don't need to # run this code, just check for link errors.) $(FILTERS_DIR)/cxx_mangling_gpu.a: $(BIN_DIR)/cxx_mangling.generator $(FILTERS_DIR)/cxx_mangling_externs.o @mkdir -p $(@D) $(CURDIR)/$< -g cxx_mangling $(GEN_AOT_OUTPUTS) -o $(CURDIR)/$(FILTERS_DIR) target=$(TARGET)-no_runtime-c_plus_plus_name_mangling-cuda-cuda_capability_30 -f "HalideTest::cxx_mangling_gpu" $(ROOT_DIR)/tools/makelib.sh $@ $@ $(FILTERS_DIR)/cxx_mangling_externs.o endif $(FILTERS_DIR)/cxx_mangling_define_extern_externs.o: $(ROOT_DIR)/test/generator/cxx_mangling_define_extern_externs.cpp $(FILTERS_DIR)/cxx_mangling.h @mkdir -p $(@D) $(CXX) $(GEN_AOT_CXX_FLAGS) -c $(filter-out %.h,$^) $(GEN_AOT_INCLUDES) -o $@ $(FILTERS_DIR)/cxx_mangling_define_extern.a: $(BIN_DIR)/cxx_mangling_define_extern.generator $(FILTERS_DIR)/cxx_mangling_define_extern_externs.o @mkdir -p $(@D) $(CURDIR)/$< -g cxx_mangling_define_extern $(GEN_AOT_OUTPUTS) -o $(CURDIR)/$(FILTERS_DIR) target=$(TARGET)-no_runtime-c_plus_plus_name_mangling-user_context -f "HalideTest::cxx_mangling_define_extern" $(ROOT_DIR)/tools/makelib.sh $@ $@ $(FILTERS_DIR)/cxx_mangling_define_extern_externs.o # pyramid needs a custom arg. $(FILTERS_DIR)/pyramid.a: $(BIN_DIR)/pyramid.generator @mkdir -p $(@D) $(CURDIR)/$< -g pyramid -f pyramid $(GEN_AOT_OUTPUTS) -o $(CURDIR)/$(FILTERS_DIR) target=$(TARGET)-no_runtime levels=10 $(FILTERS_DIR)/string_param.a: $(BIN_DIR)/string_param.generator @mkdir -p $(@D) $(CURDIR)/$< -g string_param -f string_param $(GEN_AOT_OUTPUTS) -o $(CURDIR)/$(FILTERS_DIR) target=$(TARGET)-no_runtime rpn_expr="5 y * x +" # memory_profiler_mandelbrot need profiler set $(FILTERS_DIR)/memory_profiler_mandelbrot.a: $(BIN_DIR)/memory_profiler_mandelbrot.generator @mkdir -p $(@D) $(CURDIR)/$< -g memory_profiler_mandelbrot -f memory_profiler_mandelbrot $(GEN_AOT_OUTPUTS) -o $(CURDIR)/$(FILTERS_DIR) target=$(TARGET)-no_runtime-profile $(FILTERS_DIR)/alias_with_offset_42.a: $(BIN_DIR)/alias.generator @mkdir -p $(@D) $(CURDIR)/$< -g alias_with_offset_42 -f alias_with_offset_42 $(GEN_AOT_OUTPUTS) -o $(CURDIR)/$(FILTERS_DIR) target=$(TARGET)-no_runtime METADATA_TESTER_GENERATOR_ARGS=\ input.type=uint8 input.dim=3 \ dim_only_input_buffer.type=uint8 \ untyped_input_buffer.type=uint8 untyped_input_buffer.dim=3 \ output.type=float32,float32 output.dim=3 \ input_not_nod.type=uint8 input_not_nod.dim=3 \ input_nod.dim=3 \ input_not.type=uint8 \ array_input.size=2 \ array_i8.size=2 \ array_i16.size=2 \ array_i32.size=2 \ array_h.size=2 \ buffer_array_input2.dim=3 \ buffer_array_input3.type=float32 \ buffer_array_input4.dim=3 \ buffer_array_input4.type=float32 \ buffer_array_input5.size=2 \ buffer_array_input6.size=2 \ buffer_array_input6.dim=3 \ buffer_array_input7.size=2 \ buffer_array_input7.type=float32 \ buffer_array_input8.size=2 \ buffer_array_input8.dim=3 \ buffer_array_input8.type=float32 \ buffer_f16_untyped.type=float16 \ untyped_scalar_input.type=uint8 \ array_outputs.size=2 \ array_outputs7.size=2 \ array_outputs8.size=2 \ array_outputs9.size=2 # metadata_tester is built with and without user-context $(FILTERS_DIR)/metadata_tester.a: $(BIN_DIR)/metadata_tester.generator @mkdir -p $(@D) $(CURDIR)/$< -g metadata_tester -f metadata_tester $(GEN_AOT_OUTPUTS) -o $(CURDIR)/$(FILTERS_DIR) target=$(TARGET)-no_runtime $(METADATA_TESTER_GENERATOR_ARGS) $(FILTERS_DIR)/metadata_tester_ucon.a: $(BIN_DIR)/metadata_tester.generator @mkdir -p $(@D) $(CURDIR)/$< -g metadata_tester -f metadata_tester_ucon $(GEN_AOT_OUTPUTS) -o $(CURDIR)/$(FILTERS_DIR) target=$(TARGET)-user_context-no_runtime $(METADATA_TESTER_GENERATOR_ARGS) $(BIN_DIR)/$(TARGET)/generator_aot_metadata_tester: $(FILTERS_DIR)/metadata_tester_ucon.a $(BIN_DIR)/$(TARGET)/generator_aotcpp_metadata_tester: $(FILTERS_DIR)/metadata_tester_ucon.halide_generated.cpp $(FILTERS_DIR)/multitarget.a: $(BIN_DIR)/multitarget.generator @mkdir -p $(@D) $(CURDIR)/$< -g multitarget -f "HalideTest::multitarget" $(GEN_AOT_OUTPUTS) -o $(CURDIR)/$(FILTERS_DIR) \ target=$(TARGET)-no_bounds_query-no_runtime-c_plus_plus_name_mangling,$(TARGET)-no_runtime-c_plus_plus_name_mangling \ -e assembly,bitcode,c_source,c_header,stmt_html,static_library,stmt $(FILTERS_DIR)/msan.a: $(BIN_DIR)/msan.generator @mkdir -p $(@D) $(CURDIR)/$< -g msan -f msan $(GEN_AOT_OUTPUTS) -o $(CURDIR)/$(FILTERS_DIR) target=$(TARGET)-msan # user_context needs to be generated with user_context as the first argument to its calls $(FILTERS_DIR)/user_context.a: $(BIN_DIR)/user_context.generator @mkdir -p $(@D) $(CURDIR)/$< -g user_context $(GEN_AOT_OUTPUTS) -o $(CURDIR)/$(FILTERS_DIR) target=$(TARGET)-no_runtime-user_context # ditto for user_context_insanity $(FILTERS_DIR)/user_context_insanity.a: $(BIN_DIR)/user_context_insanity.generator @mkdir -p $(@D) $(CURDIR)/$< -g user_context_insanity $(GEN_AOT_OUTPUTS) -o $(CURDIR)/$(FILTERS_DIR) target=$(TARGET)-no_runtime-user_context # matlab needs to be generated with matlab in TARGET $(FILTERS_DIR)/matlab.a: $(BIN_DIR)/matlab.generator @mkdir -p $(@D) $(CURDIR)/$< -g matlab $(GEN_AOT_OUTPUTS) -o $(CURDIR)/$(FILTERS_DIR) target=$(TARGET)-no_runtime-matlab # Some .generators have additional dependencies (usually due to define_extern usage). # These typically require two extra dependencies: # (1) Ensuring the extra _generator.cpp is built into the .generator. # (2) Ensuring the extra .a is linked into the final output. # TODO(srj): we really want to say "anything that depends on tiled_blur.a also depends on blur2x2.a"; # is there a way to specify that in Make? $(BIN_DIR)/$(TARGET)/generator_aot_tiled_blur: $(FILTERS_DIR)/blur2x2.a ifneq ($(TEST_CUDA), ) $(BIN_DIR)/$(TARGET)/generator_aot_cxx_mangling: $(FILTERS_DIR)/cxx_mangling_gpu.a endif $(BIN_DIR)/$(TARGET)/generator_aot_cxx_mangling_define_extern: $(FILTERS_DIR)/cxx_mangling.a $(BIN_DIR)/$(TARGET)/generator_aotcpp_tiled_blur: $(FILTERS_DIR)/blur2x2.halide_generated.cpp ifneq ($(TEST_CUDA), ) $(BIN_DIR)/$(TARGET)/generator_aotcpp_cxx_mangling: $(FILTERS_DIR)/cxx_mangling_gpu.halide_generated.cpp endif $(BIN_DIR)/$(TARGET)/generator_aotcpp_cxx_mangling: $(FILTERS_DIR)/cxx_mangling_externs.o $(BIN_DIR)/$(TARGET)/generator_aotcpp_cxx_mangling_define_extern: $(FILTERS_DIR)/cxx_mangling.halide_generated.cpp $(FILTERS_DIR)/cxx_mangling_externs.o $(FILTERS_DIR)/cxx_mangling_define_extern_externs.o $(BUILD_DIR)/stubuser_generator.o: $(FILTERS_DIR)/stubtest.stub.h $(FILTERS_DIR)/configure.stub.h $(BIN_DIR)/stubuser.generator: $(BUILD_DIR)/stubtest_generator.o $(BUILD_DIR)/configure_generator.o # stubtest has input and output funcs with undefined types and array sizes; this is fine for stub # usage (the types can be inferred), but for AOT compilation, we must make the types # concrete via generator args. STUBTEST_GENERATOR_ARGS=\ untyped_buffer_input.type=uint8 untyped_buffer_input.dim=3 \ simple_input.type=float32 \ array_input.type=float32 array_input.size=2 \ int_arg.size=2 \ tuple_output.type=float32,float32 \ vectorize=true $(FILTERS_DIR)/stubtest.a: $(BIN_DIR)/stubtest.generator @mkdir -p $(@D) $(CURDIR)/$< -g stubtest -f stubtest $(GEN_AOT_OUTPUTS) -o $(CURDIR)/$(FILTERS_DIR) target=$(TARGET)-no_runtime $(STUBTEST_GENERATOR_ARGS) $(FILTERS_DIR)/external_code.a: $(BIN_DIR)/external_code.generator @mkdir -p $(@D) $(CURDIR)/$< -g external_code -e static_library,c_header,registration -o $(CURDIR)/$(FILTERS_DIR) target=$(TARGET)-no_runtime external_code_is_bitcode=true $(FILTERS_DIR)/external_code.halide_generated.cpp: $(BIN_DIR)/external_code.generator @mkdir -p $(@D) $(CURDIR)/$< -g external_code -e c_source -o $(CURDIR)/$(FILTERS_DIR) target=$(TARGET)-no_runtime external_code_is_bitcode=false $(FILTERS_DIR)/autograd_grad.a: $(BIN_DIR)/autograd.generator $(DISTRIB_DIR)/lib/libautoschedule_mullapudi2016.$(SHARED_EXT) @mkdir -p $(@D) # FIXME: The autoscheduler looks for libHalide in the same # directory, which is normally a distro. But the generator # tests use bin/libHalide.so instead of a distro. For now, # just copy the autoscheduler to a place where it won't # confuse the linker. cp $(DISTRIB_DIR)/lib/libautoschedule_mullapudi2016.$(SHARED_EXT) $(BIN_DIR) $(CURDIR)/$< -g autograd $(GEN_AOT_OUTPUTS) -o $(CURDIR)/$(FILTERS_DIR) -f autograd_grad target=$(TARGET)-no_runtime auto_schedule=true -d 1 -p $(BIN_DIR)/libautoschedule_mullapudi2016.$(SHARED_EXT) -s Mullapudi2016 # Usually, it's considered best practice to have one Generator per # .cpp file, with the generator-name and filename matching; # nested_externs_generators.cpp is a counterexample, and thus requires # some special casing to get right. First, make a special rule to # build each of the Generators in nested_externs_generator.cpp (which # all have the form nested_externs_*). $(FILTERS_DIR)/nested_externs_%.a: $(BIN_DIR)/nested_externs.generator @mkdir -p $(@D) $(CURDIR)/$< -g nested_externs_$* $(GEN_AOT_OUTPUTS) -o $(CURDIR)/$(FILTERS_DIR) target=$(TARGET)-no_runtime # Similarly, gpu_multi needs two different kernels to test compilation caching. # Also requies user-context. $(FILTERS_DIR)/gpu_multi_context_threaded_%.a: $(BIN_DIR)/gpu_multi_context_threaded.generator @mkdir -p $(@D) $(CURDIR)/$< -g gpu_multi_context_threaded_$* $(GEN_AOT_OUTPUTS) -o $(CURDIR)/$(FILTERS_DIR) target=$(TARGET)-no_runtime-user_context GEN_AOT_CXX_FLAGS=$(TEST_CXX_FLAGS) -Wno-unknown-pragmas -Wno-unused-variable GEN_AOT_INCLUDES=-I$(INCLUDE_DIR) -I$(FILTERS_DIR) -I$(ROOT_DIR)/src/runtime -I$(ROOT_DIR)/test/common -I $(ROOT_DIR)/apps/support -I $(SRC_DIR)/runtime -I$(ROOT_DIR)/tools GEN_AOT_LD_FLAGS=$(COMMON_LD_FLAGS) ifneq ($(TEST_METAL), ) # Unlike cuda and opencl, which dynamically go find the appropriate symbols, metal requires actual linking. GEN_AOT_LD_FLAGS+=$(METAL_LD_FLAGS) endif # By default, %_aottest.cpp depends on $(FILTERS_DIR)/%.a/.h (but not libHalide). $(BIN_DIR)/$(TARGET)/generator_aot_%: $(ROOT_DIR)/test/generator/%_aottest.cpp $(FILTERS_DIR)/%.a $(FILTERS_DIR)/%.h $(RUNTIME_EXPORTED_INCLUDES) $(BIN_DIR)/$(TARGET)/runtime.a @mkdir -p $(@D) $(CXX) $(GEN_AOT_CXX_FLAGS) $(filter %.cpp %.o %.a,$^) $(GEN_AOT_INCLUDES) $(GEN_AOT_LD_FLAGS) -o $@ # Also make AOT testing targets that depends on the .cpp output (rather than .a). $(BIN_DIR)/$(TARGET)/generator_aotcpp_%: $(ROOT_DIR)/test/generator/%_aottest.cpp $(FILTERS_DIR)/%.halide_generated.cpp $(FILTERS_DIR)/%.h $(RUNTIME_EXPORTED_INCLUDES) $(BIN_DIR)/$(TARGET)/runtime.a @mkdir -p $(@D) $(CXX) $(GEN_AOT_CXX_FLAGS) $(filter %.cpp %.o %.a,$^) $(OPTIMIZE) $(GEN_AOT_INCLUDES) $(GEN_AOT_LD_FLAGS) -o $@ # MSAN test doesn't use the standard runtime $(BIN_DIR)/$(TARGET)/generator_aot_msan: $(ROOT_DIR)/test/generator/msan_aottest.cpp $(FILTERS_DIR)/msan.a $(FILTERS_DIR)/msan.h $(RUNTIME_EXPORTED_INCLUDES) @mkdir -p $(@D) $(CXX) $(GEN_AOT_CXX_FLAGS) $(filter-out %.h,$^) $(GEN_AOT_INCLUDES) $(GEN_AOT_LD_FLAGS) -o $@ # alias has additional deps to link in $(BIN_DIR)/$(TARGET)/generator_aot_alias: $(ROOT_DIR)/test/generator/alias_aottest.cpp $(FILTERS_DIR)/alias.a $(FILTERS_DIR)/alias_with_offset_42.a $(RUNTIME_EXPORTED_INCLUDES) $(BIN_DIR)/$(TARGET)/runtime.a @mkdir -p $(@D) $(CXX) $(GEN_AOT_CXX_FLAGS) $(filter %.cpp %.o %.a,$^) $(GEN_AOT_INCLUDES) $(GEN_AOT_LD_FLAGS) -o $@ $(BIN_DIR)/$(TARGET)/generator_aotcpp_alias: $(ROOT_DIR)/test/generator/alias_aottest.cpp $(FILTERS_DIR)/alias.halide_generated.cpp $(FILTERS_DIR)/alias_with_offset_42.halide_generated.cpp $(RUNTIME_EXPORTED_INCLUDES) $(BIN_DIR)/$(TARGET)/runtime.a @mkdir -p $(@D) $(CXX) $(GEN_AOT_CXX_FLAGS) $(filter %.cpp %.o %.a,$^) $(GEN_AOT_INCLUDES) $(GEN_AOT_LD_FLAGS) -o $@ # autograd has additional deps to link in $(BIN_DIR)/$(TARGET)/generator_aot_autograd: $(ROOT_DIR)/test/generator/autograd_aottest.cpp $(FILTERS_DIR)/autograd.a $(FILTERS_DIR)/autograd_grad.a $(RUNTIME_EXPORTED_INCLUDES) $(BIN_DIR)/$(TARGET)/runtime.a @mkdir -p $(@D) $(CXX) $(GEN_AOT_CXX_FLAGS) $(filter %.cpp %.o %.a,$^) $(GEN_AOT_INCLUDES) $(GEN_AOT_LD_FLAGS) -o $@ $(BIN_DIR)/$(TARGET)/generator_aotcpp_autograd: $(ROOT_DIR)/test/generator/autograd_aottest.cpp $(FILTERS_DIR)/autograd.halide_generated.cpp $(FILTERS_DIR)/autograd_grad.halide_generated.cpp $(RUNTIME_EXPORTED_INCLUDES) $(BIN_DIR)/$(TARGET)/runtime.a @mkdir -p $(@D) $(CXX) $(GEN_AOT_CXX_FLAGS) $(filter %.cpp %.o %.a,$^) $(GEN_AOT_INCLUDES) $(GEN_AOT_LD_FLAGS) -o $@ # nested_externs has additional deps to link in $(BIN_DIR)/$(TARGET)/generator_aot_nested_externs: $(ROOT_DIR)/test/generator/nested_externs_aottest.cpp $(FILTERS_DIR)/nested_externs_root.a $(FILTERS_DIR)/nested_externs_inner.a $(FILTERS_DIR)/nested_externs_combine.a $(FILTERS_DIR)/nested_externs_leaf.a $(RUNTIME_EXPORTED_INCLUDES) $(BIN_DIR)/$(TARGET)/runtime.a @mkdir -p $(@D) $(CXX) $(GEN_AOT_CXX_FLAGS) $(filter %.cpp %.o %.a,$^) $(GEN_AOT_INCLUDES) $(GEN_AOT_LD_FLAGS) -o $@ $(BIN_DIR)/$(TARGET)/generator_aotcpp_nested_externs: $(ROOT_DIR)/test/generator/nested_externs_aottest.cpp $(FILTERS_DIR)/nested_externs_root.halide_generated.cpp $(FILTERS_DIR)/nested_externs_inner.halide_generated.cpp $(FILTERS_DIR)/nested_externs_combine.halide_generated.cpp $(FILTERS_DIR)/nested_externs_leaf.halide_generated.cpp $(RUNTIME_EXPORTED_INCLUDES) $(BIN_DIR)/$(TARGET)/runtime.a @mkdir -p $(@D) $(CXX) $(GEN_AOT_CXX_FLAGS) $(filter %.cpp %.o %.a,$^) $(GEN_AOT_INCLUDES) $(GEN_AOT_LD_FLAGS) -o $@ # The matlab tests needs "-matlab" in the runtime $(BIN_DIR)/$(TARGET)/generator_aot_matlab: $(ROOT_DIR)/test/generator/matlab_aottest.cpp $(FILTERS_DIR)/matlab.a $(FILTERS_DIR)/matlab.h $(RUNTIME_EXPORTED_INCLUDES) $(BIN_DIR)/$(TARGET)-matlab/runtime.a @mkdir -p $(@D) $(CXX) $(GEN_AOT_CXX_FLAGS) $(filter %.cpp %.o %.a,$^) $(GEN_AOT_INCLUDES) $(GEN_AOT_LD_FLAGS) $(TEST_LD_FLAGS) -o $@ $(BIN_DIR)/$(TARGET)/generator_aotcpp_matlab: $(ROOT_DIR)/test/generator/matlab_aottest.cpp $(FILTERS_DIR)/matlab.halide_generated.cpp $(FILTERS_DIR)/matlab.h $(RUNTIME_EXPORTED_INCLUDES) $(BIN_DIR)/$(TARGET)-matlab/runtime.a @mkdir -p $(@D) $(CXX) $(GEN_AOT_CXX_FLAGS) $(filter %.cpp %.o %.a,$^) $(GEN_AOT_INCLUDES) $(GEN_AOT_LD_FLAGS) $(TEST_LD_FLAGS) -o $@ # The gpu object lifetime test needs the debug runtime $(BIN_DIR)/$(TARGET)/generator_aot_gpu_object_lifetime: $(ROOT_DIR)/test/generator/gpu_object_lifetime_aottest.cpp $(FILTERS_DIR)/gpu_object_lifetime.a $(FILTERS_DIR)/gpu_object_lifetime.h $(RUNTIME_EXPORTED_INCLUDES) $(BIN_DIR)/$(TARGET)-debug/runtime.a @mkdir -p $(@D) $(CXX) $(GEN_AOT_CXX_FLAGS) $(filter %.cpp %.o %.a,$^) $(GEN_AOT_INCLUDES) $(GEN_AOT_LD_FLAGS) $(TEST_LD_FLAGS) -o $@ # acquire_release explicitly uses CUDA/OpenCL APIs, so link those here. $(BIN_DIR)/$(TARGET)/generator_aot_acquire_release: $(ROOT_DIR)/test/generator/acquire_release_aottest.cpp $(FILTERS_DIR)/acquire_release.a $(FILTERS_DIR)/acquire_release.h $(RUNTIME_EXPORTED_INCLUDES) $(BIN_DIR)/$(TARGET)/runtime.a @mkdir -p $(@D) $(CXX) $(GEN_AOT_CXX_FLAGS) $(filter %.cpp %.o %.a,$^) $(GEN_AOT_INCLUDES) $(GEN_AOT_LD_FLAGS) $(OPENCL_LD_FLAGS) $(CUDA_LD_FLAGS) -o $@ $(BIN_DIR)/$(TARGET)/generator_aotcpp_acquire_release: $(ROOT_DIR)/test/generator/acquire_release_aottest.cpp $(FILTERS_DIR)/acquire_release.halide_generated.cpp $(FILTERS_DIR)/acquire_release.h $(RUNTIME_EXPORTED_INCLUDES) $(BIN_DIR)/$(TARGET)/runtime.a @mkdir -p $(@D) $(CXX) $(GEN_AOT_CXX_FLAGS) $(filter %.cpp %.o %.a,$^) $(GEN_AOT_INCLUDES) $(GEN_AOT_LD_FLAGS) $(OPENCL_LD_FLAGS) $(CUDA_LD_FLAGS) -o $@ # define_extern_opencl explicitly uses OpenCL APIs, so link those here. $(BIN_DIR)/$(TARGET)/generator_aot_define_extern_opencl: $(ROOT_DIR)/test/generator/define_extern_opencl_aottest.cpp $(FILTERS_DIR)/define_extern_opencl.a $(FILTERS_DIR)/define_extern_opencl.h $(RUNTIME_EXPORTED_INCLUDES) $(BIN_DIR)/$(TARGET)/runtime.a @mkdir -p $(@D) $(CXX) $(GEN_AOT_CXX_FLAGS) $(filter %.cpp %.o %.a,$^) $(GEN_AOT_INCLUDES) $(GEN_AOT_LD_FLAGS) $(OPENCL_LD_FLAGS) -o $@ $(BIN_DIR)/$(TARGET)/generator_aotcpp_define_extern_opencl: $(ROOT_DIR)/test/generator/define_extern_opencl_aottest.cpp $(FILTERS_DIR)/define_extern_opencl.halide_generated.cpp $(FILTERS_DIR)/define_extern_opencl.h $(RUNTIME_EXPORTED_INCLUDES) $(BIN_DIR)/$(TARGET)/runtime.a @mkdir -p $(@D) $(CXX) $(GEN_AOT_CXX_FLAGS) $(filter %.cpp %.o %.a,$^) $(GEN_AOT_INCLUDES) $(GEN_AOT_LD_FLAGS) $(OPENCL_LD_FLAGS) -o $@ # By default, %_jittest.cpp depends on libHalide, plus the stubs for the Generator. These are external tests that use the JIT. $(BIN_DIR)/generator_jit_%: $(ROOT_DIR)/test/generator/%_jittest.cpp $(BIN_DIR)/libHalide.$(SHARED_EXT) $(INCLUDE_DIR)/Halide.h $(FILTERS_DIR)/%.stub.h $(BUILD_DIR)/%_generator.o @mkdir -p $(@D) $(CXX) -g $(TEST_CXX_FLAGS) $(filter %.cpp %.o %.a,$^) -I$(INCLUDE_DIR) -I$(FILTERS_DIR) -I $(ROOT_DIR)/apps/support $(TEST_LD_FLAGS) -o $@ # generator_aot_multitarget is run multiple times, with different env vars. generator_aot_multitarget: $(BIN_DIR)/$(TARGET)/generator_aot_multitarget @mkdir -p $(@D) HL_MULTITARGET_TEST_USE_NOBOUNDSQUERY_FEATURE=0 $(CURDIR)/$< HL_MULTITARGET_TEST_USE_NOBOUNDSQUERY_FEATURE=1 $(CURDIR)/$< @-echo # gpu_multi_context_threaded has additional deps to link in $(BIN_DIR)/$(TARGET)/generator_aot_gpu_multi_context_threaded: $(ROOT_DIR)/test/generator/gpu_multi_context_threaded_aottest.cpp \ $(FILTERS_DIR)/gpu_multi_context_threaded_add.a \ $(FILTERS_DIR)/gpu_multi_context_threaded_mul.a \ $(RUNTIME_EXPORTED_INCLUDES) $(BIN_DIR)/$(TARGET)/runtime.a @mkdir -p $(@D) $(CXX) $(GEN_AOT_CXX_FLAGS) $(filter %.cpp %.o %.a,$^) $(GEN_AOT_INCLUDES) $(GEN_AOT_LD_FLAGS) $(OPENCL_LD_FLAGS) $(CUDA_LD_FLAGS) -o $@ $(BIN_DIR)/$(TARGET)/generator_aotcpp_gpu_multi_context_threaded: $(ROOT_DIR)/test/generator/gpu_multi_context_threaded_aottest.cpp \ $(FILTERS_DIR)/gpu_multi_context_threaded_add.halide_generated.cpp \ $(FILTERS_DIR)/gpu_multi_context_threaded_mul.halide_generated.cpp \ $(RUNTIME_EXPORTED_INCLUDES) $(BIN_DIR)/$(TARGET)/runtime.a @mkdir -p $(@D) $(CXX) $(GEN_AOT_CXX_FLAGS) $(filter %.cpp %.o %.a,$^) $(GEN_AOT_INCLUDES) $(GEN_AOT_LD_FLAGS) $(OPENCL_LD_FLAGS) $(CUDA_LD_FLAGS) -o $@ # nested externs doesn't actually contain a generator named # "nested_externs", and has no internal tests in any case. test_generator_nested_externs: @echo "Skipping" # gpu_multi actually contain a generator named # "gpu_multi", and has no internal tests in any case. test_generator_gpu_multi: @echo "Skipping" # gpu_multi_context_threaded actually contain a generator named # "gpu_multi", and has no internal tests in any case. test_generator_gpu_multi_context_threaded: @echo "Skipping" $(BUILD_DIR)/RunGenMain.o: $(ROOT_DIR)/tools/RunGenMain.cpp $(RUNTIME_EXPORTED_INCLUDES) $(ROOT_DIR)/tools/RunGen.h @mkdir -p $(@D) $(CXX) -c $< $(filter-out -g, $(TEST_CXX_FLAGS)) $(OPTIMIZE) -Os $(IMAGE_IO_CXX_FLAGS) -I$(INCLUDE_DIR) -I $(SRC_DIR)/runtime -I$(ROOT_DIR)/tools -o $@ $(FILTERS_DIR)/%.registration.o: $(FILTERS_DIR)/%.registration.cpp @mkdir -p $(@D) $(CXX) -c $< $(TEST_CXX_FLAGS) -o $@ $(FILTERS_DIR)/%.rungen: $(BUILD_DIR)/RunGenMain.o $(BIN_DIR)/$(TARGET)/runtime.a $(FILTERS_DIR)/%.registration.o $(FILTERS_DIR)/%.a @mkdir -p $(@D) $(CXX) -std=c++17 -I$(FILTERS_DIR) \ $(BUILD_DIR)/RunGenMain.o \ $(BIN_DIR)/$(TARGET)/runtime.a \ $(call alwayslink,$(FILTERS_DIR)/$*.registration.o) \ $(FILTERS_DIR)/$*.a \ $(GEN_AOT_LD_FLAGS) $(IMAGE_IO_LIBS) -o $@ RUNARGS ?= $(FILTERS_DIR)/%.run: $(FILTERS_DIR)/%.rungen $(CURDIR)/$< $(RUNARGS) @-echo $(FILTERS_DIR)/%.registration_extra.o: $(FILTERS_DIR)/%.registration.cpp @mkdir -p $(@D) $(CXX) -c $< $(TEST_CXX_FLAGS) -DHALIDE_REGISTER_EXTRA_KEY_VALUE_PAIRS_FUNC=halide_register_extra_key_value_pairs_$* -o $@ # Test the registration mechanism, independent of RunGen. # Note that this depends on the registration_extra.o (rather than registration.o) # because it compiles with HALIDE_REGISTER_EXTRA_KEY_VALUE_PAIRS_FUNC defined. $(FILTERS_DIR)/registration_test: $(ROOT_DIR)/test/generator/registration_test.cpp \ $(BIN_DIR)/$(TARGET)/runtime.a \ $(FILTERS_DIR)/blur2x2.registration_extra.o $(FILTERS_DIR)/blur2x2.a \ $(FILTERS_DIR)/cxx_mangling.registration_extra.o $(FILTERS_DIR)/cxx_mangling.a \ $(FILTERS_DIR)/pyramid.registration_extra.o $(FILTERS_DIR)/pyramid.a @mkdir -p $(@D) $(CXX) $(GEN_AOT_CXX_FLAGS) $(GEN_AOT_INCLUDES) \ $(ROOT_DIR)/test/generator/registration_test.cpp \ $(FILTERS_DIR)/blur2x2.registration_extra.o \ $(FILTERS_DIR)/cxx_mangling.registration_extra.o \ $(FILTERS_DIR)/pyramid.registration_extra.o \ $(FILTERS_DIR)/blur2x2.a \ $(FILTERS_DIR)/cxx_mangling.a \ $(FILTERS_DIR)/pyramid.a \ $(BIN_DIR)/$(TARGET)/runtime.a \ $(GEN_AOT_LD_FLAGS) $(IMAGE_IO_LIBS) -o $@ # Test RunGen itself $(FILTERS_DIR)/rungen_test: $(ROOT_DIR)/test/generator/rungen_test.cpp \ $(BIN_DIR)/$(TARGET)/runtime.a \ $(FILTERS_DIR)/example.registration.o \ $(FILTERS_DIR)/example.a @mkdir -p $(@D) $(CXX) $(GEN_AOT_CXX_FLAGS) $(IMAGE_IO_CXX_FLAGS) $(GEN_AOT_INCLUDES) \ $(ROOT_DIR)/test/generator/rungen_test.cpp \ $(BIN_DIR)/$(TARGET)/runtime.a \ $(call alwayslink,$(FILTERS_DIR)/example.registration.o) \ $(FILTERS_DIR)/example.a \ $(GEN_AOT_LD_FLAGS) $(IMAGE_IO_LIBS) -o $@ # Test linking multiple filters into a single RunGen instance $(FILTERS_DIR)/multi_rungen: $(BUILD_DIR)/RunGenMain.o $(BIN_DIR)/$(TARGET)/runtime.a \ $(FILTERS_DIR)/blur2x2.registration.o $(FILTERS_DIR)/blur2x2.a \ $(FILTERS_DIR)/cxx_mangling.registration.o $(FILTERS_DIR)/cxx_mangling.a \ $(FILTERS_DIR)/pyramid.registration.o $(FILTERS_DIR)/pyramid.a @mkdir -p $(@D) $(CXX) -std=c++17 -I$(FILTERS_DIR) \ $(BUILD_DIR)/RunGenMain.o \ $(BIN_DIR)/$(TARGET)/runtime.a \ $(call alwayslink,$(FILTERS_DIR)/blur2x2.registration.o) \ $(call alwayslink,$(FILTERS_DIR)/cxx_mangling.registration.o) \ $(call alwayslink,$(FILTERS_DIR)/pyramid.registration.o) \ $(FILTERS_DIR)/blur2x2.a \ $(FILTERS_DIR)/cxx_mangling.a \ $(FILTERS_DIR)/pyramid.a \ $(GEN_AOT_LD_FLAGS) $(IMAGE_IO_LIBS) -o $@ # Test concatenating multiple registration files as well, which should also work $(FILTERS_DIR)/multi_rungen2.registration.cpp: $(FILTERS_DIR)/blur2x2.registration.cpp $(FILTERS_DIR)/cxx_mangling.registration.cpp $(FILTERS_DIR)/pyramid.registration.cpp cat $^ > $@ $(FILTERS_DIR)/multi_rungen2: $(BUILD_DIR)/RunGenMain.o $(BIN_DIR)/$(TARGET)/runtime.a \ $(FILTERS_DIR)/multi_rungen2.registration.cpp \ $(FILTERS_DIR)/blur2x2.a \ $(FILTERS_DIR)/cxx_mangling.a \ $(FILTERS_DIR)/pyramid.a @mkdir -p $(@D) $(CXX) -std=c++17 -I$(FILTERS_DIR) $^ $(GEN_AOT_LD_FLAGS) $(IMAGE_IO_LIBS) -o $@ $(BIN_DIR)/tutorial_%: $(ROOT_DIR)/tutorial/%.cpp $(BIN_DIR)/libHalide.$(SHARED_EXT) $(INCLUDE_DIR)/Halide.h $(INCLUDE_DIR)/HalideRuntime.h @ if [[ $@ == *_run ]]; then \ export TUTORIAL=$* ;\ export LESSON=`echo $${TUTORIAL} | cut -b1-9`; \ make -f $(THIS_MAKEFILE) tutorial_$${TUTORIAL/run/generate}; \ $(CXX) $(TUTORIAL_CXX_FLAGS) $(IMAGE_IO_CXX_FLAGS) $(OPTIMIZE_FOR_BUILD_TIME) $< \ -I$(TMP_DIR) -I$(INCLUDE_DIR) $(TMP_DIR)/$${LESSON}_*.a $(GEN_AOT_LD_FLAGS) $(IMAGE_IO_LIBS) -lz -o $@; \ else \ $(CXX) $(TUTORIAL_CXX_FLAGS) $(IMAGE_IO_CXX_FLAGS) $(OPTIMIZE_FOR_BUILD_TIME) $< \ -I$(INCLUDE_DIR) -I$(ROOT_DIR)/tools $(TEST_LD_FLAGS) $(IMAGE_IO_LIBS) -o $@;\ fi $(BIN_DIR)/tutorial_lesson_15_generators: $(ROOT_DIR)/tutorial/lesson_15_generators.cpp $(BIN_DIR)/libHalide.$(SHARED_EXT) $(INCLUDE_DIR)/Halide.h $(BUILD_DIR)/GenGen.o $(CXX) $(TUTORIAL_CXX_FLAGS) $(IMAGE_IO_CXX_FLAGS) $(OPTIMIZE_FOR_BUILD_TIME) $< $(BUILD_DIR)/GenGen.o \ -I$(INCLUDE_DIR) $(TEST_LD_FLAGS) $(IMAGE_IO_LIBS) -o $@ tutorial_lesson_15_generators: $(ROOT_DIR)/tutorial/lesson_15_generators_usage.sh $(BIN_DIR)/tutorial_lesson_15_generators @-mkdir -p $(TMP_DIR) cp $(BIN_DIR)/tutorial_lesson_15_generators $(TMP_DIR)/lesson_15_generate; \ cd $(TMP_DIR); \ PATH="$${PATH}:$(CURDIR)/$(BIN_DIR)" source $(ROOT_DIR)/tutorial/lesson_15_generators_usage.sh @-echo $(BIN_DIR)/tutorial_lesson_16_rgb_generate: $(ROOT_DIR)/tutorial/lesson_16_rgb_generate.cpp $(BIN_DIR)/libHalide.$(SHARED_EXT) $(INCLUDE_DIR)/Halide.h $(BUILD_DIR)/GenGen.o $(CXX) $(TUTORIAL_CXX_FLAGS) $(IMAGE_IO_CXX_FLAGS) $(OPTIMIZE_FOR_BUILD_TIME) $< $(BUILD_DIR)/GenGen.o \ -I$(INCLUDE_DIR) $(TEST_LD_FLAGS) $(IMAGE_IO_LIBS) -o $@ $(BIN_DIR)/tutorial_lesson_16_rgb_run: $(ROOT_DIR)/tutorial/lesson_16_rgb_run.cpp $(BIN_DIR)/tutorial_lesson_16_rgb_generate @-mkdir -p $(TMP_DIR) # Run the generator $(BIN_DIR)/tutorial_lesson_16_rgb_generate -g brighten -o $(TMP_DIR) -f brighten_planar target=host layout=planar $(BIN_DIR)/tutorial_lesson_16_rgb_generate -g brighten -o $(TMP_DIR) -f brighten_interleaved target=host-no_runtime layout=interleaved $(BIN_DIR)/tutorial_lesson_16_rgb_generate -g brighten -o $(TMP_DIR) -f brighten_either target=host-no_runtime layout=either $(BIN_DIR)/tutorial_lesson_16_rgb_generate -g brighten -o $(TMP_DIR) -f brighten_specialized target=host-no_runtime layout=specialized # Compile the runner $(CXX) $(TUTORIAL_CXX_FLAGS) $(IMAGE_IO_CXX_FLAGS) $(OPTIMIZE_FOR_BUILD_TIME) $< \ -I$(INCLUDE_DIR) -L$(BIN_DIR) -I $(TMP_DIR) $(TMP_DIR)/brighten_*.a \ -lHalide $(TEST_LD_FLAGS) $(COMMON_LD_FLAGS) $(IMAGE_IO_LIBS) -o $@ @-echo $(BIN_DIR)/tutorial_lesson_21_auto_scheduler_generate: $(ROOT_DIR)/tutorial/lesson_21_auto_scheduler_generate.cpp $(BIN_DIR)/libHalide.$(SHARED_EXT) $(INCLUDE_DIR)/Halide.h $(BUILD_DIR)/GenGen.o $(CXX) $(TUTORIAL_CXX_FLAGS) $(IMAGE_IO_CXX_FLAGS) $(OPTIMIZE_FOR_BUILD_TIME) $< $(BUILD_DIR)/GenGen.o \ -I$(INCLUDE_DIR) $(TEST_LD_FLAGS) $(IMAGE_IO_LIBS) -o $@ # The values in MachineParams are: # - the maximum level of parallelism available, # - the size of the last-level cache (in bytes), # - the ratio between the cost of a miss at the last level cache and the cost # of arithmetic on the target architecture # ...in that order. LESSON_21_MACHINE_PARAMS = 32,16777216,40 $(BIN_DIR)/tutorial_lesson_21_auto_scheduler_run: $(ROOT_DIR)/tutorial/lesson_21_auto_scheduler_run.cpp $(BIN_DIR)/tutorial_lesson_21_auto_scheduler_generate $(DISTRIB_DIR)/lib/libautoschedule_mullapudi2016.$(SHARED_EXT) @-mkdir -p $(TMP_DIR) # Run the generator $(BIN_DIR)/tutorial_lesson_21_auto_scheduler_generate -g auto_schedule_gen -o $(TMP_DIR) -e static_library,c_header,schedule -f auto_schedule_false target=host auto_schedule=false # FIXME: The relative path of the autoscheduler and libHalide must be preserved on OS X, or it tries to load the wrong libHalide.dylib cp $(DISTRIB_DIR)/lib/libautoschedule_mullapudi2016.$(SHARED_EXT) $(BIN_DIR) $(BIN_DIR)/tutorial_lesson_21_auto_scheduler_generate -g auto_schedule_gen -o $(TMP_DIR) -e static_library,c_header,schedule -f auto_schedule_true target=host-no_runtime auto_schedule=true machine_params=$(LESSON_21_MACHINE_PARAMS) -p $(BIN_DIR)/libautoschedule_mullapudi2016.$(SHARED_EXT) -s Mullapudi2016 # Compile the runner $(CXX) $(TUTORIAL_CXX_FLAGS) $(IMAGE_IO_CXX_FLAGS) $(OPTIMIZE_FOR_BUILD_TIME) $< \ -I$(INCLUDE_DIR) -L$(BIN_DIR) -I $(TMP_DIR) $(TMP_DIR)/auto_schedule_*.a \ -lHalide $(TEST_LD_FLAGS) $(COMMON_LD_FLAGS) $(IMAGE_IO_LIBS) -o $@ @-echo test_internal: $(BIN_DIR)/test_internal @-mkdir -p $(TMP_DIR) cd $(TMP_DIR) ; $(CURDIR)/$< @-echo correctness_%: $(BIN_DIR)/correctness_% @-mkdir -p $(TMP_DIR) cd $(TMP_DIR) ; $(CURDIR)/$< @-echo correctness_opencl_runtime: $(BIN_DIR)/$(TARGET)/correctness_opencl_runtime @-mkdir -p $(TMP_DIR) cd $(TMP_DIR) ; $(CURDIR)/$< @-echo quiet_correctness_%: $(BIN_DIR)/correctness_% @-mkdir -p $(TMP_DIR) @cd $(TMP_DIR) ; ( $(CURDIR)/$< 2>stderr_$*.txt > stdout_$*.txt && echo -n . ) || ( echo ; echo FAILED TEST: $* ; cat stdout_$*.txt stderr_$*.txt ; false ) valgrind_%: $(BIN_DIR)/correctness_% @-mkdir -p $(TMP_DIR) cd $(TMP_DIR) ; valgrind --error-exitcode=-1 $(CURDIR)/$< @-echo # Use Intel SDE to emulate an avx 512 processor. avx512_%: $(BIN_DIR)/correctness_% @-mkdir -p $(TMP_DIR) cd $(TMP_DIR) ; sde -cnl -- $(CURDIR)/$< cd $(TMP_DIR) ; sde -knl -- $(CURDIR)/$< @-echo # This test is *supposed* to do an out-of-bounds read, so skip it when testing under valgrind valgrind_tracing_stack: $(BIN_DIR)/correctness_tracing_stack @-mkdir -p $(TMP_DIR) cd $(TMP_DIR) ; $(CURDIR)/$(BIN_DIR)/correctness_tracing_stack @-echo performance_%: $(BIN_DIR)/performance_% @-mkdir -p $(TMP_DIR) cd $(TMP_DIR) ; $(CURDIR)/$< @-echo error_%: $(BIN_DIR)/error_% @-mkdir -p $(TMP_DIR) cd $(TMP_DIR) ; $(CURDIR)/$< 2>&1 | egrep --q "terminating with uncaught exception|^terminate called|^Error|Assertion.*failed" @-echo warning_%: $(BIN_DIR)/warning_% @-mkdir -p $(TMP_DIR) cd $(TMP_DIR) ; $(CURDIR)/$< 2>&1 | egrep --q "^Warning" @-echo generator_jit_%: $(BIN_DIR)/generator_jit_% @-mkdir -p $(TMP_DIR) cd $(TMP_DIR) ; $(CURDIR)/$< @-echo generator_aot_%: $(BIN_DIR)/$(TARGET)/generator_aot_% @-mkdir -p $(TMP_DIR) cd $(TMP_DIR) ; $(CURDIR)/$< @-echo generator_aotcpp_%: $(BIN_DIR)/$(TARGET)/generator_aotcpp_% @-mkdir -p $(TMP_DIR) cd $(TMP_DIR) ; $(CURDIR)/$< @-echo $(TMP_DIR)/images/%.png: $(ROOT_DIR)/tutorial/images/%.png @-mkdir -p $(TMP_DIR)/images cp $< $(TMP_DIR)/images/ tutorial_%: $(BIN_DIR)/tutorial_% $(TMP_DIR)/images/rgb.png $(TMP_DIR)/images/gray.png @-mkdir -p $(TMP_DIR) cd $(TMP_DIR) ; $(CURDIR)/$< @-echo test_mullapudi2016: $(AUTO_SCHEDULE_TESTS:$(ROOT_DIR)/test/auto_schedule/%.cpp=auto_schedule_%) # These tests were written for the Mullapudi2016 autoscheduler. # TODO: either make them work with all autoschedulers or move them under src/autoschedulers/mullapudi2016 auto_schedule_%: $(BIN_DIR)/auto_schedule_% $(BIN_DIR)/libautoschedule_mullapudi2016.$(SHARED_EXT) @-mkdir -p $(TMP_DIR) cd $(TMP_DIR) ; $(CURDIR)/$< $(realpath $(BIN_DIR))/libautoschedule_mullapudi2016.$(SHARED_EXT) @-echo # The other autoschedulers contain their own tests test_adams2019: distrib $(MAKE) -f $(SRC_DIR)/autoschedulers/adams2019/Makefile test \ HALIDE_DISTRIB_PATH=$(CURDIR)/$(DISTRIB_DIR) test_li2018: distrib build_python_bindings $(MAKE) -f $(SRC_DIR)/autoschedulers/li2018/Makefile test \ HALIDE_DISTRIB_PATH=$(CURDIR)/$(DISTRIB_DIR) \ HALIDE_PYTHON_BINDINGS_PATH=$(CURDIR)/$(BIN_DIR)/python3_bindings time_compilation_test_%: $(BIN_DIR)/test_% $(TIME_COMPILATION) compile_times_correctness.csv make -f $(THIS_MAKEFILE) $(@:time_compilation_test_%=test_%) time_compilation_performance_%: $(BIN_DIR)/performance_% $(TIME_COMPILATION) compile_times_performance.csv make -f $(THIS_MAKEFILE) $(@:time_compilation_performance_%=performance_%) time_compilation_generator_%: $(BIN_DIR)/%.generator $(TIME_COMPILATION) compile_times_generator.csv make -f $(THIS_MAKEFILE) $(@:time_compilation_generator_%=$(FILTERS_DIR)/%.a) TEST_APPS=\ HelloMatlab \ bilateral_grid \ bgu \ blur \ c_backend \ camera_pipe \ conv_layer \ fft \ hist \ interpolate \ lens_blur \ linear_algebra \ local_laplacian \ max_filter \ nl_means \ onnx \ resize \ resnet_50 \ stencil_chain \ wavelet TEST_APPS_DEPS=$(TEST_APPS:%=%_test_app) BUILD_APPS_DEPS=$(TEST_APPS:%=%_build_app) $(BUILD_APPS_DEPS): distrib build_python_bindings @echo Building app $(@:%_build_app=%) for ${HL_TARGET}... @$(MAKE) -C $(ROOT_DIR)/apps/$(@:%_build_app=%) build \ HALIDE_DISTRIB_PATH=$(CURDIR)/$(DISTRIB_DIR) \ HALIDE_PYTHON_BINDINGS_PATH=$(CURDIR)/$(BIN_DIR)/python3_bindings \ BIN_DIR=$(CURDIR)/$(BIN_DIR)/apps/$(@:%_build_app=%)/bin \ HL_TARGET=$(HL_TARGET) \ || exit 1 ; \ $(TEST_APPS_DEPS): distrib build_python_bindings @echo Testing app $(@:%_test_app=%) for ${HL_TARGET}... @$(MAKE) -C $(ROOT_DIR)/apps/$(@:%_test_app=%) test \ HALIDE_DISTRIB_PATH=$(CURDIR)/$(DISTRIB_DIR) \ HALIDE_PYTHON_BINDINGS_PATH=$(CURDIR)/$(BIN_DIR)/python3_bindings \ BIN_DIR=$(CURDIR)/$(BIN_DIR)/apps/$(@:%_test_app=%)/bin \ HL_TARGET=$(HL_TARGET) \ || exit 1 ; \ .PHONY: test_apps build_apps $(BUILD_APPS_DEPS) build_apps: $(BUILD_APPS_DEPS) test_apps: $(BUILD_APPS_DEPS) $(MAKE) -f $(THIS_MAKEFILE) -j1 $(TEST_APPS_DEPS) build_hannk: distrib @echo Building apps/hannk for ${HL_TARGET}... @$(MAKE) -C $(ROOT_DIR)/apps/hannk build \ HALIDE_DISTRIB_PATH=$(CURDIR)/$(DISTRIB_DIR) \ HALIDE_PYTHON_BINDINGS_PATH=$(CURDIR)/$(BIN_DIR)/python3_bindings \ BIN_DIR=$(CURDIR)/$(BIN_DIR)/apps/hannk/bin \ HL_TARGET=$(HL_TARGET) \ || exit 1 ; \ test_hannk: build_hannk @echo Testing apps/hannk for ${HL_TARGET}... @$(MAKE) -C $(ROOT_DIR)/apps/hannk test \ HALIDE_DISTRIB_PATH=$(CURDIR)/$(DISTRIB_DIR) \ HALIDE_PYTHON_BINDINGS_PATH=$(CURDIR)/$(BIN_DIR)/python3_bindings \ BIN_DIR=$(CURDIR)/$(BIN_DIR)/apps/hannk/bin \ HL_TARGET=$(HL_TARGET) \ || exit 1 ; \ BENCHMARK_APPS=\ bilateral_grid \ camera_pipe \ lens_blur \ local_laplacian \ nl_means \ stencil_chain $(BENCHMARK_APPS): distrib build_python_bindings @echo Building $@ for ${HL_TARGET}... @$(MAKE) -C $(ROOT_DIR)/apps/$@ \ $(CURDIR)/$(BIN_DIR)/apps/$@/bin/$(HL_TARGET)/$@.rungen \ HALIDE_DISTRIB_PATH=$(CURDIR)/$(DISTRIB_DIR) \ HALIDE_PYTHON_BINDINGS_PATH=$(CURDIR)/$(BIN_DIR)/python3_bindings \ BIN_DIR=$(CURDIR)/$(BIN_DIR)/apps/$@/bin \ HL_TARGET=$(HL_TARGET) \ > /dev/null \ || exit 1 .PHONY: benchmark_apps $(BENCHMARK_APPS) benchmark_apps: $(BENCHMARK_APPS) @for APP in $(BENCHMARK_APPS); do \ echo ;\ echo Benchmarking $${APP} for ${HL_TARGET}... ; \ make -C $(ROOT_DIR)/apps/$${APP} \ $${APP}.benchmark \ HALIDE_DISTRIB_PATH=$(CURDIR)/$(DISTRIB_DIR) \ HALIDE_PYTHON_BINDINGS_PATH=$(CURDIR)/$(BIN_DIR)/python3_bindings \ BIN_DIR=$(CURDIR)/$(BIN_DIR)/apps/$${APP}/bin \ HL_TARGET=$(HL_TARGET) \ || exit 1 ; \ done # TODO(srj): the python bindings need to be put into the distrib folders; # this is a hopefully-temporary workaround (https://github.com/halide/Halide/issues/4368) .PHONY: build_python_bindings build_python_bindings: distrib $(BIN_DIR)/host/runtime.a $(MAKE) -C $(ROOT_DIR)/python_bindings \ -f $(ROOT_DIR)/python_bindings/Makefile \ build_python_bindings \ HALIDE_DISTRIB_PATH=$(CURDIR)/$(DISTRIB_DIR) \ BIN=$(CURDIR)/$(BIN_DIR)/python3_bindings \ PYTHON=$(PYTHON) \ OPTIMIZE=$(OPTIMIZE) .PHONY: test_python test_python: distrib $(BIN_DIR)/host/runtime.a build_python_bindings $(MAKE) -C $(ROOT_DIR)/python_bindings \ -f $(ROOT_DIR)/python_bindings/Makefile \ test \ HALIDE_DISTRIB_PATH=$(CURDIR)/$(DISTRIB_DIR) \ BIN=$(CURDIR)/$(BIN_DIR)/python3_bindings \ PYTHON=$(PYTHON) \ OPTIMIZE=$(OPTIMIZE) # It's just for compiling the runtime, so earlier clangs *might* work, # but best to peg it to the minimum llvm version. ifneq (,$(findstring clang version 3.7,$(CLANG_VERSION))) CLANG_OK=yes endif ifneq (,$(findstring clang version 3.8,$(CLANG_VERSION))) CLANG_OK=yes endif ifneq (,$(findstring clang version 4.0,$(CLANG_VERSION))) CLANG_OK=yes endif ifneq (,$(findstring clang version 5.0,$(CLANG_VERSION))) CLANG_OK=yes endif ifneq (,$(findstring clang version 6.0,$(CLANG_VERSION))) CLANG_OK=yes endif ifneq (,$(findstring clang version 7.0,$(CLANG_VERSION))) CLANG_OK=yes endif ifneq (,$(findstring clang version 7.1,$(CLANG_VERSION))) CLANG_OK=yes endif ifneq (,$(findstring clang version 8.0,$(CLANG_VERSION))) CLANG_OK=yes endif ifneq (,$(findstring clang version 9.0,$(CLANG_VERSION))) CLANG_OK=yes endif ifneq (,$(findstring clang version 10.0,$(CLANG_VERSION))) CLANG_OK=yes endif ifneq (,$(findstring clang version 11.0,$(CLANG_VERSION))) CLANG_OK=yes endif ifneq (,$(findstring clang version 11.1,$(CLANG_VERSION))) CLANG_OK=yes endif ifneq (,$(findstring clang version 12.0,$(CLANG_VERSION))) CLANG_OK=yes endif ifneq (,$(findstring clang version 13.0,$(CLANG_VERSION))) CLANG_OK=yes endif ifneq (,$(findstring clang version 14.0,$(CLANG_VERSION))) CLANG_OK=yes endif ifneq (,$(findstring Apple LLVM version 5.0,$(CLANG_VERSION))) CLANG_OK=yes endif ifneq ($(CLANG_OK), ) $(BUILD_DIR)/clang_ok: @echo "Found a new enough version of clang" mkdir -p $(BUILD_DIR) touch $(BUILD_DIR)/clang_ok else $(BUILD_DIR)/clang_ok: @echo "Can't find clang or version of clang too old (we need 3.7 or greater):" @echo "You can override this check by setting CLANG_OK=y" echo '$(CLANG_VERSION)' echo $(findstring version 3,$(CLANG_VERSION)) echo $(findstring version 3.0,$(CLANG_VERSION)) $(CLANG) --version @exit 1 endif ifneq (,$(findstring $(LLVM_VERSION_TIMES_10), 110 111 120 130 140)) LLVM_OK=yes endif ifneq ($(LLVM_OK), ) $(BUILD_DIR)/llvm_ok: $(BUILD_DIR)/rtti_ok @echo "Found a new enough version of llvm" mkdir -p $(BUILD_DIR) touch $(BUILD_DIR)/llvm_ok else $(BUILD_DIR)/llvm_ok: @echo "Can't find llvm or version of llvm too old (we need 9.0 or greater):" @echo "You can override this check by setting LLVM_OK=y" $(LLVM_CONFIG) --version @exit 1 endif ifneq ($(WITH_RTTI), ) ifneq ($(LLVM_HAS_NO_RTTI), ) else RTTI_OK=yes # Enabled in Halide and LLVM endif else RTTI_OK=yes # Enabled in LLVM but not in Halide endif ifneq ($(RTTI_OK), ) $(BUILD_DIR)/rtti_ok: mkdir -p $(BUILD_DIR) touch $(BUILD_DIR)/rtti_ok else $(BUILD_DIR)/rtti_ok: @echo "Can't enable RTTI - llvm was compiled without it." @echo "LLVM c++ flags: " $(LLVM_CXX_FLAGS) @exit 1 endif install: $(LIB_DIR)/libHalide.a $(BIN_DIR)/libHalide.$(SHARED_EXT) $(INCLUDE_DIR)/Halide.h $(RUNTIME_EXPORTED_INCLUDES) mkdir -p $(PREFIX)/include $(PREFIX)/bin $(PREFIX)/lib $(PREFIX)/share/halide/tutorial/images $(PREFIX)/share/halide/tools $(PREFIX)/share/halide/tutorial/figures cp $(LIB_DIR)/libHalide.a $(BIN_DIR)/libHalide.$(SHARED_EXT) $(PREFIX)/lib cp $(INCLUDE_DIR)/Halide.h $(PREFIX)/include cp $(INCLUDE_DIR)/HalideBuffer.h $(PREFIX)/include cp $(INCLUDE_DIR)/HalideRuntim*.h $(PREFIX)/include cp $(ROOT_DIR)/tutorial/images/*.png $(PREFIX)/share/halide/tutorial/images cp $(ROOT_DIR)/tutorial/figures/*.gif $(PREFIX)/share/halide/tutorial/figures cp $(ROOT_DIR)/tutorial/figures/*.jpg $(PREFIX)/share/halide/tutorial/figures cp $(ROOT_DIR)/tutorial/figures/*.mp4 $(PREFIX)/share/halide/tutorial/figures cp $(ROOT_DIR)/tutorial/*.cpp $(PREFIX)/share/halide/tutorial cp $(ROOT_DIR)/tutorial/*.h $(PREFIX)/share/halide/tutorial cp $(ROOT_DIR)/tutorial/*.sh $(PREFIX)/share/halide/tutorial cp $(ROOT_DIR)/tools/mex_halide.m $(PREFIX)/share/halide/tools cp $(ROOT_DIR)/tools/GenGen.cpp $(PREFIX)/share/halide/tools cp $(ROOT_DIR)/tools/RunGen.h $(PREFIX)/share/halide/tools cp $(ROOT_DIR)/tools/RunGenMain.cpp $(PREFIX)/share/halide/tools cp $(ROOT_DIR)/tools/halide_image.h $(PREFIX)/share/halide/tools cp $(ROOT_DIR)/tools/halide_image_io.h $(PREFIX)/share/halide/tools cp $(ROOT_DIR)/tools/halide_image_info.h $(PREFIX)/share/halide/tools cp $(ROOT_DIR)/tools/halide_malloc_trace.h $(PREFIX)/share/halide/tools ifeq ($(UNAME), Darwin) install_name_tool -id $(PREFIX)/lib/libHalide.$(SHARED_EXT) $(PREFIX)/lib/libHalide.$(SHARED_EXT) endif # This is a specialized 'install' for users who need Hexagon support libraries as well. install_qc: install $(HEXAGON_RUNTIME_LIBS) mkdir -p $(PREFIX)/bin $(PREFIX)/tools $(PREFIX)/support mkdir -p $(PREFIX)/lib/arm-32-android mkdir -p $(PREFIX)/lib/arm-64-android mkdir -p $(PREFIX)/lib/adsp/arm-32-android mkdir -p $(PREFIX)/lib/adsp/arm-64-android mkdir -p $(PREFIX)/lib/cdsp/arm-32-android mkdir -p $(PREFIX)/lib/cdsp/arm-64-android mkdir -p $(PREFIX)/lib/host mkdir -p $(PREFIX)/lib/v65 cp $(HEXAGON_RUNTIME_LIBS_DIR)/arm-32-android/* $(PREFIX)/lib/arm-32-android cp $(HEXAGON_RUNTIME_LIBS_DIR)/arm-64-android/* $(PREFIX)/lib/arm-64-android cp $(HEXAGON_RUNTIME_LIBS_DIR)/cdsp/arm-32-android/* $(PREFIX)/lib/cdsp/arm-32-android cp $(HEXAGON_RUNTIME_LIBS_DIR)/cdsp/arm-64-android/* $(PREFIX)/lib/cdsp/arm-64-android cp $(HEXAGON_RUNTIME_LIBS_DIR)/adsp/arm-32-android/* $(PREFIX)/lib/adsp/arm-32-android cp $(HEXAGON_RUNTIME_LIBS_DIR)/adsp/arm-64-android/* $(PREFIX)/lib/adsp/arm-64-android cp $(HEXAGON_RUNTIME_LIBS_DIR)/host/* $(PREFIX)/lib/host cp -r $(HEXAGON_RUNTIME_LIBS_DIR)/v65/* $(PREFIX)/lib/v65 ln -sf ../share/halide/tools/GenGen.cpp $(PREFIX)/tools/GenGen.cpp ln -sf ../lib/v65/hexagon_sim_remote $(PREFIX)/bin/hexagon_sim_remote ln -sf v65/libsim_qurt.a $(PREFIX)/lib/libsim_qurt.a ln -sf v65/libhalide_hexagon_remote_skel.so $(PREFIX)/lib/libhalide_hexagon_remote_skel.so # We need to capture the system libraries that we'll need to link # against, so that downstream consumers of our build rules don't # have to guess what's necessary on their system; call # llvm-config and capture the result in config files that # we include in our distribution. HALIDE_RTTI_RAW=$(if $(WITH_RTTI),1,0) $(BUILD_DIR)/halide_config.%: $(ROOT_DIR)/tools/halide_config.%.tpl @mkdir -p $(@D) cat $< | sed -e 's/@HALIDE_SYSTEM_LIBS_RAW@/${LLVM_SYSTEM_LIBS}/g' \ | sed -e 's/@HALIDE_RTTI_RAW@/${HALIDE_RTTI_RAW}/g' \ | sed -e 's;@HALIDE_LLVM_CXX_FLAGS_RAW@;${LLVM_CXX_FLAGS};g' > $@ $(DISTRIB_DIR)/lib/libHalide.$(SHARED_EXT): \ $(LIB_DIR)/libHalide.a \ $(BIN_DIR)/libHalide.$(SHARED_EXT) \ $(INCLUDE_DIR)/Halide.h \ $(RUNTIME_EXPORTED_INCLUDES) \ $(ROOT_DIR)/README*.md \ $(BUILD_DIR)/halide_config.cmake \ $(BUILD_DIR)/halide_config.make rm -rf $(DISTRIB_DIR) mkdir -p $(DISTRIB_DIR)/include \ $(DISTRIB_DIR)/bin \ $(DISTRIB_DIR)/lib \ $(DISTRIB_DIR)/tutorial \ $(DISTRIB_DIR)/tutorial/images \ $(DISTRIB_DIR)/tools \ $(DISTRIB_DIR)/tutorial/figures cp $(BIN_DIR)/libHalide.$(SHARED_EXT) $(DISTRIB_DIR)/lib cp $(LIB_DIR)/libHalide.a $(DISTRIB_DIR)/lib cp $(INCLUDE_DIR)/Halide.h $(DISTRIB_DIR)/include cp $(INCLUDE_DIR)/HalideBuffer.h $(DISTRIB_DIR)/include cp $(INCLUDE_DIR)/HalideRuntim*.h $(DISTRIB_DIR)/include cp $(INCLUDE_DIR)/HalidePyTorch*.h $(DISTRIB_DIR)/include cp $(ROOT_DIR)/tutorial/images/*.png $(DISTRIB_DIR)/tutorial/images cp $(ROOT_DIR)/tutorial/figures/*.gif $(DISTRIB_DIR)/tutorial/figures cp $(ROOT_DIR)/tutorial/figures/*.jpg $(DISTRIB_DIR)/tutorial/figures cp $(ROOT_DIR)/tutorial/figures/*.mp4 $(DISTRIB_DIR)/tutorial/figures cp $(ROOT_DIR)/tutorial/*.cpp $(DISTRIB_DIR)/tutorial cp $(ROOT_DIR)/tutorial/*.h $(DISTRIB_DIR)/tutorial cp $(ROOT_DIR)/tutorial/*.sh $(DISTRIB_DIR)/tutorial cp $(ROOT_DIR)/tools/mex_halide.m $(DISTRIB_DIR)/tools cp $(ROOT_DIR)/tools/GenGen.cpp $(DISTRIB_DIR)/tools cp $(ROOT_DIR)/tools/RunGen.h $(DISTRIB_DIR)/tools cp $(ROOT_DIR)/tools/RunGenMain.cpp $(DISTRIB_DIR)/tools cp $(ROOT_DIR)/tools/halide_benchmark.h $(DISTRIB_DIR)/tools cp $(ROOT_DIR)/tools/halide_image.h $(DISTRIB_DIR)/tools cp $(ROOT_DIR)/tools/halide_image_io.h $(DISTRIB_DIR)/tools cp $(ROOT_DIR)/tools/halide_image_info.h $(DISTRIB_DIR)/tools cp $(ROOT_DIR)/tools/halide_malloc_trace.h $(DISTRIB_DIR)/tools cp $(ROOT_DIR)/tools/halide_trace_config.h $(DISTRIB_DIR)/tools cp $(ROOT_DIR)/README*.md $(DISTRIB_DIR) cp $(BUILD_DIR)/halide_config.* $(DISTRIB_DIR) ifeq ($(UNAME), Darwin) install_name_tool -id @rpath/libHalide.$(SHARED_EXT) $(DISTRIB_DIR)/lib/libHalide.$(SHARED_EXT) endif $(DISTRIB_DIR)/lib/libautoschedule_%.$(SHARED_EXT): $(DISTRIB_DIR)/lib/libHalide.$(SHARED_EXT) $(MAKE) -f $(SRC_DIR)/autoschedulers/$*/Makefile bin/libautoschedule_$*.$(SHARED_EXT) HALIDE_DISTRIB_PATH=$(CURDIR)/$(DISTRIB_DIR) cp $(BIN_DIR)/libautoschedule_$*.$(SHARED_EXT) $(DISTRIB_DIR)/lib ifeq ($(UNAME), Darwin) install_name_tool -id @rpath/$(@F) $(CURDIR)/$@ endif # Adams2019 also includes autotuning tools $(DISTRIB_DIR)/lib/libautoschedule_adams2019.$(SHARED_EXT): $(DISTRIB_DIR)/lib/libHalide.$(SHARED_EXT) $(MAKE) -f $(SRC_DIR)/autoschedulers/adams2019/Makefile bin/libautoschedule_adams2019.$(SHARED_EXT) HALIDE_DISTRIB_PATH=$(CURDIR)/$(DISTRIB_DIR) bin/retrain_cost_model bin/featurization_to_sample bin/get_host_target cp $(BIN_DIR)/libautoschedule_adams2019.$(SHARED_EXT) $(DISTRIB_DIR)/lib/ for TOOL in retrain_cost_model featurization_to_sample get_host_target; do \ cp $(BIN_DIR)/$${TOOL} $(DISTRIB_DIR)/bin/; \ done cp $(SRC_DIR)/autoschedulers/adams2019/autotune_loop.sh $(DISTRIB_DIR)/tools/ ifeq ($(UNAME), Darwin) install_name_tool -id @rpath/$(@F) $(CURDIR)/$@ endif .PHONY: autoschedulers autoschedulers: \ $(DISTRIB_DIR)/lib/libautoschedule_mullapudi2016.$(SHARED_EXT) \ $(DISTRIB_DIR)/lib/libautoschedule_li2018.$(SHARED_EXT) \ $(DISTRIB_DIR)/lib/libautoschedule_adams2019.$(SHARED_EXT) .PHONY: distrib distrib: $(DISTRIB_DIR)/lib/libHalide.$(SHARED_EXT) autoschedulers $(DISTRIB_DIR)/halide.tgz: distrib ln -sf $(DISTRIB_DIR) halide tar -czf $(BUILD_DIR)/halide.tgz \ halide/bin \ halide/lib \ halide/include \ halide/tools \ halide/tutorial \ halide/README*.md \ halide/halide_config.* rm -rf halide mv $(BUILD_DIR)/halide.tgz $(DISTRIB_DIR)/halide.tgz $(BIN_DIR)/HalideTraceViz: $(ROOT_DIR)/util/HalideTraceViz.cpp $(INCLUDE_DIR)/HalideRuntime.h $(ROOT_DIR)/tools/halide_image_io.h $(ROOT_DIR)/tools/halide_trace_config.h $(CXX) $(OPTIMIZE) -std=c++17 $(filter %.cpp,$^) -I$(INCLUDE_DIR) -I$(ROOT_DIR)/tools -L$(BIN_DIR) -o $@ $(BIN_DIR)/HalideTraceDump: $(ROOT_DIR)/util/HalideTraceDump.cpp $(ROOT_DIR)/util/HalideTraceUtils.cpp $(INCLUDE_DIR)/HalideRuntime.h $(ROOT_DIR)/tools/halide_image_io.h $(CXX) $(OPTIMIZE) -std=c++17 $(filter %.cpp,$^) -I$(INCLUDE_DIR) -I$(ROOT_DIR)/tools -I$(ROOT_DIR)/src/runtime -L$(BIN_DIR) $(IMAGE_IO_CXX_FLAGS) $(IMAGE_IO_LIBS) -o $@ # Note: you must have CLANG_FORMAT_LLVM_INSTALL_DIR set for this rule to work. # Let's default to the Ubuntu install location. CLANG_FORMAT_LLVM_INSTALL_DIR ?= /usr/lib/llvm-12 .PHONY: format format: @CLANG_FORMAT_LLVM_INSTALL_DIR=$(CLANG_FORMAT_LLVM_INSTALL_DIR) ${ROOT_DIR}/run-clang-format.sh # Note: you must have CLANG_TIDY_LLVM_INSTALL_DIR set for these rules to work. # Let's default to the Ubuntu install location. CLANG_TIDY_LLVM_INSTALL_DIR ?= /usr/lib/llvm-12 .PHONY: clang-tidy clang-tidy: @CLANG_TIDY_LLVM_INSTALL_DIR=$(CLANG_TIDY_LLVM_INSTALL_DIR) ${ROOT_DIR}/run-clang-tidy.sh .PHONY: clang-tidy-fix clang-tidy-fix: @CLANG_TIDY_LLVM_INSTALL_DIR=$(CLANG_TIDY_LLVM_INSTALL_DIR) ${ROOT_DIR}/run-clang-tidy.sh -fix # Build the documentation. Be sure to keep this synchronized with doc/CMakeLists.txt # if you choose to edit it. # Copy ROOT_DIR to keep the following Doxyfile closer to CMake Halide_SOURCE_DIR=${ROOT_DIR} define Doxyfile # Keep the following in sync with doc/CMakeLists.txt ALPHABETICAL_INDEX = NO BUILTIN_STL_SUPPORT = YES CASE_SENSE_NAMES = NO CLASS_DIAGRAMS = NO DISTRIBUTE_GROUP_DOC = YES EXAMPLE_PATH = "${Halide_SOURCE_DIR}/tutorial" EXCLUDE = bin EXTRACT_ALL = YES EXTRACT_LOCAL_CLASSES = NO FILE_PATTERNS = *.h GENERATE_TREEVIEW = YES HIDE_FRIEND_COMPOUNDS = YES HIDE_IN_BODY_DOCS = YES HIDE_UNDOC_CLASSES = YES HIDE_UNDOC_MEMBERS = YES JAVADOC_AUTOBRIEF = YES QT_AUTOBRIEF = YES QUIET = YES RECURSIVE = YES REFERENCED_BY_RELATION = YES REFERENCES_RELATION = YES SORT_BY_SCOPE_NAME = YES SORT_MEMBER_DOCS = NO SOURCE_BROWSER = YES STRIP_CODE_COMMENTS = NO # Makefile-specific options GENERATE_LATEX = NO HAVE_DOT = NO HTML_OUTPUT = . INPUT = "${Halide_SOURCE_DIR}/src" "${Halide_SOURCE_DIR}/test" OUTPUT_DIRECTORY = ${DOC_DIR} PROJECT_NAME = Halide endef # Make the above Doxyfile variable available to the doc target. export Doxyfile .PHONY: doc doc: @-mkdir -p $(TMP_DIR) echo "$$Doxyfile" > $(TMP_DIR)/Doxyfile @-mkdir -p ${DOC_DIR} doxygen $(TMP_DIR)/Doxyfile Halide-13.0.4/README.md000066400000000000000000000407271417234750700142700ustar00rootroot00000000000000# Halide Halide is a programming language designed to make it easier to write high-performance image and array processing code on modern machines. Halide currently targets: - CPU architectures: X86, ARM, MIPS, Hexagon, PowerPC, RISC-V - Operating systems: Linux, Windows, macOS, Android, iOS, Qualcomm QuRT - GPU Compute APIs: CUDA, OpenCL, OpenGL Compute Shaders, Apple Metal, Microsoft Direct X 12 Rather than being a standalone programming language, Halide is embedded in C++. This means you write C++ code that builds an in-memory representation of a Halide pipeline using Halide's C++ API. You can then compile this representation to an object file, or JIT-compile it and run it in the same process. Halide also provides a Python binding that provides full support for writing Halide embedded in Python without C++. Halide requires C++17 (or later) to use. For more detail about what Halide is, see http://halide-lang.org. For API documentation see http://halide-lang.org/docs To see some example code, look in the tutorials directory. If you've acquired a full source distribution and want to build Halide, see the [notes below](#building-halide-with-cmake). # Getting Halide ## Binary tarballs The latest version of Halide is **Halide 13.0.4**. We provide binary releases for many popular platforms and architectures, including 32/64-bit x86 Windows, 64-bit macOS, and 32/64-bit x86/ARM Ubuntu Linux. See the releases tab on the right (or click [here](https://github.com/halide/Halide/releases/tag/v13.0.1)). ## Vcpkg If you use [vcpkg](https://github.com/microsoft/vcpkg) to manage dependencies, you can install Halide via: ``` $ vcpkg install halide:x64-windows # or x64-linux/x64-osx ``` One caveat: vcpkg installs only the minimum Halide backends required to compile code for the active platform. If you want to include all the backends, you should install `halide[target-all]:x64-windows` instead. Note that since this will build LLVM, it will take a _lot_ of disk space (up to 100GB). ## Homebrew Alternatively, if you use macOS, you can install Halide via [Homebrew](https://brew.sh/) like so: ``` $ brew install halide ``` ## Other package managers We are interested in bringing Halide 12 to other popular package managers and Linux distribution repositories including, but not limited to, Conan, Debian, [Ubuntu (or PPA)](https://github.com/halide/Halide/issues/5285), CentOS/Fedora, and Arch. If you have experience publishing packages we would be happy to work with you! If you are a maintainer of any other package distribution platform, we would be excited to work with you, too. # Platform Support There are two sets of platform requirements relevant to Halide: those required to run the compiler library in either JIT or AOT mode, and those required to run the _binary outputs_ of the AOT compiler. These are the **tested** host toolchain and platform combinations for building and running the Halide compiler library. | Compiler | Version | OS | Architectures | | ---------- | ------------ | ---------------------- | --------------- | | GCC | 7.5 | Ubuntu Linux 20.04 LTS | x86, x64, ARM32 | | GCC | 7.5 | Ubuntu Linux 18.04 LTS | ARM32, ARM64 | | MSVC | 2019 (19.28) | Windows 10 (20H2) | x86, x64 | | AppleClang | 12.0.0 | macOS 10.15 | x86_64 | | AppleClang | 12.0.0 | macOS 11.1 | ARM64 | Some users have successfully built Halide for Linux using Clang 9.0.0+, for Windows using ClangCL 11.0.0+, and for Windows ARM64 by cross-compiling with MSVC. We do not actively test these scenarios, however, so your mileage may vary. Beyond these, we are willing to support (by accepting PRs for) platform and toolchain combinations that still receive _active, first-party, public support_ from their original vendors. For instance, at time of writing, this excludes Windows 7 and includes Ubuntu 18.04 LTS. Compiled AOT pipelines are expected to have much broader platform support. The binaries use the C ABI, and we expect any compliant C compiler to be able to use the generated headers correctly. The C++ bindings currently require C++17. If you discover a compatibility problem with a generated pipeline, please open an issue. # Building Halide with Make ### TL;DR Have llvm-11.0 (or greater) installed and run `make` in the root directory of the repository (where this README is). ### Acquiring LLVM At any point in time, building Halide requires either the latest stable version of LLVM, the previous stable version of LLVM, and trunk. At the time of writing, this means versions 12.0 and 11.0 are supported, but 10.0 is not. The commands `llvm-config` and `clang` must be somewhere in the path. If your OS does not have packages for LLVM, you can find binaries for it at http://llvm.org/releases/download.html. Download an appropriate package and then either install it, or at least put the `bin` subdirectory in your path. (This works well on OS X and Ubuntu.) If you want to build it yourself, first check it out from GitHub: ``` % git clone --depth 1 --branch llvmorg-12.0.0 https://github.com/llvm/llvm-project.git ``` (If you want to build LLVM 11.x, use branch `llvmorg-11.1.0`; for current trunk, use `main`) Then build it like so: ``` % cmake -DCMAKE_BUILD_TYPE=Release \ -DLLVM_ENABLE_PROJECTS="clang;lld;clang-tools-extra" \ -DLLVM_TARGETS_TO_BUILD="X86;ARM;NVPTX;AArch64;Mips;Hexagon;WebAssembly" \ -DLLVM_ENABLE_TERMINFO=OFF -DLLVM_ENABLE_ASSERTIONS=ON \ -DLLVM_ENABLE_EH=ON -DLLVM_ENABLE_RTTI=ON -DLLVM_BUILD_32_BITS=OFF \ -S llvm-project/llvm -B llvm-build % cmake --build llvm-build % cmake --install llvm-build --prefix llvm-install ``` Running a serial build will be slow. To improve speed, try running a parallel build. That's done by default in Ninja; for make, use the option -j NNN, where NNN is the number of parallel jobs, e.g. the number of CPUs you have. Then, point Halide to it: ``` % export LLVM_ROOT=$PWD/llvm-install % export LLVM_CONFIG=$LLVM_ROOT/bin/llvm-config ``` Note that you _must_ add `clang` to `LLVM_ENABLE_PROJECTS`; adding `lld` to `LLVM_ENABLE_PROJECTS` is only required when using WebAssembly, and adding `clang-tools-extra` is only necessary if you plan to contribute code to Halide (so that you can run `clang-tidy` on your pull requests). We recommend enabling both in all cases to simplify builds. You can disable exception handling (EH) and RTTI if you don't want the Python bindings. ### Building Halide with make With `LLVM_CONFIG` set (or `llvm-config` in your path), you should be able to just run `make` in the root directory of the Halide source tree. `make run_tests` will run the JIT test suite, and `make test_apps` will make sure all the apps compile and run (but won't check their output). There is no `make install`. If you want to make an install package, use CMake. ### Building Halide out-of-tree with make If you wish to build Halide in a separate directory, you can do that like so: % cd .. % mkdir halide_build % cd halide_build % make -f ../Halide/Makefile # Building Halide with CMake ### MacOS and Linux Follow the above instructions to build LLVM or acquire a suitable binary release. Then change directory to the Halide repository and run: ``` % cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DLLVM_DIR=$LLVM_ROOT/lib/cmake/llvm -S . -B build % cmake --build build ``` `LLVM_DIR` is the folder in the LLVM installation tree **(do not use the build tree by mistake)** that contains `LLVMConfig.cmake`. It is not required to set this variable if you have a suitable system-wide version installed. If you have multiple system-wide versions installed, you can specify the version with `Halide_REQUIRE_LLVM_VERSION`. Remove `-G Ninja` if you prefer to build with a different generator. ### Windows We suggest building with Visual Studio 2019. Your mileage may vary with earlier versions. Be sure to install the "C++ CMake tools for Windows" in the Visual Studio installer. For older versions of Visual Studio, do not install the CMake tools, but instead acquire CMake and Ninja from their respective project websites. These instructions start from the `D:` drive. We assume this git repo is cloned to `D:\Halide`. We also assume that your shell environment is set up correctly. For a 64-bit build, run: ``` D:\> "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 ``` For a 32-bit build, run: ``` D:\> "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64_x86 ``` #### Managing dependencies with vcpkg The best way to get compatible dependencies on Windows is to use [vcpkg](https://github.com/Microsoft/vcpkg). Install it like so: ``` D:\> git clone https://github.com/Microsoft/vcpkg.git D:\> cd vcpkg D:\> .\bootstrap-vcpkg.bat D:\vcpkg> .\vcpkg integrate install ... CMake projects should use: "-DCMAKE_TOOLCHAIN_FILE=D:/vcpkg/scripts/buildsystems/vcpkg.cmake" ``` Then install the libraries. For a 64-bit build, run: ``` D:\vcpkg> .\vcpkg install libpng:x64-windows libjpeg-turbo:x64-windows llvm[target-all,clang-tools-extra]:x64-windows ``` To support 32-bit builds, also run: ``` D:\vcpkg> .\vcpkg install libpng:x86-windows libjpeg-turbo:x86-windows llvm[target-all,clang-tools-extra]:x86-windows ``` #### Building Halide Create a separate build tree and call CMake with vcpkg's toolchain. This will build in either 32-bit or 64-bit depending on the environment script (`vcvars`) that was run earlier. ``` D:\Halide> cmake -G Ninja ^ -DCMAKE_BUILD_TYPE=Release ^ -DCMAKE_TOOLCHAIN_FILE=D:/vcpkg/scripts/buildsystems/vcpkg.cmake ^ -S . -B build ``` **Note:** If building with Python bindings on 32-bit (enabled by default), be sure to point CMake to the installation path of a 32-bit Python 3. You can do this by specifying, for example: `"-DPython3_ROOT_DIR=C:\Program Files (x86)\Python38-32"`. Then run the build with: ``` D:\Halide> cmake --build build --config Release ``` To run all the tests: ``` D:\Halide> cd build D:\Halide\build> ctest -C Release ``` Subsets of the tests can be selected with `-L` and include `correctness`, `python`, `error`, and the other directory names under `/tests`. #### Building LLVM (optional) Follow these steps if you want to build LLVM yourself. First, download LLVM's sources (these instructions use the latest 12.0 release) ``` D:\> git clone --depth 1 --branch llvmorg-12.0.0 https://github.com/llvm/llvm-project.git ``` For a 64-bit build, run: ``` D:\> cmake -G Ninja ^ -DCMAKE_BUILD_TYPE=Release ^ -DLLVM_ENABLE_PROJECTS=clang;lld;clang-tools-extra ^ -DLLVM_ENABLE_TERMINFO=OFF ^ -DLLVM_TARGETS_TO_BUILD=X86;ARM;NVPTX;AArch64;Mips;Hexagon ^ -DLLVM_ENABLE_ASSERTIONS=ON ^ -DLLVM_ENABLE_EH=ON ^ -DLLVM_ENABLE_RTTI=ON ^ -DLLVM_BUILD_32_BITS=OFF ^ -S llvm-project\llvm -B llvm-build ``` For a 32-bit build, run: ``` D:\> cmake -G Ninja ^ -DCMAKE_BUILD_TYPE=Release ^ -DLLVM_ENABLE_PROJECTS=clang;lld;clang-tools-extra ^ -DLLVM_ENABLE_TERMINFO=OFF ^ -DLLVM_TARGETS_TO_BUILD=X86;ARM;NVPTX;AArch64;Mips;Hexagon ^ -DLLVM_ENABLE_ASSERTIONS=ON ^ -DLLVM_ENABLE_EH=ON ^ -DLLVM_ENABLE_RTTI=ON ^ -DLLVM_BUILD_32_BITS=ON ^ -S llvm-project\llvm -B llvm32-build ``` Finally, run: ``` D:\> cmake --build llvm-build --config Release D:\> cmake --install llvm-build --prefix llvm-install ``` You can substitute `Debug` for `Release` in the above `cmake` commands if you want a debug build. Make sure to add `-DLLVM_DIR=D:/llvm-install/lib/cmake/llvm` to the Halide CMake command to override `vcpkg`'s LLVM. **MSBuild:** If you want to build LLVM with MSBuild instead of Ninja, use `-G "Visual Studio 16 2019" -Thost=x64 -A x64` or `-G "Visual Studio 16 2019" -Thost=x64 -A Win32` in place of `-G Ninja`. #### If all else fails... Do what the build-bots do: https://buildbot.halide-lang.org/master/#/builders If the column that best matches your system is red, then maybe things aren't just broken for you. If it's green, then you can click the "stdio" links in the latest build to see what commands the build bots run, and what the output was. # Some useful environment variables `HL_TARGET=...` will set Halide's AOT compilation target. `HL_JIT_TARGET=...` will set Halide's JIT compilation target. `HL_DEBUG_CODEGEN=1` will print out pseudocode for what Halide is compiling. Higher numbers will print more detail. `HL_NUM_THREADS=...` specifies the number of threads to create for the thread pool. When the async scheduling directive is used, more threads than this number may be required and thus allocated. A maximum of 256 threads is allowed. (By default, the number of cores on the host is used.) `HL_TRACE_FILE=...` specifies a binary target file to dump tracing data into (ignored unless at least one `trace_` feature is enabled in `HL_TARGET` or `HL_JIT_TARGET`). The output can be parsed programmatically by starting from the code in `utils/HalideTraceViz.cpp`. # Using Halide on OSX Precompiled Halide distributions are built using XCode's command-line tools with Apple clang 500.2.76. This means that we link against libc++ instead of libstdc++. You may need to adjust compiler options accordingly if you're using an older XCode which does not default to libc++. # Halide for Hexagon HVX Halide supports offloading work to Qualcomm Hexagon DSP on Qualcomm Snapdragon 845/710 devices or newer. The Hexagon DSP provides a set of 128 byte vector instruction extensions - the Hexagon Vector eXtensions (HVX). HVX is well suited for image processing, and Halide for Hexagon HVX will generate the appropriate HVX vector instructions from a program authored in Halide. Halide can be used to compile Hexagon object files directly, by using a target such as `hexagon-32-qurt-hvx`. Halide can also be used to offload parts of a pipeline to Hexagon using the `hexagon` scheduling directive. To enable the `hexagon` scheduling directive, include the `hvx` target feature in your target. The currently supported combination of targets is to use the HVX target features with an x86 linux host (to use the simulator) or with an ARM android target (to use Hexagon DSP hardware). For examples of using the `hexagon` scheduling directive on both the simulator and a Hexagon DSP, see the blur example app. To build and run an example app using the Hexagon target, 1. Obtain and build trunk LLVM and Clang. (Earlier versions of LLVM may work but are not actively tested and thus not recommended.) 2. Download and install the Hexagon SDK and Hexagon Tools. Hexagon SDK 4.3.0 or later is needed. Hexagon Tools 8.4 or later is needed. 3. Build and run an example for Hexagon HVX ### 1. Obtain and build trunk LLVM and Clang (Follow the instructions given previously, just be sure to check out the `main` branch.) ### 2. Download and install the Hexagon SDK and Hexagon Tools Go to https://developer.qualcomm.com/software/hexagon-dsp-sdk/tools 1. Select the Hexagon Series 600 Software and download & run QPM and install the Hexagon SDK 4.3.0 version or later for Linux. 2. untar the installer 3. Run the extracted installer to install the Hexagon SDK and Hexagon Tools, selecting Installation of Hexagon SDK into `/location/of/SDK/Hexagon_SDK/4.x` and the Hexagon tools into `/location/of/SDK/Hexagon_Tools/8.x` 4. Set an environment variable to point to the SDK installation location ``` export SDK_LOC=/location/of/SDK ``` ### 3. Build and run an example for Hexagon HVX In addition to running Hexagon code on device, Halide also supports running Hexagon code on the simulator from the Hexagon tools. To build and run the blur example in Halide/apps/blur on the simulator: ``` cd apps/blur export HL_HEXAGON_SIM_REMOTE=../../src/runtime/hexagon_remote/bin/v65/hexagon_sim_remote export HL_HEXAGON_TOOLS=$SDK_LOC/Hexagon_Tools/8.x/Tools/ LD_LIBRARY_PATH=../../src/runtime/hexagon_remote/bin/host/:$HL_HEXAGON_TOOLS/lib/iss/:. HL_TARGET=host-hvx make test ``` ### To build and run the blur example in Halide/apps/blur on Android: To build the example for Android, first ensure that you have Android NDK r19b or later installed, and the ANDROID_NDK_ROOT environment variable points to it. (Note that Qualcomm Hexagon SDK v4.3.0 includes Android NDK r19c, which is fine.) Now build and run the blur example using the script to run it on device: ``` export HL_HEXAGON_TOOLS=$SDK_LOC/HEXAGON_Tools/8.4.11/Tools/ HL_TARGET=arm-64-android-hvx ./adb_run_on_device.sh ``` Halide-13.0.4/README_cmake.md000066400000000000000000002214441417234750700154250ustar00rootroot00000000000000# Halide and CMake This is a comprehensive guide to the three main usage stories of the Halide CMake build. 1. Compiling or packaging Halide from source. 2. Building Halide programs using the official CMake package. 3. Contributing to Halide and updating the build files. The following sections cover each in detail. ## Table of Contents - [Getting started](#getting-started) - [Installing CMake](#installing-cmake) - [Installing dependencies](#installing-dependencies) - [Building Halide with CMake](#building-halide-with-cmake) - [Basic build](#basic-build) - [Build options](#build-options) - [Find module options](#find-module-options) - [Using Halide from your CMake build](#using-halide-from-your-cmake-build) - [A basic CMake project](#a-basic-cmake-project) - [JIT mode](#jit-mode) - [AOT mode](#aot-mode) - [Autoschedulers](#autoschedulers) - [RunGenMain](#rungenmain) - [Halide package documentation](#halide-package-documentation) - [Components](#components) - [Variables](#variables) - [Imported targets](#imported-targets) - [Functions](#functions) - [`add_halide_library`](#add_halide_library) - [`add_halide_generator`](#add_halide_generator) - [Contributing CMake code to Halide](#contributing-cmake-code-to-halide) - [General guidelines and best practices](#general-guidelines-and-best-practices) - [Prohibited commands list](#prohibited-commands-list) - [Prohibited variables list](#prohibited-variables-list) - [Adding tests](#adding-tests) - [Adding apps](#adding-apps) # Getting started This section covers installing a recent version of CMake and the correct dependencies for building and using Halide. If you have not used CMake before, we strongly suggest reading through the [CMake documentation][cmake-docs] first. ## Installing CMake Halide requires at least version 3.16, which was released in November 2019. Fortunately, getting a recent version of CMake couldn't be easier, and there are multiple good options on any system to do so. Generally, one should always have the most recent version of CMake installed system-wide. CMake is committed to backwards compatibility and even the most recent release can build projects over a decade old. ### Cross-platform The Python package manager `pip3` has the newest version of CMake at all times. This might be the most convenient method since Python 3 is an optional dependency for Halide, anyway. ``` $ pip3 install --upgrade cmake ``` See the [PyPI website][pypi-cmake] for more details. ### Windows On Windows, there are three primary methods for installing an up-to-date CMake: 1. If you have Visual Studio 2019 installed, you can get CMake 3.17 through the Visual Studio installer. This is the recommended way of getting CMake if you are able to use Visual Studio 2019. See Microsoft's [documentation][vs2019-cmake-docs] for more details. 2. If you use [Chocolatey][chocolatey], its [CMake package][choco-cmake] is kept up to date. It should be as simple as `choco install cmake`. 3. Otherwise, you should install CMake from [Kitware's website][cmake-download]. ### macOS On macOS, the [Homebrew][homebrew] [CMake package][brew-cmake] is kept up to date. Simply run: ``` $ brew update $ brew install cmake ``` to install the newest version of CMake. If your environment prevents you from installing Homebrew, the binary release on [Kitware's website][cmake-download] is also a viable option. ### Ubuntu Linux There are a few good ways to install a modern CMake on Ubuntu: 1. If you're on Ubuntu Linux 20.04 (focal), then simply running `sudo apt install cmake` will get you CMake 3.16. 2. If you are on an older Ubuntu release or would like to use the newest CMake, try installing via the snap store: `snap install cmake`. Be sure you do not already have `cmake` installed via APT. The snap package automatically stays up to date. 3. For older versions of Debian, Ubuntu, Mint, and derivatives, Kitware provides an [APT repository][cmake-apt] with up-to-date releases. Note that this is still useful for Ubuntu 20.04 because it will remain up to date. 4. If all else fails, you might need to build CMake from source (eg. on old Ubuntu versions running on ARM). In that case, follow the directions posted on [Kitware's website][cmake-from-source]. For other Linux distributions, check with your distribution's package manager or use pip as detailed above. Snap packages might also be available. **Note:** On WSL 1, the snap service is not available; in this case, prefer to use the APT repository. On WSL 2, all methods are available. ## Installing dependencies We generally recommend using a package manager to fetch Halide's dependencies. Except where noted, we recommend using [vcpkg][vcpkg] on Windows, [Homebrew][homebrew] on macOS, and APT on Ubuntu 20.04 LTS. Only LLVM and Clang are _absolutely_ required to build Halide. Halide always supports three LLVM versions: the current major version, the previous major version, and trunk. The LLVM and Clang versions must match exactly. For most users, we recommend using a binary release of LLVM rather than building it yourself. However, to run all of the tests and apps, an extended set is needed. This includes [lld][lld], [Python 3][python], [libpng][libpng], [libjpeg][libjpeg], [Doxygen][doxygen], [OpenBLAS][openblas], [ATLAS][atlas], and [Eigen3][eigen]. While not required to build any part of Halide, we find that [Ninja][ninja] is the best backend build tool across all platforms. Note that CMake has many special variables for overriding the locations of packages and executables. A partial list can be found in the ["find module options"](#find-module-options) section below, and more can be found in the documentation for the CMake [find_package][find_package] command. Normally, you should prefer to make sure your environment is set up so that CMake can find dependencies automatically. For instance, if you want CMake to use a particular version of Python, create a [virtual environment][venv] and activate it _before_ configuring Halide. ### Windows We assume you have vcpkg installed at `D:\vcpkg`. Follow the instructions in the [vcpkg README][vcpkg] to install. Start by installing LLVM. ``` D:\vcpkg> .\vcpkg install llvm[target-all,enable-assertions,clang-tools-extra]:x64-windows D:\vcpkg> .\vcpkg install llvm[target-all,enable-assertions,clang-tools-extra]:x86-windows ``` This will also install Clang and LLD. The `enable-assertions` option is not strictly necessary but will make debugging during development much smoother. These builds will take a long time and a lot of disk space. After they are built, it is safe to delete the intermediate build files and caches in `D:\vcpkg\buildtrees` and `%APPDATA%\local\vcpkg`. Then install the other libraries: ``` D:\vcpkg> .\vcpkg install libpng:x64-windows libjpeg-turbo:x64-windows openblas:x64-windows eigen3:x64-windows D:\vcpkg> .\vcpkg install libpng:x86-windows libjpeg-turbo:x86-windows openblas:x86-windows eigen3:x86-windows ``` To build the documentation, you will need to install [Doxygen][doxygen]. This can be done either through [Chocolatey][choco-doxygen] or from the [Doxygen website][doxygen-download]. ``` > choco install doxygen ``` To build the Python bindings, you will need to install Python 3. This should be done by running the official installer from the [Python website][python]. Be sure to download the debugging symbols through the installer. This will require using the "Advanced Installation" workflow. Although it is not strictly necessary, it is convenient to install Python system-wide on Windows (ie. `C:\Program Files`). This makes it easy for CMake to find without needing to manually set the `PATH`. Once Python is installed, you can install the Python module dependencies either globally or in a [virtual environment][venv] by running ``` > pip3 install -r .\python_bindings\requirements.txt ``` from the root of the repository. If you would like to use [Ninja][ninja], note that it is installed alongside CMake when using the Visual Studio 2019 installer. Alternatively, you can install via [Chocolatey][choco-ninja] or place the [pre-built binary][ninja-download] from their website in the PATH. ``` > choco install ninja ``` ### macOS On macOS, it is possible to install all dependencies via [Homebrew][homebrew]: ``` $ brew install llvm libpng libjpeg python@3.8 openblas doxygen ninja ``` The `llvm` package includes `clang`, `clang-format`, and `lld`, too. Don't forget to install the Python module dependencies: ``` $ pip3 install -r python_bindings/requirements.txt ``` ### Ubuntu Finally, on Ubuntu 20.04 LTS, you should install the following packages (this includes the Python module dependencies): ``` dev@ubuntu:~$ sudo apt install \ clang-tools lld llvm-dev libclang-dev liblld-10-dev \ libpng-dev libjpeg-dev libgl-dev \ python3-dev python3-numpy python3-scipy python3-imageio python3-pybind11 \ libopenblas-dev libeigen3-dev libatlas-base-dev \ doxygen ninja-build ``` # Building Halide with CMake ## Basic build These instructions assume that your working directory is the Halide repo root. ### Windows If you plan to use the Ninja generator, be sure to be in the developer command prompt corresponding to your intended environment. Note that whatever your intended target system (x86, x64, or arm), you must use the 64-bit _host tools_ because the 32-bit tools run out of memory during the linking step with LLVM. More information is available from [Microsoft's documentation][msvc-cmd]. You should either open the correct Developer Command Prompt directly or run the [`vcvarsall.bat`][vcvarsall] script with the correct argument, ie. one of the following: ``` D:\> "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 D:\> "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64_x86 D:\> "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64_arm ``` Then, assuming that vcpkg is installed to `D:\vcpkg`, simply run: ``` > cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=D:\vcpkg\scripts\buildsystems\vcpkg.cmake -S . -B build > cmake --build .\build ``` Valid values of [`CMAKE_BUILD_TYPE`][cmake_build_type] are `Debug`, `RelWithDebInfo`, `MinSizeRel`, and `Release`. When using a single-configuration generator (like Ninja) you must specify a build type when configuring Halide (or any other CMake project). Otherwise, if you wish to create a Visual Studio based build system, you can configure with: ``` > cmake -G "Visual Studio 16 2019" -Thost=x64 -A x64 ^ -DCMAKE_TOOLCHAIN_FILE=D:\vcpkg\scripts\buildsystems\vcpkg.cmake ^ -S . -B build > cmake --build .\build --config Release -j %NUMBER_OF_PROCESSORS% ``` Because the Visual Studio generator is a _multi-config generator_, you don't set `CMAKE_BUILD_TYPE` at configure-time, but instead pass the configuration to the build (and test/install) commands with the `--config` flag. More documentation is available in the [CMake User Interaction Guide][cmake-user-interaction]. The process is similar for 32-bit: ``` > cmake -G "Visual Studio 16 2019" -Thost=x64 -A Win32 ^ -DCMAKE_TOOLCHAIN_FILE=D:\vcpkg\scripts\buildsystems\vcpkg.cmake ^ -S . -B build > cmake --build .\build --config Release -j %NUMBER_OF_PROCESSORS% ``` In both cases, the `-Thost=x64` flag ensures that the correct host tools are used. **Note:** due to limitations in MSBuild, incremental builds using the VS generators will not detect changes to headers in the `src/runtime` folder. We recommend using Ninja for day-to-day development and use Visual Studio only if you need it for packaging. ### macOS and Linux The instructions here are straightforward. Assuming your environment is set up correctly, just run: ``` dev@host:~/Halide$ cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -S . -B build dev@host:~/Halide$ cmake --build ./build ``` If you omit `-G Ninja`, a Makefile-based generator will likely be used instead. In either case, [`CMAKE_BUILD_TYPE`][cmake_build_type] must be set to one of the standard types: `Debug`, `RelWithDebInfo`, `MinSizeRel`, or `Release`. ### CMake Presets If you are using CMake 3.19+, we provide several [presets][cmake_presets] to make the above commands more convenient. The following CMake preset commands correspond to the longer ones above. ``` > cmake --preset=msvc-release # Ninja generator, MSVC compiler, Release build > cmake --preset=win64 # VS 2019 generator, 64-bit build > cmake --preset=win32 # VS 2019 generator, 32-bit build $ cmake --preset=gcc-release # Ninja generator, GCC compiler, Release build $ cmake --list-presets # Get full list of presets. ``` The Windows and MSVC presets assume that the environment variable `VCPKG_ROOT` is set and points to the root of the vcpkg installation. Note that the GCC presets do not define `NDEBUG` in release configurations, departing from the usual CMake behavior. ## Installing Once built, Halide will need to be installed somewhere before using it in a separate project. On any platform, this means running the [`cmake --install`][cmake-install] command in one of two ways. For a single-configuration generator (like Ninja), run either: ``` dev@host:~/Halide$ cmake --install ./build --prefix /path/to/Halide-install > cmake --install .\build --prefix X:\path\to\Halide-install ``` For a multi-configuration generator (like Visual Studio) run: ``` dev@host:~/Halide$ cmake --install ./build --prefix /path/to/Halide-install --config Release > cmake --install .\build --prefix X:\path\to\Halide-install --config Release ``` Of course, make sure that you build the corresponding config before attempting to install it. ## Build options Halide reads and understands several options that can configure the build. The following are the most consequential and control how Halide is actually compiled. | Option | Default | Description | |------------------------------------------|-----------------------|------------------------------------------------------------------------------------------------------------------| | [`BUILD_SHARED_LIBS`][build_shared_libs] | `ON` | Standard CMake variable that chooses whether to build as a static or shared library. | | `Halide_BUNDLE_LLVM` | `OFF` | When building Halide as a static library, unpack the LLVM static libraries and add those objects to libHalide.a. | | `Halide_SHARED_LLVM` | `OFF` | Link to the shared version of LLVM. Not available on Windows. | | `Halide_ENABLE_RTTI` | _inherited from LLVM_ | Enable RTTI when building Halide. Recommended to be set to `ON` | | `Halide_ENABLE_EXCEPTIONS` | `ON` | Enable exceptions when building Halide | | `Halide_TARGET` | _empty_ | The default target triple to use for `add_halide_library` (and the generator tests, by extension) | The following options are _advanced_ and should not be required in typical workflows. Generally, these are used by Halide's own CI infrastructure, or as escape hatches for third-party packagers. | Option | Default | Description | |-----------------------------|--------------------------------------------------------------------|------------------------------------------------------------------------------------------| | `Halide_CLANG_TIDY_BUILD` | `OFF` | Used internally to generate fake compile jobs for runtime files when running clang-tidy. | | `Halide_CCACHE_BUILD` | `OFF` | Use ccache with Halide-recommended settings to accelerate rebuilds. | | `Halide_CCACHE_PARAMS` | `CCACHE_CPP2=yes CCACHE_HASHDIR=yes CCACHE_SLOPPINESS=pch_defines` | Options to pass to `ccache` when using `Halide_CCACHE_BUILD`. | | `Halide_SOVERSION_OVERRIDE` | `${Halide_VERSION_MAJOR}` | Override the SOVERSION for libHalide. Expects a positive integer (i.e. not a version). | The following options are only available when building Halide directly, ie. not through the [`add_subdirectory`][add_subdirectory] or [`FetchContent`][fetchcontent] mechanisms. They control whether non-essential targets (like tests and documentation) are built. | Option | Default | Description | |------------------------|----------------------|------------------------------------------------------------------| | `WITH_TESTS` | `ON` | Enable building unit and integration tests | | `WITH_PYTHON_BINDINGS` | `ON` if Python found | Enable building Python 3.x bindings | | `WITH_DOCS` | `OFF` | Enable building the documentation via Doxygen | | `WITH_UTILS` | `ON` | Enable building various utilities including the trace visualizer | | `WITH_TUTORIALS` | `ON` | Enable building the tutorials | The following options control whether to build certain test subsets. They only apply when `WITH_TESTS=ON`: | Option | Default | Description | |---------------------------|---------|-----------------------------------| | `WITH_TEST_AUTO_SCHEDULE` | `ON` | enable the auto-scheduling tests | | `WITH_TEST_CORRECTNESS` | `ON` | enable the correctness tests | | `WITH_TEST_ERROR` | `ON` | enable the expected-error tests | | `WITH_TEST_WARNING` | `ON` | enable the expected-warning tests | | `WITH_TEST_PERFORMANCE` | `ON` | enable performance testing | | `WITH_TEST_GENERATOR` | `ON` | enable the AOT generator tests | The following options enable/disable various LLVM backends (they correspond to LLVM component names): | Option | Default | Description | |----------------------|----------------------|-------------------------------------| | `TARGET_AARCH64` | `ON`, _if available_ | Enable the AArch64 backend | | `TARGET_AMDGPU` | `ON`, _if available_ | Enable the AMD GPU backend | | `TARGET_ARM` | `ON`, _if available_ | Enable the ARM backend | | `TARGET_HEXAGON` | `ON`, _if available_ | Enable the Hexagon backend | | `TARGET_MIPS` | `ON`, _if available_ | Enable the MIPS backend | | `TARGET_NVPTX` | `ON`, _if available_ | Enable the NVidia PTX backend | | `TARGET_POWERPC` | `ON`, _if available_ | Enable the PowerPC backend | | `TARGET_RISCV` | `ON`, _if available_ | Enable the RISC V backend | | `TARGET_WEBASSEMBLY` | `ON`, _if available_ | Enable the WebAssembly backend. | | `TARGET_X86` | `ON`, _if available_ | Enable the x86 (and x86_64) backend | The following options enable/disable various Halide-specific backends: | Option | Default | Description | |-----------------------|---------|----------------------------------------| | `TARGET_OPENCL` | `ON` | Enable the OpenCL-C backend | | `TARGET_METAL` | `ON` | Enable the Metal backend | | `TARGET_D3D12COMPUTE` | `ON` | Enable the Direct3D 12 Compute backend | The following options are WebAssembly-specific. They only apply when `TARGET_WEBASSEMBLY=ON`: | Option | Default | Description | |-------------------|---------|------------------------------------------------------------| | `WITH_WABT` | `ON` | Include WABT Interpreter for WASM testing | | `WITH_WASM_SHELL` | `ON` | Download a wasm shell (e.g. d8) for testing AOT wasm code. | ### Find module options Halide uses the following find modules to search for certain dependencies. These modules accept certain variables containing hints for the search process. Before setting any of these variables, closely study the [`find_package`][find_package] documentation. All of these variables should be set at the CMake command line via the `-D` flag. First, Halide expects to find LLVM and Clang through the `CONFIG` mode of `find_package`. You can tell Halide where to find these dependencies by setting the corresponding `_DIR` variables: | Variable | Description | |-------------|------------------------------------------------| | `LLVM_DIR` | `$LLVM_ROOT/lib/cmake/LLVM/LLVMConfig.cmake` | | `Clang_DIR` | `$LLVM_ROOT/lib/cmake/Clang/ClangConfig.cmake` | Here, `$LLVM_ROOT` is assumed to point to the root of an LLVM installation tree. This is either a system path or one produced by running `cmake --install` (as detailed in the main README.md). When building LLVM (and any other `CONFIG` packages) manually, it is a common mistake to point CMake to a _build tree_ rather than an _install tree_. Doing so often produces inscrutable errors. When using CMake 3.18 or above, some of Halide's tests will search for CUDA using the [`FindCUDAToolkit`][findcudatoolkit] module. If it doesn't find your CUDA installation automatically, you can point it to it by setting: | Variable | Description | |--------------------|---------------------------------------------------| | `CUDAToolkit_ROOT` | Path to the directory containing `bin/nvcc[.exe]` | | `CUDA_PATH` | _Environment_ variable, same as above. | If the CMake version is lower than 3.18, the deprecated [`FindCUDA`][findcuda] module will be used instead. It reads the variable `CUDA_TOOLKIT_ROOT_DIR` instead of `CUDAToolkit_ROOT` above. TODO(https://github.com/halide/Halide/issues/5633): update this section for OpenGLCompute, which needs some (but maybe not all) of this. When targeting OpenGL, the [`FindOpenGL`][findopengl] and [`FindX11`][findx11] modules will be used to link AOT generated binaries. These modules can be overridden by setting the following variables: | Variable | Description | |-------------------------|----------------------------------| | `OPENGL_egl_LIBRARY` | Path to the EGL library. | | `OPENGL_glu_LIBRARY` | Path to the GLU library. | | `OPENGL_glx_LIBRARY` | Path to the GLVND GLX library. | | `OPENGL_opengl_LIBRARY` | Path to the GLVND OpenGL library | | `OPENGL_gl_LIBRARY` | Path to the OpenGL library. | The OpenGL paths will need to be set if you intend to use OpenGL with X11 on macOS. Halide also searches for `libpng` and `libjpeg-turbo` through the [`FindPNG`][findpng] and [`FindJPEG`][findjpeg] modules, respectively. They can be overridden by setting the following variables. | Variable | Description | |---------------------|----------------------------------------------------| | `PNG_LIBRARIES` | Paths to the libraries to link against to use PNG. | | `PNG_INCLUDE_DIRS` | Path to `png.h`, etc. | | `JPEG_LIBRARIES` | Paths to the libraries needed to use JPEG. | | `JPEG_INCLUDE_DIRS` | Paths to `jpeglib.h`, etc. | When `WITH_DOCS` is set to `ON`, Halide searches for Doxygen using the [`FindDoxygen`][finddoxygen] module. It can be overridden by setting the following variable. | Variable | Description | |----------------------|---------------------------------| | `DOXYGEN_EXECUTABLE` | Path to the Doxygen executable. | When compiling for an OpenCL target, Halide uses the [`FindOpenCL`][findopencl] target to locate the libraries and include paths. These can be overridden by setting the following variables: | Variable | Description | |-----------------------|-------------------------------------------------------| | `OpenCL_LIBRARIES` | Paths to the libraries to link against to use OpenCL. | | `OpenCL_INCLUDE_DIRS` | Include directories for OpenCL. | Lastly, Halide searches for Python 3 using the [`FindPython3`][findpython3] module, _not_ the deprecated `FindPythonInterp` and `FindPythonLibs` modules, like other projects you might have encountered. You can select which Python installation to use by setting the following variable. | Variable | Description | |--------------------|-------------------------------------------------------| | `Python3_ROOT_DIR` | Define the root directory of a Python 3 installation. | # Using Halide from your CMake build This section assumes some basic familiarity with CMake but tries to be explicit in all its examples. To learn more about CMake, consult the [documentation][cmake-docs] and engage with the community on the [CMake Discourse][cmake-discourse]. Note: previous releases bundled a `halide.cmake` module that was meant to be [`include()`][include]-ed into your project. This has been removed. Please upgrade to the new package config module. ## A basic CMake project There are two main ways to use Halide in your application: as a **JIT compiler** for dynamic pipelines or an **ahead-of-time (AOT) compiler** for static pipelines. CMake provides robust support for both use cases. No matter how you intend to use Halide, you will need some basic CMake boilerplate. ```cmake cmake_minimum_required(VERSION 3.16) project(HalideExample) set(CMAKE_CXX_STANDARD 17) # or newer set(CMAKE_CXX_STANDARD_REQUIRED YES) set(CMAKE_CXX_EXTENSIONS NO) find_package(Halide REQUIRED) ``` The [`cmake_minimum_required`][cmake_minimum_required] command is required to be the first command executed in a CMake program. It disables all of the deprecated behavior ("policies" in CMake lingo) from earlier versions. The [`project`][project] command sets the name of the project (and has arguments for versioning, language support, etc.) and is required by CMake to be called immediately after setting the minimum version. The next three variables set the project-wide C++ standard. The first, [`CMAKE_CXX_STANDARD`][cmake_cxx_standard], simply sets the standard version. Halide requires at least C++17. The second, [`CMAKE_CXX_STANDARD_REQUIRED`][cmake_cxx_standard_required], tells CMake to fail if the compiler cannot provide the requested standard version. Lastly, [`CMAKE_CXX_EXTENSIONS`][cmake_cxx_extensions] tells CMake to disable vendor-specific extensions to C++. This is not necessary to simply use Halide, but we require it when authoring new code in the Halide repo. Finally, we use [`find_package`][find_package] to locate Halide on your system. If Halide is not globally installed, you will need to add the root of the Halide installation directory to [`CMAKE_PREFIX_PATH`][cmake_prefix_path] at the CMake command line. ``` dev@ubuntu:~/myproj$ cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="/path/to/Halide-install" -S . -B build ``` ## JIT mode To use Halide in JIT mode (like the [tutorials][halide-tutorials] do, for example), you can simply link to `Halide::Halide`. ```cmake # ... same project setup as before ... add_executable(my_halide_app main.cpp) target_link_libraries(my_halide_app PRIVATE Halide::Halide) ``` Then `Halide.h` will be available to your code and everything should just work. That's it! ## AOT mode Using Halide in AOT mode is more complicated so we'll walk through it step by step. Note that this only applies to Halide generators, so it might be useful to re-read the [tutorial][halide-generator-tutorial] on generators. Assume (like in the tutorial) that you have a source file named `my_generators.cpp` and that in it you have generator classes `MyFirstGenerator` and `MySecondGenerator` with registered names `my_first_generator` and `my_second_generator` respectively. Then the first step is to add a **generator executable** to your build: ```cmake # ... same project setup as before ... add_executable(my_generators my_generators.cpp) target_link_libraries(my_generators PRIVATE Halide::Generator) ``` Using the generator executable, we can add a Halide library corresponding to `MyFirstGenerator`. ```cmake # ... continuing from above add_halide_library(my_first_generator FROM my_generators) ``` This will create a static library target in CMake that corresponds to the output of running your generator. The second generator in the file requires generator parameters to be passed to it. These are also easy to handle: ```cmake # ... continuing from above add_halide_library(my_second_generator FROM my_generators PARAMS parallel=false scale=3.0 rotation=ccw output.type=uint16) ``` Adding multiple configurations is easy, too: ```cmake # ... continuing from above add_halide_library(my_second_generator_2 FROM my_generators GENERATOR my_second_generator PARAMS scale=9.0 rotation=ccw output.type=float32) add_halide_library(my_second_generator_3 FROM my_generators GENERATOR my_second_generator PARAMS parallel=false output.type=float64) ``` Here, we had to specify which generator to use (`my_second_generator`) since it uses the target name by default. The functions in these libraries will be named after the target names, `my_second_generator_2` and `my_second_generator_3`, by default, but it is possible to control this via the `FUNCTION_NAME` parameter. Each one of these targets, ``, carries an associated `.runtime` target, which is also a static library containing the Halide runtime. It is transitively linked through `` to targets that link to ``. On an operating system like Linux, where weak linking is available, this is not an issue. However, on Windows, this can fail due to symbol redefinitions. In these cases, you must declare that two Halide libraries share a runtime, like so: ```cmake # ... updating above add_halide_library(my_second_generator_2 FROM my_generators GENERATOR my_second_generator USE_RUNTIME my_first_generator.runtime PARAMS scale=9.0 rotation=ccw output.type=float32) add_halide_library(my_second_generator_3 FROM my_generators GENERATOR my_second_generator USE_RUNTIME my_first_generator.runtime PARAMS parallel=false output.type=float64) ``` This will even work correctly when different combinations of targets are specified for each halide library. A "greatest common denominator" target will be chosen that is compatible with all of them (or the build will fail). ### Autoschedulers When the autoschedulers are included in the release package, they are very simple to apply to your own generators. For example, we could update the definition of the `my_first_generator` library above to use the `Adams2019` autoscheduler: ```cmake add_halide_library(my_second_generator FROM my_generators AUTOSCHEDULER Halide::Adams2019 PARAMS auto_schedule=true) ``` ### RunGenMain Halide provides a generic driver for generators to be used during development for benchmarking and debugging. Suppose you have a generator executable called `my_gen` and a generator within called `my_filter`. Then you can pass a variable name to the `REGISTRATION` parameter of `add_halide_library` which will contain the name of a generated C++ source that should be linked to `Halide::RunGenMain` and `my_filter`. For example: ```cmake add_halide_library(my_filter FROM my_gen REGISTRATION filter_reg_cpp) add_executable(runner ${filter_reg_cpp}) target_link_libraries(runner PRIVATE my_filter Halide::RunGenMain) ``` Then you can run, debug, and benchmark your generator through the `runner` executable. ## Halide package documentation Halide provides a CMake _package configuration_ module. The intended way to use the CMake build is to run `find_package(Halide ...)` in your `CMakeLists.txt` file. Closely read the [`find_package` documentation][find_package] before proceeding. ### Components The Halide package script understands a handful of optional components when loading the package. First, if you plan to use the Halide Image IO library, you will want to include the `png` and `jpeg` components when loading Halide. Second, Halide releases can contain a variety of configurations: static, shared, debug, release, etc. CMake handles Debug/Release configurations automatically, but generally only allows one type of library to be loaded. The package understands two components, `static` and `shared`, that specify which type of library you would like to load. For example, if you want to make sure that you link against shared Halide, you can write: ```cmake find_package(Halide REQUIRED COMPONENTS shared) ``` If the shared libraries are not available, this will result in a failure. If no component is specified, then the `Halide_SHARED_LIBS` variable is checked. If it is defined and set to true, then the shared libraries will be loaded or the package loading will fail. Similarly, if it is defined and set to false, the static libraries will be loaded. If no component is specified and `Halide_SHARED_LIBS` is _not_ defined, then the [`BUILD_SHARED_LIBS`][build_shared_libs] variable will be inspected. If it is **not defined** or **defined and set to true**, then it will attempt to load the shared libs and fall back to the static libs if they are not available. Similarly, if `BUILD_SHARED_LIBS` is **defined and set to false**, then it will try the static libs first then fall back to the shared libs. ### Variables Variables that control package loading: | Variable | Description | |----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `Halide_SHARED_LIBS` | override `BUILD_SHARED_LIBS` when loading the Halide package via `find_package`. Has no effect when using Halide via `add_subdirectory` as a Git or `FetchContent` submodule. | Variables set by the package: | Variable | Description | |----------------------------|--------------------------------------------------------------------| | `Halide_VERSION` | The full version string of the loaded Halide package | | `Halide_VERSION_MAJOR` | The major version of the loaded Halide package | | `Halide_VERSION_MINOR` | The minor version of the loaded Halide package | | `Halide_VERSION_PATCH` | The patch version of the loaded Halide package | | `Halide_VERSION_TWEAK` | The tweak version of the loaded Halide package | | `Halide_HOST_TARGET` | The Halide target triple corresponding to "host" for this build. | | `Halide_CMAKE_TARGET` | The Halide target triple corresponding to the active CMake target. | | `Halide_ENABLE_EXCEPTIONS` | Whether Halide was compiled with exception support | | `Halide_ENABLE_RTTI` | Whether Halide was compiled with RTTI | ### Imported targets Halide defines the following targets that are available to users: | Imported target | Description | |----------------------|--------------------------------------------------------------------------------------------------------------------------------------| | `Halide::Halide` | this is the JIT-mode library to use when using Halide from C++. | | `Halide::Generator` | this is the target to use when defining a generator executable. It supplies a `main()` function. | | `Halide::Runtime` | adds include paths to the Halide runtime headers | | `Halide::Tools` | adds include paths to the Halide tools, including the benchmarking utility. | | `Halide::ImageIO` | adds include paths to the Halide image IO utility and sets up dependencies to PNG / JPEG if they are available. | | `Halide::RunGenMain` | used with the `REGISTRATION` parameter of `add_halide_library` to create simple runners and benchmarking tools for Halide libraries. | The following targets are not guaranteed to be available: | Imported target | Description | |-------------------------|------------------------------------------------------------------------------------------------------------------------------------------| | `Halide::Python` | this is a Python 3 module that can be referenced as `$` when setting up Python tests or the like from CMake. | | `Halide::Adams19` | the Adams et.al. 2019 autoscheduler (no GPU support) | | `Halide::Li18` | the Li et.al. 2018 gradient autoscheduler (limited GPU support) | | `Halide::Mullapudi2016` | the Mullapudi et.al. 2016 autoscheduler (no GPU support) | ### Functions Currently, only two functions are defined: #### `add_halide_library` This is the main function for managing generators in AOT compilation. The full signature follows: ``` add_halide_library( FROM [GENERATOR generator-name] [FUNCTION_NAME function-name] [NAMESPACE cpp-namespace] [USE_RUNTIME hl-target] [PARAMS param1 [param2 ...]] [TARGETS target1 [target2 ...]] [FEATURES feature1 [feature2 ...]] [PLUGINS plugin1 [plugin2 ...]] [AUTOSCHEDULER scheduler-name] [GRADIENT_DESCENT] [C_BACKEND] [REGISTRATION OUTVAR] [HEADER OUTVAR] [ OUTVAR]) extra-output = ASSEMBLY | BITCODE | COMPILER_LOG | CPP_STUB | FEATURIZATION | LLVM_ASSEMBLY | PYTHON_EXTENSION | PYTORCH_WRAPPER | SCHEDULE | STMT | STMT_HTML ``` This function creates a called `` corresponding to running the `` (an executable target which links to `Halide::Generator`) one time, using command line arguments derived from the other parameters. The arguments `GENERATOR` and `FUNCTION_NAME` default to ``. They correspond to the `-g` and `-f` command line flags, respectively. `NAMESPACE` is syntactic sugar to specify the C++ namespace (if any) of the generated function; you can also specify the C++ namespace (if any) directly in the `FUNCTION_NAME` argument, but for repeated declarations or very long namespaces, specifying this separately can provide more readable build files. If `USE_RUNTIME` is not specified, this function will create another target called `.runtime` which corresponds to running the generator with `-r` and a compatible list of targets. This runtime target is an INTERFACE dependency of ``. If multiple runtime targets need to be linked together, setting `USE_RUNTIME` to another Halide library, `` will prevent the generation of `.runtime` and instead use `.runtime`. Parameters can be passed to a generator via the `PARAMS` argument. Parameters should be space-separated. Similarly, `TARGETS` is a space-separated list of targets for which to generate code in a single function. They must all share the same platform/bits/os triple (eg. `arm-32-linux`). Features that are in common among all targets, including device libraries (like `cuda`) should go in `FEATURES`. Every element of `TARGETS` must begin with the same `arch-bits-os` triple. This function understands two _meta-triples_, `host` and `cmake`. The meta-triple `host` is equal to the `arch-bits-os` triple used to compile Halide along with all of the supported instruction set extensions. On platforms that support running both 32 and 64-bit programs, this will not necessarily equal the platform the compiler is running on or that CMake is targeting. The meta-triple `cmake` is equal to the `arch-bits-os` of the current CMake target. This is useful if you want to make sure you are not unintentionally cross-compiling, which would result in an [`IMPORTED` target][imported-target] being created. When `TARGETS` is empty and the `host` target would not cross-compile, then `host` will be used. Otherwise, `cmake` will be used and an author warning will be issued. To set the default autoscheduler, set the `AUTOSCHEDULER` argument to a target named like `Namespace::Scheduler`, for example `Halide::Adams19`. This will set the `-s` flag on the generator command line to `Scheduler` and add the target to the list of plugins. Additional plugins can be loaded by setting the `PLUGINS` argument. If the argument to `AUTOSCHEDULER` does not contain `::` or it does not name a target, it will be passed to the `-s` flag verbatim. If `GRADIENT_DESCENT` is set, then the module will be built suitably for gradient descent calculation in TensorFlow or PyTorch. See `Generator::build_gradient_module()` for more documentation. This corresponds to passing `-d 1` at the generator command line. If the `C_BACKEND` option is set, this command will invoke the configured C++ compiler on a generated source. Note that a `.runtime` target is _not_ created in this case, and the `USE_RUNTIME` option is ignored. Other options work as expected. If `REGISTRATION` is set, the path (relative to `CMAKE_CURRENT_BINARY_DIR`) to the generated `.registration.cpp` file will be set in `OUTVAR`. This can be used to generate a runner for a Halide library that is useful for benchmarking and testing, as documented above. This is equivalent to setting `-e registration` at the generator command line. If `HEADER` is set, the path (relative to `CMAKE_CURRENT_BINARY_DIR`) to the generated `.h` header file will be set in `OUTVAR`. This can be used with `install(FILES)` to conveniently deploy the generated header along with your library. Lastly, each of the `extra-output` arguments directly correspond to an extra output (via `-e`) from the generator. The value `OUTVAR` names a variable into which a path (relative to [`CMAKE_CURRENT_BINARY_DIR`][cmake_current_binary_dir]) to the extra file will be written. #### `add_halide_generator` This function aids in creating cross-compilable builds that use Halide generators. ``` add_halide_generator( target [PACKAGE_NAME package-name] [PACKAGE_NAMESPACE namespace] [EXPORT_FILE export-file] [[SOURCES] source1 ...] ) ``` Every named argument is optional, and the function uses the following default arguments: * If `PACKAGE_NAME` is not provided, it defaults to `${PROJECT_NAME}-halide_generators`. * If `PACKAGE_NAMESPACE` is not provided, it defaults to `${PROJECT_NAME}::halide_generators::`. * If `EXPORT_FILE` is not provided, it defaults to `${PROJECT_BINARY_DIR}/cmake/${ARG_PACKAGE_NAME}-config.cmake` The `SOURCES` keyword marks the beginning of sources to be used to build ``, if it is not loaded. All unparsed arguments will be interpreted as sources. This function guarantees that a Halide generator target named `` is available. It will first search for a package named `` using `find_package`; if it is found, it is assumed that it provides the target. Otherwise, it will create an executable target named `target` and an `ALIAS` target ``. This function also creates a custom target named `` if it does not exist and `` would exist. In this case, `` will depend on ``, this enables easy building of _just_ the Halide generators managed by this function. After the call, `_FOUND` will be set to true if the host generators were imported (and hence won't be built). Otherwise, it will be set to false. This variable may be used to conditionally set properties on ``. Please see [test/integration/xc](https://github.com/halide/Halide/tree/master/test/integration/xc) for a simple example and [apps/hannk](https://github.com/halide/Halide/tree/master/apps/hannk) for a complete app that uses it extensively. ## Cross compiling Cross-compiling in CMake can be tricky, since CMake doesn't easily support compiling for both the host platform and the cross-platform within the same build. Unfortunately, Halide generator executables are just about always designed to run on the host platform. Each project will be set up differently and have different requirements, but here are some suggestions for effective use of CMake in these scenarios. ### Use `add_halide_generator` If you are writing new programs that use Halide, you might wish to use our helper, `add_halide_generator`. When using this helper, you are expected to build your project twice: once for your build host and again for your intended target. When building the host build, you can use the `` (see the documentation above) target to build _just_ the generators. Then, in the target build, set `_ROOT` to the host build directory. For example: ``` $ cmake -G Ninja -S . -B build-host -DCMAKE_BUILD_TYPE=Release $ cmake --build build-host --target $ cmake -G Ninja -S . -B build-target -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_TOOLCHAIN_FILE=/path/to/target-tc.cmake \ -D_ROOT:FILEPATH=$PWD/build-host $ cmake --build build-target ``` ### Use a super-build A CMake super-build consists of breaking down a project into sub-projects that are isolated by [toolchain][cmake-toolchains]. The basic structure is to have an outermost project that only coordinates the sub-builds via the [`ExternalProject`][externalproject] module. One would then use Halide to build a generator executable in one self-contained project, then export that target to be used in a separate project. The second project would be configured with the target [toolchain][cmake-toolchains] and would call `add_halide_library` with no `TARGETS` option and set `FROM` equal to the name of the imported generator executable. Obviously, this is a significant increase in complexity over a typical CMake project. This is very compatible with the `add_halide_generator` strategy above. ### Use `ExternalProject` directly A lighter weight alternative to the above is to use [`ExternalProject`][externalproject] directly in your parent build. Configure the parent build with the target [toolchain][cmake-toolchains], and configure the inner project to use the host toolchain. Then, manually create an [`IMPORTED` target][imported-executable] for your generator executable and call `add_halide_library` as described above. The main drawback of this approach is that creating accurate `IMPORTED` targets is difficult since predicting the names and locations of your binaries across all possible platform and CMake project generators is difficult. In particular, it is hard to predict executable extensions in cross-OS builds. ### Use an emulator or run on device The [`CMAKE_CROSSCOMPILING_EMULATOR`][cmake_crosscompiling_emulator] variable allows one to specify a command _prefix_ to run a target-system binary on the host machine. One could set this to a custom shell script that uploads the generator executable, runs it on the device and copies back the results. ### Bypass CMake The previous two options ensure that the targets generated by `add_halide_library` will be _normal_ static libraries. This approach does not use [`ExternalProject`][externalproject], but instead produces `IMPORTED` targets. The main drawback of `IMPORTED` targets is that they are considered second-class in CMake. In particular, they cannot be installed with the typical [`install(TARGETS)` command][install-targets]. Instead, they must be installed using [`install(FILES)`][install-files] and the [`$`][target-file] generator expression. # Contributing CMake code to Halide When contributing new CMake code to Halide, keep in mind that the minimum version is 3.16. Therefore, it is possible (and indeed required) to use modern CMake best practices. Like any large and complex system with a dedication to preserving backwards compatibility, CMake is difficult to learn and full of traps. While not comprehensive, the following serves as a guide for writing quality CMake code and outlines the code quality expectations we have as they apply to CMake. ## General guidelines and best practices The following are some common mistakes that lead to subtly broken builds. - **Reading the build directory.** While setting up the build, the build directory should be considered _write only_. Using the build directory as a read/write temporary directory is acceptable as long as all temp files are cleaned up by the end of configuration. - **Not using [generator expressions][cmake-genex].** Declarative is better than imperative and this is no exception. Conditionally adding to a target property can leak unwanted details about the build environment into packages. Some information is not accurate or available except via generator expressions, eg. the build configuration. - **Using the wrong variable.** `CMAKE_SOURCE_DIR` doesn't always point to the Halide source root. When someone uses Halide via [`FetchContent`][fetchcontent], it will point to _their_ source root instead. The correct variable is [`Halide_SOURCE_DIR`][project-name_source_dir]. If you want to know if the compiler is MSVC, check it directly with the [`MSVC`][msvc] variable; don't use [`WIN32`][win32]. That will be wrong when compiling with clang on Windows. In most cases, however, a generator expression will be more appropriate. - **Using directory properties.** Directory properties have vexing behavior and are essentially deprecated from CMake 3.0+. Propagating target properties is the way of the future. - **Using the wrong visibility.** Target properties can be `PRIVATE`, `INTERFACE`, or both (aka `PUBLIC`). Pick the most conservative one for each scenario. Refer to the [transitive usage requirements][cmake-propagation] docs for more information. - **Needlessly expanding variables** The [`if`][cmake_if] and [`foreach`][cmake_foreach] commands generally expand variables when provided by name. Expanding such variables manually can unintentionally change the behavior of the command. Use `foreach (item IN LISTS list)` instead of `foreach (item ${list})`. Similarly, use `if (varA STREQUAL varB)` instead of `if ("${varA}" STREQUAL "${varB}")` and _definitely_ don't use `if (${varA} STREQUAL ${varB})` since that will fail (in the best case) if either variable's value contains a semi-colon (due to argument expansion). ### Prohibited commands list As mentioned above, using directory properties is brittle and they are therefore _not allowed_. The following functions may not appear in any new CMake code. | Command | Alternative | |-------------------------------------|----------------------------------------------------------------------------------------------------| | `add_compile_definitions` | Use [`target_compile_definitions`][target_compile_definitions] | | `add_compile_options` | Use [`target_compile_options`][target_compile_options] | | `add_definitions` | Use [`target_compile_definitions`][target_compile_definitions] | | `add_link_options` | Use [`target_link_options`][target_link_options], but prefer not to use either | | `get_directory_property` | Use cache variables or target properties | | `get_property(... DIRECTORY)` | Use cache variables or target properties | | `include_directories` | Use [`target_include_directories`][target_include_directories] | | `link_directories` | Use [`target_link_libraries`][target_link_libraries] | | `link_libraries` | Use [`target_link_libraries`][target_link_libraries] | | `remove_definitions` | [Generator expressions][cmake-genex] in [`target_compile_definitions`][target_compile_definitions] | | `set_directory_properties` | Use cache variables or target properties | | `set_property(... DIRECTORY)` | Use cache variables or target properties | | `target_link_libraries(target lib)` | Use [`target_link_libraries`][target_link_libraries] _with a visibility specifier_ (eg. `PRIVATE`) | As an example, it was once common practice to write code similar to this: ```cmake # WRONG: do not do this include_directories(include) add_library(my_lib source1.cpp ..) ``` However, this has two major pitfalls. First, it applies to _all_ targets created in that directory, even those before the call to `include_directories` and those created in [`include()`][include]-ed CMake files. As CMake files get larger and more complex, this behavior gets harder to pinpoint. This is particularly vexing when using the `link_libraries` or `add_defintions` commands. Second, this form does not provide a way to _propagate_ the include directory to consumers of `my_lib`. The correct way to do this is: ```cmake # CORRECT add_library(my_lib source1.cpp ...) target_include_directories(my_lib PUBLIC $) ``` This is better in many ways. It only affects the target in question. It propagates the include path to the targets linking to it (via `PUBLIC`). It also does not incorrectly export the host-filesystem-specific include path when installing or packaging the target (via `$`). If common properties need to be grouped together, use an INTERFACE target (better) or write a function (worse). There are also several functions that are disallowed for other reasons: | Command | Reason | Alternative | |---------------------------------|-----------------------------------------------------------------------------------|----------------------------------------------------------------------------------------| | `aux_source_directory` | Interacts poorly with incremental builds and Git | List source files explicitly | | `build_command` | CTest internal function | Use CTest build-and-test mode via [`CMAKE_CTEST_COMMAND`][cmake_ctest_command] | | `cmake_host_system_information` | Usually misleading information. | Inspect [toolchain][cmake-toolchains] variables and use generator expressions. | | `cmake_policy(... OLD)` | OLD policies are deprecated by definition. | Instead, fix the code to work with the new policy. | | `create_test_sourcelist` | We use our own unit testing solution | See the [adding tests](#adding-tests) section. | | `define_property` | Adds unnecessary complexity | Use a cache variable. Exceptions under special circumstances. | | `enable_language` | Halide is C/C++ only | [`FindCUDAToolkit`][findcudatoolkit] or [`FindCUDA`][findcuda], appropriately guarded. | | `file(GLOB ...)` | Interacts poorly with incremental builds and Git | List source files explicitly. Allowed if not globbing for source files. | | `fltk_wrap_ui` | Halide does not use FLTK | None | | `include_external_msproject` | Halide must remain portable | Write a CMake package config file or find module. | | `include_guard` | Use of recursive inclusion is not allowed | Write (recursive) functions. | | `include_regular_expression` | Changes default dependency checking behavior | None | | `load_cache` | Superseded by [`FetchContent`][fetchcontent]/[`ExternalProject`][externalproject] | Use aforementioned modules | | `macro` | CMake macros are not hygienic and are therefore error-prone | Use functions instead. | | `site_name` | Privacy: do not want leak host name information | Provide a cache variable, generate a unique name. | | `variable_watch` | Debugging helper | None. Not needed in production. | Lastly, do not introduce any dependencies via [`find_package`][find_package] without broader approval. Confine dependencies to the `dependencies/` subtree. ### Prohibited variables list Any variables that are specific to languages that are not enabled should, of course, be avoided. But of greater concern are variables that are easy to misuse or should not be overridden for our end-users. The following (non-exhaustive) list of variables shall not be used in code merged into master. | Variable | Reason | Alternative | |---------------------------------|-----------------------------------------------|---------------------------------------------------------------------------------------------------------| | `CMAKE_ROOT` | Code smell | Rely on `find_package` search options; include `HINTS` if necessary | | `CMAKE_DEBUG_TARGET_PROPERTIES` | Debugging helper | None | | `CMAKE_FIND_DEBUG_MODE` | Debugging helper | None | | `CMAKE_RULE_MESSAGES` | Debugging helper | None | | `CMAKE_VERBOSE_MAKEFILE` | Debugging helper | None | | `CMAKE_BACKWARDS_COMPATIBILITY` | Deprecated | None | | `CMAKE_BUILD_TOOL` | Deprecated | `${CMAKE_COMMAND} --build` or [`CMAKE_MAKE_PROGRAM`][cmake_make_program] (but see below) | | `CMAKE_CACHEFILE_DIR` | Deprecated | [`CMAKE_BINARY_DIR`][cmake_binary_dir], but see below | | `CMAKE_CFG_INTDIR` | Deprecated | `$`, `$`, target resolution of [`add_custom_command`][add_custom_command], etc. | | `CMAKE_CL_64` | Deprecated | [`CMAKE_SIZEOF_VOID_P`][cmake_sizeof_void_p] | | `CMAKE_COMPILER_IS_*` | Deprecated | [`CMAKE__COMPILER_ID`][cmake_lang_compiler_id] | | `CMAKE_HOME_DIRECTORY` | Deprecated | [`CMAKE_SOURCE_DIR`][cmake_source_dir], but see below | | `CMAKE_DIRECTORY_LABELS` | Directory property | None | | `CMAKE_BUILD_TYPE` | Only applies to single-config generators. | `$` | | `CMAKE_*_FLAGS*` (w/o `_INIT`) | User-only | Write a [toolchain][cmake-toolchains] file with the corresponding `_INIT` variable | | `CMAKE_COLOR_MAKEFILE` | User-only | None | | `CMAKE_ERROR_DEPRECATED` | User-only | None | | `CMAKE_CONFIGURATION_TYPES` | We only support the four standard build types | None | Of course feel free to insert debugging helpers _while developing_ but please remove them before review. Finally, the following variables are allowed, but their use must be motivated: | Variable | Reason | Alternative | |------------------------------------------------|-----------------------------------------------------|----------------------------------------------------------------------------------------------| | [`CMAKE_SOURCE_DIR`][cmake_source_dir] | Points to global source root, not Halide's. | [`Halide_SOURCE_DIR`][project-name_source_dir] or [`PROJECT_SOURCE_DIR`][project_source_dir] | | [`CMAKE_BINARY_DIR`][cmake_binary_dir] | Points to global build root, not Halide's | [`Halide_BINARY_DIR`][project-name_binary_dir] or [`PROJECT_BINARY_DIR`][project_binary_dir] | | [`CMAKE_MAKE_PROGRAM`][cmake_make_program] | CMake abstracts over differences in the build tool. | Prefer CTest's build and test mode or CMake's `--build` mode | | [`CMAKE_CROSSCOMPILING`][cmake_crosscompiling] | Often misleading. | Inspect relevant variables directly, eg. [`CMAKE_SYSTEM_NAME`][cmake_system_name] | | [`BUILD_SHARED_LIBS`][build_shared_libs] | Could override user setting | None, but be careful to restore value when overriding for a dependency | Any use of these functions and variables will block a PR. ## Adding tests When adding a file to any of the folders under `test`, be aware that CI expects that every `.c` and `.cpp` appears in the `CMakeLists.txt` file _on its own line_, possibly as a comment. This is to avoid globbing and also to ensure that added files are not missed. For most test types, it should be as simple as adding to the existing lists, which must remain in alphabetical order. Generator tests are trickier, but following the existing examples is a safe way to go. ## Adding apps If you're contributing a new app to Halide: great! Thank you! There are a few guidelines you should follow when writing a new app. - Write the app as if it were a top-level project. You should call `find_package(Halide)` and set the C++ version to 11. - Call [`enable_testing()`][enable_testing] and add a small test that runs the app. - Don't assume your app will have access to a GPU. Write your schedules to be robust to varying buildbot hardware. - Don't assume your app will be run on a specific OS, architecture, or bitness. Write your apps to be robust (ideally efficient) on all supported platforms. - If you rely on any additional packages, don't include them as `REQUIRED`, instead test to see if their targets are available and, if not, call `return()` before creating any targets. In this case, print a `message(STATUS "[SKIP] ...")`, too. - Look at the existing apps for examples. - Test your app with ctest before opening a PR. Apps are built as part of the test, rather than the main build. [add_custom_command]: https://cmake.org/cmake/help/latest/command/add_custom_command.html [add_library]: https://cmake.org/cmake/help/latest/command/add_library.html [add_subdirectory]: https://cmake.org/cmake/help/latest/command/add_subdirectory.html [atlas]: http://math-atlas.sourceforge.net/ [brew-cmake]: https://formulae.brew.sh/cask/cmake#default [build_shared_libs]: https://cmake.org/cmake/help/latest/variable/BUILD_SHARED_LIBS.html [choco-cmake]: https://chocolatey.org/packages/cmake/ [choco-doxygen]: https://chocolatey.org/packages/doxygen.install [choco-ninja]: https://chocolatey.org/packages/ninja [chocolatey]: https://chocolatey.org/ [cmake-apt]: https://apt.kitware.com/ [cmake-discourse]: https://discourse.cmake.org/ [cmake-docs]: https://cmake.org/cmake/help/latest/ [cmake-download]: https://cmake.org/download/ [cmake-from-source]: https://cmake.org/install/ [cmake-genex]: https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html [cmake-install]: https://cmake.org/cmake/help/latest/manual/cmake.1.html#install-a-project [cmake-propagation]: https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#transitive-usage-requirements [cmake-toolchains]: https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html [cmake-user-interaction]: https://cmake.org/cmake/help/latest/guide/user-interaction/index.html#setting-build-variables [cmake_binary_dir]: https://cmake.org/cmake/help/latest/variable/CMAKE_BINARY_DIR.html [cmake_build_type]: https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html [cmake_crosscompiling]: https://cmake.org/cmake/help/latest/variable/CMAKE_CROSSCOMPILING.html [cmake_crosscompiling_emulator]: https://cmake.org/cmake/help/latest/variable/CMAKE_CROSSCOMPILING_EMULATOR.html [cmake_ctest_command]: https://cmake.org/cmake/help/latest/variable/CMAKE_CTEST_COMMAND.html [cmake_current_binary_dir]: https://cmake.org/cmake/help/latest/variable/CMAKE_CURRENT_BINARY_DIR.html [cmake_cxx_extensions]: https://cmake.org/cmake/help/latest/variable/CMAKE_CXX_EXTENSIONS.html [cmake_cxx_standard]: https://cmake.org/cmake/help/latest/variable/CMAKE_CXX_STANDARD.html [cmake_cxx_standard_required]: https://cmake.org/cmake/help/latest/variable/CMAKE_CXX_STANDARD_REQUIRED.html [cmake_foreach]: https://cmake.org/cmake/help/latest/command/foreach.html [cmake_if]: https://cmake.org/cmake/help/latest/command/if.html [cmake_lang_compiler_id]: https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER_ID.html [cmake_make_program]: https://cmake.org/cmake/help/latest/variable/CMAKE_MAKE_PROGRAM.html [cmake_minimum_required]: https://cmake.org/cmake/help/latest/command/cmake_minimum_required.html [cmake_prefix_path]: https://cmake.org/cmake/help/latest/variable/CMAKE_PREFIX_PATH.html [cmake_presets]: https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html [cmake_sizeof_void_p]: https://cmake.org/cmake/help/latest/variable/CMAKE_SIZEOF_VOID_P.html [cmake_source_dir]: https://cmake.org/cmake/help/latest/variable/CMAKE_SOURCE_DIR.html [cmake_system_name]: https://cmake.org/cmake/help/latest/variable/CMAKE_SYSTEM_NAME.html [doxygen-download]: https://www.doxygen.nl/download.html [doxygen]: https://www.doxygen.nl/index.html [eigen]: http://eigen.tuxfamily.org/index.php?title=Main_Page [enable_testing]: https://cmake.org/cmake/help/latest/command/enable_testing.html [externalproject]: https://cmake.org/cmake/help/latest/module/ExternalProject.html [fetchcontent]: https://cmake.org/cmake/help/latest/module/FetchContent.html [find_package]: https://cmake.org/cmake/help/latest/command/find_package.html [findcuda]: https://cmake.org/cmake/help/latest/module/FindCUDA.html [findcudatoolkit]: https://cmake.org/cmake/help/latest/module/FindCUDAToolkit.html [finddoxygen]: https://cmake.org/cmake/help/latest/module/FindDoxygen.html [findjpeg]: https://cmake.org/cmake/help/latest/module/FindJPEG.html [findopencl]: https://cmake.org/cmake/help/latest/module/FindOpenCL.html [findopengl]: https://cmake.org/cmake/help/latest/module/FindOpenGL.html [findpng]: https://cmake.org/cmake/help/latest/module/FindPNG.html [findpython3]: https://cmake.org/cmake/help/latest/module/FindPython3.html [findx11]: https://cmake.org/cmake/help/latest/module/FindX11.html [halide-generator-tutorial]: https://halide-lang.org/tutorials/tutorial_lesson_15_generators.html [halide-tutorials]: https://halide-lang.org/tutorials/tutorial_introduction.html [homebrew]: https://brew.sh [imported-executable]: https://cmake.org/cmake/help/latest/command/add_executable.html#imported-executables [imported-target]: https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#imported-targets [include]: https://cmake.org/cmake/help/latest/command/include.html [install-files]: https://cmake.org/cmake/help/latest/command/install.html#files [install-targets]: https://cmake.org/cmake/help/latest/command/install.html#targets [libjpeg]: https://www.libjpeg-turbo.org/ [libpng]: http://www.libpng.org/pub/png/libpng.html [lld]: https://lld.llvm.org/ [msvc]: https://cmake.org/cmake/help/latest/variable/MSVC.html [msvc-cmd]: https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=vs-2019 [ninja-download]: https://github.com/ninja-build/ninja/releases [ninja]: https://ninja-build.org/ [openblas]: https://www.openblas.net/ [project]: https://cmake.org/cmake/help/latest/command/project.html [project-name_binary_dir]: https://cmake.org/cmake/help/latest/variable/PROJECT-NAME_BINARY_DIR.html [project-name_source_dir]: https://cmake.org/cmake/help/latest/variable/PROJECT-NAME_SOURCE_DIR.html [project_source_dir]: https://cmake.org/cmake/help/latest/variable/PROJECT_SOURCE_DIR.html [project_binary_dir]: https://cmake.org/cmake/help/latest/variable/PROJECT_BINARY_DIR.html [pypi-cmake]: https://pypi.org/project/cmake/ [python]: https://www.python.org/downloads/ [target-file]: https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#target-dependent-queries [target_compile_definitions]: https://cmake.org/cmake/help/latest/command/target_compile_definitions.html [target_compile_options]: https://cmake.org/cmake/help/latest/command/target_compile_options.html [target_include_directories]: https://cmake.org/cmake/help/latest/command/target_include_directories.html [target_link_libraries]: https://cmake.org/cmake/help/latest/command/target_link_libraries.html [target_link_options]: https://cmake.org/cmake/help/latest/command/target_link_options.html [vcpkg]: https://github.com/Microsoft/vcpkg [vcvarsall]: https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=vs-2019#vcvarsall-syntax [venv]: https://docs.python.org/3/tutorial/venv.html [vs2019-cmake-docs]: https://docs.microsoft.com/en-us/cpp/build/cmake-projects-in-visual-studio?view=vs-2019 [win32]: https://cmake.org/cmake/help/latest/variable/WIN32.html Halide-13.0.4/README_rungen.md000066400000000000000000000301021417234750700156300ustar00rootroot00000000000000# Running and Benchmarking Halide Generators ## Overview `RunGen` is a simple(ish) wrapper that allows an arbitrary Generator to be built into a single executable that can be run directly from bash, without needing to wrap it in your own custom main() driver. It also implements a rudimentary benchmarking and memory-usage functionality. If you use the standard CMake rules for Generators, you get RunGen functionality automatically. (If you use Make, you might need to add an extra rule or two to your Makefile; all the examples in `apps/` already have these rules.) For every `halide_library` (or `halide_library_from_generator`) rule, there is an implicit `name.rungen` rule that generates an executable that wraps the Generator library: ``` # In addition to defining a static library named "local_laplacian", this rule # also implicitly defines an executable target named "local_laplacian.rungen" halide_library( local_laplacian SRCS local_laplacian_generator.cc ) ``` You can build and run this like any other executable: ``` $ make bin/local_laplacian.rungen && ./bin/local_laplacian.rungen Usage: local_laplacian.rungen argument=value [argument=value... ] [flags] ...typical "usage" text... ``` To be useful, you need to pass in values for the Generator's inputs (and locations for the output(s)) on the command line, of course. You can use the `--describe` flag to see the names and expected types: ``` # ('make bin/local_laplacian.rungen && ' prefix omitted henceforth for clarity) $ ./bin/local_laplacian.rungen --describe Filter name: "local_laplacian" Input "input" is of type Buffer with 3 dimensions Input "levels" is of type int32 Input "alpha" is of type float32 Input "beta" is of type float32 Output "local_laplacian" is of type Buffer with 3 dimensions ``` Warning: Outputs may have `$X` (where `X` is a small integer) appended to their names in some cases (or, in the case of Generators that don't explicitly declare outputs via `Output<>`, an autogenerated name of the form `fX`). If this happens, don't forget to escape the `$` with a backslash as necessary. These are both bugs we intend to fix; see https://github.com/halide/Halide/issues/2194 As a convenience, there is also an implicit target that builds-and-runs, named simply "NAME.run": ``` # This is equivalent to "make bin/local_laplacian.rungen && ./bin/local_laplacian.rungen" $ make bin/local_laplacian.run Usage: local_laplacian.rungen argument=value [argument=value... ] [flags] # To pass arguments to local_laplacian.rungen, set the RUNARGS var: $ make bin/local_laplacian.run RUNARGS=--describe Filter name: "local_laplacian" Input "input" is of type Buffer with 3 dimensions Input "levels" is of type int32 Input "alpha" is of type float32 Input "beta" is of type float32 Output "local_laplacian" is of type Buffer with 3 dimensions ``` Inputs are specified as `name=value` pairs, in any order. Scalar inputs are specified the typical text form, while buffer inputs (and outputs) are specified via paths to image files. RunGen currently can read/write image files in any format supported by halide_image_io.h; at this time, that means .png, .jpg, .ppm, .pgm, and .tmp formats. (We plan to add .tiff and .mat (level 5) in the future.) ``` $ ./bin/local_laplacian.rungen input=../images/rgb_small16.png levels=8 alpha=1 beta=1 output=/tmp/out.png $ display /tmp/out.png ``` You can also specify any scalar input as `default` or `estimate`, which will use the default value specified for the input, or the value specified by `set_estimate` for that input. (If the relevant value isn't set for that input, a runtime error occurs.) ``` $ ./bin/local_laplacian.rungen input=../images/rgb_small16.png levels=8 alpha=estimate beta=default output=/tmp/out.png $ display /tmp/out.png ``` If you specify an input or output file format that doesn't match the required type/dimensions for an argument (e.g., using an 8-bit PNG for an Input, or a grayscale image for a 3-dimensional input), RunGen will try to coerce the inputs to something sensible; that said, it's hard to always get this right, so warnings are **always** issued whenever an input or output is modified in any way. ``` # This filter expects a 16-bit RGB image as input, but we're giving it an 8-bit grayscale image: $ ./bin/local_laplacian.rungen input=../images/gray.png levels=8 alpha=1 beta=1 output=/tmp/out.png Warning: Image for Input "input" has 2 dimensions, but this argument requires at least 3 dimensions: adding dummy dimensions of extent 1. Warning: Image loaded for argument "input" is type uint8 but this argument expects type uint16; data loss may have occurred. ``` By default, we try to guess a suitable size for the output image(s), based mainly on the size of the input images (if any); you can also specify explicit output extents. (Note that output_extents are subject to constraints already imposed by the particular Generator's logic, so arbitrary values for --output_extents may produce runtime errors.) ``` # Constrain output extents to 100x200x3 $ ./bin/local_laplacian.rungen --output_extents=[100,200,3] input=../images/rgb_small16.png levels=8 alpha=1 beta=1 output=/tmp/out.png ``` Sometimes you don't care what the particular element values for an input are (e.g. for benchmarking), and you just want an image of a particular size; in that case, you can use the `zero:[]` pseudo-file; it infers the _type_ from the Generator, and inits every element to zero: ``` # Input is a 3-dimensional image with extent 123, 456, and 3 # (bluring an image of all zeroes isn't very interesting, of course) $ ./bin/local_laplacian.rungen --output_extents=[100,200,3] input=zero:[123,456,3] levels=8 alpha=1 beta=1 output=/tmp/out.png ``` You can also specify arbitrary (nonzero) constants: ``` # Input is a 3-dimensional image with extent 123, 456, and 3, # filled with a constant value of 42 $ ./bin/local_laplacian.rungen --output_extents=[100,200,3] input=constant:42:[123,456,3] levels=8 alpha=1 beta=1 output=/tmp/out.png ``` Similarly, you can create identity images where only the diagonal elements are 1-s (rest are 0-s) by invoking `identity:[]`. Diagonal elements are defined as those whose first two coordinates are equal. There's also a `random:SEED:[]` pseudo-file, which fills the image with uniform noise based on a specific random-number seed: ``` # Input is a 3-dimensional image with extent 123, 456, and 3 $ ./bin/local_laplacian.rungen --output_extents=[100,200,3] input=random:42:[123,456,3] levels=8 alpha=1 beta=1 output=/tmp/out.png ``` Instead of specifying an explicit set of extents for a pseudo-input, you can use the string `auto`, which will run a bounds query to choose a legal set of extents for that input given the known output extents. (This is only useful when used in conjunction with the `--output_extents` flag.) ``` $ ./bin/local_laplacian.rungen --output_extents=[100,200,3] input=zero:auto levels=8 alpha=1 beta=1 output=/tmp/out.png ``` You can also specify `estimate` for the extents, which will use the estimate values provided, typically (but not necessarily) for auto_schedule. (If there aren't estimates for all of the buffer's dimensions, a runtime error occurs.) ``` $ ./bin/local_laplacian.rungen --output_extents=[100,200,3] input=zero:auto levels=8 alpha=1 beta=1 output=/tmp/out.png ``` You can combine the two and specify `estimate_then_auto` for the extents, which will attempt to use the estimate values; if a given input buffer has no estimates, it will fall back to the bounds-query result for that input: ``` $ ./bin/local_laplacian.rungen --output_extents=[100,200,3] input=zero:estimate_then_auto levels=8 alpha=1 beta=1 output=/tmp/out.png ``` Similarly, you can use `estimate` for `--output_extents`, which will use the estimate values for each output. (If there aren't estimates for all of the outputs, a runtime error occurs.) ``` $ ./bin/local_laplacian.rungen --output_extents=estimate input=zero:auto levels=8 alpha=1 beta=1 output=/tmp/out.png ``` If you don't want to explicitly specify all (or any!) of the input values, you can use the `--default_input_buffers` and `--default_input_scalars` flags, which provide wildcards for any omitted inputs: ``` $ ./bin/local_laplacian.rungen --output_extents=[100,200,3] --default_input_buffers=random:0:auto --default_input_scalars=estimate output=/tmp/out.png ``` In this case, all input buffers will be sized according to bounds query, and filled with a random seed; all input scalars will be initialized to their declared default values. (If they have no declared default value, a zero of the appropriate type will be used.) Note: `--default_input_buffers` can produce surprising sizes! For instance, any input that uses `BoundaryConditions::repeat_edge` to wrap itself can legally be set to almost any size, so you may legitimately get an input with extent=1 in all dimensions; whether this is useful to you or not depends on the code. It's highly recommended you do testing with the `--verbose` flag (which will log the calculated sizes) to reality-check that you are getting what you expect, especially for benchmarking. A common case (especially for benchmarking) is to specify using estimates for all inputs and outputs; for this, you can specify `--estimate_all`, which is just a shortcut for `--default_input_buffers=estimate_then_auto --default_input_scalars=estimate --output_extents=estimate`. ## Benchmarking To run a benchmark, use the `--benchmarks=all` flag: ``` $ ./bin/local_laplacian.rungen --benchmarks=all input=zero:[1920,1080,3] levels=8 alpha=1 beta=1 --output_extents=[100,200,3] Benchmark for local_laplacian produces best case of 0.0494629 sec/iter, over 3 blocks of 10 iterations. Best output throughput is 39.9802 mpix/sec. ``` You can use `--default_input_buffers` and `--default_input_scalars` here as well: ``` $ ./bin/local_laplacian.rungen --benchmarks=all --default_input_buffers --default_input_scalars --output_extents=estimate Benchmark for local_laplacian produces best case of 0.0494629 sec/iter, over 3 blocks of 10 iterations. Best output throughput is 39.9802 mpix/sec. ``` Note: `halide_benchmark.h` is known to be inaccurate for GPU filters; see https://github.com/halide/Halide/issues/2278 ## Measuring Memory Usage To track memory usage, use the `--track_memory` flag, which measures the high-water-mark of CPU memory usage. ``` $ ./bin/local_laplacian.rungen --track_memory input=zero:[1920,1080,3] levels=8 alpha=1 beta=1 --output_extents=[100,200,3] Maximum Halide memory: 82688420 bytes for output of 1.97754 mpix. ``` Warning: `--track_memory` may degrade performance; don't combine it with `--benchmark` or expect meaningful timing measurements when using it. ## Using RunGen in Make To add support for RunGen to your Makefile, you need to add rules something like this (see `apps/support/Makefile.inc` for an example): ``` HALIDE_DISTRIB ?= /path/to/halide/distrib/folder $(BIN)/RunGenMain.o: $(HALIDE_DISTRIB)/tools/RunGenMain.cpp @mkdir -p $(@D) @$(CXX) -c $< $(CXXFLAGS) $(LIBPNG_CXX_FLAGS) $(LIBJPEG_CXX_FLAGS) -I$(BIN) -o $@ .PRECIOUS: $(BIN)/%.rungen $(BIN)/%.rungen: $(BIN)/%.a $(BIN)/%.registration.cpp $(BIN)/RunGenMain.o $(CXX) $(CXXFLAGS) $^ -o $@ $(LIBPNG_LIBS) $(LIBJPEG_LIBS) $(LDFLAGS) RUNARGS ?= $(BIN)/%.run: $(BIN)/%.rungen @$(CURDIR)/$< $(RUNARGS) ``` Note that the `%.registration.cpp` file is created by running a generator and specifying `registration` in the comma-separated list of files to emit; these are also generated by default if `-e` is not used on the generator command line. ## Known Issues & Caveats - If your Generator uses `define_extern()`, you must have all link-time dependencies declared properly via `FILTER_DEPS`; otherwise, you'll fail to link. - The code does its best to detect when inputs or outputs need to be chunky/interleaved (rather than planar), but in unusual cases it might guess wrong; if your Generator uses buffers with unusual stride setups, RunGen might fail at runtime. (If this happens, please file a bug!) - The code for deducing good output sizes is rudimentary and needs to be smartened; it will sometimes make bad decisions which will prevent the filter from executing. (If this happens, please file a bug!) Halide-13.0.4/README_webassembly.md000066400000000000000000000212051417234750700166530ustar00rootroot00000000000000# WebAssembly Support for Halide Halide supports WebAssembly (Wasm) code generation from Halide using the LLVM backend. As WebAssembly itself is still under active development, Halide's support has some limitations. Some of the most important: - We require using LLVM 11 or later for Wasm codegen; earlier versions of LLVM will not work. - Fixed-width SIMD (128 bit) can be enabled via Target::WasmSimd128. - Sign-extension operations can be enabled via Target::WasmSignExt. - Non-trapping float-to-int conversions can be enabled via Target::WasmSatFloatToInt. - Threads have very limited support via Target::WasmThreads; see [below](#using-threads) for more details. - Halide's JIT for Wasm is extremely limited and really useful only for internal testing purposes. # Additional Tooling Requirements: - In additional to the usual install of LLVM and clang, you'll need lld. All should be at least v11 or later (codegen will be improved under LLVM v12/trunk, at least as of July 2020). - Locally-installed version of Emscripten, 1.39.19+ Note that for all of the above, earlier versions might work, but have not been tested. # AOT Limitations Halide outputs a Wasm object (.o) or static library (.a) file, much like any other architecture; to use it, of course, you must link it to suitable calling code. Additionally, you must link to something that provides an implementation of `libc`; as a practical matter, this means using the Emscripten tool to do your linking, as it provides the most complete such implementation we're aware of at this time. - Halide ahead-of-time tests assume/require that you have Emscripten installed and available on your system, with the `EMSDK` environment variable set properly. # JIT Limitations It's important to reiterate that the WebAssembly JIT mode is not (and will never be) appropriate for anything other than limited self tests, for a number of reasons: - It actually uses an interpreter (from the WABT toolkit [https://github.com/WebAssembly/wabt]) to execute wasm bytecode; not surprisingly, this can be *very* slow. - Wasm effectively runs in a private, 32-bit memory address space; while the host has access to that entire space, the reverse is not true, and thus any `define_extern` calls require copying all `halide_buffer_t` data across the Wasm<->host boundary in both directions. This has severe implications for existing benchmarks, which don't currently attempt to account for this extra overhead. (This could possibly be improved by modeling the Wasm JIT's buffer support as a `device` model that would allow lazy copy-on-demand.) - Host functions used via `define_extern` or `HalideExtern` cannot accept or return values that are pointer types or 64-bit integer types; this includes things like `const char *` and `user_context`. Fixing this is tractable, but is currently omitted as the fix is nontrivial and the tests that are affected are mostly non-critical. (Note that `halide_buffer_t*` is explicitly supported as a special case, however.) - Threading isn't supported at all (yet); all `parallel()` schedules will be run serially. - The `.async()` directive isn't supported at all, not even in serial-emulation mode. - You can't use `Param` (or any other arbitrary pointer type) with the Wasm jit. - You can't use `Func.debug_to_file()`, `Func.set_custom_do_par_for()`, `Func.set_custom_do_task()`, or `Func.set_custom_allocator()`. - The implementation of `malloc()` used by the JIT is incredibly simpleminded and unsuitable for anything other than the most basic of tests. - GPU usage (or any buffer usage that isn't 100% host-memory) isn't supported at all yet. (This should be doable, just omitted for now.) Note that while some of these limitations may be improved in the future, some are effectively intrinsic to the nature of this problem. Realistically, this JIT implementation is intended solely for running Halide self-tests (and even then, a number of them are fundamentally impractical to support in a hosted-Wasm environment and are disabled). In sum: don't plan on using Halide JIT mode with Wasm unless you are working on the Halide library itself. # To Use Halide For WebAssembly: - Ensure WebAssembly is in LLVM_TARGETS_TO_BUILD; if you use the default (`"all"`) then it's already present, but otherwise, add it explicitly: ``` -DLLVM_TARGETS_TO_BUILD="X86;ARM;NVPTX;AArch64;Mips;PowerPC;Hexagon;WebAssembly ``` ## Enabling wasm JIT If you want to run `test_correctness` and other interesting parts of the Halide test suite (and you almost certainly will), you'll need to ensure that LLVM is built with wasm-ld: - Ensure that you have lld in LVM_ENABLE_PROJECTS: ``` cmake -DLLVM_ENABLE_PROJECTS="clang;lld" ... ``` - To run the JIT tests, set `HL_JIT_TARGET=wasm-32-wasmrt` (possibly adding `wasm_simd128`, `wasm_signext`, and/or `wasm_sat_float_to_int`) and run CMake/CTest normally. Note that wasm testing is only support under CMake (not via Make). ## Enabling wasm AOT If you want to test ahead-of-time code generation (and you almost certainly will), you need to install Emscripten locally. - The simplest way to install is probably via the Emscripten emsdk (https://emscripten.org/docs/getting_started/downloads.html). - To run the AOT tests, set `HL_TARGET=wasm-32-wasmrt` (possibly adding `wasm_simd128`, `wasm_signext`, and/or `wasm_sat_float_to_int`) and run CMake/CTest normally. Note that wasm testing is only support under CMake (not via Make). # Running benchmarks The `test_performance` benchmarks are misleading (and thus useless) for Wasm, as they include JIT overhead as described elsewhere. Suitable benchmarks for Wasm will be provided at a later date. (See https://github.com/halide/Halide/issues/5119 and https://github.com/halide/Halide/issues/5047 to track progress.) # Using Threads You can use the `wasm_threads` feature to enable use of a normal pthread-based thread pool in Halide code, but with some careful caveats: - This requires that you use a wasm runtime environment that provides pthread-compatible wrappers. At this time of this writing, the only environment known to support this well is Emscripten (when using the `-pthread` flag, and compiling for a Web environment). In this configuration, Emscripten goes to great lengths to make WebWorkers available via the pthreads API. (You can see an example of this usage in apps/HelloWasm.) Note that not all wasm runtimes support WebWorkers; generally, you need a full browser environment to make this work (though some versions of some shell tools may also support this, e.g. nodejs). - There is currently no support for using threads in a WASI environment, due to current limitations in the WASI specification. (We hope that this will improve in the future.) - There is no support for using threads in the Halide JIT environment, and no plans to add them anytime in the near-term future. # Known Limitations And Caveats - Current trunk LLVM (as of July 2020) doesn't reliably generate all of the Wasm SIMD ops that are available; see https://github.com/halide/Halide/issues/5130 for tracking information as these are fixed. - Using the JIT requires that we link the `wasm-ld` tool into libHalide; with some work this need could possibly be eliminated. - OSX and Linux-x64 have been tested. Windows hasn't; it should be supportable with some work. (Patches welcome.) - None of the `apps/` folder has been investigated yet. Many of them should be supportable with some work. (Patches welcome.) - We currently use v8/d8 as a test environment for AOT code; we may want to consider using Node or (better yet) headless Chrome instead (which is probably required to allow for using threads in AOT code). # Known TODO: - There's some invasive hackiness in Codgen_LLVM to support the JIT trampolines; this really should be refactored to be less hacky. - Can we rework JIT to avoid the need to link in wasm-ld? This might be doable, as the wasm object files produced by the LLVM backend are close enough to an executable form that we could likely make it work with some massaging on our side, but it's not clear whether this would be a bad idea or not (i.e., would it be unreasonably fragile). - Buffer-copying overhead in the JIT could possibly be dramatically improved by modeling the copy as a "device" (i.e. `copy_to_device()` would copy from host -> wasm); this would make the performance benchmarks much more useful. - Can we support threads in the JIT without an unreasonable amount of work? Unknown at this point. Halide-13.0.4/apps/000077500000000000000000000000001417234750700137425ustar00rootroot00000000000000Halide-13.0.4/apps/CMakeLists.txt000066400000000000000000000036741417234750700165140ustar00rootroot00000000000000## # Test apps from the perspective of a consuming project. ## cmake_minimum_required(VERSION 3.16) project(Halide_apps) if (WIN32) option(ENABLE_APPS_HANNK "Build apps/hannk" OFF) else () option(ENABLE_APPS_HANNK "Build apps/hannk" ON) endif () enable_testing() # add_subdirectory(HelloAndroid) # TODO(#5374): missing CMake build # add_subdirectory(HelloAndroidCamera2) # TODO(#5374): missing CMake build # add_subdirectory(HelloMatlab) # TODO(#5374): missing CMake build # add_subdirectory(HelloPyTorch) # TODO(#5374): missing CMake build # add_subdirectory(HelloWasm) # TODO(#5374): missing CMake build # add_subdirectory(HelloiOS) # TODO(#5374): missing CMake build # add_subdirectory(auto_viz) # TODO(#5374): missing CMake build add_subdirectory(bgu) add_subdirectory(bilateral_grid) add_subdirectory(blur) add_subdirectory(c_backend) add_subdirectory(camera_pipe) add_subdirectory(conv_layer) add_subdirectory(cuda_mat_mul) add_subdirectory(depthwise_separable_conv) add_subdirectory(fft) if (ENABLE_APPS_HANNK) add_subdirectory(hannk) endif () add_subdirectory(harris) # add_subdirectory(hexagon_benchmarks) # TODO(#5374): missing CMake build # add_subdirectory(hexagon_dma) # TODO(#5374): missing CMake build add_subdirectory(hist) add_subdirectory(iir_blur) add_subdirectory(interpolate) add_subdirectory(lens_blur) add_subdirectory(linear_algebra) # add_subdirectory(linear_blur) # TODO(#5374): missing CMake build add_subdirectory(local_laplacian) add_subdirectory(max_filter) add_subdirectory(nl_means) # add_subdirectory(nn_ops) # TODO(#5374): missing CMake build # add_subdirectory(onnx) # TODO(#5374): missing CMake build # add_subdirectory(openglcompute) # TODO(#5374): missing CMake build add_subdirectory(resize) # add_subdirectory(resnet_50) # TODO(#5374): missing CMake build # add_subdirectory(simd_op_check) # TODO(#5374): missing CMake build add_subdirectory(stencil_chain) add_subdirectory(unsharp) add_subdirectory(wavelet) Halide-13.0.4/apps/HelloAndroid/000077500000000000000000000000001417234750700163065ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroid/.gitignore000066400000000000000000000001631417234750700202760ustar00rootroot00000000000000.gradle/** gen/** gradle_build/** HelloAndroid.iml local.properties obj/** proguard-project.txt project.properties Halide-13.0.4/apps/HelloAndroid/AndroidManifest.xml000066400000000000000000000015371417234750700221050ustar00rootroot00000000000000 Halide-13.0.4/apps/HelloAndroid/README.md000066400000000000000000000057311417234750700175730ustar00rootroot00000000000000HelloHalide is a simple application which applies a tone curve and sharpening to a video preview from the camera on a phone or tablet. This application builds for multiple native ABIs. (At present armeabi, armeabi-v7a, arm64-v8a, mips, x86_64, and x86 are supported. mips64 is not presently working.) Halide code is generated for each architecture. This build is meant to use Android command line tools. (An IDE is not required.) In order to build, the following will be required: - Android NDK -- This can be downloaded here: https://developer.android.com/tools/sdk/ndk/index.html After installing, make sure the top-level directory of the install is in the PATH. (It should contain an executable ndk-build file.) - Android SDK -- This can be downloaded here: http://developer.android.com/sdk/index.html The standalone SDK is desired. Once downloaded, the "android" program in the tools directory of the install will need to be run. It should bring up a UI allowing one to choose components to install. HelloAndroid currently depends on the android-17 release. (It can easily be made to run on others, but that is what the scripts are setup to build against.) Make sure the tools directory is on one's PATH. - Apache Ant -- which can be downloaded here: http://ant.apache.org/bindownload.cgi make sure the bin directory is on one's PATH. If everything is setup correctly, running the build.sh script in this directory, with the current directory set to here, whould build the HelloAndroid apk and install it on a connected Android device. # Gradle To use Gradle create local.properties file in this folder with sdk.dir and ndk.dir variables defined like so: ``` sdk.dir=/Users/joe/Downloads/android-sdk ndk.dir=/Users/joe/Downloads/android-ndk ``` After that run `gradlew build` which will produce .apk file ready for deployment to the Android device. On Linux/Mac you can use `build-gradle.sh` to build, deploy and run this sample application. Pay attention to the list of platforms supported by your Halide installation. They are listed in jni/Application.mk APP_ABI variable and in build.gradle archs map. For example, if your Halide installation was built without mips support or without arm64-v8a, remove them from APP_ABI and archs. Both list and map should match, otherwise you will be getting compilation errors complaining about a missing hello.h file: ``` :compileDebugNdkClassic FAILED FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':compileDebugNdkClassic'. ... Output: /private/tmp/7/halide/apps/HelloAndroid/jni/native.cpp:9:30: fatal error: hello.h: No such file or directory #include "hello.h" ``` # Android Studio To load project into Android Studio use "File/Import Project..." in Android Studio and point to apps/HelloAndroid/build.gradle file. You will have to edit automatically-generated local.properties file to add ndk.dir property so it points to your Android NDK installation as described in Gradle section above. Halide-13.0.4/apps/HelloAndroid/ant.properties000066400000000000000000000012721417234750700212100ustar00rootroot00000000000000# This file is used to override default values used by the Ant build system. # # This file must be checked into Version Control Systems, as it is # integral to the build system of your project. # This file is only used by the Ant script. # You can use this to override default values such as # 'source.dir' for the location of your java source folder and # 'out.dir' for the location of your output folder. # You can also use it define how the release builds are signed by declaring # the following properties: # 'key.store' for the location of your keystore and # 'key.alias' for the name of the key to use. # The password will be asked during the build when you use the 'release' target. Halide-13.0.4/apps/HelloAndroid/build-gradle.sh000077500000000000000000000007611417234750700212040ustar00rootroot00000000000000#!/bin/bash # Gradle needs to know where the NDK is. # The easiest way is to set the ANDROID_NDK_HOME environment variable. # Otherwise, set ndk.dir in local.properties (even though the file itself says # that it's only used by ant). # However, if you run "android update" (say, via build.sh), this variable will # be clobbered. ./gradlew build && adb install -r gradle_build/outputs/apk/HelloAndroid-debug.apk && adb shell am start com.example.hellohalide/com.example.hellohalide.CameraActivity Halide-13.0.4/apps/HelloAndroid/build.gradle000066400000000000000000000126571417234750700206000ustar00rootroot00000000000000import org.apache.tools.ant.taskdefs.condition.Os // Avoid conflicts with Bazel on case-insensitive filesystems buildDir = 'gradle_build' repositories { jcenter() } buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.2.2' } } //////////////////////////////////////////////////////////////////////////////// // Use gradle's native C++ plugin to build the Halide generator. // // sources: defines all the C++ source files. We only have one SourceSet called // hello_generator. // // executables: we only make one binary called hello_generator. Here is where // we pass compiler and linker flags. // // binaries.withType: binaries is a collection, which in our case is just the // hello_generator executable. withType() filters the collection by type. // binary is the iteration variable. -> defines the body of the lambda: // for each binary: // for each halide_target / Android ABI mapping: // for each generator: // run the generator with -g and target set // make the later ndkBuild task depend on this task. apply plugin: "cpp" sources { hello_generator { cpp(CppSourceSet) { source { srcDirs "jni/", "${projectDir}/../../tools/" include "hello_generator.cpp", "GenGen.cpp" } } } } executables { hello_generator { binaries.all { cppCompiler.args "-std=c++17", "-g", "-Wall", "-fno-rtti", "-I", "${projectDir}/../../include", "-I", "${projectDir}/../../build/include" // "/bin" assumes Makefile build for Halide; "/build/lib" assumes CMake build linker.args "-lHalide", "-ldl", "-lpthread", "-lz", "-L", "${projectDir}/../../bin", "-L", "${projectDir}/../../build/lib" } } } binaries.withType(NativeExecutableBinary) { binary -> def bin = "${projectDir}/bin" def linkTask = binary.tasks.link println "linktask output file is " + linkTask.outputFile Map archs = [ // armeabi and armeabi-v7a are the same as far as Halide is concerned "armeabi": "arm-32-android", "armeabi-v7a": "arm-32-android", "arm64-v8a": "arm-64-android", "mips": "mips-32-android", "x86_64": "x86-64-android-sse41", "x86": "x86-32-android" ] archs.each { arch -> println "creating task for: " + arch.key + " -> " + arch.value def android_abi = arch.key def hl_target = arch.value def task_name = "generate_halide_binary_${binary.name.capitalize()}_${android_abi}" def destDir = new File(bin, "${android_abi}") def generateHalideTask = task(task_name) { dependsOn linkTask doFirst { println "Executing: " + linkTask.outputFile + " ..." destDir.mkdirs() def envVars = [ "DYLD_LIBRARY_PATH=${projectDir}/../../bin", "LD_LIBRARY_PATH=${projectDir}/../../bin" ] def proc = [linkTask.outputFile, "-g", "hello", "-o", "${destDir}", "target=${hl_target}"].execute(envVars, destDir) proc.waitFor() if (proc.exitValue() != 0) { println "return code: ${proc.exitValue()}" println "stderr: ${proc.err.text}" println "stdout: ${proc.in.text}" } } } // Call this task generateHalideTask. binary.builtBy generateHalideTask // Tell gradle that the task called "ndkBuild" below depends // on generateHalideTask. ndkBuild.dependsOn generateHalideTask } println "done with archs" } //////////////////////////////////////////////////////////////////////////////// apply plugin: 'com.android.application' android { compileSdkVersion 21 buildToolsVersion "21.1.2" defaultConfig { applicationId "com.example.hellohalide" minSdkVersion 21 targetSdkVersion 21 versionCode 1 versionName "1.0" } compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_7 } sourceSets { main { java.srcDirs = ["src/"] // Setting jni.srcDirs to [] disables the automatic ndk-build call // which would use parameters defined in build.gradle. Use our own // task (ndkBuild) below. jni.srcDirs = [] jniLibs.srcDirs = ["bin/lib/"] // default is src/main/jniLibs manifest.srcFile "AndroidManifest.xml" res.srcDirs = ["res/"] // default is src/main/res } } // Call regular ndk-build (ndk-build.cmd on Windows) script from // app directory. task ndkBuild(type: Exec) { def ndkDir = project.android.ndkDirectory def ndkBuildCmd = "" if (Os.isFamily(Os.FAMILY_WINDOWS)) { ndkBuildCmd = "ndk-build.cmd" } else { ndkBuildCmd = "ndk-build" } commandLine "$ndkDir/$ndkBuildCmd", "NDK_GEN_OUT=./bin/gen", "NDK_LIBS_OUT=./bin/lib", "NDK_OUT=./bin/obj" } tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn ndkBuild } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } task wrapper(type: Wrapper) { gradleVersion = '2.2' } Halide-13.0.4/apps/HelloAndroid/build.sh000077500000000000000000000017711417234750700177520ustar00rootroot00000000000000#!/bin/bash set -e android update project -p . --target android-17 mkdir -p bin c++ jni/hello_generator.cpp ../../tools/GenGen.cpp \ -g -fno-rtti -Wall -std=c++17 \ -I ../../include -I ../../build/include \ -L ../../bin -lHalide -ldl -lpthread -lz \ -o bin/hello_generator # 64-bit MIPS (mips-64-android,mips64) currently does not build since # llvm will not compile for the R6 version of the ISA without Nan2008 # and the gcc toolchain used by the Android build setup requires those # two options together. for archs in arm-32-android,armeabi arm-32-android-armv7s,armeabi-v7a arm-64-android,arm64-v8a mips-32-android,mips x86-64-android-sse41,x86_64 x86-32-android,x86 ; do IFS=, set $archs HL_TARGET=$1 ANDROID_ABI=$2 mkdir -p bin/$ANDROID_ABI ./bin/hello_generator -g hello -o bin/$ANDROID_ABI target=$HL_TARGET unset IFS done pwd ndk-build NDK_GEN_OUT=./bin/gen NDK_LIBS_OUT=./bin/lib NDK_OUT=./bin/obj ant debug adb install -r bin/HelloAndroid-debug.apk adb logcat Halide-13.0.4/apps/HelloAndroid/build.xml000066400000000000000000000076301417234750700201350ustar00rootroot00000000000000 Halide-13.0.4/apps/HelloAndroid/gradle/000077500000000000000000000000001417234750700175445ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroid/gradle/wrapper/000077500000000000000000000000001417234750700212245ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroid/gradle/wrapper/gradle-wrapper.jar000066400000000000000000001435121417234750700246440ustar00rootroot00000000000000PK UxE META-INF/PK UxE{MAVMETA-INF/MANIFEST.MFMLK-. K-*ϳR03-IM+I, dZ)%bµrrPK UxEorg/PK UxE org/gradle/PK UxEorg/gradle/wrapper/PK UxEhdf#org/gradle/wrapper/Download$1.class}M 0h5Z+v/ ׆p!.3̳{?~~&(P0MHa3e2&p lÐ|e;D-l ׽C!C"v=lrKOx RhO]!'"՞@yMB` !k>"APݶ-_}ɻDu_yks~ r[=*ek€a)? rg'U ewRĎw s'⥧Ǔ9JZ Y >HH,θ1Ppt1prUNN!;$ i}On->+ſC Of$#5;#*uJID)6j -5}+kY_1}h璥>C0EZQl\!@1JQ!NbN)R_p槩r'GڸS6[Kn0֢\V7pM^E\dMPK UxEXs"org/gradle/wrapper/IDownload.classE 0  ^b AP^26J;t>;ɗ|{z~+%5O&WΔ(a_4[gR#!XbQVg={}1AYCX'R5c/J$S@pP\mKulPK UxEz\Q-org/gradle/wrapper/GradleUserHomeLookup.classS[OAF]R(j[[ZU˪T Od .dYlW$jj>G5=R+ȃɹws??~XªQx)I)`^F\F ṂzQFRhMK K [A*_ɮoANϖvӟtp854˰ZsM0ݍ+e錞K{zahӱa{jr⿅ >4fڦ?(06 %L7k}8e*)v0 DqZ5*>F]m4xqNuj}g'-mZ0Zjw䜦[b!ڋ3)UD0A\>yIA$Rf MxfFӴ*e]ӫxwԯ x wuH𘗽P`{!!}%nx/ q}Jhͮ0,މ=q@{,Qzii“G7 !8CH3 `_[(`+8$U)<$4OZd4}/z@:CYׅ"D "Vv I (&%꿮)[|SW/9s ,n%BrUv/PK UxE] 3org/gradle/wrapper/ExclusiveFileAccessManager.classVKpem&im!@!PlP(ӂbhZ 6]ݍMK} >u蝣2#-XGGǃ://߷6?  Gw^D>tIq WiA9% NߏQ#583x6HSq0(3dD-*pWb~~֤':u$SzOut$%R1%+F.k[kP0vU 6E AJJΛ4lStAjfPM&$xf5)PVuU33ާX^{XXʴrdu56n)j/dbAS;4]mdBK1jOqڢnr-hkz,ceK(.<4̋y5cӘ![vnfF$Թ gPaL13 aД 5R96YK,Ap/]l \ak:rAC}ѫ .ZjMǗf}uUQebPMfA=YT[ {[K8Lb<sHi"3+/a2FXY22֯u{(2NS)G//T> 3h ڸ7B(^:Ga*{Pl6\;#4͠v )l y&ͳ`sua$&&s"\^&x3^9O&39qߝ}~9z(sL7R <7o :ǐG3ăVL=W_ߠ(~׉_hy?;Cr|1C_JV,9fx6'2!Ƽ!09'($)^RV-=wj$\7ud/j-'I%4۵ 2ۤG*1 <PK UxEc`-org/gradle/wrapper/WrapperConfiguration.classn@g8N7Ρ--@[QU6@QB[I*ؑSDC!fN, ?y~:9w(w7͋fzusY.xCCF4Ĩ75%c0.w*&UVVqF IJrN kxB \»'/;'k00#IR,TkA i CeG4G۳B1p3r중2SL6 zl'K9lF#N,wEc"Ұ(v 6[+U32vٸfL;6bfDt,f&6nh4# T;j nID5/G'"皶EY(sJhfZ)Ԭ&Yv숔XH`8BVXnə"Rd`KQW8kKtedTgȄejrm)3.oer$K.uڡz9Gp]LY[pcxb٧ NRzFKKSA7sȧy+:2`ligh鰑qUܠt~`fVT;j:V03v; glcJusyI\\+ؘ_b?ڭbA">qHǸY|u*qSr*-=~PqKǏIAtK.XڮG&`ۊ5K 2c3EݾH}tױHk/u5kXlH"5 "M;|L^x|I;Y%79R, [rng}zlj2 t᳼w2iIa%EVFi.OoΔu9mX<VM{ 7J/Q7و 70_C<.ȿ&(r>)U>'K۱T/) nEh<AXBC4E%/ADo_݃>蓛='O/6.6my">FA_ ,b` ("TCj;'JT|p3Q}4}gx[C8AP"AB;&ꇈ.JziE\"&?nqAKO8:aN>GbF'-&=eh=q /ӋONOp 7gBC8\QJ Xzc^sw PK UxErn&org/gradle/wrapper/PathAssembler.classVcWy8sصb',IS(ID*Nڸkk#o*ﺻĆr(}Z)Ĵ~][*7i73ߛ7ƿ8Rn) CQ(LٶdŋqQ[$'WRQܔ[2FA|$gR q|Sq|gEd| _Q|)/хUQ _1|Ko}q'C9y' XZqp\X(e*PsۃEqtGKC#3SÓG秦'sc$Fnh7lQ3 )0 LLwV+t&&ǟ:`k>ekY4|3}(4y0 TРJ =-u/g5ېur Bwek++ܥ~FLMvo 3zgF{(lMtwoIlquu 9&ilb\cEx{q֩|d/k%З˺h}(莫WrŒmkS? ;(PmVW ?suS^uu2(̆c΂9 s.nxSWXvq`w*CRPJ.d pQy<ŏT *5sxZSEnYO,Jע(żn ?gF*~! _k̻gMU1YN$K\E1pC_tCFGŸUU_xG.;`rkp Ⲃu;Y2]cYgU*擦&HܤaܤO>]aF(TdžKF Irfח7(In 3%I$K u`obM%Tw-5ִp-UhWf^A;]Tp!joCb1 Cݾ۫S(#-S:^p>if~y"c<{Fw12~C %FJ+yͥpD"s( 6]eL/-yk63u1Y;)-lé\}j_,iEfӚ~'lpv2:oFx *W p}nۺ?vV1r WpV8(z t ~J rC')q1μ}$i8ӳt,$0m6KOQηә2+{*{3D΅6b@|&2&qh q(c›v&vzROPdҭH-[!1PiaуUfWB 6.q\Kȱ [Fͅ=$Oq|}t]s,v玬s@14:,v-21)hbf1C,]gM>|C _kdqB]32Rռ$hbFhy'[ZpU<ћ!/b机A==HW=fd`TaF2fƓ jUڶaGy\Qy}ĿT8yN22IAүa=VBD=d+xﺔ%|4#j>K>GXy B:|P;XLJ|PK UxE org/gradle/wrapper/Install.classX |uO{j5t!-Xc tKX`l]%xGڑ#΂D8qppl'ihzM:n&8d[ѦuӴM&=N'=~mziCofOi1}o×_%- EO4ߒOKx4+)H=VuA^ Rȷ@+pfin (7KRƭ&MANٸE o Qr`AŻswo.# e a؊L@"1 ƃ_׸ˈ"2VV#QcFaB`@cIog|bMl,$LZo>=9i3ިaAU :gVBan&{ @UKmZ;h,. mBFh.ܰA!cfʚ]}MT JDϪQJVtA%YȡnP>)ܣr/)/~*.nVkE=AB=*!vV ,)gګ9~*_PPS:!?926_VU>/yD(]ꖑYKr^~T ?!֯.pHn{u׎C+\_(KƦOd:y#w\"s +A˾,uA+կoyEk.'S.~vG/8He*v^U`$36b?D\vG9XS fM 8iUၩd@Q RyՈKi;He=jAqݸ8H j 3a Ƣzn,rvB.&% i<[XO撶ϿIjLɃɗM=zI3uWǀmfWUfpFbr.oEBݹM\T[Jd6x{C\X̾S#ޑd\FyRe[(yE*#OQ >;2upIMEs~ޘo‡TMᔖ2-?Ǒ9IJ>k?B? >Pܟ3B9.{_ux-T%)֭*r H%:#v oMt3E"i_%t*Nq\ɝs+Ǥ+N>м@J"" @e-/R8D-q( C[(:Ȧ3%g(@~[iPbP>6O+hWu0Y-RE9 y[r^/gF*&LkՑgK?+v9:Gr|>!aG2=xMER0K4ܲ@ᶗ-HexZ^y 7N/]y֕PZ#Gp]TOcN;Z5ܳZ ;r3z(z 'yRqz ̔{/G^0/6t7xp[ok?䟧Hm _[Jy_֜Gc88u iQ4R}bafH? nҟH\۝U;hDz1?xoK)/"UGZ*h/jx*"汈uZS[/䛧'isԱHՖʭ 2_]E.P/^KtޠڐRy P`l8rwCs3/U;p8vp$L5Ч3p3wFO;~+賎۫k_LSMQ|HTx{[*iiy<GH~X M i*/:ID~*I,`jqgߺWl p-g$<ϞH`HN0!hF4  'üBLClxpf}8"ʚk\#`P'npHd\\5&#X?|jEV8]n`F oyexȿ@''/ 'Ck~R+g vt>\@N~d *$mpq84dB``E2h=@/:ib֎tZ V]D@Gߛ-=X36Xǜ@K_ iOQykO\}aA|2W[̿e(Hk" fEl__sDl/A7 b9 'fE\ߤ/Q܏=RUk BfW6Q跥ԀIv5)۾UwKJ>ܕ^SUvӟ:_C-+B'/?]Xh+E }3a1!8k?r1-I{H?PK UxEL -org/gradle/wrapper/BootstrapMainStarter.classVY[V=²l1pNSJ4 `:/FD,.iڗ6/|M/vd7w;s̽co/eqWF/f$/aVF+dü,aI1XzwMڴYV5#nͬI,_ m5F:-HO͌i:tV"0 ! a\~X@]T-B4 3L5HpO̎JTpP;"%5)%YҎ:l/O~1yn$۷5JьTL]f9dzByd.hNuT'[UzifJ9TV"܃ )xt\:JFvhؓDA| KAt'zEܪE=gϱ()xCM{T G >Ed4Ѕ׵m _+5rÏÏFyK7 wT92`fg̜ ԩ6 ڻ,R}5(Nimm;==荜+AU*tS(\z&+PUYȲ"Z?,S*O8TTp#]p7ZLgw)⾵,+̞;CנӺBͧ`Z%ܮqfLUE:jښq`>;|4{Dj6R\a(\K$"\&T)3զ@j1-2 X#5E|@-봋,:u;O`L!&;͡cԭ“?G1&1_҄7_&ƄM<'|@3LZ p0b CyJ&_1@$CҊC4}xWnM+vuon$"I&/OP1EѼtİyt,mbiory\ ˿+Z$|cqVv (Aq=:Mawxq1):L%>=ZYJDvPK UxEE C (org/gradle/wrapper/WrapperExecutor.classXw`#Grqlg;e3KHBh<^XNRYd82H[hX-mInh @Kҽ.{M}wg\߻7xO~p 0^k¸-ZBkeua>7(nQ(`ob֑2E6KCwλP=27~>e ø'ΏQtX5-_3u_1+4ɝ0|!c|E/ Jŗe1+Q|_FT/5:׵eohpǖ#Cý#c bZgVMtlMWl-goղE] ]R> K HVT o<$̼nن^Pĵh>m/Sm64ޥ4NY{4+GvhD9n\FwNcB~Ӛ蜰LVci$:sCS40sdjiZ4h{ iSpEk*Ow.RU [oԸn Lk٭e9G-=YzQ` EPpJWAN;I fJ]> (-ҵ#beJӚgi \l[JN9HlۦLYX}2þDm9)4cTIyrQw{}f'tۏNE*hk}:)ȉUW[Adg]i>-?G%(!͚ " :hT|" FMaFdSy"xzqkU>oP)kNVRFߩsMv;71M0 ҕ-Dwh:DUן Ze[v۪4CA,gߕ!{>H1gSz{6;iLBKEuWr7r[9h蘄,f3 Y{)w*Lq"?ן#SH́D.NԮHVvu/+}gn=(Izު[ǣ%iPQ7<>FeU 󅷵2/3sTExK{-q-<)[ z|O`pVgłg6^2g$_?T"/K8_wQ_}Ɠ*@((l4Nנ9dj}bnfv,SIG(Ұt vrek TP"!e~,%v#2F {|ĉ/ISzQL*=KE.{2n*IM"iKOAnIePp6碼iVcгS9~ݓү)깴^aV~qU:/|% 8 @)a[q Ø&,z1cڤ|j! Wܹ;1z^DѧDmGАHAcCS^`4:e2Mc VLTw[ŝ3ܽUޙCh^r IFK3گXJ-g?랪{1܏xI.)^%:Fi%T@ϟ ‰6Mڅ|.) '5Nq `ih1p`(j9N0{p;&[ЀW0J OM4 :Rfػ_5űS-ޭPm>K= W>PK UxE”" *org/gradle/wrapper/GradleWrapperMain.classX x^y#lA0,HBlBbllml됖VHWzwh6iӻ$me7nBϤMJ,-̼ ?#*v[|9@/T"r/V/^ŭr2/+REܯƫUUp :xD]wTNw VF/oRoVp&ܧbޢ*JpyvĻw=rxx@9ާ fU*¼)xXťxDi|؋3c >.~Bn>*7@zI )/Wi-r7g ŗ/ *:@Pუ}# ;<4|hPN?czb*8j%.35҆@xo߁P_obG4v xz. E`:>i$1C3zlLOF<豦) !39JꑘgUГ;F Ŝt KOkRE4_ڊƂ RO cƥf;aӖI1JڳDYG" 4,6qDi,"o-v4}F/_xoNU.A/],&eVB%(ӄG+B*RΒ\4BxV4n7)QRTjeF`gHV bq@ S5pLXGf<fSF`ƎEQ94y4\$ZMIvvNG+A3`$\JSt"B.unUA~JRbd C aW@jGDH 8~"VkzLb l!]FM4O\X,S,ձy`h>+,q*̬8@ jYPjZOu'q#aKhǝz qC.gܳ嬝vXXӎFJ.np8W}ɭj[؋u'1SbGwLc店 ;6%64Xvܽ2ͣ\-` (سJVvB<`Lpq G!!\o%E`*ÒPq Σ|b'e)މ2_ǧfP6>jR-,Ke~O[5sXީVG 2XN߻yDʶy sX3y4My%º tۅA3Y؈z` Zq q6Ѥ/q$ 7rKCKqta<_klĝ"ӓ(#0xC)=Ca頣AḝI!h36^(06߆Y9iKK /8U؀n[Rd WVE,mHZ⥷ ^lkypw`RZl`kepqաy\:>Ntށ<emsb;OgrWy6۲40ȵ\B(# QdfWGG A'N}]Xeugkocqe)ٷ)G/)6 rk`N'~^4ћEK#_M7Gud:W3M fڵ23T Ͻ Pc9Sӛ*x&nzWЕYE <YХ| ގ:'X9`X|<xrG(77}DBɓG:[ 8 V (dc' ޭ OiY(ԌZÊj!=]71mP VelӓNn l/薹6& EN]-$bpb Z"!pt4`&ԝfLr[(V<Mٙ>}=<+TӔv%$Kg`T+FΗ cp8p%zאg;ikefk>۔2lLb1sDDJr@ʧD(Ŷ,G`aÉ5K)73Q&}x243wLFyYzԜM- hʶ[)RLضVʎJy56QJf|t/x/t֪Xz ܄Z:LS7PqM5RW:e: o⬊ye]oCB҆Tn pNGX'ԇT|/T|T|o|Vy|? B'Mae܏B<'L8)~/>K*~e&vuL5KS/F&L[C|Fu&uVyice"?nOEWug]x5='_B{g`]bݯ%;IPLi)>ō-hS=iw/N9"KPodzzC밞7Ш %R8r "j %1xBUx/Q[Jk@SfƋtǒ!$R _Ge+iUԤ1 }!ԓTL| I X*捣b]Y~><%#8:# 4^Be֨b!RIcYq7*_b];{sLƱT** `# M)5_%.Uq{S,vݩp),jC٤dЕqK[[f A% R l"PS4 ianPoa`XD;Z>~l'C #S]~LEU+F^k%-؋m8,њ)·c;<<;Hla}$ IvPE#oD43ԧ7K`]N{7B7U2PK UxEj jV8org/gradle/wrapper/PathAssembler$LocalDistribution.classR[KAftq[yk[KA!|(L!N MJP?U<3Ҩ|ؙs.s˿ū9`OM}Q&m5ȏT0芟"VY~ܪ+Mc56-ډiK` {DjyT򏄽Ilֲ$,4T*? {M Fɡkmjs M%ydw-~[ؑ%Ru<[5'_n$6E<`=fAxwZIDډ?7 U46?S@h=W-ĝPK UxEۅ'9z !org/gradle/wrapper/Download.classVi[~GH0 0E%ncGNSHeuef䥛itItI׸mة-\C>/ m;I`=.s9,瞹:!"Ģt:.ࢊEl%$Gqux(Ⲏ6\U K&/ 7i F[r߫RokxMw4|W4|_*~xCś*~ HYp& WA_cٕ'޲|lGAtf3gO+PR vLؖ뙖7oʢEu|ԩI+h3Ki(Ħ.тi-='o-aۼp\>[y︂Cm+N9h[b\\ Bjg¼* zywvF3W"ѓe`9&'k[#ْ\@jFfST|Aif.[ÜpUj@%tUDAfؔ 2 ̧9e ĒRFxʋ΍3%\2c/&tJŸW)sfރĈ5bL;ywSVydsY*J7jD慕ں:zIFFlQx.Y.;Y!foVc qGpr8]HIV[O ?Wp:mE/ Uko I347FZHGc4d*h]Y#=}T_p_qCMo^-VĈ*XUqqV KX|F.UY1*mb]峢sElpG1a#P3 Xo*7>h xMz8SY[;[p, U4uޗxP_?wyֵuWx'ŢY.$4t-|Fce=cXB\qwvA)y6a u$oDROjFzWQ{[-݆̊u^|톦ࡆڭ:}Sn61nӪ$WjVD4=r2h*Z|Ge([]"}ov&=$ܹY}\yBy9züQ?ְ~189g$q|+{x]@* F W8vCމ0^D0/P)0m)L ~] w+=DנfUhwNj>rЏclU(I>[o@ŁU in$S3x)΃<`? j֕i%`G2hf mFm_Et<\A,$I5u vƃt'C׵9Cq2Gon}geޭwaW1[|c=E>ZvF*{ CCCp\G_hV:n|x5=V[!e(WcqS(AbHQ4gx3KE"RzHB,_#7 eP.e7(E(1J+S\EL33s4j?YKjܭ׸[r]~+eaN0OA*s,?75<2c}>{tl?d0v@>B5hGVt&8΄t&3j\Mgt=<́53 |IZ? )kOg^>Y S8Y^YBuG 0 ] 4GtnhרGPK UxEB=PN#gradle-wrapper-classpath.propertiesSO)IUHIM,RS/S02Q042126Vpv Q0204*(JM.)M/JLIM**+MPK UxE qbuild-receipt.properties=n JBv\zTU!&*@$7o<3]gL,ԏKf<Ε7RCNŷ,/z%~8Lǖy➏R7q=2^{?yZPK UxEorg/gradle/cli/PK UxE<S1org/gradle/cli/AbstractCommandLineConverter.classT]oA= +mt>BHhBem` Cߢ/42YPa9{s?p# 5ϕBy9yEx\Ye ZpՆaEjw I7|ZU c:tiw]HaٲzQdu;BrQfظ&DV\%6# ǹƙun]s̷X3ػe9H%ҲIk.=,ȍ-1ak^1蔕)9(id0^}y_7бp:%`i6t*㰊jBL F vUWm_ImuוD I8H7Լ&%DDՄ3qONB :ACvsπb0\8y 3CEw&T*kY+$@B!K͡5IYF6VANwh`+&XEKH,έQFV# J#hRq +dAy ~#TN*)oްOOSxΑ 86'??'k<ų@zV`PK UxE2_e(org/gradle/cli/CommandLineParser$1.classA 0EhZ v庈kCPEv-iIp.<S\p>?fxCDlnmMJ]k'iu#0BWՔ!f,By@wZ͕t!BI]#HI9|g|{ -|PK UxERB <org/gradle/cli/CommandLineParser$MissingOptionArgState.class]O`6d 2 c&/1N4`W5S/ ^H#2-sKƖ&9O״ 1UQ4%ի*gE)D15u KD10ؓp :@^3\ٲŪ+^1UqQ)B&@)ʊ! B@n!fU(AiW|ۤᲵMnR# yd8!>] ZEGO*%UoulGQ/\TMn˹-02#/hAlu@t%-q*2Nw e&BgsQ\gݧ-F͌& nX{~ϐ2zfZC R6A Ӱἆ%GAa3@Lv0Lc8~csC7]Saf=/b !i!WiXN$!9!:">i!z&|'d&w`8Ig9NOXFiХ uD5x Rl( 38qhKCO p:mO.6p'%0o %rC?7o@Ӹ<=@QO b쫇|CMa"!˰߰d^7Uܰ^t^EY3G5Dh8%h+aVE3D*PK UxEM2=org/gradle/cli/CommandLineParser$OptionStringComparator.classTOAfeam`ZPd) HJ  ަ Yvɛ{&ƳvBkj8tޛyo/ jѱcр%:UlQNJU-`!?`nbHzT(gHuO:{|"<Cbq,l ߷YqDݶ̚-M oyޕJ z-Qӹ|H Nl#Kݑ]:Պ}^!C ެ\kW=jA;W{D9!ŒeAS/@%ئRƾj n5nIJ dOcy_e[o9 =}&fH]ͰqiR-x/ rahf2=BF=Y \ KaڙdiZ_L*SHhpPsED?!Fq`pZl{ݺ=1#[s!B{./zi|CG1ǐIVy&$nR$B;C'r."{i"Llr".03m`Y(N͒V055QM<3t Ʃ`1< mcd3B= `OPK UxE# GK1org/gradle/cli/CommandLineArgumentException.classJ1O3Zm+Uו0tD23k*|(1IK-Y  2aEE9炧=OQzTqvK9fU v#tiˀFCb!ė*BE{2ȅ 9`)K,Ihh\x &J>p1YITةQcBW~ͿDcD y f@]tӻLA^%6uV18(c]3 2gy=ݴoa̝̩ kqv>PK UxE?h=org/gradle/cli/CommandLineParser$KnownOptionParserState.classXkx~dY&Vdsд!@LawL73ۙJ[^6V{zJB^֢Oy<}ߟ=gfvݰ?ܾs@;ޕw%!cL!XIy^l^^\OIcB w10X/LtL{$|Uz|={el}2oɷd|a=_P8? cu 'yy(agL K%yT¯$PkXk戄ٗmivOBsh['Xh43g~vt&@A˰qlŀ1bjn&5 wfbqԴ]L0 KB}qeF;zylXqLҟ;C Dl2XwiMU9^܀¬[2ԘnհT ky|qG\R-VlFtw[^ZpwL&tJ%Fڬuu[s-ά }A*I/m^E> @YK#m^:y}` b(`Vʎ7hZ8h W '̇۶g vGVlWpv(؉)BA 4.nS:vA :WV:ujմ\UTBq>:ȲI6)Oݦ%ݣ6uBsԤmq=ajl-N+8*7+xC bH”.k8e9tTij$ *9 cNsxF ^ ~ڛJjFN趾d/?BQ2xEE*~!Ů656ד#f"zHxS[,mUbj%pAMi /}2h4i-lӨo/F[Xulxz o,<#^Z<;^=F݉5y豖 g7eÿ%8#^+XLw6j=K֕ xr^ i/=Tqܼ42b6vc&>ܰh0g|,eŨCgm}C~Rqᦊl>hAdf^]2gbV% %jO2!ǃL&~spfc9OvtYSr\w 7V*9dpŮ[ [3Gҩ7~vOrDx (Sl}izKg:$D)ahJb9gP6hhVD +$D땐h<Y<*6JBx M'X>bAlwĶ%Y9!e} n/*XO߯i;BPK UxEk7org/gradle/cli/CommandLineParser$OptionComparator.classUmOP~nQ:oSD oe b0!c,Zvğ_Hb"6sJC{=9Ϲ~P4dW%,(c ^JX^IXu E ^3tmm2$r}d }w5C}5\ޱgVnkR,)XN];ڡ5P ЬC渺3y  ,#e}0Ђ/]i'jjV]zaՋ S6^~ u- TtY+y&duK< Y$jj7cv 2W[VAۛ+mS*(uB1lņ,i^\r 8;c =x\8npﹸvr CQo *]] 4|[Tuޒ%`anot.AAiU WGŵ S/co4<}u!TZi>Jv!a<@*QȒ̜!q ;G'.!v {nD<|ڊ֋1(Н0Q I9b|b$m:ݳtBHO\g3(W`iL9I k aXtβE$i,:AyLS)""J?QAX_PK UxEb'n?org/gradle/cli/CommandLineParser$UnknownOptionParserState.classURA==$a2@(""UZ`$SdL__\H*~7= B%q}q[A :0A0iDq5k rCw˺& ezabq [vJ%nWL[F ! ɕgY6rkk X>O 6E=}9A{gN)Ҧ>曖.^]S`{jHO~噎-pe}^^rJI=R7٠cSޒ{2iOcinی1^#r޲t1b7?4yvo=)L^)aFZ֜[c9*z'̼n$T BAa F&00 mGd6a4j3 C'/n{._VƵձ+1DX UR%H}4+.L_c=:"L32}F7>L`g%.dJ\)+QLgq.:K^dI׵{""¾j4e8 ț#u`@Ts䥓?|pP{fr mEhQr!"XOٯUVH/.\ 鋘6?9R?SͩUÕ@FcH:U1-NcjXc4Uy<blfq=PK UxE"zZ &org/gradle/cli/CommandLineOption.classV[sV˱E  cP@HICEUGT\Y S¤tCg'C~GVdٲKΞ՞ow=m;0%c:6Lu`; fx%p -xK ܆*cAF>ꩂ4!#x,ƠpG(ߍ%qKFI{dY5~G*n4gXBǔ^4Ubkֿn ,[7'yBQbeI3%5r&u#q2Qy[wHHSYJWɬjJf@H7h[Ҭ,J8ڲ -7ܨq&nԝR1GC (ONT4{Zj̨.2jyi~\PSDz5,žcKBO}p,̮V!^ԜUmH(Q"lbQ-#a("Zrw6 ivΝ=w _|dŦmTҜ1d{mC);BNDfQkikɄaXq2ЯܵRB7"$(XAy/A7A#>;:|(F ͹=U&KcEZP|yq- S+·\U|HQS$dú݄31TMZ@wťK) sAChU0^]<. uʓGa(M"%z.업cg"W=d1fIٔd}F6,O).a9Ţ,se,~Bٿŋ#H r."Y,3❂Ĕh%aG1C Bրަd0vN_y)]}C[m#U mO]ծ7!VWT{z,jVT, AfDm dUO kjUj38QESV-J-墨l۱n`KFO{3FDe4uI\6%Bl5ܸ`e۠<3-ԡLԖ!J9v ]F(=75sٛ5}?{^?ꎹbxm%;sf횳hmNIxoM&?: C]G(سbqu_u|C7u| Wuo+H-ekg{nl]u?Tp{j.g-ٯ:bJǏc~NC: u *~8%sӽ(z,>`u(]tѼLQq :~ :~ D OV\#ZFg,~!3CwHEnZG$]hec9gڝfl;+}<p;/o'_ cuլ7[s_+a {0{&`vN7s0ċʼnrsqf&8 *BW?=qc4㽔(M(D:"cסRS-t*݂*Rإ蚹n[H(^ZHRqh,{DRTzØ۸ύ;{W"9:L!YDaL^X8Џq/!G=If11<&|x'#ې8 H1"G)\MRtqItboOH·Ĥľ5!ߑ? !1Z\c\웎{F]ʇS=6\w.8 Ti߸ #W%#'!yr#1S8S06|38-I")XZ V z'*=#7ppNPJGfFM*vX! Bg鴏 ]5HgUR(sKX d1߰6kGDg6+! \<$/$Ӟæ<~xQ~L%s@T}wCG4x̯.Psn)"{T@wX ˌ菜58o]$EZЈ/g"%1B-)i~G-QFBJFn^$mPK UxEA5l| :org/gradle/cli/ProjectPropertiesCommandLineConverter.classKO@D|?Pâu#Q+$C;1m  JW&.(1D,9vo/[@yl汕G)v }FHWkwLS!]nY7ZK:̿cJDZRysV;H+-)nkS#cruLXgh|BjFYDΏ%L%񎅎*_?ֈ:("<ڄbJՍ ؊tf^*K ߵ XUVi01k p8wZ8T0g?PaΛm=C Ss | 1\Zq-}C_JEˉjE+ w'PK UxE2lWJForg/gradle/cli/CommandLineParser$CaseInsensitiveStringComparator.classS]oA=3|,bYŊ/b JbB$jBfmvƿŗ`|G,L C{ι=wo4<O2H%= Ttjnੁ}dK9*8b+' ; ]wI_zǢoS$u>(>*A[Ue/3n3̎Hm ߗzck쉡-,N3U?ϗ^i e;^{*΅e gl͑HC9Y\Y,X f.Ggab@HFSϢ/@tOL]u(#_k#ܩ7onaܾN25h8)Jeb[11_b7İ#j1lFד>^I>7ʢ0uI;, W/pdiM O: 䡟 I%'/;Lق)<$O#30VQ+qvC#B7>8^C~,rPK UxE( ]UT*&org/gradle/cli/CommandLineParser.classY |Tչrgn."Y"d% l&̄ *JZ^( 1uֶu}^m{k&ޙL.&Ǐ{Μ||͏;NDs ϟUN>:&5I֣AOk9ȺN9_64SQ\ϣP>hU>bNWOb&#S< Rt*eTRiS.+*S) f *9պ9<ϐOg괄i\2괜ktEBX%:#VXy2i|NZ>#*u2svv.+sy[/* [{m/ߍ2a|Ho\zoŢWN|6xXgΗ/c3[EY*m32u3LcWw&ñhc2::͸53M3hŠ&N+^nۣ]Q{rOXƤ4ގ/8\ipSQ}8lmMMA֤GGƨsDk+0-`jŭqci2V־LYH #ZL^n- +]nŅ LU̝fUW2[m5fRE1.NA]ov&nɮ84\=1mU6Eb񶪶#*GUe h)x6#خn1_ x0SbuƭfS@x;RCa )%jᄹ5bh8SR[kDYձՊBl*lF֛v0Ę ٞKr9"~LNY4d`+ndl? V* a%T+!h8 %/3A.~+ڂW"b˻/iDs61C^x:2,#">El5wMy]-t|Ъg+=6;;S Y5lays@HJFqz Fn+Fޭ f76^3;+fts.l|r9ВA,h%/S0碄'2=Sى oIJzL,bSIdXVHAX Գl4#]gEqnyU@C8fqNj4#pafkA𝞣Iv̸7λ-F-.X_Dfqv+ qr&޺ Ld"=.d[Z['m\vR>d b5a*3:l%͞4dh(E{TX,Ώ9Jg8,]H荱x3j8XIwt0 tA_;&xJvv%aS찷8a9i!‡3P'4x6!zx`gd_W{䳗zϵ՟J}_m5򵀸ܰ2s|B!7,ex|l-oۀe%ŒYe_; >wռL,;cg!#34Uhcq NpErA>d%C˷|o|?_anh毤b!%tuq˂ vIuW ?v%(mfunWt Vxp، [[pGY"ŋbdCMƒfKKq,cHMHdpxfYLh /kd~XFcѤBv3 uvx!@|^2s'|_55dbɦe{6u^Q߽ӽ-J ~߀Q% hȗC8#piB O<1oxp:bfTiIӻ^yӝHZx@EsFWxBI7RRl\.GdaƗ< 8ƹ1}šsn@v,2녃GfڝT6 QcLI[]avoz<1Ď.3!H +Yퟷø]LtmM8[Tҵ!ѝ%.*37l׷fbd&3{W -mv VW+,RYɴ5v|pJ\ 7c.W')ˤOWGYI7vi+ږlWa Ǣ hʁ2 &%n`j7nS[<չ!,fB|ô eC%DrϮOOGߍ4=6S-]JZGi+uS3]I-t#YȰVDY=K;~ )BQ(ND;\JIO]H;y#m͝t9+Ï^~ >\Wi?Ct=n?-W?$%{`Ȇ𽃦c8z#dLd= Yl: M'I9 +j `ߠ+ii^fZ~AG.,qTR=ϛC|4o[ǐG)QTgep/^t@gF$2/)3pKKwyX؇df^H  n^OW})Y[HVM]G?L 6иJKT'>(ɩ6de6jxa-~~WrWtD7(/oKi84\ -Ig!UDk~^SʈoҷlxVДeg>k˛utvCe_hLOtx+5ja=ޒcTX i*Pn+t >_arwsG&+_Ch}RO;AUQ[SsjP?69 k~E{-~uh h?wPK UxE_>ң)3org/gradle/cli/CommandLineParser$AfterOptions.classmOP( @ 1Q|Dt1wkծ5wE#]|!Je<1Mz99s۟PƊ'IW1!y &TU,2~=x6x !fu'\lkug!s6tL![/Hvfe׹[‘zdL[N!e`oyXuyej&!&)bA02]yr^5Vf6R\4dr] C0ԖQi26{{J.-ߏ޺&Ww{Ֆ/IU0ᘓ*3Le o13/#|]ˣ%D3zaS2u7XMc qaA78yWN*%1|avť-N x!*JB)>#iIShln|AjTDVИF(J9DRR; %܊1C!˩1(|GFJfKmt$F5kj|EFߧjr dY+!kmrQ>э=ep2n&0ft9\9E'tN* iϤK49hPK UxEGf3org/gradle/cli/CommandLineParser$OptionString.classSNA=]ʗ(U-e)'#  XlwD w+Bs;s=??~ &cAYs)TҘa! ei,pW]p_8 =[wfnsak璳bv0[=כ)m1$j^C0dlWv8Bv-(wAP ;e(|¯9<Zkߴ>o8ª;UZ-6d7_8'_AyKBkxy>Eӂ4Ui 1 z]A@Z Moz~]{*Ka:r摎, b^hxc+ ݥNC:`U L1r) ;{2̜?3zE9nB;;esy-w'i< MI^NN֤ʍЛh8Yq|9wvc 91Ȩ(` (OaʓbmDm>X1#Ka ~B>FJg!6l|;4 kaCԍx0r/iA';`CG G¡c#'30@ÌnmaF⺙igM1*[Ĥ=\E7i PK UxEx&T` ;org/gradle/cli/AbstractPropertiesCommandLineConverter.classV[wU L2悡5&I  i-4J`Ei+v fpfD{_ m\KWu dY\go}_p?H8"%ެHO%"ͧ= IX6@7=q|';y !H"r k7b0tuVɫ}%_&I cbj| f1\f)^2bYZ ڦbZ:c듶r*&2 M n8&M2jV)DĜ2W5( ,MIzn)嚺Re9hst4%D  Tmgv֭ttKzAm" e7tv٧) ٹW v"Qys;]^W/ypF,w5h}ے6&FOڕ.e`ZcCQ@Q,_Q+WDh2DDYFCF0-6j qdqțt+#y:*[0JZEf~]r~N WScXD\/ô.'Ƕk_4ЫTS!Wn[0( 5R%պ<a՝ISؾꢦ.Ci$h{wfЪCMx(t'9%f9o=,N=M柃B&; ﭣ/ N?gyO:aeJ^/F}o b b4kt"tZ3 яU0fx'ySr 6 aadB3 /)LF}Atc^l?$ͼA_ !7Vkg렾@ ‡CGGDoЅph.` (rroYJ]kKIrIn#)`,r|4 mYYBY-B1>q?PK UxE ,org/gradle/cli/ParsedCommandLineOption.classS[OA-"\A(-ʊP1!iĤoC;Ylw- &JD}G.I|9|93|`+)dPPQL!B0冊I,-,&q[~器+䲤⾊ {lqWAW-+ b^ f~,Cz2$J^YA4_T[Wjls6)5fn2Gsy;+c&k_2U`V]Rm4=a[T.ipoSP0/DND=t=Z+jpS0? KOrbjrjd0ajWKp &N&7YָE4Wl/xY92,BS*jx<Iy2=4yt Zce[ZҚE̙swy' :iB&1!CŴ3*f5$0b^E!YsMKc2\(4ff[\xf}f!?\t]($zr,.épx| luj6%;fOxզPɭq…% v2^l"P+ܧ8ش癄[2۟kVMa*W`sQ(r Q.$uv\ y;>ަVv[fnYx2=Y#X13:ncTŢ%,Xѱ5Pg),V5H3 K; 3'<<JڵSΐ!/g&W;;^ݸ v,ly/x-/TQZ]܉\E/˕=lk<RwgrŁtZ.=EPhh+"J6mL+"F~OA-, f1B 娆E$5"y  3@AU'2P*= QE3D5@}C2Pw'3y=RHI8[-vtn5@ $}_+:)+C EoPK UxE'H g)org/gradle/cli/CommandLineConverter.classQMK@}ԯ'"4 FM)HQ ޷lI7ݔ6MBya=t$S l)8A {Oyb :˄3I5' JXdT"qx{a/4OR1=Q615 ڹ6ƇEWbRh{'qj1M8zta,gZTRwZ\SYVSݜnhUYB/n/1Oz_G86\fjAʚajJuG-UʙeZ7^[u(5}2(Y٪Zk$N(@yA(تeٺip|0Xh5UUJ`[QtZw&~ժ:ѷ3<MSn9j*ߌq\6 G J*yN;{2#hfc f*SL Èaq!y" Ǘ axIbtxh.x%0&X}?:Ui4^}R֚Be*"nE& ̗he;*J"b68pÕ7rC.?V-0fO~^y뱉6{*B^*Y-z=:7CRyʍհjHC*dfN͔W{M ^pCMPzkt_gBR,]x;^Vw+eM+" ;zf7i^/O3}xb]C[B]d5c|Q%G7GO=m~} ҈'ҮOC.i^yb;30rؑ^!yڢ{f U5$:2lދ9eX Lm1 }IbR$Yy|M7PK UxE;|9org/gradle/cli/SystemPropertiesCommandLineConverter.classJ@ثmjE5BDąR/P~ӑ$&BJW 'iAY3͜l "lYlE <& d@HgL{:rRs:C*X4NĬQ ۴;hZ3a ѽG!]Gv7S"5eb o}ɸGtFMz9y~X{()spL`7e.KV, TXxɢfDTEGPWJmh~49AjxѰ sh gԙn85].FԒs9Q΢*s/@Ug J*ce+s+1 $p6/t-,;h-.Z >kZPK UxE-h2org/gradle/cli/CommandLineParser$ParserState.classSoPN) sT4706|3M$m f{@ú[s-?&>GmdiҞ|~pF62΢jv,-4WׄTqB0;%v=^(>{J` aŴ9,D!PK UxEF= ;org/gradle/cli/CommandLineParser$AfterFirstSubCommand.classVRPN[J;be-x)U.R(XE_( |gtPq猏C8I K0㟳{v|gw9| E͈4тHA/pK\3*B;ExqOH0ԛoB Нҍ\$gȫy%ͫ!k)USdqW5ռ0l%^--1x[+T^ɓğҳr~I6T/ =]kS1&U`fV Ҍ)F2/ Y88f-IMy$ M1eLo H2ڼ})MzٛZʑ"P\\y6O\}9ݲ'JBKeվm gËYzK/ Z1}**2 ~CG&1%`Z 3t9eaёgںokǔ@g%Ku`|G%E5e uS閻5ϗ4ڪ۲b}B\EU6:YPFJjh>3L578")&COH)YslH#?nA;ΙZwQW+S ^ͼ8W'AE[=|>>Јs6MMT > wH{im::^A:HG8d"Fx&O+\AX!vѸq HW69Z e+˝}с; \G7Ĺ(( ]LSh`cB p.9Bj1 D'($U<"z@'bj']GZ f<_PK UxE٥FDgradle-cli-classpath.propertiesSO)IUHIM,RS/S02Q042125Wpv Q0204*(JM.)**+MPK UxE AMETA-INF/PK UxE{MAV)META-INF/MANIFEST.MFPK UxEAorg/PK UxE Aorg/gradle/PK UxEAorg/gradle/wrapper/PK UxEhdf#org/gradle/wrapper/Download$1.classPK UxE[pDorg/gradle/wrapper/Download$SystemPropertiesProxyAuthenticator.classPK UxEXs"zorg/gradle/wrapper/IDownload.classPK UxEz\Q-dorg/gradle/wrapper/GradleUserHomeLookup.classPK UxE] 3 org/gradle/wrapper/ExclusiveFileAccessManager.classPK UxEc`-!org/gradle/wrapper/WrapperConfiguration.classPK UxEQ}i 0org/gradle/wrapper/SystemPropertiesHandler.classPK UxErn&org/gradle/wrapper/PathAssembler.classPK UxE Xorg/gradle/wrapper/Install.classPK UxEL -,org/gradle/wrapper/BootstrapMainStarter.classPK UxEE C (1org/gradle/wrapper/WrapperExecutor.classPK UxE”" *<org/gradle/wrapper/GradleWrapperMain.classPK UxE{x "Forg/gradle/wrapper/Install$1.classPK UxEj jV8Lorg/gradle/wrapper/PathAssembler$LocalDistribution.classPK UxEۅ'9z !Norg/gradle/wrapper/Download.classPK UxEB=PN#dVgradle-wrapper-classpath.propertiesPK UxE qVbuild-receipt.propertiesPK UxEAWorg/gradle/cli/PK UxE<S1)Xorg/gradle/cli/AbstractCommandLineConverter.classPK UxE2_e(Zorg/gradle/cli/CommandLineParser$1.classPK UxERB <[org/gradle/cli/CommandLineParser$MissingOptionArgState.classPK UxEM2=^org/gradle/cli/CommandLineParser$OptionStringComparator.classPK UxE# GK1aorg/gradle/cli/CommandLineArgumentException.classPK UxE?h=$corg/gradle/cli/CommandLineParser$KnownOptionParserState.classPK UxEk7Fkorg/gradle/cli/CommandLineParser$OptionComparator.classPK UxEb'n?hnorg/gradle/cli/CommandLineParser$UnknownOptionParserState.classPK UxE"zZ &qorg/gradle/cli/CommandLineOption.classPK UxEl\ϧ8|worg/gradle/cli/CommandLineParser$OptionParserState.classPK UxE#4P*&yyorg/gradle/cli/ParsedCommandLine.classPK UxEA5l| :org/gradle/cli/ProjectPropertiesCommandLineConverter.classPK UxE2lWJForg/gradle/cli/CommandLineParser$CaseInsensitiveStringComparator.classPK UxE( ]UT*&iorg/gradle/cli/CommandLineParser.classPK UxE_>ң)3org/gradle/cli/CommandLineParser$AfterOptions.classPK UxEGf3org/gradle/cli/CommandLineParser$OptionString.classPK UxEx&T` ;؝org/gradle/cli/AbstractPropertiesCommandLineConverter.classPK UxE ,org/gradle/cli/ParsedCommandLineOption.classPK UxEs=org/gradle/cli/CommandLineParser$OptionAwareParserState.classPK UxE'H g)org/gradle/cli/CommandLineConverter.classPK UxEC| <org/gradle/cli/CommandLineParser$BeforeFirstSubCommand.classPK UxE;|9.org/gradle/cli/SystemPropertiesCommandLineConverter.classPK UxE-h2org/gradle/cli/CommandLineParser$ParserState.classPK UxEF= ;Xorg/gradle/cli/CommandLineParser$AfterFirstSubCommand.classPK UxE٥FDgradle-cli-classpath.propertiesPK00qHalide-13.0.4/apps/HelloAndroid/gradle/wrapper/gradle-wrapper.properties000066400000000000000000000003461417234750700262610ustar00rootroot00000000000000#Mon Jan 05 14:23:44 PST 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-2.2-bin.zip Halide-13.0.4/apps/HelloAndroid/gradlew000077500000000000000000000115001417234750700176560ustar00rootroot00000000000000#!/usr/bin/env bash ############################################################################## ## ## Gradle start up script for UN*X ## ############################################################################## # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS="" APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" warn ( ) { echo "$*" } die ( ) { echo echo "$*" echo exit 1 } # OS specific support (must be 'true' or 'false'). cygwin=false darwin=false case "`uname`" in CYGWIN* ) cygwin=true ;; Darwin* ) darwin=true ;; esac # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" # Need this for relative symlinks. while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`"/$link" fi done SAVED="`pwd`" cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" cd "$SAVED" >/dev/null CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD="$MAX_FD_LIMIT" fi ulimit -n $MAX_FD if [ $? -ne 0 ] ; then warn "Could not set maximum file descriptor limit: $MAX_FD" fi else warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi # For Darwin, add options to specify how the application appears in the dock if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi # For Cygwin, switch paths to Windows format before running java if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` SEP="" for dir in $ROOTDIRSRAW ; do ROOTDIRS="$ROOTDIRS$SEP$dir" SEP="|" done OURCYGPATTERN="(^($ROOTDIRS))" # Add a user-defined pattern to the cygpath arguments if [ "$GRADLE_CYGPATTERN" != "" ] ; then OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" fi # Now convert the arguments - kludge to limit ourselves to /bin/sh i=0 for arg in "$@" ; do CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` else eval `echo args$i`="\"$arg\"" fi i=$((i+1)) done case $i in (0) set -- ;; (1) set -- "$args0" ;; (2) set -- "$args0" "$args1" ;; (3) set -- "$args0" "$args1" "$args2" ;; (4) set -- "$args0" "$args1" "$args2" "$args3" ;; (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules function splitJvmOpts() { JVM_OPTS=("$@") } eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" Halide-13.0.4/apps/HelloAndroid/gradlew.bat000066400000000000000000000045441417234750700204320ustar00rootroot00000000000000@if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS= set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if "%ERRORLEVEL%" == "0" goto init echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto init echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :init @rem Get command-line arguments, handling Windowz variants if not "%OS%" == "Windows_NT" goto win9xME_args if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. set CMD_LINE_ARGS= set _SKIP=2 :win9xME_args_slurp if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* goto execute :4NT_args @rem Get arguments from the 4NT Shell from JP Software set CMD_LINE_ARGS=%$ :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega Halide-13.0.4/apps/HelloAndroid/jni/000077500000000000000000000000001417234750700170665ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroid/jni/Android.mk000066400000000000000000000010251417234750700207750ustar00rootroot00000000000000LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := HelloAndroid LOCAL_ARM_MODE := arm LOCAL_SRC_FILES := hello_wrapper.cpp LOCAL_LDFLAGS := -L$(LOCAL_PATH)/../jni LOCAL_LDLIBS := -lm -llog -landroid $(LOCAL_PATH)/../bin/$(TARGET_ARCH_ABI)/hello.a LOCAL_STATIC_LIBRARIES := android_native_app_glue LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../include $(LOCAL_PATH)/../../../build/include $(LOCAL_PATH)/../bin/$(TARGET_ARCH_ABI)/ include $(BUILD_SHARED_LIBRARY) $(call import-module,android/native_app_glue) Halide-13.0.4/apps/HelloAndroid/jni/Application.mk000066400000000000000000000005671417234750700216720ustar00rootroot00000000000000# Can't use "APP_ABI = all" as 64-bit MIPS currently does not build since # llvm will not compile for the R6 version of the ISA without Nan2008 # and the gcc toolchain used by the Android build setup requires those # two options together. APP_ABI := armeabi armeabi-v7a arm64-v8a mips x86_64 x86 APP_PLATFORM := android-17 APP_STL := gnustl_static APP_CPPFLAGS := -std=c++17 Halide-13.0.4/apps/HelloAndroid/jni/hello_generator.cpp000066400000000000000000000025111417234750700227420ustar00rootroot00000000000000#include "Halide.h" using namespace Halide; namespace { class Hello : public Generator { public: Input> input{"input", 2}; Output> result{"result", 2}; void generate() { tone_curve(x) = cast(pow(cast(x) / 256.0f, 1.8f) * 256.0f); Func clamped = BoundaryConditions::repeat_edge(input); curved(x, y) = tone_curve(clamped(x, y)); Func sharper; sharper(x, y) = 9 * curved(x, y) - 2 * (curved(x - 1, y) + curved(x + 1, y) + curved(x, y - 1) + curved(x, y + 1)); result(x, y) = cast(clamp(sharper(x, y), 0, 255)); } void schedule() { Var yi; tone_curve.compute_root(); result.split(y, y, yi, 60).vectorize(x, 8).parallel(y); curved.store_at(result, y).compute_at(result, yi); // We want to handle inputs that may be rotated 180 due to camera module placement. // Unset the default stride constraint input.dim(0).set_stride(Expr()); // Make specialized versions for input stride +/-1 to get dense vector loads curved.specialize(input.dim(0).stride() == 1); curved.specialize(input.dim(0).stride() == -1); } private: Var x{"x"}, y{"y"}; Func tone_curve, curved; }; } // namespace HALIDE_REGISTER_GENERATOR(Hello, hello) Halide-13.0.4/apps/HelloAndroid/jni/hello_wrapper.cpp000066400000000000000000000076171417234750700224500ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "HalideRuntime.h" #include "HalideRuntimeOpenCL.h" #include "hello.h" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "halide_native", __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "halide_native", __VA_ARGS__) #define DEBUG 1 extern "C" int halide_host_cpu_count(); extern "C" int halide_start_clock(void *user_context); extern "C" int64_t halide_current_time_ns(); void handler(void * /* user_context */, const char *msg) { LOGE("%s", msg); } extern "C" { JNIEXPORT void JNICALL Java_com_example_hellohalide_CameraPreview_processFrame( JNIEnv *env, jobject obj, jbyteArray jSrc, jint j_w, jint j_h, jint j_orientation, jobject surf) { const int w = j_w, h = j_h, orientation = j_orientation; halide_start_clock(NULL); halide_set_error_handler(handler); unsigned char *src = (unsigned char *)env->GetByteArrayElements(jSrc, NULL); if (!src) { LOGD("src is null\n"); return; } LOGD("[output window size] j_w = %d, j_h = %d", j_w, j_h); LOGD("[src array length] jSrc.length = %d", env->GetArrayLength(jSrc)); ANativeWindow *win = ANativeWindow_fromSurface(env, surf); static bool first_call = true; static unsigned counter = 0; static unsigned times[16]; if (first_call) { LOGD("According to Halide, host system has %d cpus\n", halide_host_cpu_count()); LOGD("Resetting buffer format"); ANativeWindow_setBuffersGeometry(win, w, h, 0); first_call = false; for (int t = 0; t < 16; t++) { times[t] = 0; } } ANativeWindow_Buffer buf; ARect rect = {0, 0, w, h}; if (int err = ANativeWindow_lock(win, &buf, NULL)) { LOGD("ANativeWindow_lock failed with error code %d\n", err); return; } uint8_t *dst = (uint8_t *)buf.bits; // If we're using opencl, use the gpu backend for it. #if COMPILING_FOR_OPENCL halide_opencl_set_device_type("gpu"); #endif // Make these static so that we can reuse device allocations across frames. static halide_buffer_t srcBuf = {0}; static halide_dimension_t srcDim[2]; static halide_buffer_t dstBuf = {0}; static halide_dimension_t dstDim[2]; if (dst) { srcBuf.host = (uint8_t *)src; srcBuf.set_host_dirty(); srcBuf.dim = srcDim; srcBuf.dim[0].min = 0; srcBuf.dim[0].extent = w; srcBuf.dim[0].stride = 1; srcBuf.dim[1].min = 0; srcBuf.dim[1].extent = h; srcBuf.dim[1].stride = w; srcBuf.type = halide_type_of(); if (orientation >= 180) { // Camera sensor is probably upside down (e.g. Nexus 5x) srcBuf.host += w * h - 1; srcBuf.dim[0].stride = -1; srcBuf.dim[1].stride = -w; } dstBuf.host = dst; dstBuf.dim = dstDim; dstBuf.dim[0].min = 0; dstBuf.dim[0].extent = w; dstBuf.dim[0].stride = 1; dstBuf.dim[1].min = 0; dstBuf.dim[1].extent = h; dstBuf.dim[1].stride = w; dstBuf.type = halide_type_of(); // Just set chroma to gray. memset(dst + w * h, 128, (w * h) / 2); int64_t t1 = halide_current_time_ns(); hello(&srcBuf, &dstBuf); halide_copy_to_host(NULL, &dstBuf); int64_t t2 = halide_current_time_ns(); unsigned elapsed_us = (t2 - t1) / 1000; times[counter & 15] = elapsed_us; counter++; unsigned min = times[0]; for (int i = 1; i < 16; i++) { if (times[i] < min) min = times[i]; } LOGD("Time taken: %d (%d)", elapsed_us, min); } ANativeWindow_unlockAndPost(win); ANativeWindow_release(win); env->ReleaseByteArrayElements(jSrc, (jbyte *)src, 0); } } Halide-13.0.4/apps/HelloAndroid/res/000077500000000000000000000000001417234750700170775ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroid/res/drawable-hdpi/000077500000000000000000000000001417234750700216025ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroid/res/drawable-hdpi/ic_launcher.png000066400000000000000000000222651417234750700245730ustar00rootroot00000000000000PNG  IHDRHHUGbKGDC pHYsgR vpAgHHy#IDATx͜y%Uuk:s瞛dFGDE(јhL$*O4qbFx*4Dno\U{:Ksڿ[kPW8LJl.zw8}j_ǘo,\; }s^!yC29VA p8:d1thf/ +Žp/%!:y*ܲrN]|<˨8*b!]zc9%9(!8 `ĝ{\s6)/QO6ů ):t6*.Yelz cܰÿ 9ÒP} |ճl" ӽGX?N֞!nذu_4mh0^w'eg1xu{{MyToFX0}r;V:4IIҢ:̑qA^x^֦ЀEś cå[ݚS$ԆRqїPVO>X0c)C=ass8zH5#Ǔ C"-3r2urO\NqNq4g<:d4Ż`3#H?z]L}ICԗtH;;_*5= vw~ؚrv-Y'ymYF:GW>Ōr<C1U*^^.x 8qyx,k/?aK^h–59OnAJw޻od2eԡ3^ c.=4} = u{ا>7nಛ_RCq 4fz/QG6xcWw|Q>v jm4f oh6ֱc*<ˡ#Ya, t/?=;6\QwuPA =5<թGj/\ &PRM,V8YY' mPb>sa^dJrjρb`SV%3SS1"qHge_%ë#rtHb6>C"%ƺ+Ũ@0bQT1R  Jfy`J9SvRݻ-s{‹Tb1HFq:ǣؾQf;S^rgt>vdDY2j2JCT3`2IT#щiFHĘ",-`=:@h WB'i(WZ|!ry8Xw^X%2)M2Djiǭ[w<][o|O/;+uytiTES*jVq25<ɡ.gZDv&l;7nS{vN>64Zr~懧?/rpxm/pj2{F ;E)Ҟ;ro[sw>Դ[j F>pWZ.aeh8R5DF̀2EyB2syJ :N˓ y'ѴY\w=oe}_@O[lɒhvlo>@{ffj{z[_ \[fR7xF]ԵiUss{]Z~ O|WrZ;&|O;o,Mc&%Ms(*5KeHCSY`!N,Qb |Lu#O=iWI;<<X$KI4z_?Y+\IIjBi֋UJj]_&ccd#Bt^gxe  yiεS$wlMY&$mwhvh{{zLh洛]fxҞ'K 훍WR0X! IxUj uhhxDnHcvl_?~CXQYQiL:˱{[VuO\6Ϫ)6M`IQ)ҞٜmڿOy=7RH c˄kǰ8q\! A^.RFr|^#N_:"Fw,dianvnuu݊>)gBReEu 8!xBe_ +&bDئRLi!Pf1@] `D-W>YE88B\$ (Oy/ j_ a9[0Ct E҇ξ B)WOkYLBCELEZ!A\ F .Kiu2fz(f7`R@x1a^ji4բL#Ì }>* DDv3 (xny2J;:WF *Hg1rץvWr!q3>^M#[ SMF 9ZѺ od { Z %t PBՀu11UD"XgA]oi_%i>@Yj!C_вXs:l6%6k}E"@|g W<17=}C+Y6PYFC=ThufxUG{W+,B8ƇWs֩M/a{Q*[V8fp} (q/-H/9t|o T'N/sA,.g͒S|?oZn-j= p?G(} +yward=Y3)(Fbl{{a2V`M5|[_%W?Kؽ#kcT[Hp͋ڟ_oaQ.zh?zW.bffc?=B(ɛ.c˄/|ɵxJϧ (憆x^̣XDAUNG1e*i-Ņ,h 4nB>8sW5_y^}'.]yFuEQ5Z]Kva^Ji&?@CL6`D;jq@S\y0OY)bPOdyyI7/ Gu<_8g/cE`qdk鳧>@L[lkb)L̈)^qAK] O2}VR`lwǯ O>eO 9YOHq?Ed^Kž-"T.@Uy{HlْP Y`2}3!/GY}0 g\j!0ɾߑiqFĠ0!M{upoyyFР!_k":|F 1*k2}Ml@Bhx~n\nS֐M_U~AthP@uPT#E!?@c)l`>"lXѲ8W5{~+)/U6J4DZ"o"5h*ƈ.d"'].y| fP;R>ۏ:s)TBGCH?|fvE13*]. %wiH[5&$ B[T6&BY5[WG5dT,Z"@ig,p |(NQtE;X=x_&BPW#\+Uե+\h[}W`Mҕl2굱R 0ZuAl~UQ6 FE>$5~tW"Q)hgC1+eXk-i>྇nV.94H|ˎ/y| LTC xO:}sJ'>"gW cD_wE_|L3slwhc֫Xl:N˯:߿Gt6DffJgYUiT]ZIK'kII6[규LR5z~߹fO.~Q :=jahueH~̻=ZXlE, sC~;p/U缛c:Pwz)14M׫~vϊ:l=W|kj,?/:F Y&,m\;hZY)Ǯ8'\w WV кpQcuP}Æ%+O$~h<δ]h^淿kt~~/Wu,g՚_<}9# +ʿ_g>s+C(lcTBTBT1V%o*Cg'#M=pûmڣD DWp$z#?fӃYrlmټG6O{A'?XӖgm|~^uUf-vըL1c1U֬[Ay~ix$I&|۵w?7rO^1/,/ueE UKaHM:E_?훭:љ㧵2@{.gbu̷>;?O }%/ᡇ 2vwegbWr_]lf]'ѹyKogv8ԕ8 _AMLttdesNh0Z?mC7HDŽ~!H1,_>$f;K5KX|1mk)̪ X42N|vvεv~Zׯ-[X,YfIz:8 ^r1SK&cػgF4n}Ulq5jf"+&P ?a|]OёtyK?P T|T 339"MdI%:TRIVjT*NJn5ƨ6N{yyI夽NGӣlS12Ku G.x%å#Z' /!X0=4XWjDLJz@SZ=OcsM5K!oͥ?i|kGڽMg|o]UBYQamAJ$tX 섇GC1'~XO聺y~D2qP=f%4juXDҘ% #cpLm(RIV&$V* **CjJ-"J,H`gk`z[%+oogPx9_K_5^I*Zp%J(YEu)´ `id];.wе "jm1B0! aC<"`#3y⏃p7le;T#D!rk Q**6*Ү)捌Phf q\T-%N"l smb1=W~/Pw娉 cbk%BuRZb) X|uo\YQc ͲMP*qT1EA2$PL(՚-͋آcL Ћ^ LaD;Pxa* ֭<|n;|:eeF /:H*B&F\kօ''4Nz.5a·M7}U]1aH(cc45ӻ8C^ׇF%P:ء?NЩ]fێ{6e=^Bbfdڻp[/mj܃][-3{Zre|d9˴ZV~K3$,k-Aٷ/8=]u?U/oWq/gؚozOeù衦OmӏCycιWZGZǭ_kDU G&&'شzm8M 7޸ok34ۅVm3'—f0F .O?t h|@|r%tEXtdate:create2011-09-22T09:32:32-07:00b%tEXtdate:modify2011-09-16T07:27:36-07:00wjTIENDB`Halide-13.0.4/apps/HelloAndroid/res/drawable-ldpi/000077500000000000000000000000001417234750700216065ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroid/res/drawable-ldpi/ic_launcher.png000066400000000000000000000052511417234750700245730ustar00rootroot00000000000000PNG  IHDR$$sRGBbKGD pHYsgRtIME  1 )IDATXõ{_Uu?kyonH $T ЎV,0Qґ)%R:V0H*ۊ2*Ih#J 0$M;{>{sK*3{g}w}lD{5ϝwdּ0rYoußߺko886;qz9Go}?z}jCd>PsegС^[_ S긬Ú7=Gݽi gfznqs)`7DQDy;od)""D!ۖ^7䬙==cdЭE2 pUլLŜ|>gvX O7A+ VD=d&!a!m[d?y(wl?z gLЊ{ b%%X-q$)QG 2 9:S;AN[_s)lxdwϲV3`Ȃ#_(͔V+١ A'[2\,pV_tn Cj9 zWG\)G 9uԒ)I3ptXXi3|󽷽rǤEq06_vz9nw;Q $ b:0a Il?X2밉t"{osミ|L ; QjZ5 QvF{1IĖ$H eXk5MS\& Ǟ{Dpo)L|71ϻ+1xW{~9pD>wp켼X?Tͨ=%" (U /bpb%hdp!6~MZ6_ws=O]pߟt~TkT}d3cˀ4bT ŢĀ4QđŦFjsN*ygOZwK*!i5Jc%UP%̪Xvc "Ċ")b374qđ4 QTQ@n sBEg9u2x8q(B2{)L~y,m,/9:ȬSp9ũq01CL)8YF8\1Oջh|gkxi:v9l9p)gejTD xm&FGevԻ2ro!\d{6]ѽE^i)Z)WUSN9eJ$ᄅQHw@M$w)¬38K θ4fϫ;]"H[U3%Q8ɟIamU4)Ip|j~~V>su)sؼ126OO"K5/ .װo<_uЁph_N,jLTLESY80%q-~7c_Vm MUL(i:h;^SQ99k ^ΘXJ*'3Sv\-iӍQr;H&$"a|SEFs|{}0(ɋ/^.׀0$H.7> J阮Tt7=ƱZ,s'P*4PbP3x4q<~#0{mj)J+ Xr 56]X©DY9AUgr&YmX+] +l:?/m}ܺ&b bmGi6̚&%<|{Y={ QO227SmTiݣoʋWGs~GgEWջ8tVl [8> >bD\uI$:'x?ve>R_rݩY"W]?8Q?}y|O]wɟ]U1O'o "C!R,-}sZ6q:Iݷ}_>nY!Z-FU 8B&A_U=Q'ĉt:8 Gðz&e7&h׌oܿozFwozARJ~6ML 0EWov4[׾7_rxf%LYJ" ڳ {/N4JL@/_- pW~[?t 2V~2mfZ]i9F-I`SoxWe]\R/S,z*vdRd&JK<5Q'4χrweHQdiv2Ai·D%y"ŲGV\)iQurZ.PiS2xtu,JPR,e`q+wNL=Az{פs?REAĆX~/7=U[['30~̷jIENDB`Halide-13.0.4/apps/HelloAndroid/res/drawable-mdpi/000077500000000000000000000000001417234750700216075ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroid/res/drawable-mdpi/ic_launcher.png000066400000000000000000000121651417234750700245760ustar00rootroot00000000000000PNG  IHDR00WbKGDC pHYsgR vpAg00WIDATh޵YiU9o{^&IBA& ( "`b *HQdZTef !aJKHޔ7{V9gQvKZZ}^U}>vq<8cx%~UO|To=V| b0@@R\UA'TX}M'1x8ViZ"]J03o `Mz6 4hQ1GeZ,bH ($F:,,K9NԩhL\eXu߸cTj%׳Wc\zgtp DiD(mBSh^ GT!GUS[QCp(r) r_N;]#.uTȝp.SĶVZA˖dCi/?A*BD)Ѓ,RXİp`XpM=eԓբQ@s5{ym?n*S_M 8r\?CaAp#mz>S1GXĜ"i&6qV:' Xkޑ?*u w}N"ҢX{vcg?=YA" @A`9k-\ʈL9;GItKX"R>죎*@ kK  cwR[۱U*zRͨbc]a!&iH53sablظiu˗~<F+gog Ax!&T oرZxQ{|"seR D9EvdYF`cX3~d8҃}난\`ֶ/p`4 =kx'w=ta:\\c=&bT;<@ ձYPB<qo=c8 YK7^V5cT1_!6?#(²ŗ>"K|T`qd)QQZt:+*%vOҤD (DE Mᛗc8'MM}) jcRQ/JAgUfl!톹Rx?+Wm^=pl] '9(LEQ= Y5ʎ/!fs{H @ M1 xϝ+3(-س__y덫Z|8v];8:  qW̧2ooWMhmmVL]>TjIj]UF+wK]v0VJLPl ꛅիnƔ % 1%B_ɅT-:MNıC*WG å;xq0LhC0!Q=ɾäE!+Ԍwv∩P,fDINISrNt3C}l~򚂜BjFQl30@)42>·Hiq^ (4Ydj%q[!N"DHFN&*挸B;'S" Q}9=npra.fDP%sg,ٷ0M LISDf eʙ3~譈#q@SVäOțN,lh-Noǚb{Uh l^ōϔً̭H!xSCD#2!BHMHDy/1L iRGT< w? w? iʹs=N[5XuGpop`B-dK35#zsf\"C*-feVHm=qһC[#4y,d̟uF^7VlBav ^a/Y;҆VrhA!(Pd\fHBSD /[LK6&ph(xΌXW9鄈/)C) S>Ug "Ks`xɛUB@7)5fBjcv_u%(XG4Yɵxs&|'_~>>pGpؼOa2 ( !fa@# !rPT${J4P# 38gqK7$BG[|Rl|s pR/p{/A ۆRt1G~&y 6 l=\> HnG eH9f"ho #Sij)[S=}|Xc-ߊwGϝM2*ă="lM!\Lnd@jT$tAD, , jHU0w싋p}?c+oy0sւ7\ehENg?+kf+ Y*`tew05ׁ`T3+/j8#F5mFoA.ùP ^$i(^CgM/ 9EmJ,*d ZR&f Ez|gY)$e8xpPHKēg f+(i5nG p2^͑Y_5zFےլj́$& Bi-JR5Xt)ADPl}!';rl72|!0 `H$(.=/1q\s|YPAS4@ Dј@lK9 G(9x ['Ag5I=}pȞ/ qI ݉ۆ\r\jG͚=ͯg=o2Ļc%.ٱqo%tEXtdate:create2011-09-22T09:32:32-07:00b%tEXtdate:modify2011-09-16T07:27:36-07:00wjTIENDB`Halide-13.0.4/apps/HelloAndroid/res/drawable-xhdpi/000077500000000000000000000000001417234750700217725ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroid/res/drawable-xhdpi/ic_launcher.png000066400000000000000000000340571417234750700247650ustar00rootroot00000000000000PNG  IHDR``w8bKGDC pHYsgR vpAg``x7XIDATx}w%Uoo휡9QTQA3*`#bz&8`Б"D Mjh龝'W9MouNݺ{[kKM~?f7ߍ=`l~[WT0 Qs!@2:}ҽdw%spz3J1?m*#^{ރUOP"{v)].C"UO2Ow]Y2%M9#N{kZn*@r:X|NTD1y6!B$ Ћ PC UhfA'lQOœԥx\ ^\z^.^c֭q wq.bw1O-C26kYW9YQ۶Ι;oLJށ}x  X%a&;4,ZHȢIMl!܆= G?:9T q1`GX+_`#mtъ7aGVaӚ tmȲ&z{v2h"y9fΜy1SisX'8=QQlh$X@8Xh1!X`XGEF~~y̪G[pܓ#+Zk[7FO><6ބZV>r6 ?npsg/]e(;n{ w(\a1Rax8Ee"L1b'cp>S p0Ք0n1'Q-<bh4/f햷X尵+iZ{sC^q;ѮncE 5B9^ VmM}cZ(K_|9Ka-pOP{#C_&E8^w8߿=jrF1G͊OpQlZӺOl\t1=b[{ޛ[(z㳗Vh( qYgԙO\/m?gG#JaO5h`ш,  b$A@P Dm,`;L,0΍C#>zH_㑇Źrrk =}$~GqFcڂ/ߝ9?|{T}d=9]CQGL1$B`800 f &t`.=dM:+?\v<@r¢0|оC@HYO?h#0_>`FnZW!7X6X.b0 *L>p F p`xXX8:u`Hr}exx{˷W=R3>~i#?ۋggml41^ b6k 3Covuu'(Na~\+:F!zP4D01 zXhؔ-sYcMAPα} sҏkJ` M6Nse8ݿ")&{_+وi&{Y{ˊGMLa*Bpֈh&5XtuVq+/wi?#x Ї(cz*Ի1HPfa5X`1IbY'@N?ͤ4P'uAЉÇ_lg'bIhv*Cd A ފ /"lr((‚0B  /; T,vf0 0 8^ $XHZ>2]7Kgn6F6:ӻ>TLތq* 615;=/`7ac(axЃtF+|88R^ ék1F[ca:5|Ȇ߯'y֢ql[|;vhjB2W- S= p\D)0XhXh1T 5#A `Xpяw ǀsgvH%K?;J@*$ݫ{gT.^},86u]0eF T!D͌pKX(ь0B`U ,00h $]wu8]#Y9Z-{knZs 0)tnTF$N3xfʓQƾKE.'3c4޷&9n6 s>f f2 DpΒlv7~/y.р=Ey 6Gg*#uW$LhpF@@px4fm6Lk$ЉOXmFL3⑘,SJKpObJa)X ! mCS5o3ວNEfqhϧS澞%g%嚭 ZUlUC#SXdՉE6COhݷю1YB#.FJ^<qRSHHQ &<_ȀW Sաx`6\fk757 X Ro3 HAPF 6L%"%ܦҮ2D73}oc P{a.@N+[v3;AD CmolU,e jA:@,-5ٜ?7_k U/? g֩[f(hD?3?L t-\J;<[/W`DƘ4"R&kc8k G7> ' b@ɭGޓ=!Zc ޱ5AcBZDA/dH)"cYĂ4K؁I9oZ&X`bbBwN$^D2\бXS=3+B(|iBUu a`4m\c Fjj"Mͩc4+%Q+GEaK:mdL[ڵ2]1iD~2:8ǰ}ԁ> f! f8vDdg>^8EOZ߱>I +ǀhۛ$-' D L>'9]u9a(9K:0p`f8ga5\ι~S@O#>%84!eo2AXHcOFqd 4C+V&"W#{EU>*0 mSBD9Cp6;Dh "o85K٫~g)l7_>2h5U&br<p_߿dqQ{a1 01lfpƍ?ͻMFshs\mIt4hK; u$jkmwc'KyvA&FZk\[2-`Mg i}j3hɬEYЪ.GF"^0@!I*@x `a|v_O} XBlƟQR DSi] cjXaTmozrYcuB:g=rb.m=sJL:O涶׎jL4瘘 qI*=wπ %ISMYTe1мN YF~|#&6<:`w;BHH$ w81gi_pFCRHr 1%~Ԛۧ3lc4`ù eϱ:%ˤ={b1mF3F4jj_# ̂7uN0 4[c}c#5V˹tKHc0jӀf2DH)3DzH\|͑ύ+̻QP FM"Dv8 n:0!9nxʰb>PT!3+0I}^ ҈3ť]uu\۱x6-|NR5Hi@Hb1e c;q/Wcw>`֍۰u'houlvkWFiNY /F\{sB`zU~JĿ7Vis axtX3.Lhh٪q+` $;ܡvrJ;ݶt#w. q{|I8b@J:q7 ;M;ֶ~7Ϡ iGձj'oP1O[g5;hΉN?yF}Y.U;۞i%>Z|xY=0ܢ +>Uՠ-BA@`D?jm|nclIwxir -LV\+.%, a 2Q!K‚@ E>a`-42<86IF(Q( J@PJ!*HDX b!*d OCVk:` #-ǔ"i:icFܲЉQҬ7eʼ7}+ڧlΝai#jYءՌl&h55gYsfb%Ռ`gTG+{ݶzX4tf36 b)PDRO&Q>VuU9ȃ޳ρ1k>GW Xغ. #[-LѬ[Ht0NH BP%z{==SBGr__?&זB˶nC_=t#iDAo}[YR(tns3jCܲW4UcjOo8p BHE 10 D*Q޾A*PBB}d3@NZY3N܇6~h#8&$C{4jT'cctɣ}(g33@1S.e7:Up1 rAM!s눝 zȳaB94͓K@hS?/SktyGS@;]Ք\)Bh;K%̺.fv0evۈce8ialrbޔ$vcV-#&~FtrCnh9fKxzlGE&bq= 4+2?k@MXZt%R"oEضp{HZS:нK_ra쉟M@lG%C0;ft X;3L( ٟ؏:aitY%Mqʇ`Q} ߕG<,aT n/+* )dΑL=3I}9-13pZZdAK[ fN]1[q+غ0ZY@Erh2fs`BFt`ff6ˇcP>ӏFyNFv03g$ &)+cxxո_lldɖz8BH}B@gh)w.83m"gvN?ҫ`23,Ă:C8;s&T1z;pS}Kf0 0:QL>i^@sLNpk`ՀoHl `X!Hg@`v:0JQP(Bm萖|LHLX8B\wIH!ӎ vYTWOS g)(X΀"mMDT ЭwWFv^m7$cE^=(qMtp##쐺 Tоٝ5wđ: '}]p--u8#/]w1!!RFX<ۑp )$~sxy+>> ?-SaLҖ|_ Xȍ-:=[,}j:QX9I ʢv$ٱbdJy^/E߀?B|[!|%ppaǀK,9>o)%qMWW^6߃C<yU8S!de pwE; xC" pgY&a@ɰ#I~qO_H$:H d P ,42>B3Xg/>M8M˾kn&>yKpޯY~› r񋫿o>O7&@;8bߋ4 ͒"zƬK; U;QsX:(J)BX͐ayC)VII@z6^!I#|v;wƾx+/Ɖ~)ᛸmٕXwܑbnFmʈg~8]ޕò^O#>:/%##t"$IWQ;O+bcbNzgcig"4N!Lp;:25ͤ zyٰc c5=/:_0wq y9:$`vB=-|Gu.:q̼HMnI(Н`fi~p4&K;g\BPL:Ob]Ju*7;;:&otiΡ:لNMg"p0o1 )]{VFw6}YgIHΥ-0IՔvh{ZtIΆ"G:y*KRPRM!"JC;a$@sd@`h*\ ]!Q<{뿍{{dIXk%,A,cuZNN</4 uL# |eɷߧi}nIods$ѡ`qf&:ȝ<+Y&ڷu; } `#i]:4H.ܡm~pv@G jΙ|I)7];0) !.' ewQڧ޶\QM)΁Kߙ96 yT,! ^ 93!mAڤD,>/ PρDqjNFlW0R2Vu`L+YuB j<ؤT (#O) JQݬZ%DH@%-b= ODP*+/@> snAa2r^!x =FڲeK0[Q?KIuWTYAYg1C1;q:PzPU[We'':*s)</-|n7( 3,c[RRt*f@4S p9S% jYoGX7<6$W. 0Y(">gYHk5[-Y :ie}13U(ڲ;8 K9kشn ??^bVddNx碟-7RBJѱ?o.&1cA"EgK1,=T( @ҬJX_,sJ~O$IP椴Y׌'?{|O]vr(zp/݌nw@6+Yݶh9p2~QᲪMhTͷ7S(dzyԊ FX`]8.Oau1VXm{>AYs{Po/?z٨] 'ckΟ ժ=ucZ7XWH:CY}ӥ(J Ϯ9t+OFsRJ0{Yd`:~\oLv۬ v|xe AP!CH܅5w۶\x+ߏ: zڙ"@d$q㭿ů6ySp n{Ī3K3I?7Oƣ/^?~߉•,nQ'~q_P,Fwq@"  PcނAtLp&?r戭 BHHp˝܏_Fp̘2d@~R@Fgx;:wqk!b0LE+a5aKU`S/rvhx`5hEϝpOFiS{! D*#/~WZؔПdT 5?_ W^kb~߫`5Vutm8#nB !,/_}5>}۱fh%D:+siox, :HPʯΑ3AHʉn:X;c3ГC[bH BkHͧx0N;aT*G0 mPX2 ̙tht~4<.{/BBh%kA!a̮69,Y'PظdjV7*%.Άxgy/_F0u pYٓ(%X, B:N:v[IWY`d6oޠ7wЦotJ*eSu YnLԆz U˿'yGC"P$,FO\RE"&*\x[p?*f&c߫=-Z.ʯd;,Uڑ(|X ۪h5 ,x @" lY32.yr~EDr6` ZmkV(.0Nsu鹐YJ|w"*h6bm|猑 WAS!RI(A~L󡵛̺8:o@@ n:!6!:9n1AHlqCuݫ䦍k'X;}^hnܺxpo/cIaW8il ( " ;}6g䗳 ) RBt pkVY kt+^lK.c[knxX )K5cެX} W7 }{leWi&q'ǂKS^G`lJ(VȳiH A@"HB$E2"`(SNYm[ؚǂ0| GqÍ+*8O/yu-?|_qaaؓ,Y~wz+&m F[-"S)PO|+S&()  !D]dGȿ3 )>ׂ{2 oO}N6X䞋ϾZwp,=Ϗϳ<.ipa-OY"rq=鸳gxOWm}pX QTwF{lAdp "GN<@ deGipNs^#]RVl9`Cqꎷ;0YW]y7yJ _k7>VyEk>uCCՉZ*ZzvU8nAJ%AIQ*PJEAUBTBXFPDE* ฅ8D6ѭشqƷY7 ی]r^2'g?63y#U~2 ȎJ̙3c2>˾;}buCIklDIR bRB5)HMB 9b%FdC| $6Il ?,6<пCY[:f߶iuK,޷G܌ gB}_̗>z˳ |(tA$XVPF:ݟ$դphV9݆auCk=? im?\}/o~$H' ** )}F2 `N۪+]SpK"T7]J|`7+U"Ö;DT)*zz=DP,B_GET!9[W86zu*bb9BXQ,(HB>u3;4k<7w9mvۿ-ڃ{[ȄxfH%;\:f XyфH Halide-13.0.4/apps/HelloAndroid/res/values/000077500000000000000000000000001417234750700203765ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroid/res/values/strings.xml000066400000000000000000000001611417234750700226070ustar00rootroot00000000000000 HelloHalide Halide-13.0.4/apps/HelloAndroid/src/000077500000000000000000000000001417234750700170755ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroid/src/com/000077500000000000000000000000001417234750700176535ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroid/src/com/example/000077500000000000000000000000001417234750700213065ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroid/src/com/example/hellohalide/000077500000000000000000000000001417234750700235605ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroid/src/com/example/hellohalide/CameraActivity.java000066400000000000000000000030031417234750700273240ustar00rootroot00000000000000package com.example.hellohalide; import android.app.Activity; import android.os.Bundle; import android.hardware.Camera; import android.util.Log; import android.widget.FrameLayout; import android.view.SurfaceView; public class CameraActivity extends Activity { private static final String TAG = "CameraActivity"; private Camera camera; private CameraPreview preview; private SurfaceView filtered; public static Camera getCameraInstance() { Camera c = null; try { c = Camera.open(); } catch (Exception e) { Log.d(TAG, "Could not open camera"); } return c; } @Override public void onCreate(Bundle b) { super.onCreate(b); setContentView(R.layout.main); // Create a canvas for drawing stuff on filtered = new SurfaceView(this); // Create our Preview view and set it as the content of our activity. preview = new CameraPreview(this, filtered); FrameLayout layout = (FrameLayout) findViewById(R.id.camera_preview); layout.addView(preview); layout.addView(filtered); filtered.setZOrderOnTop(true); } @Override public void onResume() { super.onResume(); camera = getCameraInstance(); preview.setCamera(camera); } @Override public void onPause() { super.onPause(); if (camera != null) { preview.setCamera(null); camera.release(); camera = null; } } }Halide-13.0.4/apps/HelloAndroid/src/com/example/hellohalide/CameraPreview.java000066400000000000000000000100651417234750700271570ustar00rootroot00000000000000package com.example.hellohalide; import android.hardware.Camera; import android.util.Log; import java.io.IOException; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.Surface; import android.content.Context; import android.graphics.Canvas; import android.graphics.ImageFormat; /** A basic Camera preview class */ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback, Camera.PreviewCallback { private static final String TAG = "CameraPreview"; private Camera mCamera; private SurfaceView mFiltered; private byte[] mPreviewData; private int mCameraOrientation; // Link to native Halide code static { System.loadLibrary("HelloAndroid"); } private static native void processFrame(byte[] src, int w, int h, int orientation, Surface dst); public CameraPreview(Context context, SurfaceView filtered) { super(context); mFiltered = filtered; mFiltered.getHolder().setFormat(ImageFormat.YV12); mPreviewData = null; // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. getHolder().addCallback(this); } public void onPreviewFrame(byte[] data, Camera camera) { if (camera != mCamera) { Log.d(TAG, "Unknown Camera!"); return; } if (mFiltered.getHolder().getSurface().isValid()) { Camera.Size s = camera.getParameters().getPreviewSize(); processFrame(data, s.width, s.height, mCameraOrientation, mFiltered.getHolder().getSurface()); } else { Log.d(TAG, "Invalid Surface!"); } // re-enqueue this buffer camera.addCallbackBuffer(data); } private void startPreview(SurfaceHolder holder) { if (mCamera == null) { return; } try { configureCamera(); mCamera.setPreviewCallbackWithBuffer(this); mCamera.setPreviewDisplay(holder); mCamera.startPreview(); } catch (Exception e){ Log.d(TAG, "Error starting camera preview: " + e.getMessage()); } } private void stopPreview() { if (mCamera == null) { return; } try { mCamera.stopPreview(); } catch (Exception e){ // ignore: tried to stop a non-existent preview Log.d(TAG, "tried to stop a non-existent preview"); } } private void configureCamera() { Camera.Parameters p = mCamera.getParameters(); Camera.Size s = p.getPreviewSize(); Log.d(TAG, "Camera Preview Size: " + s.width + "x" + s.height); p.setPreviewFormat(ImageFormat.YV12); if (mPreviewData == null) { int stride = ((s.width + 15) / 16) * 16; int y_size = stride * s.height; int c_stride = ((stride/2 + 15) / 16) * 16; int c_size = c_stride * s.height/2; int size = y_size + c_size * 2; mPreviewData = new byte[size]; } mCamera.addCallbackBuffer(mPreviewData); mCamera.setParameters(p); } public void surfaceCreated(SurfaceHolder holder) { Log.d(TAG, "surfaceCreated"); startPreview(holder); } public void surfaceDestroyed(SurfaceHolder holder) { Log.d(TAG, "surfaceDestroyed"); stopPreview(); } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { Log.d(TAG, "surfaceChanged"); stopPreview(); configureCamera(); startPreview(holder); } public void setCamera(Camera c) { if (mCamera != null) { mCamera.stopPreview(); } mCamera = c; android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); // Assume that we opened camera 0 android.hardware.Camera.getCameraInfo(0, info); mCameraOrientation = info.orientation; if (mCamera != null) { startPreview(getHolder()); } } } Halide-13.0.4/apps/HelloAndroid/src/com/example/hellohalide/FrameHandler.java000066400000000000000000000004711417234750700267550ustar00rootroot00000000000000package com.example.hellohalide; import android.hardware.Camera; import android.util.Log; public class FrameHandler implements Camera.PreviewCallback { private static final String TAG = "FrameHandler"; public void onPreviewFrame(byte[] data, Camera camera) { Log.d(TAG, "Got a frame!"); } }Halide-13.0.4/apps/HelloAndroidCamera2/000077500000000000000000000000001417234750700175015ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroidCamera2/.gitignore000066400000000000000000000001501417234750700214650ustar00rootroot00000000000000.gradle/** gen/** gradle_build/** *.iml local.properties obj/** proguard-project.txt project.properties Halide-13.0.4/apps/HelloAndroidCamera2/AndroidManifest.xml000066400000000000000000000027741417234750700233040ustar00rootroot00000000000000 Halide-13.0.4/apps/HelloAndroidCamera2/README.md000066400000000000000000000100671417234750700207640ustar00rootroot00000000000000HelloAndroidCamera2 is a simple application which uses Halide to process images streamed from the Android camera2 API. It reads every frame into the CPU via an ImageReader and uses Halide to either blit the frame to the output surface (converting between YUV formats), or apply an edge detector on the luma channel. This example requires a phone or tablet that supports the camera2 API (Android API level 21 or above). This sample has been tested on Nexus 5, Nexus 6 and Nexus 9. CAVEAT: This example uses the not-so-well-documented ANativeWindow C API to directly write into the graphics buffers that support the Java "Surface" and "SurfaceView" classes. In particular, we rely on the YV12 format and use the ANativeWindow API to "reconfigure" buffers so that they do not have to match the resolution of the display. This exploits the hardware scaler to resample the displayed image. However, although camera2 reports a set of supported resolutions for ImageReader, there is no such enumeration for the display. On untested devices, chooseOptimalSize() may return camera resolution for which there is no matching graphics resolution. This will lead to a green screen with a logcat error message that looks something like: E/halide_native( 6146): ANativeWindow buffer locked but its size was 1920 x 1440, expected 1440 x 1080 This application builds for multiple native ABIs. (At present armeabi, armeabi-v7a, arm64-v8a, mips, x86_64, and x86 are supported. mips64 is not presently working.) Halide code is generated for each architecture. This build is meant to use Android command line tools. (An IDE is not required.) In order to build, the following will be required: - Android NDK -- This can be downloaded here: https://developer.android.com/tools/sdk/ndk/index.html After installing, make sure the top-level directory of the install is in the PATH. (It should contain an executable ndk-build file.) - Android SDK -- This can be downloaded here: http://developer.android.com/sdk/index.html The standalone SDK is desired. Once downloaded, the "android" program in the tools directory of the install will need to be run. It should bring up a UI allowing one to choose components to install. HelloAndroidCamera2 currently depends on the android-21 release. Make sure the tools directory is on one's PATH. - Apache Ant -- which can be downloaded here: http://ant.apache.org/bindownload.cgi make sure the bin directory is on one's PATH. If everything is setup correctly, running the build.sh script in this directory, with the current directory set to here, whould build the HelloAndroidCamera2 apk and install it on a connected Android device. # Gradle To use Gradle create local.properties file in this folder with sdk.dir and ndk.dir variables defined like so: ``` sdk.dir=/Users/joe/Downloads/android-sdk ndk.dir=/Users/joe/Downloads/android-ndk ``` After that run `gradlew build` which will produce .apk file ready for deployment to the Android device. On Linux/Mac you can use `build-gradle.sh` to build, deploy and run this sample application. Pay attention to the list of platforms supported by your Halide installation. They are listed in jni/Application.mk APP_ABI variable and in build.gradle archs map. For example, if your Halide installation was built without mips support or without arm64-v8a, remove them from APP_ABI and archs. Both list and map should match, otherwise you will be getting compilation errors complaining about a missing halide_generated.h file: ``` :ndkBuild FAILED FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':ndkBuild'. ... Output: /private/tmp/7/halide/apps/HelloAndroidCamera2/jni/native.cpp:11:26: fatal error: deinterleave.h: No such file or directory #include "deinterleave.h" ``` # Android Studio To load project into Android Studio use "File/Import Project..." in Android Studio and point to apps/HelloAndroidCamera2/build.gradle file. You will have to edit automatically-generated local.properties file to add ndk.dir property so it points to your Android NDK installation as described in Gradle section above. Halide-13.0.4/apps/HelloAndroidCamera2/ant.properties000066400000000000000000000013251417234750700224020ustar00rootroot00000000000000# This file is used to override default values used by the Ant build system. # # This file must be checked into Version Control Systems, as it is # integral to the build system of your project. # This file is only used by the Ant script. # You can use this to override default values such as # 'source.dir' for the location of your java source folder and # 'out.dir' for the location of your output folder. # You can also use it define how the release builds are signed by declaring # the following properties: # 'key.store' for the location of your keystore and # 'key.alias' for the name of the key to use. # The password will be asked during the build when you use the 'release' target. java.source=7 java.target=7Halide-13.0.4/apps/HelloAndroidCamera2/build-gradle.sh000077500000000000000000000010101417234750700223630ustar00rootroot00000000000000#!/bin/bash # Gradle needs to know where the NDK is. # The easiest way is to set the ANDROID_NDK_HOME environment variable. # Otherwise, set ndk.dir in local.properties (even though the file itself says # that it's only used by ant). # However, if you run "android update" (say, via build.sh), this variable will # be clobbered. ./gradlew build && adb install -r gradle_build/outputs/apk/HelloAndroidCamera2-debug.apk && adb shell am start com.example.helloandroidcamera2/com.example.helloandroidcamera2.CameraActivity Halide-13.0.4/apps/HelloAndroidCamera2/build.gradle000066400000000000000000000133331417234750700217630ustar00rootroot00000000000000import org.apache.tools.ant.taskdefs.condition.Os // Avoid conflicts with Bazel on case-insensitive filesystems buildDir = 'gradle_build' repositories { jcenter() } buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.2.2' } } //////////////////////////////////////////////////////////////////////////////// // Use gradle's native C++ plugin to build the Halide generator. // // sources: defines all the C++ source files. We only have one SourceSet called // halide_generator. // // executables: we only make one binary called halide_generator. Here is where // we pass compiler and linker flags. // // binaries.withType: binaries is a collection, which in our case is just the // halide_generator executable. withType() filters the collection by type. // binary is the iteration variable. -> defines the body of the lambda: // for each binary: // for each halide_target / Android ABI mapping: // for each generator: // run the generator with -g and target set // make the later ndkBuild task depend on this task. apply plugin: "cpp" sources { halide_generator { cpp(CppSourceSet) { source { srcDirs "jni/" include "deinterleave_generator.cpp" include "edge_detect_generator.cpp" } source { srcDirs "../../tools" include "GenGen.cpp" } } } } executables { halide_generator { binaries.all { cppCompiler.args "-std=c++17", "-g", "-Wall", "-fno-rtti", "-I", "${projectDir}/../../include", "-I", "${projectDir}/../../build/include" // "/bin" assumes Makefile build for Halide; "/build/lib" assumes CMake build linker.args "-lHalide", "-ldl", "-lpthread", "-lz", "-L", "${projectDir}/../../bin", "-L", "${projectDir}/../../build/lib" } } } binaries.withType(NativeExecutableBinary) { binary -> def bin = "${projectDir}/bin" def linkTask = binary.tasks.link println "linktask output file is " + linkTask.outputFile Map archs = [ // armeabi and armeabi-v7a are the same as far as Halide is concerned "armeabi": "arm-32-android", "armeabi-v7a": "arm-32-android", "arm64-v8a": "arm-64-android", "mips": "mips-32-android", "x86_64": "x86-64-android-sse41", "x86": "x86-32-android" ] def generators = ["deinterleave", "edge_detect"] archs.each { arch -> println "creating task for: " + arch.key + " -> " + arch.value def android_abi = arch.key def hl_target = arch.value def task_name = "generate_halide_binary_${binary.name.capitalize()}_${android_abi}" def destDir = new File(bin, "${android_abi}") def generateHalideTask = task(task_name) { dependsOn linkTask doFirst { println "Executing: " + linkTask.outputFile + " ..." destDir.mkdirs() def envVars = [ "DYLD_LIBRARY_PATH=${projectDir}/../../bin", "LD_LIBRARY_PATH=${projectDir}/../../bin" ] generators.each { generator -> def proc = [linkTask.outputFile, "-g", generator, "-o", ".", "target=$hl_target"] .execute(envVars, destDir) proc.waitFor() if (proc.exitValue() != 0) { println "return code: ${proc.exitValue()}" println "stderr: ${proc.err.text}" println "stdout: ${proc.in.text}" } } } } // Call this task generateHalideTask. binary.builtBy generateHalideTask // Tell gradle that the task called "ndkBuild" below depends // on generateHalideTask. ndkBuild.dependsOn generateHalideTask } println "done with archs" } //////////////////////////////////////////////////////////////////////////////// apply plugin: 'com.android.application' android { compileSdkVersion 21 buildToolsVersion "21.1.2" defaultConfig { applicationId "com.example.helloandroidcamera2" minSdkVersion 21 targetSdkVersion 21 versionCode 1 versionName "1.0" } compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_7 } sourceSets { main { java.srcDirs = ["src/"] // Setting jni.srcDirs to [] disables the automatic ndk-build call // which would use parameters defined in build.gradle. Use our own // task (ndkBuild) below. jni.srcDirs = [] jniLibs.srcDirs = ["bin/lib/"] // default is src/main/jniLibs manifest.srcFile "AndroidManifest.xml" res.srcDirs = ["res/"] // default is src/main/res } } // Call regular ndk-build (ndk-build.cmd on Windows) script from // app directory. task ndkBuild(type: Exec) { def ndkDir = project.android.ndkDirectory def ndkBuildCmd = "" if (Os.isFamily(Os.FAMILY_WINDOWS)) { ndkBuildCmd = "ndk-build.cmd" } else { ndkBuildCmd = "ndk-build" } commandLine "$ndkDir/$ndkBuildCmd", "NDK_GEN_OUT=./bin/gen", "NDK_LIBS_OUT=./bin/lib", "NDK_OUT=./bin/obj" } tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn ndkBuild } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } task wrapper(type: Wrapper) { gradleVersion = '2.2' } Halide-13.0.4/apps/HelloAndroidCamera2/build.sh000077500000000000000000000027551417234750700211500ustar00rootroot00000000000000#!/bin/bash set -e android update project -p . --subprojects --target android-21 if [ -z "$ANDROID_NDK_HOME" ]; then echo "Set ANDROID_NDK_HOME to point to your android ndk root directory" exit 1 fi mkdir -p bin c++ jni/edge_detect_generator.cpp ../../tools/GenGen.cpp \ -g -fno-rtti -Wall -std=c++17 \ -I ../../include -I ../../build/include \ -L ../../bin -lHalide -ldl -lpthread -lz \ -o bin/edge_detect_generator c++ jni/deinterleave_generator.cpp ../../tools/GenGen.cpp \ -g -fno-rtti -Wall -std=c++17 \ -I ../../include -I ../../build/include \ -L ../../bin -lHalide -ldl -lpthread -lz \ -o bin/deinterleave_generator # 64-bit MIPS (mips-64-android,mips64) currently does not build since # llvm will not compile for the R6 version of the ISA without Nan2008 # and the gcc toolchain used by the Android build setup requires those # two options together. for archs in arm-32-android,armeabi arm-32-android-armv7s,armeabi-v7a arm-64-android,arm64-v8a mips-32-android,mips x86-64-android-sse41,x86_64 x86-32-android,x86 ; do IFS=, set $archs HL_TARGET=$1 ANDROID_ABI=$2 mkdir -p bin/$ANDROID_ABI ./bin/edge_detect_generator -g edge_detect -o bin/$ANDROID_ABI target=$HL_TARGET ./bin/deinterleave_generator -g deinterleave -o bin/$ANDROID_ABI target=$HL_TARGET unset IFS done ${ANDROID_NDK_HOME}/ndk-build NDK_GEN_OUT=./bin/gen NDK_LIBS_OUT=./bin/lib NDK_OUT=./bin/obj ant debug adb install -r bin/HelloAndroidCamera2-debug.apk adb logcat Halide-13.0.4/apps/HelloAndroidCamera2/build.xml000066400000000000000000000076371417234750700213370ustar00rootroot00000000000000 Halide-13.0.4/apps/HelloAndroidCamera2/gradle/000077500000000000000000000000001417234750700207375ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroidCamera2/gradle/wrapper/000077500000000000000000000000001417234750700224175ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroidCamera2/gradle/wrapper/gradle-wrapper.jar000066400000000000000000001435121417234750700260370ustar00rootroot00000000000000PK UxE META-INF/PK UxE{MAVMETA-INF/MANIFEST.MFMLK-. K-*ϳR03-IM+I, dZ)%bµrrPK UxEorg/PK UxE org/gradle/PK UxEorg/gradle/wrapper/PK UxEhdf#org/gradle/wrapper/Download$1.class}M 0h5Z+v/ ׆p!.3̳{?~~&(P0MHa3e2&p lÐ|e;D-l ׽C!C"v=lrKOx RhO]!'"՞@yMB` !k>"APݶ-_}ɻDu_yks~ r[=*ek€a)? rg'U ewRĎw s'⥧Ǔ9JZ Y >HH,θ1Ppt1prUNN!;$ i}On->+ſC Of$#5;#*uJID)6j -5}+kY_1}h璥>C0EZQl\!@1JQ!NbN)R_p槩r'GڸS6[Kn0֢\V7pM^E\dMPK UxEXs"org/gradle/wrapper/IDownload.classE 0  ^b AP^26J;t>;ɗ|{z~+%5O&WΔ(a_4[gR#!XbQVg={}1AYCX'R5c/J$S@pP\mKulPK UxEz\Q-org/gradle/wrapper/GradleUserHomeLookup.classS[OAF]R(j[[ZU˪T Od .dYlW$jj>G5=R+ȃɹws??~XªQx)I)`^F\F ṂzQFRhMK K [A*_ɮoANϖvӟtp854˰ZsM0ݍ+e錞K{zahӱa{jr⿅ >4fڦ?(06 %L7k}8e*)v0 DqZ5*>F]m4xqNuj}g'-mZ0Zjw䜦[b!ڋ3)UD0A\>yIA$Rf MxfFӴ*e]ӫxwԯ x wuH𘗽P`{!!}%nx/ q}Jhͮ0,މ=q@{,Qzii“G7 !8CH3 `_[(`+8$U)<$4OZd4}/z@:CYׅ"D "Vv I (&%꿮)[|SW/9s ,n%BrUv/PK UxE] 3org/gradle/wrapper/ExclusiveFileAccessManager.classVKpem&im!@!PlP(ӂbhZ 6]ݍMK} >u蝣2#-XGGǃ://߷6?  Gw^D>tIq WiA9% NߏQ#583x6HSq0(3dD-*pWb~~֤':u$SzOut$%R1%+F.k[kP0vU 6E AJJΛ4lStAjfPM&$xf5)PVuU33ާX^{XXʴrdu56n)j/dbAS;4]mdBK1jOqڢnr-hkz,ceK(.<4̋y5cӘ![vnfF$Թ gPaL13 aД 5R96YK,Ap/]l \ak:rAC}ѫ .ZjMǗf}uUQebPMfA=YT[ {[K8Lb<sHi"3+/a2FXY22֯u{(2NS)G//T> 3h ڸ7B(^:Ga*{Pl6\;#4͠v )l y&ͳ`sua$&&s"\^&x3^9O&39qߝ}~9z(sL7R <7o :ǐG3ăVL=W_ߠ(~׉_hy?;Cr|1C_JV,9fx6'2!Ƽ!09'($)^RV-=wj$\7ud/j-'I%4۵ 2ۤG*1 <PK UxEc`-org/gradle/wrapper/WrapperConfiguration.classn@g8N7Ρ--@[QU6@QB[I*ؑSDC!fN, ?y~:9w(w7͋fzusY.xCCF4Ĩ75%c0.w*&UVVqF IJrN kxB \»'/;'k00#IR,TkA i CeG4G۳B1p3r중2SL6 zl'K9lF#N,wEc"Ұ(v 6[+U32vٸfL;6bfDt,f&6nh4# T;j nID5/G'"皶EY(sJhfZ)Ԭ&Yv숔XH`8BVXnə"Rd`KQW8kKtedTgȄejrm)3.oer$K.uڡz9Gp]LY[pcxb٧ NRzFKKSA7sȧy+:2`ligh鰑qUܠt~`fVT;j:V03v; glcJusyI\\+ؘ_b?ڭbA">qHǸY|u*qSr*-=~PqKǏIAtK.XڮG&`ۊ5K 2c3EݾH}tױHk/u5kXlH"5 "M;|L^x|I;Y%79R, [rng}zlj2 t᳼w2iIa%EVFi.OoΔu9mX<VM{ 7J/Q7و 70_C<.ȿ&(r>)U>'K۱T/) nEh<AXBC4E%/ADo_݃>蓛='O/6.6my">FA_ ,b` ("TCj;'JT|p3Q}4}gx[C8AP"AB;&ꇈ.JziE\"&?nqAKO8:aN>GbF'-&=eh=q /ӋONOp 7gBC8\QJ Xzc^sw PK UxErn&org/gradle/wrapper/PathAssembler.classVcWy8sصb',IS(ID*Nڸkk#o*ﺻĆr(}Z)Ĵ~][*7i73ߛ7ƿ8Rn) CQ(LٶdŋqQ[$'WRQܔ[2FA|$gR q|Sq|gEd| _Q|)/хUQ _1|Ko}q'C9y' XZqp\X(e*PsۃEqtGKC#3SÓG秦'sc$Fnh7lQ3 )0 LLwV+t&&ǟ:`k>ekY4|3}(4y0 TРJ =-u/g5ېur Bwek++ܥ~FLMvo 3zgF{(lMtwoIlquu 9&ilb\cEx{q֩|d/k%З˺h}(莫WrŒmkS? ;(PmVW ?suS^uu2(̆c΂9 s.nxSWXvq`w*CRPJ.d pQy<ŏT *5sxZSEnYO,Jע(żn ?gF*~! _k̻gMU1YN$K\E1pC_tCFGŸUU_xG.;`rkp Ⲃu;Y2]cYgU*擦&HܤaܤO>]aF(TdžKF Irfח7(In 3%I$K u`obM%Tw-5ִp-UhWf^A;]Tp!joCb1 Cݾ۫S(#-S:^p>if~y"c<{Fw12~C %FJ+yͥpD"s( 6]eL/-yk63u1Y;)-lé\}j_,iEfӚ~'lpv2:oFx *W p}nۺ?vV1r WpV8(z t ~J rC')q1μ}$i8ӳt,$0m6KOQηә2+{*{3D΅6b@|&2&qh q(c›v&vzROPdҭH-[!1PiaуUfWB 6.q\Kȱ [Fͅ=$Oq|}t]s,v玬s@14:,v-21)hbf1C,]gM>|C _kdqB]32Rռ$hbFhy'[ZpU<ћ!/b机A==HW=fd`TaF2fƓ jUڶaGy\Qy}ĿT8yN22IAүa=VBD=d+xﺔ%|4#j>K>GXy B:|P;XLJ|PK UxE org/gradle/wrapper/Install.classX |uO{j5t!-Xc tKX`l]%xGڑ#΂D8qppl'ihzM:n&8d[ѦuӴM&=N'=~mziCofOi1}o×_%- EO4ߒOKx4+)H=VuA^ Rȷ@+pfin (7KRƭ&MANٸE o Qr`AŻswo.# e a؊L@"1 ƃ_׸ˈ"2VV#QcFaB`@cIog|bMl,$LZo>=9i3ިaAU :gVBan&{ @UKmZ;h,. mBFh.ܰA!cfʚ]}MT JDϪQJVtA%YȡnP>)ܣr/)/~*.nVkE=AB=*!vV ,)gګ9~*_PPS:!?926_VU>/yD(]ꖑYKr^~T ?!֯.pHn{u׎C+\_(KƦOd:y#w\"s +A˾,uA+կoyEk.'S.~vG/8He*v^U`$36b?D\vG9XS fM 8iUၩd@Q RyՈKi;He=jAqݸ8H j 3a Ƣzn,rvB.&% i<[XO撶ϿIjLɃɗM=zI3uWǀmfWUfpFbr.oEBݹM\T[Jd6x{C\X̾S#ޑd\FyRe[(yE*#OQ >;2upIMEs~ޘo‡TMᔖ2-?Ǒ9IJ>k?B? >Pܟ3B9.{_ux-T%)֭*r H%:#v oMt3E"i_%t*Nq\ɝs+Ǥ+N>м@J"" @e-/R8D-q( C[(:Ȧ3%g(@~[iPbP>6O+hWu0Y-RE9 y[r^/gF*&LkՑgK?+v9:Gr|>!aG2=xMER0K4ܲ@ᶗ-HexZ^y 7N/]y֕PZ#Gp]TOcN;Z5ܳZ ;r3z(z 'yRqz ̔{/G^0/6t7xp[ok?䟧Hm _[Jy_֜Gc88u iQ4R}bafH? nҟH\۝U;hDz1?xoK)/"UGZ*h/jx*"汈uZS[/䛧'isԱHՖʭ 2_]E.P/^KtޠڐRy P`l8rwCs3/U;p8vp$L5Ч3p3wFO;~+賎۫k_LSMQ|HTx{[*iiy<GH~X M i*/:ID~*I,`jqgߺWl p-g$<ϞH`HN0!hF4  'üBLClxpf}8"ʚk\#`P'npHd\\5&#X?|jEV8]n`F oyexȿ@''/ 'Ck~R+g vt>\@N~d *$mpq84dB``E2h=@/:ib֎tZ V]D@Gߛ-=X36Xǜ@K_ iOQykO\}aA|2W[̿e(Hk" fEl__sDl/A7 b9 'fE\ߤ/Q܏=RUk BfW6Q跥ԀIv5)۾UwKJ>ܕ^SUvӟ:_C-+B'/?]Xh+E }3a1!8k?r1-I{H?PK UxEL -org/gradle/wrapper/BootstrapMainStarter.classVY[V=²l1pNSJ4 `:/FD,.iڗ6/|M/vd7w;s̽co/eqWF/f$/aVF+dü,aI1XzwMڴYV5#nͬI,_ m5F:-HO͌i:tV"0 ! a\~X@]T-B4 3L5HpO̎JTpP;"%5)%YҎ:l/O~1yn$۷5JьTL]f9dzByd.hNuT'[UzifJ9TV"܃ )xt\:JFvhؓDA| KAt'zEܪE=gϱ()xCM{T G >Ed4Ѕ׵m _+5rÏÏFyK7 wT92`fg̜ ԩ6 ڻ,R}5(Nimm;==荜+AU*tS(\z&+PUYȲ"Z?,S*O8TTp#]p7ZLgw)⾵,+̞;CנӺBͧ`Z%ܮqfLUE:jښq`>;|4{Dj6R\a(\K$"\&T)3զ@j1-2 X#5E|@-봋,:u;O`L!&;͡cԭ“?G1&1_҄7_&ƄM<'|@3LZ p0b CyJ&_1@$CҊC4}xWnM+vuon$"I&/OP1EѼtİyt,mbiory\ ˿+Z$|cqVv (Aq=:Mawxq1):L%>=ZYJDvPK UxEE C (org/gradle/wrapper/WrapperExecutor.classXw`#Grqlg;e3KHBh<^XNRYd82H[hX-mInh @Kҽ.{M}wg\߻7xO~p 0^k¸-ZBkeua>7(nQ(`ob֑2E6KCwλP=27~>e ø'ΏQtX5-_3u_1+4ɝ0|!c|E/ Jŗe1+Q|_FT/5:׵eohpǖ#Cý#c bZgVMtlMWl-goղE] ]R> K HVT o<$̼nن^Pĵh>m/Sm64ޥ4NY{4+GvhD9n\FwNcB~Ӛ蜰LVci$:sCS40sdjiZ4h{ iSpEk*Ow.RU [oԸn Lk٭e9G-=YzQ` EPpJWAN;I fJ]> (-ҵ#beJӚgi \l[JN9HlۦLYX}2þDm9)4cTIyrQw{}f'tۏNE*hk}:)ȉUW[Adg]i>-?G%(!͚ " :hT|" FMaFdSy"xzqkU>oP)kNVRFߩsMv;71M0 ҕ-Dwh:DUן Ze[v۪4CA,gߕ!{>H1gSz{6;iLBKEuWr7r[9h蘄,f3 Y{)w*Lq"?ן#SH́D.NԮHVvu/+}gn=(Izު[ǣ%iPQ7<>FeU 󅷵2/3sTExK{-q-<)[ z|O`pVgłg6^2g$_?T"/K8_wQ_}Ɠ*@((l4Nנ9dj}bnfv,SIG(Ұt vrek TP"!e~,%v#2F {|ĉ/ISzQL*=KE.{2n*IM"iKOAnIePp6碼iVcгS9~ݓү)깴^aV~qU:/|% 8 @)a[q Ø&,z1cڤ|j! Wܹ;1z^DѧDmGАHAcCS^`4:e2Mc VLTw[ŝ3ܽUޙCh^r IFK3گXJ-g?랪{1܏xI.)^%:Fi%T@ϟ ‰6Mڅ|.) '5Nq `ih1p`(j9N0{p;&[ЀW0J OM4 :Rfػ_5űS-ޭPm>K= W>PK UxE”" *org/gradle/wrapper/GradleWrapperMain.classX x^y#lA0,HBlBbllml됖VHWzwh6iӻ$me7nBϤMJ,-̼ ?#*v[|9@/T"r/V/^ŭr2/+REܯƫUUp :xD]wTNw VF/oRoVp&ܧbޢ*JpyvĻw=rxx@9ާ fU*¼)xXťxDi|؋3c >.~Bn>*7@zI )/Wi-r7g ŗ/ *:@Pუ}# ;<4|hPN?czb*8j%.35҆@xo߁P_obG4v xz. E`:>i$1C3zlLOF<豦) !39JꑘgUГ;F Ŝt KOkRE4_ڊƂ RO cƥf;aӖI1JڳDYG" 4,6qDi,"o-v4}F/_xoNU.A/],&eVB%(ӄG+B*RΒ\4BxV4n7)QRTjeF`gHV bq@ S5pLXGf<fSF`ƎEQ94y4\$ZMIvvNG+A3`$\JSt"B.unUA~JRbd C aW@jGDH 8~"VkzLb l!]FM4O\X,S,ձy`h>+,q*̬8@ jYPjZOu'q#aKhǝz qC.gܳ嬝vXXӎFJ.np8W}ɭj[؋u'1SbGwLc店 ;6%64Xvܽ2ͣ\-` (سJVvB<`Lpq G!!\o%E`*ÒPq Σ|b'e)މ2_ǧfP6>jR-,Ke~O[5sXީVG 2XN߻yDʶy sX3y4My%º tۅA3Y؈z` Zq q6Ѥ/q$ 7rKCKqta<_klĝ"ӓ(#0xC)=Ca頣AḝI!h36^(06߆Y9iKK /8U؀n[Rd WVE,mHZ⥷ ^lkypw`RZl`kepqաy\:>Ntށ<emsb;OgrWy6۲40ȵ\B(# QdfWGG A'N}]Xeugkocqe)ٷ)G/)6 rk`N'~^4ћEK#_M7Gud:W3M fڵ23T Ͻ Pc9Sӛ*x&nzWЕYE <YХ| ގ:'X9`X|<xrG(77}DBɓG:[ 8 V (dc' ޭ OiY(ԌZÊj!=]71mP VelӓNn l/薹6& EN]-$bpb Z"!pt4`&ԝfLr[(V<Mٙ>}=<+TӔv%$Kg`T+FΗ cp8p%zאg;ikefk>۔2lLb1sDDJr@ʧD(Ŷ,G`aÉ5K)73Q&}x243wLFyYzԜM- hʶ[)RLضVʎJy56QJf|t/x/t֪Xz ܄Z:LS7PqM5RW:e: o⬊ye]oCB҆Tn pNGX'ԇT|/T|T|o|Vy|? B'Mae܏B<'L8)~/>K*~e&vuL5KS/F&L[C|Fu&uVyice"?nOEWug]x5='_B{g`]bݯ%;IPLi)>ō-hS=iw/N9"KPodzzC밞7Ш %R8r "j %1xBUx/Q[Jk@SfƋtǒ!$R _Ge+iUԤ1 }!ԓTL| I X*捣b]Y~><%#8:# 4^Be֨b!RIcYq7*_b];{sLƱT** `# M)5_%.Uq{S,vݩp),jC٤dЕqK[[f A% R l"PS4 ianPoa`XD;Z>~l'C #S]~LEU+F^k%-؋m8,њ)·c;<<;Hla}$ IvPE#oD43ԧ7K`]N{7B7U2PK UxEj jV8org/gradle/wrapper/PathAssembler$LocalDistribution.classR[KAftq[yk[KA!|(L!N MJP?U<3Ҩ|ؙs.s˿ū9`OM}Q&m5ȏT0芟"VY~ܪ+Mc56-ډiK` {DjyT򏄽Ilֲ$,4T*? {M Fɡkmjs M%ydw-~[ؑ%Ru<[5'_n$6E<`=fAxwZIDډ?7 U46?S@h=W-ĝPK UxEۅ'9z !org/gradle/wrapper/Download.classVi[~GH0 0E%ncGNSHeuef䥛itItI׸mة-\C>/ m;I`=.s9,瞹:!"Ģt:.ࢊEl%$Gqux(Ⲏ6\U K&/ 7i F[r߫RokxMw4|W4|_*~xCś*~ HYp& WA_cٕ'޲|lGAtf3gO+PR vLؖ뙖7oʢEu|ԩI+h3Ki(Ħ.тi-='o-aۼp\>[y︂Cm+N9h[b\\ Bjg¼* zywvF3W"ѓe`9&'k[#ْ\@jFfST|Aif.[ÜpUj@%tUDAfؔ 2 ̧9e ĒRFxʋ΍3%\2c/&tJŸW)sfރĈ5bL;ywSVydsY*J7jD慕ں:zIFFlQx.Y.;Y!foVc qGpr8]HIV[O ?Wp:mE/ Uko I347FZHGc4d*h]Y#=}T_p_qCMo^-VĈ*XUqqV KX|F.UY1*mb]峢sElpG1a#P3 Xo*7>h xMz8SY[;[p, U4uޗxP_?wyֵuWx'ŢY.$4t-|Fce=cXB\qwvA)y6a u$oDROjFzWQ{[-݆̊u^|톦ࡆڭ:}Sn61nӪ$WjVD4=r2h*Z|Ge([]"}ov&=$ܹY}\yBy9züQ?ְ~189g$q|+{x]@* F W8vCމ0^D0/P)0m)L ~] w+=DנfUhwNj>rЏclU(I>[o@ŁU in$S3x)΃<`? j֕i%`G2hf mFm_Et<\A,$I5u vƃt'C׵9Cq2Gon}geޭwaW1[|c=E>ZvF*{ CCCp\G_hV:n|x5=V[!e(WcqS(AbHQ4gx3KE"RzHB,_#7 eP.e7(E(1J+S\EL33s4j?YKjܭ׸[r]~+eaN0OA*s,?75<2c}>{tl?d0v@>B5hGVt&8΄t&3j\Mgt=<́53 |IZ? )kOg^>Y S8Y^YBuG 0 ] 4GtnhרGPK UxEB=PN#gradle-wrapper-classpath.propertiesSO)IUHIM,RS/S02Q042126Vpv Q0204*(JM.)M/JLIM**+MPK UxE qbuild-receipt.properties=n JBv\zTU!&*@$7o<3]gL,ԏKf<Ε7RCNŷ,/z%~8Lǖy➏R7q=2^{?yZPK UxEorg/gradle/cli/PK UxE<S1org/gradle/cli/AbstractCommandLineConverter.classT]oA= +mt>BHhBem` Cߢ/42YPa9{s?p# 5ϕBy9yEx\Ye ZpՆaEjw I7|ZU c:tiw]HaٲzQdu;BrQfظ&DV\%6# ǹƙun]s̷X3ػe9H%ҲIk.=,ȍ-1ak^1蔕)9(id0^}y_7бp:%`i6t*㰊jBL F vUWm_ImuוD I8H7Լ&%DDՄ3qONB :ACvsπb0\8y 3CEw&T*kY+$@B!K͡5IYF6VANwh`+&XEKH,έQFV# J#hRq +dAy ~#TN*)oްOOSxΑ 86'??'k<ų@zV`PK UxE2_e(org/gradle/cli/CommandLineParser$1.classA 0EhZ v庈kCPEv-iIp.<S\p>?fxCDlnmMJ]k'iu#0BWՔ!f,By@wZ͕t!BI]#HI9|g|{ -|PK UxERB <org/gradle/cli/CommandLineParser$MissingOptionArgState.class]O`6d 2 c&/1N4`W5S/ ^H#2-sKƖ&9O״ 1UQ4%ի*gE)D15u KD10ؓp :@^3\ٲŪ+^1UqQ)B&@)ʊ! B@n!fU(AiW|ۤᲵMnR# yd8!>] ZEGO*%UoulGQ/\TMn˹-02#/hAlu@t%-q*2Nw e&BgsQ\gݧ-F͌& nX{~ϐ2zfZC R6A Ӱἆ%GAa3@Lv0Lc8~csC7]Saf=/b !i!WiXN$!9!:">i!z&|'d&w`8Ig9NOXFiХ uD5x Rl( 38qhKCO p:mO.6p'%0o %rC?7o@Ӹ<=@QO b쫇|CMa"!˰߰d^7Uܰ^t^EY3G5Dh8%h+aVE3D*PK UxEM2=org/gradle/cli/CommandLineParser$OptionStringComparator.classTOAfeam`ZPd) HJ  ަ Yvɛ{&ƳvBkj8tޛyo/ jѱcр%:UlQNJU-`!?`nbHzT(gHuO:{|"<Cbq,l ߷YqDݶ̚-M oyޕJ z-Qӹ|H Nl#Kݑ]:Պ}^!C ެ\kW=jA;W{D9!ŒeAS/@%ئRƾj n5nIJ dOcy_e[o9 =}&fH]ͰqiR-x/ rahf2=BF=Y \ KaڙdiZ_L*SHhpPsED?!Fq`pZl{ݺ=1#[s!B{./zi|CG1ǐIVy&$nR$B;C'r."{i"Llr".03m`Y(N͒V055QM<3t Ʃ`1< mcd3B= `OPK UxE# GK1org/gradle/cli/CommandLineArgumentException.classJ1O3Zm+Uו0tD23k*|(1IK-Y  2aEE9炧=OQzTqvK9fU v#tiˀFCb!ė*BE{2ȅ 9`)K,Ihh\x &J>p1YITةQcBW~ͿDcD y f@]tӻLA^%6uV18(c]3 2gy=ݴoa̝̩ kqv>PK UxE?h=org/gradle/cli/CommandLineParser$KnownOptionParserState.classXkx~dY&Vdsд!@LawL73ۙJ[^6V{zJB^֢Oy<}ߟ=gfvݰ?ܾs@;ޕw%!cL!XIy^l^^\OIcB w10X/LtL{$|Uz|={el}2oɷd|a=_P8? cu 'yy(agL K%yT¯$PkXk戄ٗmivOBsh['Xh43g~vt&@A˰qlŀ1bjn&5 wfbqԴ]L0 KB}qeF;zylXqLҟ;C Dl2XwiMU9^܀¬[2ԘnհT ky|qG\R-VlFtw[^ZpwL&tJ%Fڬuu[s-ά }A*I/m^E> @YK#m^:y}` b(`Vʎ7hZ8h W '̇۶g vGVlWpv(؉)BA 4.nS:vA :WV:ujմ\UTBq>:ȲI6)Oݦ%ݣ6uBsԤmq=ajl-N+8*7+xC bH”.k8e9tTij$ *9 cNsxF ^ ~ڛJjFN趾d/?BQ2xEE*~!Ů656ד#f"zHxS[,mUbj%pAMi /}2h4i-lӨo/F[Xulxz o,<#^Z<;^=F݉5y豖 g7eÿ%8#^+XLw6j=K֕ xr^ i/=Tqܼ42b6vc&>ܰh0g|,eŨCgm}C~Rqᦊl>hAdf^]2gbV% %jO2!ǃL&~spfc9OvtYSr\w 7V*9dpŮ[ [3Gҩ7~vOrDx (Sl}izKg:$D)ahJb9gP6hhVD +$D땐h<Y<*6JBx M'X>bAlwĶ%Y9!e} n/*XO߯i;BPK UxEk7org/gradle/cli/CommandLineParser$OptionComparator.classUmOP~nQ:oSD oe b0!c,Zvğ_Hb"6sJC{=9Ϲ~P4dW%,(c ^JX^IXu E ^3tmm2$r}d }w5C}5\ޱgVnkR,)XN];ڡ5P ЬC渺3y  ,#e}0Ђ/]i'jjV]zaՋ S6^~ u- TtY+y&duK< Y$jj7cv 2W[VAۛ+mS*(uB1lņ,i^\r 8;c =x\8npﹸvr CQo *]] 4|[Tuޒ%`anot.AAiU WGŵ S/co4<}u!TZi>Jv!a<@*QȒ̜!q ;G'.!v {nD<|ڊ֋1(Н0Q I9b|b$m:ݳtBHO\g3(W`iL9I k aXtβE$i,:AyLS)""J?QAX_PK UxEb'n?org/gradle/cli/CommandLineParser$UnknownOptionParserState.classURA==$a2@(""UZ`$SdL__\H*~7= B%q}q[A :0A0iDq5k rCw˺& ezabq [vJ%nWL[F ! ɕgY6rkk X>O 6E=}9A{gN)Ҧ>曖.^]S`{jHO~噎-pe}^^rJI=R7٠cSޒ{2iOcinی1^#r޲t1b7?4yvo=)L^)aFZ֜[c9*z'̼n$T BAa F&00 mGd6a4j3 C'/n{._VƵձ+1DX UR%H}4+.L_c=:"L32}F7>L`g%.dJ\)+QLgq.:K^dI׵{""¾j4e8 ț#u`@Ts䥓?|pP{fr mEhQr!"XOٯUVH/.\ 鋘6?9R?SͩUÕ@FcH:U1-NcjXc4Uy<blfq=PK UxE"zZ &org/gradle/cli/CommandLineOption.classV[sV˱E  cP@HICEUGT\Y S¤tCg'C~GVdٲKΞ՞ow=m;0%c:6Lu`; fx%p -xK ܆*cAF>ꩂ4!#x,ƠpG(ߍ%qKFI{dY5~G*n4gXBǔ^4Ubkֿn ,[7'yBQbeI3%5r&u#q2Qy[wHHSYJWɬjJf@H7h[Ҭ,J8ڲ -7ܨq&nԝR1GC (ONT4{Zj̨.2jyi~\PSDz5,žcKBO}p,̮V!^ԜUmH(Q"lbQ-#a("Zrw6 ivΝ=w _|dŦmTҜ1d{mC);BNDfQkikɄaXq2ЯܵRB7"$(XAy/A7A#>;:|(F ͹=U&KcEZP|yq- S+·\U|HQS$dú݄31TMZ@wťK) sAChU0^]<. uʓGa(M"%z.업cg"W=d1fIٔd}F6,O).a9Ţ,se,~Bٿŋ#H r."Y,3❂Ĕh%aG1C Bրަd0vN_y)]}C[m#U mO]ծ7!VWT{z,jVT, AfDm dUO kjUj38QESV-J-墨l۱n`KFO{3FDe4uI\6%Bl5ܸ`e۠<3-ԡLԖ!J9v ]F(=75sٛ5}?{^?ꎹbxm%;sf횳hmNIxoM&?: C]G(سbqu_u|C7u| Wuo+H-ekg{nl]u?Tp{j.g-ٯ:bJǏc~NC: u *~8%sӽ(z,>`u(]tѼLQq :~ :~ D OV\#ZFg,~!3CwHEnZG$]hec9gڝfl;+}<p;/o'_ cuլ7[s_+a {0{&`vN7s0ċʼnrsqf&8 *BW?=qc4㽔(M(D:"cסRS-t*݂*Rإ蚹n[H(^ZHRqh,{DRTzØ۸ύ;{W"9:L!YDaL^X8Џq/!G=If11<&|x'#ې8 H1"G)\MRtqItboOH·Ĥľ5!ߑ? !1Z\c\웎{F]ʇS=6\w.8 Ti߸ #W%#'!yr#1S8S06|38-I")XZ V z'*=#7ppNPJGfFM*vX! Bg鴏 ]5HgUR(sKX d1߰6kGDg6+! \<$/$Ӟæ<~xQ~L%s@T}wCG4x̯.Psn)"{T@wX ˌ菜58o]$EZЈ/g"%1B-)i~G-QFBJFn^$mPK UxEA5l| :org/gradle/cli/ProjectPropertiesCommandLineConverter.classKO@D|?Pâu#Q+$C;1m  JW&.(1D,9vo/[@yl汕G)v }FHWkwLS!]nY7ZK:̿cJDZRysV;H+-)nkS#cruLXgh|BjFYDΏ%L%񎅎*_?ֈ:("<ڄbJՍ ؊tf^*K ߵ XUVi01k p8wZ8T0g?PaΛm=C Ss | 1\Zq-}C_JEˉjE+ w'PK UxE2lWJForg/gradle/cli/CommandLineParser$CaseInsensitiveStringComparator.classS]oA=3|,bYŊ/b JbB$jBfmvƿŗ`|G,L C{ι=wo4<O2H%= Ttjnੁ}dK9*8b+' ; ]wI_zǢoS$u>(>*A[Ue/3n3̎Hm ߗzck쉡-,N3U?ϗ^i e;^{*΅e gl͑HC9Y\Y,X f.Ggab@HFSϢ/@tOL]u(#_k#ܩ7onaܾN25h8)Jeb[11_b7İ#j1lFד>^I>7ʢ0uI;, W/pdiM O: 䡟 I%'/;Lق)<$O#30VQ+qvC#B7>8^C~,rPK UxE( ]UT*&org/gradle/cli/CommandLineParser.classY |Tչrgn."Y"d% l&̄ *JZ^( 1uֶu}^m{k&ޙL.&Ǐ{Μ||͏;NDs ϟUN>:&5I֣AOk9ȺN9_64SQ\ϣP>hU>bNWOb&#S< Rt*eTRiS.+*S) f *9պ9<ϐOg괄i\2괜ktEBX%:#VXy2i|NZ>#*u2svv.+sy[/* [{m/ߍ2a|Ho\zoŢWN|6xXgΗ/c3[EY*m32u3LcWw&ñhc2::͸53M3hŠ&N+^nۣ]Q{rOXƤ4ގ/8\ipSQ}8lmMMA֤GGƨsDk+0-`jŭqci2V־LYH #ZL^n- +]nŅ LU̝fUW2[m5fRE1.NA]ov&nɮ84\=1mU6Eb񶪶#*GUe h)x6#خn1_ x0SbuƭfS@x;RCa )%jᄹ5bh8SR[kDYձՊBl*lF֛v0Ę ٞKr9"~LNY4d`+ndl? V* a%T+!h8 %/3A.~+ڂW"b˻/iDs61C^x:2,#">El5wMy]-t|Ъg+=6;;S Y5lays@HJFqz Fn+Fޭ f76^3;+fts.l|r9ВA,h%/S0碄'2=Sى oIJzL,bSIdXVHAX Գl4#]gEqnyU@C8fqNj4#pafkA𝞣Iv̸7λ-F-.X_Dfqv+ qr&޺ Ld"=.d[Z['m\vR>d b5a*3:l%͞4dh(E{TX,Ώ9Jg8,]H荱x3j8XIwt0 tA_;&xJvv%aS찷8a9i!‡3P'4x6!zx`gd_W{䳗zϵ՟J}_m5򵀸ܰ2s|B!7,ex|l-oۀe%ŒYe_; >wռL,;cg!#34Uhcq NpErA>d%C˷|o|?_anh毤b!%tuq˂ vIuW ?v%(mfunWt Vxp، [[pGY"ŋbdCMƒfKKq,cHMHdpxfYLh /kd~XFcѤBv3 uvx!@|^2s'|_55dbɦe{6u^Q߽ӽ-J ~߀Q% hȗC8#piB O<1oxp:bfTiIӻ^yӝHZx@EsFWxBI7RRl\.GdaƗ< 8ƹ1}šsn@v,2녃GfڝT6 QcLI[]avoz<1Ď.3!H +Yퟷø]LtmM8[Tҵ!ѝ%.*37l׷fbd&3{W -mv VW+,RYɴ5v|pJ\ 7c.W')ˤOWGYI7vi+ږlWa Ǣ hʁ2 &%n`j7nS[<չ!,fB|ô eC%DrϮOOGߍ4=6S-]JZGi+uS3]I-t#YȰVDY=K;~ )BQ(ND;\JIO]H;y#m͝t9+Ï^~ >\Wi?Ct=n?-W?$%{`Ȇ𽃦c8z#dLd= Yl: M'I9 +j `ߠ+ii^fZ~AG.,qTR=ϛC|4o[ǐG)QTgep/^t@gF$2/)3pKKwyX؇df^H  n^OW})Y[HVM]G?L 6иJKT'>(ɩ6de6jxa-~~WrWtD7(/oKi84\ -Ig!UDk~^SʈoҷlxVДeg>k˛utvCe_hLOtx+5ja=ޒcTX i*Pn+t >_arwsG&+_Ch}RO;AUQ[SsjP?69 k~E{-~uh h?wPK UxE_>ң)3org/gradle/cli/CommandLineParser$AfterOptions.classmOP( @ 1Q|Dt1wkծ5wE#]|!Je<1Mz99s۟PƊ'IW1!y &TU,2~=x6x !fu'\lkug!s6tL![/Hvfe׹[‘zdL[N!e`oyXuyej&!&)bA02]yr^5Vf6R\4dr] C0ԖQi26{{J.-ߏ޺&Ww{Ֆ/IU0ᘓ*3Le o13/#|]ˣ%D3zaS2u7XMc qaA78yWN*%1|avť-N x!*JB)>#iIShln|AjTDVИF(J9DRR; %܊1C!˩1(|GFJfKmt$F5kj|EFߧjr dY+!kmrQ>э=ep2n&0ft9\9E'tN* iϤK49hPK UxEGf3org/gradle/cli/CommandLineParser$OptionString.classSNA=]ʗ(U-e)'#  XlwD w+Bs;s=??~ &cAYs)TҘa! ei,pW]p_8 =[wfnsak璳bv0[=כ)m1$j^C0dlWv8Bv-(wAP ;e(|¯9<Zkߴ>o8ª;UZ-6d7_8'_AyKBkxy>Eӂ4Ui 1 z]A@Z Moz~]{*Ka:r摎, b^hxc+ ݥNC:`U L1r) ;{2̜?3zE9nB;;esy-w'i< MI^NN֤ʍЛh8Yq|9wvc 91Ȩ(` (OaʓbmDm>X1#Ka ~B>FJg!6l|;4 kaCԍx0r/iA';`CG G¡c#'30@ÌnmaF⺙igM1*[Ĥ=\E7i PK UxEx&T` ;org/gradle/cli/AbstractPropertiesCommandLineConverter.classV[wU L2悡5&I  i-4J`Ei+v fpfD{_ m\KWu dY\go}_p?H8"%ެHO%"ͧ= IX6@7=q|';y !H"r k7b0tuVɫ}%_&I cbj| f1\f)^2bYZ ڦbZ:c듶r*&2 M n8&M2jV)DĜ2W5( ,MIzn)嚺Re9hst4%D  Tmgv֭ttKzAm" e7tv٧) ٹW v"Qys;]^W/ypF,w5h}ے6&FOڕ.e`ZcCQ@Q,_Q+WDh2DDYFCF0-6j qdqțt+#y:*[0JZEf~]r~N WScXD\/ô.'Ƕk_4ЫTS!Wn[0( 5R%պ<a՝ISؾꢦ.Ci$h{wfЪCMx(t'9%f9o=,N=M柃B&; ﭣ/ N?gyO:aeJ^/F}o b b4kt"tZ3 яU0fx'ySr 6 aadB3 /)LF}Atc^l?$ͼA_ !7Vkg렾@ ‡CGGDoЅph.` (rroYJ]kKIrIn#)`,r|4 mYYBY-B1>q?PK UxE ,org/gradle/cli/ParsedCommandLineOption.classS[OA-"\A(-ʊP1!iĤoC;Ylw- &JD}G.I|9|93|`+)dPPQL!B0冊I,-,&q[~器+䲤⾊ {lqWAW-+ b^ f~,Cz2$J^YA4_T[Wjls6)5fn2Gsy;+c&k_2U`V]Rm4=a[T.ipoSP0/DND=t=Z+jpS0? KOrbjrjd0ajWKp &N&7YָE4Wl/xY92,BS*jx<Iy2=4yt Zce[ZҚE̙swy' :iB&1!CŴ3*f5$0b^E!YsMKc2\(4ff[\xf}f!?\t]($zr,.épx| luj6%;fOxզPɭq…% v2^l"P+ܧ8ش癄[2۟kVMa*W`sQ(r Q.$uv\ y;>ަVv[fnYx2=Y#X13:ncTŢ%,Xѱ5Pg),V5H3 K; 3'<<JڵSΐ!/g&W;;^ݸ v,ly/x-/TQZ]܉\E/˕=lk<RwgrŁtZ.=EPhh+"J6mL+"F~OA-, f1B 娆E$5"y  3@AU'2P*= QE3D5@}C2Pw'3y=RHI8[-vtn5@ $}_+:)+C EoPK UxE'H g)org/gradle/cli/CommandLineConverter.classQMK@}ԯ'"4 FM)HQ ޷lI7ݔ6MBya=t$S l)8A {Oyb :˄3I5' JXdT"qx{a/4OR1=Q615 ڹ6ƇEWbRh{'qj1M8zta,gZTRwZ\SYVSݜnhUYB/n/1Oz_G86\fjAʚajJuG-UʙeZ7^[u(5}2(Y٪Zk$N(@yA(تeٺip|0Xh5UUJ`[QtZw&~ժ:ѷ3<MSn9j*ߌq\6 G J*yN;{2#hfc f*SL Èaq!y" Ǘ axIbtxh.x%0&X}?:Ui4^}R֚Be*"nE& ̗he;*J"b68pÕ7rC.?V-0fO~^y뱉6{*B^*Y-z=:7CRyʍհjHC*dfN͔W{M ^pCMPzkt_gBR,]x;^Vw+eM+" ;zf7i^/O3}xb]C[B]d5c|Q%G7GO=m~} ҈'ҮOC.i^yb;30rؑ^!yڢ{f U5$:2lދ9eX Lm1 }IbR$Yy|M7PK UxE;|9org/gradle/cli/SystemPropertiesCommandLineConverter.classJ@ثmjE5BDąR/P~ӑ$&BJW 'iAY3͜l "lYlE <& d@HgL{:rRs:C*X4NĬQ ۴;hZ3a ѽG!]Gv7S"5eb o}ɸGtFMz9y~X{()spL`7e.KV, TXxɢfDTEGPWJmh~49AjxѰ sh gԙn85].FԒs9Q΢*s/@Ug J*ce+s+1 $p6/t-,;h-.Z >kZPK UxE-h2org/gradle/cli/CommandLineParser$ParserState.classSoPN) sT4706|3M$m f{@ú[s-?&>GmdiҞ|~pF62΢jv,-4WׄTqB0;%v=^(>{J` aŴ9,D!PK UxEF= ;org/gradle/cli/CommandLineParser$AfterFirstSubCommand.classVRPN[J;be-x)U.R(XE_( |gtPq猏C8I K0㟳{v|gw9| E͈4тHA/pK\3*B;ExqOH0ԛoB Нҍ\$gȫy%ͫ!k)USdqW5ռ0l%^--1x[+T^ɓğҳr~I6T/ =]kS1&U`fV Ҍ)F2/ Y88f-IMy$ M1eLo H2ڼ})MzٛZʑ"P\\y6O\}9ݲ'JBKeվm gËYzK/ Z1}**2 ~CG&1%`Z 3t9eaёgںokǔ@g%Ku`|G%E5e uS閻5ϗ4ڪ۲b}B\EU6:YPFJjh>3L578")&COH)YslH#?nA;ΙZwQW+S ^ͼ8W'AE[=|>>Јs6MMT > wH{im::^A:HG8d"Fx&O+\AX!vѸq HW69Z e+˝}с; \G7Ĺ(( ]LSh`cB p.9Bj1 D'($U<"z@'bj']GZ f<_PK UxE٥FDgradle-cli-classpath.propertiesSO)IUHIM,RS/S02Q042125Wpv Q0204*(JM.)**+MPK UxE AMETA-INF/PK UxE{MAV)META-INF/MANIFEST.MFPK UxEAorg/PK UxE Aorg/gradle/PK UxEAorg/gradle/wrapper/PK UxEhdf#org/gradle/wrapper/Download$1.classPK UxE[pDorg/gradle/wrapper/Download$SystemPropertiesProxyAuthenticator.classPK UxEXs"zorg/gradle/wrapper/IDownload.classPK UxEz\Q-dorg/gradle/wrapper/GradleUserHomeLookup.classPK UxE] 3 org/gradle/wrapper/ExclusiveFileAccessManager.classPK UxEc`-!org/gradle/wrapper/WrapperConfiguration.classPK UxEQ}i 0org/gradle/wrapper/SystemPropertiesHandler.classPK UxErn&org/gradle/wrapper/PathAssembler.classPK UxE Xorg/gradle/wrapper/Install.classPK UxEL -,org/gradle/wrapper/BootstrapMainStarter.classPK UxEE C (1org/gradle/wrapper/WrapperExecutor.classPK UxE”" *<org/gradle/wrapper/GradleWrapperMain.classPK UxE{x "Forg/gradle/wrapper/Install$1.classPK UxEj jV8Lorg/gradle/wrapper/PathAssembler$LocalDistribution.classPK UxEۅ'9z !Norg/gradle/wrapper/Download.classPK UxEB=PN#dVgradle-wrapper-classpath.propertiesPK UxE qVbuild-receipt.propertiesPK UxEAWorg/gradle/cli/PK UxE<S1)Xorg/gradle/cli/AbstractCommandLineConverter.classPK UxE2_e(Zorg/gradle/cli/CommandLineParser$1.classPK UxERB <[org/gradle/cli/CommandLineParser$MissingOptionArgState.classPK UxEM2=^org/gradle/cli/CommandLineParser$OptionStringComparator.classPK UxE# GK1aorg/gradle/cli/CommandLineArgumentException.classPK UxE?h=$corg/gradle/cli/CommandLineParser$KnownOptionParserState.classPK UxEk7Fkorg/gradle/cli/CommandLineParser$OptionComparator.classPK UxEb'n?hnorg/gradle/cli/CommandLineParser$UnknownOptionParserState.classPK UxE"zZ &qorg/gradle/cli/CommandLineOption.classPK UxEl\ϧ8|worg/gradle/cli/CommandLineParser$OptionParserState.classPK UxE#4P*&yyorg/gradle/cli/ParsedCommandLine.classPK UxEA5l| :org/gradle/cli/ProjectPropertiesCommandLineConverter.classPK UxE2lWJForg/gradle/cli/CommandLineParser$CaseInsensitiveStringComparator.classPK UxE( ]UT*&iorg/gradle/cli/CommandLineParser.classPK UxE_>ң)3org/gradle/cli/CommandLineParser$AfterOptions.classPK UxEGf3org/gradle/cli/CommandLineParser$OptionString.classPK UxEx&T` ;؝org/gradle/cli/AbstractPropertiesCommandLineConverter.classPK UxE ,org/gradle/cli/ParsedCommandLineOption.classPK UxEs=org/gradle/cli/CommandLineParser$OptionAwareParserState.classPK UxE'H g)org/gradle/cli/CommandLineConverter.classPK UxEC| <org/gradle/cli/CommandLineParser$BeforeFirstSubCommand.classPK UxE;|9.org/gradle/cli/SystemPropertiesCommandLineConverter.classPK UxE-h2org/gradle/cli/CommandLineParser$ParserState.classPK UxEF= ;Xorg/gradle/cli/CommandLineParser$AfterFirstSubCommand.classPK UxE٥FDgradle-cli-classpath.propertiesPK00qHalide-13.0.4/apps/HelloAndroidCamera2/gradle/wrapper/gradle-wrapper.properties000066400000000000000000000003461417234750700274540ustar00rootroot00000000000000#Wed Jul 15 16:34:43 PDT 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-2.2-all.zip Halide-13.0.4/apps/HelloAndroidCamera2/gradlew000077500000000000000000000116551417234750700210640ustar00rootroot00000000000000#!/usr/bin/env bash ############################################################################## ## ## Gradle start up script for UN*X ## ############################################################################## # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS="" APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" warn ( ) { echo "$*" } die ( ) { echo echo "$*" echo exit 1 } # OS specific support (must be 'true' or 'false'). cygwin=false darwin=false case "`uname`" in CYGWIN* ) cygwin=true ;; Darwin* ) darwin=true ;; esac # For Cygwin, ensure paths are in UNIX format before anything is touched. if $cygwin ; then [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` fi # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" # Need this for relative symlinks. while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`"/$link" fi done SAVED="`pwd`" cd "`dirname \"$PRG\"`/" >&- APP_HOME="`pwd -P`" cd "$SAVED" >&- CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD="$MAX_FD_LIMIT" fi ulimit -n $MAX_FD if [ $? -ne 0 ] ; then warn "Could not set maximum file descriptor limit: $MAX_FD" fi else warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi # For Darwin, add options to specify how the application appears in the dock if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi # For Cygwin, switch paths to Windows format before running java if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` SEP="" for dir in $ROOTDIRSRAW ; do ROOTDIRS="$ROOTDIRS$SEP$dir" SEP="|" done OURCYGPATTERN="(^($ROOTDIRS))" # Add a user-defined pattern to the cygpath arguments if [ "$GRADLE_CYGPATTERN" != "" ] ; then OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" fi # Now convert the arguments - kludge to limit ourselves to /bin/sh i=0 for arg in "$@" ; do CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` else eval `echo args$i`="\"$arg\"" fi i=$((i+1)) done case $i in (0) set -- ;; (1) set -- "$args0" ;; (2) set -- "$args0" "$args1" ;; (3) set -- "$args0" "$args1" "$args2" ;; (4) set -- "$args0" "$args1" "$args2" "$args3" ;; (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules function splitJvmOpts() { JVM_OPTS=("$@") } eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" Halide-13.0.4/apps/HelloAndroidCamera2/gradlew.bat000066400000000000000000000045441417234750700216250ustar00rootroot00000000000000@if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS= set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if "%ERRORLEVEL%" == "0" goto init echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto init echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :init @rem Get command-line arguments, handling Windowz variants if not "%OS%" == "Windows_NT" goto win9xME_args if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. set CMD_LINE_ARGS= set _SKIP=2 :win9xME_args_slurp if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* goto execute :4NT_args @rem Get arguments from the 4NT Shell from JP Software set CMD_LINE_ARGS=%$ :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega Halide-13.0.4/apps/HelloAndroidCamera2/jni/000077500000000000000000000000001417234750700202615ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroidCamera2/jni/Android.mk000066400000000000000000000013151417234750700221720ustar00rootroot00000000000000LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := HelloAndroidCamera2 LOCAL_ARM_MODE := arm LOCAL_SRC_FILES := \ AndroidBufferUtilities.cpp \ HalideFilters.cpp \ LockedSurface.cpp \ YuvBufferT.cpp LOCAL_LDFLAGS := -L$(LOCAL_PATH)/../jni LOCAL_LDLIBS := -lm -llog -landroid -latomic LOCAL_LDLIBS += $(LOCAL_PATH)/../bin/$(TARGET_ARCH_ABI)/deinterleave.a LOCAL_LDLIBS += $(LOCAL_PATH)/../bin/$(TARGET_ARCH_ABI)/edge_detect.a LOCAL_STATIC_LIBRARIES := android_native_app_glue LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../include $(LOCAL_PATH)/../../../build/include $(LOCAL_PATH)/../bin/$(TARGET_ARCH_ABI)/ include $(BUILD_SHARED_LIBRARY) $(call import-module,android/native_app_glue) Halide-13.0.4/apps/HelloAndroidCamera2/jni/AndroidBufferUtilities.cpp000066400000000000000000000066341417234750700254040ustar00rootroot00000000000000#include "AndroidBufferUtilities.h" #include #include #include "LockedSurface.h" #include "YuvBufferT.h" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "AndroidBufferUtilities", __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "AndroidBufferUtilities", __VA_ARGS__) extern "C" { JNIEXPORT jlong JNICALL Java_com_example_helloandroidcamera2_AndroidBufferUtilities_allocNativeYuvBufferT( JNIEnv *env, jobject, jint srcWidth, jint srcHeight, jobject srcLumaByteBuffer, jint srcLumaRowStrideBytes, jobject srcChromaUByteBuffer, jobject srcChromaVByteBuffer, jint srcChromaElementStrideBytes, jint srcChromaRowStrideBytes) { uint8_t *srcLumaPtr = reinterpret_cast( env->GetDirectBufferAddress(srcLumaByteBuffer)); uint8_t *srcChromaUPtr = reinterpret_cast( env->GetDirectBufferAddress(srcChromaUByteBuffer)); uint8_t *srcChromaVPtr = reinterpret_cast( env->GetDirectBufferAddress(srcChromaVByteBuffer)); if (srcLumaPtr == nullptr || srcChromaUPtr == nullptr || srcChromaVPtr == nullptr) { return 0L; } YuvBufferT *buffer = new YuvBufferT(srcLumaPtr, srcWidth, srcHeight, 1 /* srcLumaElementStrideBytes */, srcLumaRowStrideBytes, srcChromaUPtr, srcWidth / 2, srcHeight / 2, srcChromaElementStrideBytes, srcChromaRowStrideBytes, srcChromaVPtr, srcWidth / 2, srcHeight / 2, srcChromaElementStrideBytes, srcChromaRowStrideBytes); return reinterpret_cast(buffer); } JNIEXPORT jboolean JNICALL Java_com_example_helloandroidcamera2_AndroidBufferUtilities_freeNativeYuvBufferT( JNIEnv *env, jobject obj, jlong handle) { if (handle == 0L) { return false; } YuvBufferT *yuvBufferT = reinterpret_cast(handle); delete yuvBufferT; return true; } JNIEXPORT jboolean JNICALL Java_com_example_helloandroidcamera2_AndroidBufferUtilities_rotateNativeYuvBufferT180( JNIEnv *env, jobject obj, jlong handle) { if (handle == 0L) { return false; } YuvBufferT *yuvBufferT = reinterpret_cast(handle); yuvBufferT->rotate180(); return true; } JNIEXPORT jlong JNICALL Java_com_example_helloandroidcamera2_AndroidBufferUtilities_lockSurface( JNIEnv *env, jobject obj, jobject surface) { return reinterpret_cast(LockedSurface::lock(env, surface)); } JNIEXPORT jlong JNICALL Java_com_example_helloandroidcamera2_AndroidBufferUtilities_allocNativeYuvBufferTFromSurfaceHandle( JNIEnv *env, jobject obj, jlong lockedSurfaceHandle) { if (lockedSurfaceHandle == 0L) { return 0L; } LockedSurface *ls = reinterpret_cast(lockedSurfaceHandle); YuvBufferT tmp = ls->yuvView(); if (tmp.isNull()) { return 0L; } YuvBufferT *yuvBufferT = new YuvBufferT(tmp); return reinterpret_cast(yuvBufferT); } JNIEXPORT jboolean JNICALL Java_com_example_helloandroidcamera2_AndroidBufferUtilities_unlockSurface( JNIEnv *env, jobject obj, jlong lockedSurfaceHandle) { if (lockedSurfaceHandle == 0L) { return false; } LockedSurface *ls = reinterpret_cast(lockedSurfaceHandle); delete ls; return true; } } // extern "C" Halide-13.0.4/apps/HelloAndroidCamera2/jni/AndroidBufferUtilities.h000066400000000000000000000022131417234750700250360ustar00rootroot00000000000000#ifndef ANDROID_BUFFER_UTILITIES_H #define ANDROID_BUFFER_UTILITIES_H #include extern "C" { JNIEXPORT jlong JNICALL Java_com_example_helloandroidcamera2_AndroidBufferUtilities_allocNativeYuvBufferT( JNIEnv *env, jobject, jint srcWidth, jint srcHeight, jobject srcLumaByteBuffer, jint srcLumaRowStrideBytes, jobject srcChromaUByteBuffer, jobject srcChromaVByteBuffer, jint srcChromaElementStrideBytes, jint srcChromaRowStrideBytes); JNIEXPORT jboolean JNICALL Java_com_example_helloandroidcamera2_AndroidBufferUtilities_freeNativeYuvBufferT( JNIEnv *env, jobject obj, jlong handle); JNIEXPORT jlong JNICALL Java_com_example_helloandroidcamera2_AndroidBufferUtilities_lockSurface( JNIEnv *env, jobject obj, jobject surface); JNIEXPORT jlong JNICALL Java_com_example_helloandroidcamera2_AndroidBufferUtilities_allocNativeYuvBufferTFromSurfaceHandle( JNIEnv *env, jobject obj, jlong surfaceWrapperHandle); JNIEXPORT jboolean JNICALL Java_com_example_helloandroidcamera2_AndroidBufferUtilities_unlockSurface( JNIEnv *env, jobject obj, jlong surfaceWrapperHandle); } // extern "C" #endif // ANDROID_BUFFER_UTILITIES_H Halide-13.0.4/apps/HelloAndroidCamera2/jni/Application.mk000066400000000000000000000006131417234750700230550ustar00rootroot00000000000000# Can't use "APP_ABI = all" as 64-bit MIPS currently does not build since # llvm will not compile for the R6 version of the ISA without Nan2008 # and the gcc toolchain used by the Android build setup requires those # two options together. APP_ABI := armeabi armeabi-v7a arm64-v8a mips x86_64 x86 APP_PLATFORM := android-21 APP_STL := c++_static APP_CPPFLAGS := -std=c++17 -fno-rtti -fexceptions Halide-13.0.4/apps/HelloAndroidCamera2/jni/HalideFilters.cpp000066400000000000000000000136351417234750700235140ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "native", __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "native", __VA_ARGS__) #include "AndroidBufferUtilities.h" #include "HalideRuntime.h" #include "YuvBufferT.h" #include "deinterleave.h" #include "edge_detect.h" #define DEBUG 1 // Extern functions from the Halide runtime that are not exposed in // HalideRuntime.h. extern "C" int halide_host_cpu_count(); extern "C" int64_t halide_current_time_ns(); // Override Halide's print to use LOGD and also print the time. extern "C" void halide_print(void *, const char *msg) { static int64_t t0 = halide_current_time_ns(); int64_t t1 = halide_current_time_ns(); LOGD("%d: %s\n", (int)(t1 - t0) / 1000000, msg); t0 = t1; } extern "C" { bool checkEqualExtents(YuvBufferT *src, YuvBufferT *dst) { if (src->luma().width() != dst->luma().width() || src->luma().height() != dst->luma().height() || src->chromaU().width() != dst->chromaU().width() || src->chromaU().height() != dst->chromaU().height() || src->chromaV().width() != dst->chromaV().width() || src->chromaV().height() != dst->chromaV().height()) { LOGE("failed: src and dst extents must be equal.\n\t" "src extents: luma: %d, %d, chromaU: %d, %d, chromaV: %d, %d.\n\t" "dst extents: luma: %d, %d, chromaU: %d, %d, chromaV: %d, %d.", src->luma().width(), src->luma().height(), src->chromaU().width(), src->chromaU().height(), src->chromaV().width(), src->chromaV().height(), dst->luma().width(), dst->luma().height(), dst->chromaU().width(), dst->chromaU().height(), dst->chromaV().width(), dst->chromaV().height()); return false; } else { return true; } } JNIEXPORT bool JNICALL Java_com_example_helloandroidcamera2_HalideFilters_copyHalide( JNIEnv *env, jobject obj, jlong srcYuvBufferTHandle, jlong dstYuvBufferTHandle) { if (srcYuvBufferTHandle == 0L || dstYuvBufferTHandle == 0L) { LOGE("copyHalide failed: src and dst must not be null"); return false; } YuvBufferT *src = reinterpret_cast(srcYuvBufferTHandle); YuvBufferT *dst = reinterpret_cast(dstYuvBufferTHandle); if (!checkEqualExtents(src, dst)) { return false; } YuvBufferT::ChromaStorage srcChromaStorage = src->chromaStorage(); YuvBufferT::ChromaStorage dstChromaStorage = dst->chromaStorage(); bool succeeded; int halideErrorCode; // Use Halide deinterleave if the source chroma is interleaved and destination chroma is planar. // Other, fall back to slow copy. if ((srcChromaStorage == YuvBufferT::ChromaStorage::kInterleavedUFirst || srcChromaStorage == YuvBufferT::ChromaStorage::kInterleavedVFirst) && (dstChromaStorage == YuvBufferT::ChromaStorage::kPlanarPackedUFirst || dstChromaStorage == YuvBufferT::ChromaStorage::kPlanarPackedVFirst || dstChromaStorage == YuvBufferT::ChromaStorage::kPlanarGeneric)) { // Copy the luma channel directly. dst->luma().copy_from(src->luma()); // Use Halide to deinterleave the chroma channels. auto srcInterleavedChroma = src->interleavedChromaView(); auto dstPlanarChromaU = dst->chromaU(); auto dstPlanarChromaV = dst->chromaV(); if (srcChromaStorage == YuvBufferT::ChromaStorage::kInterleavedUFirst) { halideErrorCode = deinterleave(srcInterleavedChroma, dstPlanarChromaU, dstPlanarChromaV); } else { halideErrorCode = deinterleave(srcInterleavedChroma, dstPlanarChromaV, dstPlanarChromaU); } succeeded = (halideErrorCode != halide_error_code_success); if (halideErrorCode != halide_error_code_success) { LOGE("deinterleave failed with error code: %d", halideErrorCode); } } else { (*dst).copy_from(*src); } return succeeded; } JNIEXPORT bool JNICALL Java_com_example_helloandroidcamera2_HalideFilters_edgeDetectHalide( JNIEnv *env, jobject obj, jlong srcYuvBufferTHandle, jlong dstYuvBufferTHandle) { if (srcYuvBufferTHandle == 0L || dstYuvBufferTHandle == 0L) { LOGE("edgeDetectHalide failed: src and dst must not be null"); return false; } YuvBufferT *src = reinterpret_cast(srcYuvBufferTHandle); YuvBufferT *dst = reinterpret_cast(dstYuvBufferTHandle); if (!checkEqualExtents(src, dst)) { return false; } static bool first_call = true; static unsigned counter = 0; static unsigned times[16]; if (first_call) { LOGD("According to Halide, host system has %d cpus\n", halide_host_cpu_count()); first_call = false; for (int t = 0; t < 16; t++) { times[t] = 0; } } // Set chrominance to 128 to appear grayscale. dst->fillUV(128, 128); auto srcLuma = src->luma(); auto dstLuma = dst->luma(); int64_t t1 = halide_current_time_ns(); int err = edge_detect(srcLuma, dstLuma); if (err != halide_error_code_success) { LOGE("edge_detect failed with error code: %d", err); } int64_t t2 = halide_current_time_ns(); unsigned elapsed_us = (t2 - t1) / 1000; times[counter & 15] = elapsed_us; counter++; unsigned min = times[0]; for (int i = 1; i < 16; i++) { if (times[i] < min) { min = times[i]; } } LOGD("Time taken: %d us (minimum: %d us)", elapsed_us, min); return (err != halide_error_code_success); } } // extern "C" Halide-13.0.4/apps/HelloAndroidCamera2/jni/LockedSurface.cpp000066400000000000000000000041451417234750700235030ustar00rootroot00000000000000#include "LockedSurface.h" // Defined in http://developer.android.com/reference/android/graphics/ImageFormat.html #define IMAGE_FORMAT_YV12 842094169 // Round x up to a multiple of mask. // E.g., ALIGN(x, 16) means round x up to the nearest multiple of 16. #define ALIGN(x, mask) (((x) + (mask)-1) & ~((mask)-1)) LockedSurface *LockedSurface::lock(JNIEnv *env, jobject surface) { LockedSurface *output = new LockedSurface; output->window_ = ANativeWindow_fromSurface(env, surface); if (int err = ANativeWindow_lock(output->window_, &(output->buffer_), NULL)) { ANativeWindow_release(output->window_); delete output; output = nullptr; } return output; } LockedSurface::~LockedSurface() { ANativeWindow_unlockAndPost(window_); ANativeWindow_release(window_); window_ = nullptr; } const ANativeWindow_Buffer &LockedSurface::buffer() const { return buffer_; } YuvBufferT LockedSurface::yuvView() const { if (buffer_.format != IMAGE_FORMAT_YV12) { return YuvBufferT(); } // This is guaranteed by the YV12 format, see android.graphics.ImageFormat. uint8_t *lumaPtr = reinterpret_cast(buffer_.bits); uint32_t lumaRowStrideBytes = buffer_.stride; uint32_t lumaSizeBytes = lumaRowStrideBytes * buffer_.height; uint32_t chromaRowStrideBytes = ALIGN(buffer_.stride / 2, 16); // Size of one chroma plane. uint32_t chromaSizeBytes = chromaRowStrideBytes * buffer_.height / 2; // Yes, V is actually first. uint8_t *chromaVPtr = lumaPtr + lumaSizeBytes; uint8_t *chromaUPtr = lumaPtr + lumaSizeBytes + chromaSizeBytes; return YuvBufferT(lumaPtr, buffer_.width, buffer_.height, 1 /* lumaElementStrideBytes */, lumaRowStrideBytes, chromaUPtr, buffer_.width / 2, buffer_.height / 2, 1 /* chromaUElementStrideBytes */, chromaRowStrideBytes, chromaVPtr, buffer_.width / 2, buffer_.height / 2, 1 /* chromaVElementStrideBytes */, chromaRowStrideBytes); } Halide-13.0.4/apps/HelloAndroidCamera2/jni/LockedSurface.h000066400000000000000000000013561417234750700231510ustar00rootroot00000000000000#ifndef LOCKED_SURFACE_H #define LOCKED_SURFACE_H #include #include #include #include "YuvBufferT.h" // Wraps an RAII pattern around locking an ANativeWindow. class LockedSurface { public: // Lock a Surface, returning a lock object, or nullptr if it failed. static LockedSurface *lock(JNIEnv *env, jobject surface); ~LockedSurface(); const ANativeWindow_Buffer &buffer() const; // If buffer() is a compatible YUV format, returns a non-null YuvBufferT. // Otherwise, output.isNull() will be true. YuvBufferT yuvView() const; private: LockedSurface() = default; ANativeWindow *window_; ANativeWindow_Buffer buffer_; }; #endif // LOCKED_SURFACE_HHalide-13.0.4/apps/HelloAndroidCamera2/jni/YuvBufferT.cpp000066400000000000000000000164301417234750700230320ustar00rootroot00000000000000#include "YuvBufferT.h" #include #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "YuvBufferT", __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "YuvBufferT", __VA_ARGS__) YuvBufferT::YuvBufferT(uint8_t *lumaPointer, int32_t lumaWidth, int32_t lumaHeight, int32_t lumaElementStrideBytes, int32_t lumaRowStrideBytes, uint8_t *chromaUPointer, int32_t chromaUWidth, int32_t chromaUHeight, int32_t chromaUElementStrideBytes, int32_t chromaURowStrideBytes, uint8_t *chromaVPointer, int32_t chromaVWidth, int32_t chromaVHeight, int32_t chromaVElementStrideBytes, int32_t chromaVRowStrideBytes) { assert(lumaPointer != nullptr); assert(chromaUPointer != nullptr); assert(chromaVPointer != nullptr); halide_dimension_t lumaShape[] = { {0, lumaWidth, lumaElementStrideBytes}, {0, lumaHeight, lumaRowStrideBytes}}; luma_ = Halide::Runtime::Buffer(lumaPointer, 2, lumaShape); halide_dimension_t chromaUShape[] = { {0, chromaUWidth, chromaUElementStrideBytes}, {0, chromaUHeight, chromaURowStrideBytes}}; chromaU_ = Halide::Runtime::Buffer(chromaUPointer, 2, chromaUShape); halide_dimension_t chromaVShape[] = { {0, chromaVWidth, chromaVElementStrideBytes}, {0, chromaVHeight, chromaVRowStrideBytes}}; chromaV_ = Halide::Runtime::Buffer(chromaVPointer, 2, chromaVShape); // See if chroma is stored according to a well known format. chromaStorage_ = ChromaStorage::kOther; // U and V must have the same extents and strides. if (chromaU_.width() == chromaV_.width() && chromaU_.height() == chromaV_.height() && chromaU_.dim(0).stride() == chromaV_.dim(0).stride() && chromaU_.dim(1).stride() == chromaV_.dim(1).stride()) { // If strides are exactly 2, check if they are interleaved. if (chromaU_.dim(0).stride() == 2 && chromaV_.dim(0).stride() == 2) { if (chromaU_.data() == chromaV_.data() - 1) { chromaStorage_ = ChromaStorage::kInterleavedUFirst; } else if (chromaV_.data() == chromaU_.data() - 1) { chromaStorage_ = ChromaStorage::kInterleavedVFirst; } } else if (chromaU_.dim(0).stride() == 1 && chromaV_.dim(0).stride() == 1) { // If element stride is 1, then they're planar. // If there is no space at the end of each row, they might be packed. // Check if one directly follows the other. if (chromaU_.width() == chromaU_.dim(1).stride() && chromaV_.width() == chromaV_.dim(1).stride()) { if (&chromaU_(0, chromaU_.height()) == &chromaV_(0, 0)) { chromaStorage_ = ChromaStorage::kPlanarPackedUFirst; } else if (&chromaV_(0, chromaU_.height()) == &chromaU_(0, 0)) { chromaStorage_ = ChromaStorage::kPlanarPackedVFirst; } } else { chromaStorage_ = ChromaStorage::kPlanarGeneric; } } } interleavedChromaView_ = Halide::Runtime::Buffer(); if (chromaStorage_ == ChromaStorage::kInterleavedUFirst) { halide_dimension_t chromaShape[] = { {0, chromaUWidth * 2, 1}, {0, chromaUHeight, chromaURowStrideBytes}}; interleavedChromaView_ = Halide::Runtime::Buffer(chromaUPointer, 2, chromaShape); } else if (chromaStorage_ == ChromaStorage::kInterleavedVFirst) { halide_dimension_t chromaShape[] = { {0, chromaVWidth * 2, 1}, {0, chromaVHeight, chromaVRowStrideBytes}}; interleavedChromaView_ = Halide::Runtime::Buffer(chromaVPointer, 2, chromaShape); } else if (chromaStorage_ == ChromaStorage::kPlanarPackedUFirst) { packedPlanarChromaView_ = chromaU_; packedPlanarChromaView_.crop(1, 0, chromaUHeight * 2); } else if (chromaStorage_ == ChromaStorage::kPlanarPackedVFirst) { packedPlanarChromaView_ = chromaV_; packedPlanarChromaView_.crop(1, 0, chromaVHeight * 2); } interleavedChromaView_.set_host_dirty(); packedPlanarChromaView_.set_host_dirty(); chromaU_.set_host_dirty(); chromaV_.set_host_dirty(); luma_.set_host_dirty(); } bool YuvBufferT::isNull() const { return luma_.data() == nullptr; } Halide::Runtime::Buffer YuvBufferT::luma() const { return luma_; } Halide::Runtime::Buffer YuvBufferT::chromaU() const { return chromaU_; } Halide::Runtime::Buffer YuvBufferT::chromaV() const { return chromaV_; } YuvBufferT::ChromaStorage YuvBufferT::chromaStorage() const { return chromaStorage_; } Halide::Runtime::Buffer YuvBufferT::interleavedChromaView() const { return interleavedChromaView_; } Halide::Runtime::Buffer YuvBufferT::packedPlanarChromaView() const { return packedPlanarChromaView_; } void YuvBufferT::copy_from(const YuvBufferT &other) { luma_.copy_from(other.luma_); if (interleavedChromaView_.data() && other.interleavedChromaView_.data()) { interleavedChromaView_.copy_from(other.interleavedChromaView_); } else if (packedPlanarChromaView_.data() && other.packedPlanarChromaView_.data()) { packedPlanarChromaView_.copy_from(other.packedPlanarChromaView_); } else { chromaU_.copy_from(other.chromaU_); chromaV_.copy_from(other.chromaV_); } } void YuvBufferT::fill(uint8_t y, uint8_t u, uint8_t v) { luma_.fill(y); fillUV(u, v); } void YuvBufferT::fillUV(uint8_t u, uint8_t v) { if (interleavedChromaView_.data() && u == v) { interleavedChromaView_.fill(u); } else if (packedPlanarChromaView_.data() && u == v) { packedPlanarChromaView_.fill(v); } else { chromaU_.fill(u); chromaV_.fill(v); } } namespace { Halide::Runtime::Buffer rotateBuffer180(Halide::Runtime::Buffer buf) { if (buf.data() == nullptr) return buf; halide_dimension_t shape[] = { {0, buf.dim(0).extent(), -buf.dim(0).stride()}, {0, buf.dim(1).extent(), -buf.dim(1).stride()}, }; return Halide::Runtime::Buffer(&buf(buf.width() - 1, buf.height() - 1), 2, shape); } }; // namespace void YuvBufferT::rotate180() { luma_ = rotateBuffer180(luma_); chromaU_ = rotateBuffer180(chromaU_); chromaV_ = rotateBuffer180(chromaV_); packedPlanarChromaView_ = rotateBuffer180(packedPlanarChromaView_); interleavedChromaView_ = rotateBuffer180(interleavedChromaView_); // Rotating the above two views effectively swaps U and V. switch (chromaStorage_) { case ChromaStorage::kPlanarPackedUFirst: chromaStorage_ = ChromaStorage::kPlanarPackedVFirst; break; case ChromaStorage::kPlanarPackedVFirst: chromaStorage_ = ChromaStorage::kPlanarPackedUFirst; break; case ChromaStorage::kInterleavedUFirst: chromaStorage_ = ChromaStorage::kInterleavedVFirst; break; case ChromaStorage::kInterleavedVFirst: chromaStorage_ = ChromaStorage::kInterleavedUFirst; break; default: // nothing break; }; } Halide-13.0.4/apps/HelloAndroidCamera2/jni/YuvBufferT.h000066400000000000000000000072301417234750700224750ustar00rootroot00000000000000#ifndef YUV_BUFFER_T_H #define YUV_BUFFER_T_H #include "HalideBuffer.h" #include "HalideRuntime.h" #include #include class YuvBufferT { public: enum class ChromaStorage { // UVUVUV... Interleaved U and V with element stride 2 // UVUVUV... and arbitrary row stride. // U and V have the same extents and strides. kInterleavedUFirst, // VUVUVU... Interleaved V and U with element stride 2 // VUVUVU... and arbitrary row stride. // U and V have the same extents and strides. kInterleavedVFirst, // U and V and stored in separate planes, with U first, followed // immediately by V. Element stride = 1, row stride = width. // U and V have the same extents and strides. kPlanarPackedUFirst, // V and U and stored in separate planes, with V first, followed // immediately by U. Element stride = 1, row stride = width. // U and V have the same extents and strides. kPlanarPackedVFirst, // U and V are stored in separate planes. // Element stride = 1, row stride = arbitrary. // U and V have the same extents and strides. kPlanarGeneric, // Some other arbitrary interleaving of chroma not easily classified. kOther }; // Make a null YuvBufferT. YuvBufferT() = default; YuvBufferT(uint8_t *lumaPointer, int32_t lumaWidth, int32_t lumaHeight, int32_t lumaElementStrideBytes, int32_t lumaRowStrideBytes, uint8_t *chromaUPointer, int32_t chromaUWidth, int32_t chromaUHeight, int32_t chromaUElementStrideBytes, int32_t chromaURowStrideBytes, uint8_t *chromaVPointer, int32_t chromaVWidth, int32_t chromaVHeight, int32_t chromaVElementStrideBytes, int32_t chromaVRowStrideBytes); YuvBufferT(const YuvBufferT ©) = default; bool isNull() const; Halide::Runtime::Buffer luma() const; Halide::Runtime::Buffer chromaU() const; Halide::Runtime::Buffer chromaV() const; ChromaStorage chromaStorage() const; // If chroma channels are interleaved, return an interleaved // Halide::Runtime::Buffer with: // - The host pointer pointing to whichever chroma buffer is first in // memory. // - Twice the width. // Otherwise, returns a Halide::Runtime::Buffer pointing to nullptr. Halide::Runtime::Buffer interleavedChromaView() const; // If chroma channels are planar and tightly packed (one directly // follows the other, with the same size and strides), then // returns a Halide::Runtime::Buffer with: // - The host pointer pointing to whichever chroma buffer is first in // memory. // - Twice the height. // Otherwise, returns a Halide::Runtime::Buffer pointing to nullptr. Halide::Runtime::Buffer packedPlanarChromaView() const; // Rotate the buffer 180 degrees. Cheap. Just messes with the strides. void rotate180(); // Copy the contents from another YuvBufferT void copy_from(const YuvBufferT &other); // Fill the buffer with a fixed YUV value void fill(uint8_t y, uint8_t u, uint8_t v); // Fill the chroma with a fixed UV value void fillUV(uint8_t u, uint8_t v); private: Halide::Runtime::Buffer luma_; Halide::Runtime::Buffer chromaU_; Halide::Runtime::Buffer chromaV_; ChromaStorage chromaStorage_; Halide::Runtime::Buffer interleavedChromaView_; Halide::Runtime::Buffer packedPlanarChromaView_; }; #endif // YUV_BUFFER_T_H Halide-13.0.4/apps/HelloAndroidCamera2/jni/deinterleave_generator.cpp000066400000000000000000000017021417234750700255020ustar00rootroot00000000000000#include "Halide.h" namespace { class Deinterleave : public Halide::Generator { public: Input> uvInterleaved{"uvInterleaved", 2}; // There is no way to declare a Buffer, so we must use Output instead Output result{"result", {UInt(8), UInt(8)}, 2}; void generate() { Var x, y; result(x, y) = {uvInterleaved(2 * x, y), uvInterleaved(2 * x + 1, y)}; // CPU schedule: // Parallelize over scan lines, 4 scanlines per task. // Independently, vectorize over x. result .parallel(y, 4) .vectorize(x, natural_vector_size(UInt(8))); // Cope with rotated inputs uvInterleaved.dim(0).set_stride(Expr()); result.specialize(uvInterleaved.dim(0).stride() == 1); result.specialize(uvInterleaved.dim(0).stride() == -1); } }; } // namespace HALIDE_REGISTER_GENERATOR(Deinterleave, deinterleave) Halide-13.0.4/apps/HelloAndroidCamera2/jni/edge_detect_generator.cpp000066400000000000000000000024431417234750700252720ustar00rootroot00000000000000#include "Halide.h" namespace { class EdgeDetect : public Halide::Generator { public: Input> input{"input", 2}; Output> result{"result", 2}; void generate() { Var x, y; Func clamped = Halide::BoundaryConditions::repeat_edge(input); // Upcast to 16-bit Func in16; in16(x, y) = cast(clamped(x, y)); // Gradients in x and y. Func gx; Func gy; gx(x, y) = (in16(x + 1, y) - in16(x - 1, y)) / 2; gy(x, y) = (in16(x, y + 1) - in16(x, y - 1)) / 2; // Gradient magnitude. Func grad_mag; grad_mag(x, y) = (gx(x, y) * gx(x, y) + gy(x, y) * gy(x, y)); // Draw the result result(x, y) = cast(clamp(grad_mag(x, y), 0, 255)); // CPU schedule: // Parallelize over scan lines, 4 scanlines per task. // Independently, vectorize in x. result .compute_root() .vectorize(x, 8) .parallel(y, 8); // Cope with rotated inputs input.dim(0).set_stride(Expr()); result.specialize(input.dim(0).stride() == 1); result.specialize(input.dim(0).stride() == -1); } }; } // namespace HALIDE_REGISTER_GENERATOR(EdgeDetect, edge_detect) Halide-13.0.4/apps/HelloAndroidCamera2/res/000077500000000000000000000000001417234750700202725ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroidCamera2/res/drawable-hdpi/000077500000000000000000000000001417234750700227755ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroidCamera2/res/drawable-hdpi/ic_launcher.png000066400000000000000000000222651417234750700257660ustar00rootroot00000000000000PNG  IHDRHHUGbKGDC pHYsgR vpAgHHy#IDATx͜y%Uuk:s瞛dFGDE(јhL$*O4qbFx*4Dno\U{:Ksڿ[kPW8LJl.zw8}j_ǘo,\; }s^!yC29VA p8:d1thf/ +Žp/%!:y*ܲrN]|<˨8*b!]zc9%9(!8 `ĝ{\s6)/QO6ů ):t6*.Yelz cܰÿ 9ÒP} |ճl" ӽGX?N֞!nذu_4mh0^w'eg1xu{{MyToFX0}r;V:4IIҢ:̑qA^x^֦ЀEś cå[ݚS$ԆRqїPVO>X0c)C=ass8zH5#Ǔ C"-3r2urO\NqNq4g<:d4Ż`3#H?z]L}ICԗtH;;_*5= vw~ؚrv-Y'ymYF:GW>Ōr<C1U*^^.x 8qyx,k/?aK^h–59OnAJw޻od2eԡ3^ c.=4} = u{ا>7nಛ_RCq 4fz/QG6xcWw|Q>v jm4f oh6ֱc*<ˡ#Ya, t/?=;6\QwuPA =5<թGj/\ &PRM,V8YY' mPb>sa^dJrjρb`SV%3SS1"qHge_%ë#rtHb6>C"%ƺ+Ũ@0bQT1R  Jfy`J9SvRݻ-s{‹Tb1HFq:ǣؾQf;S^rgt>vdDY2j2JCT3`2IT#щiFHĘ",-`=:@h WB'i(WZ|!ry8Xw^X%2)M2Djiǭ[w<][o|O/;+uytiTES*jVq25<ɡ.gZDv&l;7nS{vN>64Zr~懧?/rpxm/pj2{F ;E)Ҟ;ro[sw>Դ[j F>pWZ.aeh8R5DF̀2EyB2syJ :N˓ y'ѴY\w=oe}_@O[lɒhvlo>@{ffj{z[_ \[fR7xF]ԵiUss{]Z~ O|WrZ;&|O;o,Mc&%Ms(*5KeHCSY`!N,Qb |Lu#O=iWI;<<X$KI4z_?Y+\IIjBi֋UJj]_&ccd#Bt^gxe  yiεS$wlMY&$mwhvh{{zLh洛]fxҞ'K 훍WR0X! IxUj uhhxDnHcvl_?~CXQYQiL:˱{[VuO\6Ϫ)6M`IQ)ҞٜmڿOy=7RH c˄kǰ8q\! A^.RFr|^#N_:"Fw,dianvnuu݊>)gBReEu 8!xBe_ +&bDئRLi!Pf1@] `D-W>YE88B\$ (Oy/ j_ a9[0Ct E҇ξ B)WOkYLBCELEZ!A\ F .Kiu2fz(f7`R@x1a^ji4բL#Ì }>* DDv3 (xny2J;:WF *Hg1rץvWr!q3>^M#[ SMF 9ZѺ od { Z %t PBՀu11UD"XgA]oi_%i>@Yj!C_вXs:l6%6k}E"@|g W<17=}C+Y6PYFC=ThufxUG{W+,B8ƇWs֩M/a{Q*[V8fp} (q/-H/9t|o T'N/sA,.g͒S|?oZn-j= p?G(} +yward=Y3)(Fbl{{a2V`M5|[_%W?Kؽ#kcT[Hp͋ڟ_oaQ.zh?zW.bffc?=B(ɛ.c˄/|ɵxJϧ (憆x^̣XDAUNG1e*i-Ņ,h 4nB>8sW5_y^}'.]yFuEQ5Z]Kva^Ji&?@CL6`D;jq@S\y0OY)bPOdyyI7/ Gu<_8g/cE`qdk鳧>@L[lkb)L̈)^qAK] O2}VR`lwǯ O>eO 9YOHq?Ed^Kž-"T.@Uy{HlْP Y`2}3!/GY}0 g\j!0ɾߑiqFĠ0!M{upoyyFР!_k":|F 1*k2}Ml@Bhx~n\nS֐M_U~AthP@uPT#E!?@c)l`>"lXѲ8W5{~+)/U6J4DZ"o"5h*ƈ.d"'].y| fP;R>ۏ:s)TBGCH?|fvE13*]. %wiH[5&$ B[T6&BY5[WG5dT,Z"@ig,p |(NQtE;X=x_&BPW#\+Uե+\h[}W`Mҕl2굱R 0ZuAl~UQ6 FE>$5~tW"Q)hgC1+eXk-i>྇nV.94H|ˎ/y| LTC xO:}sJ'>"gW cD_wE_|L3slwhc֫Xl:N˯:߿Gt6DffJgYUiT]ZIK'kII6[규LR5z~߹fO.~Q :=jahueH~̻=ZXlE, sC~;p/U缛c:Pwz)14M׫~vϊ:l=W|kj,?/:F Y&,m\;hZY)Ǯ8'\w WV кpQcuP}Æ%+O$~h<δ]h^淿kt~~/Wu,g՚_<}9# +ʿ_g>s+C(lcTBTBT1V%o*Cg'#M=pûmڣD DWp$z#?fӃYrlmټG6O{A'?XӖgm|~^uUf-vըL1c1U֬[Ay~ix$I&|۵w?7rO^1/,/ueE UKaHM:E_?훭:љ㧵2@{.gbu̷>;?O }%/ᡇ 2vwegbWr_]lf]'ѹyKogv8ԕ8 _AMLttdesNh0Z?mC7HDŽ~!H1,_>$f;K5KX|1mk)̪ X42N|vvεv~Zׯ-[X,YfIz:8 ^r1SK&cػgF4n}Ulq5jf"+&P ?a|]OёtyK?P T|T 339"MdI%:TRIVjT*NJn5ƨ6N{yyI夽NGӣlS12Ku G.x%å#Z' /!X0=4XWjDLJz@SZ=OcsM5K!oͥ?i|kGڽMg|o]UBYQamAJ$tX 섇GC1'~XO聺y~D2qP=f%4juXDҘ% #cpLm(RIV&$V* **CjJ-"J,H`gk`z[%+oogPx9_K_5^I*Zp%J(YEu)´ `id];.wе "jm1B0! aC<"`#3y⏃p7le;T#D!rk Q**6*Ү)捌Phf q\T-%N"l smb1=W~/Pw娉 cbk%BuRZb) X|uo\YQc ͲMP*qT1EA2$PL(՚-͋آcL Ћ^ LaD;Pxa* ֭<|n;|:eeF /:H*B&F\kօ''4Nz.5a·M7}U]1aH(cc45ӻ8C^ׇF%P:ء?NЩ]fێ{6e=^Bbfdڻp[/mj܃][-3{Zre|d9˴ZV~K3$,k-Aٷ/8=]u?U/oWq/gؚozOeù衦OmӏCycιWZGZǭ_kDU G&&'شzm8M 7޸ok34ۅVm3'—f0F .O?t h|@|r%tEXtdate:create2011-09-22T09:32:32-07:00b%tEXtdate:modify2011-09-16T07:27:36-07:00wjTIENDB`Halide-13.0.4/apps/HelloAndroidCamera2/res/drawable-ldpi/000077500000000000000000000000001417234750700230015ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroidCamera2/res/drawable-ldpi/ic_launcher.png000066400000000000000000000052511417234750700257660ustar00rootroot00000000000000PNG  IHDR$$sRGBbKGD pHYsgRtIME  1 )IDATXõ{_Uu?kyonH $T ЎV,0Qґ)%R:V0H*ۊ2*Ih#J 0$M;{>{sK*3{g}w}lD{5ϝwdּ0rYoußߺko886;qz9Go}?z}jCd>PsegС^[_ S긬Ú7=Gݽi gfznqs)`7DQDy;od)""D!ۖ^7䬙==cdЭE2 pUլLŜ|>gvX O7A+ VD=d&!a!m[d?y(wl?z gLЊ{ b%%X-q$)QG 2 9:S;AN[_s)lxdwϲV3`Ȃ#_(͔V+١ A'[2\,pV_tn Cj9 zWG\)G 9uԒ)I3ptXXi3|󽷽rǤEq06_vz9nw;Q $ b:0a Il?X2밉t"{osミ|L ; QjZ5 QvF{1IĖ$H eXk5MS\& Ǟ{Dpo)L|71ϻ+1xW{~9pD>wp켼X?Tͨ=%" (U /bpb%hdp!6~MZ6_ws=O]pߟt~TkT}d3cˀ4bT ŢĀ4QđŦFjsN*ygOZwK*!i5Jc%UP%̪Xvc "Ċ")b374qđ4 QTQ@n sBEg9u2x8q(B2{)L~y,m,/9:ȬSp9ũq01CL)8YF8\1Oջh|gkxi:v9l9p)gejTD xm&FGevԻ2ro!\d{6]ѽE^i)Z)WUSN9eJ$ᄅQHw@M$w)¬38K θ4fϫ;]"H[U3%Q8ɟIamU4)Ip|j~~V>su)sؼ126OO"K5/ .װo<_uЁph_N,jLTLESY80%q-~7c_Vm MUL(i:h;^SQ99k ^ΘXJ*'3Sv\-iӍQr;H&$"a|SEFs|{}0(ɋ/^.׀0$H.7> J阮Tt7=ƱZ,s'P*4PbP3x4q<~#0{mj)J+ Xr 56]X©DY9AUgr&YmX+] +l:?/m}ܺ&b bmGi6̚&%<|{Y={ QO227SmTiݣoʋWGs~GgEWջ8tVl [8> >bD\uI$:'x?ve>R_rݩY"W]?8Q?}y|O]wɟ]U1O'o "C!R,-}sZ6q:Iݷ}_>nY!Z-FU 8B&A_U=Q'ĉt:8 Gðz&e7&h׌oܿozFwozARJ~6ML 0EWov4[׾7_rxf%LYJ" ڳ {/N4JL@/_- pW~[?t 2V~2mfZ]i9F-I`SoxWe]\R/S,z*vdRd&JK<5Q'4χrweHQdiv2Ai·D%y"ŲGV\)iQurZ.PiS2xtu,JPR,e`q+wNL=Az{פs?REAĆX~/7=U[['30~̷jIENDB`Halide-13.0.4/apps/HelloAndroidCamera2/res/drawable-mdpi/000077500000000000000000000000001417234750700230025ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroidCamera2/res/drawable-mdpi/ic_launcher.png000066400000000000000000000121651417234750700257710ustar00rootroot00000000000000PNG  IHDR00WbKGDC pHYsgR vpAg00WIDATh޵YiU9o{^&IBA& ( "`b *HQdZTef !aJKHޔ7{V9gQvKZZ}^U}>vq<8cx%~UO|To=V| b0@@R\UA'TX}M'1x8ViZ"]J03o `Mz6 4hQ1GeZ,bH ($F:,,K9NԩhL\eXu߸cTj%׳Wc\zgtp DiD(mBSh^ GT!GUS[QCp(r) r_N;]#.uTȝp.SĶVZA˖dCi/?A*BD)Ѓ,RXİp`XpM=eԓբQ@s5{ym?n*S_M 8r\?CaAp#mz>S1GXĜ"i&6qV:' Xkޑ?*u w}N"ҢX{vcg?=YA" @A`9k-\ʈL9;GItKX"R>죎*@ kK  cwR[۱U*zRͨbc]a!&iH53sablظiu˗~<F+gog Ax!&T oرZxQ{|"seR D9EvdYF`cX3~d8҃}난\`ֶ/p`4 =kx'w=ta:\\c=&bT;<@ ձYPB<qo=c8 YK7^V5cT1_!6?#(²ŗ>"K|T`qd)QQZt:+*%vOҤD (DE Mᛗc8'MM}) jcRQ/JAgUfl!톹Rx?+Wm^=pl] '9(LEQ= Y5ʎ/!fs{H @ M1 xϝ+3(-س__y덫Z|8v];8:  qW̧2ooWMhmmVL]>TjIj]UF+wK]v0VJLPl ꛅիnƔ % 1%B_ɅT-:MNıC*WG å;xq0LhC0!Q=ɾäE!+Ԍwv∩P,fDINISrNt3C}l~򚂜BjFQl30@)42>·Hiq^ (4Ydj%q[!N"DHFN&*挸B;'S" Q}9=npra.fDP%sg,ٷ0M LISDf eʙ3~譈#q@SVäOțN,lh-Noǚb{Uh l^ōϔً̭H!xSCD#2!BHMHDy/1L iRGT< w? w? iʹs=N[5XuGpop`B-dK35#zsf\"C*-feVHm=qһC[#4y,d̟uF^7VlBav ^a/Y;҆VrhA!(Pd\fHBSD /[LK6&ph(xΌXW9鄈/)C) S>Ug "Ks`xɛUB@7)5fBjcv_u%(XG4Yɵxs&|'_~>>pGpؼOa2 ( !fa@# !rPT${J4P# 38gqK7$BG[|Rl|s pR/p{/A ۆRt1G~&y 6 l=\> HnG eH9f"ho #Sij)[S=}|Xc-ߊwGϝM2*ă="lM!\Lnd@jT$tAD, , jHU0w싋p}?c+oy0sւ7\ehENg?+kf+ Y*`tew05ׁ`T3+/j8#F5mFoA.ùP ^$i(^CgM/ 9EmJ,*d ZR&f Ez|gY)$e8xpPHKēg f+(i5nG p2^͑Y_5zFےլj́$& Bi-JR5Xt)ADPl}!';rl72|!0 `H$(.=/1q\s|YPAS4@ Dј@lK9 G(9x ['Ag5I=}pȞ/ qI ݉ۆ\r\jG͚=ͯg=o2Ļc%.ٱqo%tEXtdate:create2011-09-22T09:32:32-07:00b%tEXtdate:modify2011-09-16T07:27:36-07:00wjTIENDB`Halide-13.0.4/apps/HelloAndroidCamera2/res/drawable-xhdpi/000077500000000000000000000000001417234750700231655ustar00rootroot00000000000000Halide-13.0.4/apps/HelloAndroidCamera2/res/drawable-xhdpi/ic_launcher.png000066400000000000000000000340571417234750700261600ustar00rootroot00000000000000PNG  IHDR``w8bKGDC pHYsgR vpAg``x7XIDATx}w%Uoo휡9QTQA3*`#bz&8`Б"D Mjh龝'W9MouNݺ{[kKM~?f7ߍ=`l~[WT0 Qs!@2:}ҽdw%spz3J1?m*#^{ރUOP"{v)].C"UO2Ow]Y2%M9#N{kZn*@r:X|NTD1y6!B$ Ћ PC UhfA'lQOœԥx\ ^\z^.^c֭q wq.bw1O-C26kYW9YQ۶Ι;oLJށ}x  X%a&;4,ZHȢIMl!܆= G?:9T q1`GX+_`#mtъ7aGVaӚ tmȲ&z{v2h"y9fΜy1SisX'8=QQlh$X@8Xh1!X`XGEF~~y̪G[pܓ#+Zk[7FO><6ބZV>r6 ?npsg/]e(;n{ w(\a1Rax8Ee"L1b'cp>S p0Ք0n1'Q-<bh4/f햷X尵+iZ{sC^q;ѮncE 5B9^ VmM}cZ(K_|9Ka-pOP{#C_&E8^w8߿=jrF1G͊OpQlZӺOl\t1=b[{ޛ[(z㳗Vh( qYgԙO\/m?gG#JaO5h`ш,  b$A@P Dm,`;L,0΍C#>zH_㑇Źrrk =}$~GqFcڂ/ߝ9?|{T}d=9]CQGL1$B`800 f &t`.=dM:+?\v<@r¢0|оC@HYO?h#0_>`FnZW!7X6X.b0 *L>p F p`xXX8:u`Hr}exx{˷W=R3>~i#?ۋggml41^ b6k 3Covuu'(Na~\+:F!zP4D01 zXhؔ-sYcMAPα} sҏkJ` M6Nse8ݿ")&{_+وi&{Y{ˊGMLa*Bpֈh&5XtuVq+/wi?#x Ї(cz*Ի1HPfa5X`1IbY'@N?ͤ4P'uAЉÇ_lg'bIhv*Cd A ފ /"lr((‚0B  /; T,vf0 0 8^ $XHZ>2]7Kgn6F6:ӻ>TLތq* 615;=/`7ac(axЃtF+|88R^ ék1F[ca:5|Ȇ߯'y֢ql[|;vhjB2W- S= p\D)0XhXh1T 5#A `Xpяw ǀsgvH%K?;J@*$ݫ{gT.^},86u]0eF T!D͌pKX(ь0B`U ,00h $]wu8]#Y9Z-{knZs 0)tnTF$N3xfʓQƾKE.'3c4޷&9n6 s>f f2 DpΒlv7~/y.р=Ey 6Gg*#uW$LhpF@@px4fm6Lk$ЉOXmFL3⑘,SJKpObJa)X ! mCS5o3ວNEfqhϧS澞%g%嚭 ZUlUC#SXdՉE6COhݷю1YB#.FJ^<qRSHHQ &<_ȀW Sաx`6\fk757 X Ro3 HAPF 6L%"%ܦҮ2D73}oc P{a.@N+[v3;AD CmolU,e jA:@,-5ٜ?7_k U/? g֩[f(hD?3?L t-\J;<[/W`DƘ4"R&kc8k G7> ' b@ɭGޓ=!Zc ޱ5AcBZDA/dH)"cYĂ4K؁I9oZ&X`bbBwN$^D2\бXS=3+B(|iBUu a`4m\c Fjj"Mͩc4+%Q+GEaK:mdL[ڵ2]1iD~2:8ǰ}ԁ> f! f8vDdg>^8EOZ߱>I +ǀhۛ$-' D L>'9]u9a(9K:0p`f8ga5\ι~S@O#>%84!eo2AXHcOFqd 4C+V&"W#{EU>*0 mSBD9Cp6;Dh "o85K٫~g)l7_>2h5U&br<p_߿dqQ{a1 01lfpƍ?ͻMFshs\mIt4hK; u$jkmwc'KyvA&FZk\[2-`Mg i}j3hɬEYЪ.GF"^0@!I*@x `a|v_O} XBlƟQR DSi] cjXaTmozrYcuB:g=rb.m=sJL:O涶׎jL4瘘 qI*=wπ %ISMYTe1мN YF~|#&6<:`w;BHH$ w81gi_pFCRHr 1%~Ԛۧ3lc4`ù eϱ:%ˤ={b1mF3F4jj_# ̂7uN0 4[c}c#5V˹tKHc0jӀf2DH)3DzH\|͑ύ+̻QP FM"Dv8 n:0!9nxʰb>PT!3+0I}^ ҈3ť]uu\۱x6-|NR5Hi@Hb1e c;q/Wcw>`֍۰u'houlvkWFiNY /F\{sB`zU~JĿ7Vis axtX3.Lhh٪q+` $;ܡvrJ;ݶt#w. q{|I8b@J:q7 ;M;ֶ~7Ϡ iGձj'oP1O[g5;hΉN?yF}Y.U;۞i%>Z|xY=0ܢ +>Uՠ-BA@`D?jm|nclIwxir -LV\+.%, a 2Q!K‚@ E>a`-42<86IF(Q( J@PJ!*HDX b!*d OCVk:` #-ǔ"i:icFܲЉQҬ7eʼ7}+ڧlΝai#jYءՌl&h55gYsfb%Ռ`gTG+{ݶzX4tf36 b)PDRO&Q>VuU9ȃ޳ρ1k>GW Xغ. #[-LѬ[Ht0NH BP%z{==SBGr__?&זB˶nC_=t#iDAo}[YR(tns3jCܲW4UcjOo8p BHE 10 D*Q޾A*PBB}d3@NZY3N܇6~h#8&$C{4jT'cctɣ}(g33@1S.e7:Up1 rAM!s눝 zȳaB94͓K@hS?/SktyGS@;]Ք\)Bh;K%̺.fv0evۈce8ialrbޔ$vcV-#&~FtrCnh9fKxzlGE&bq= 4+2?k@MXZt%R"oEضp{HZS:нK_ra쉟M@lG%C0;ft X;3L( ٟ؏:aitY%Mqʇ`Q} ߕG<,aT n/+* )dΑL=3I}9-13pZZdAK[ fN]1[q+غ0ZY@Erh2fs`BFt`ff6ˇcP>ӏFyNFv03g$ &)+cxxո_lldɖz8BH}B@gh)w.83m"gvN?ҫ`23,Ă:C8;s&T1z;pS}Kf0 0:QL>i^@sLNpk`ՀoHl `X!Hg@`v:0JQP(Bm萖|LHLX8B\wIH!ӎ vYTWOS g)(X΀"mMDT ЭwWFv^m7$cE^=(qMtp##쐺 Tоٝ5wđ: '}]p--u8#/]w1!!RFX<ۑp )$~sxy+>> ?-SaLҖ|_ Xȍ-:=[,}j:QX9I ʢv$ٱbdJy^/E߀?B|[!|%ppaǀK,9>o)%qMWW^6߃C<yU8S!de pwE; xC" pgY&a@ɰ#I~qO_H$:H d P ,42>B3Xg/>M8M˾kn&>yKpޯY~› r񋫿o>O7&@;8bߋ4 ͒"zƬK; U;QsX:(J)BX͐ayC)VII@z6^!I#|v;wƾx+/Ɖ~)ᛸmٕXwܑbnFmʈg~8]ޕò^O#>:/%##t"$IWQ;O+bcbNzgcig"4N!Lp;:25ͤ zyٰc c5=/:_0wq y9:$`vB=-|Gu.:q̼HMnI(Н`fi~p4&K;g\BPL:Ob]Ju*7;;:&otiΡ:لNMg"p0o1 )]{VFw6}YgIHΥ-0IՔvh{ZtIΆ"G:y*KRPRM!"JC;a$@sd@`h*\ ]!Q<{뿍{{dIXk%,A,cuZNN</4 uL# |eɷߧi}nIods$ѡ`qf&:ȝ<+Y&ڷu; } `#i]:4H.ܡm~pv@G jΙ|I)7];0) !.' ewQڧ޶\QM)΁Kߙ96 yT,! ^ 93!mAڤD,>/ PρDqjNFlW0R2Vu`L+YuB j<ؤT (#O) JQݬZ%DH@%-b= ODP*+/@> snAa2r^!x =FڲeK0[Q?KIuWTYAYg1C1;q:PzPU[We'':*s)</-|n7( 3,c[RRt*f@4S p9S% jYoGX7<6$W. 0Y(">gYHk5[-Y :ie}13U(ڲ;8 K9kشn ??^bVddNx碟-7RBJѱ?o.&1cA"EgK1,=T( @ҬJX_,sJ~O$IP椴Y׌'?{|O]vr(zp/݌nw@6+Yݶh9p2~QᲪMhTͷ7S(dzyԊ FX`]8.Oau1VXm{>AYs{Po/?z٨] 'ckΟ ժ=ucZ7XWH:CY}ӥ(J Ϯ9t+OFsRJ0{Yd`:~\oLv۬ v|xe AP!CH܅5w۶\x+ߏ: zڙ"@d$q㭿ů6ySp n{Ī3K3I?7Oƣ/^?~߉•,nQ'~q_P,Fwq@"  PcނAtLp&?r戭 BHHp˝܏_Fp̘2d@~R@Fgx;:wqk!b0LE+a5aKU`S/rvhx`5hEϝpOFiS{! D*#/~WZؔПdT 5?_ W^kb~߫`5Vutm8#nB !,/_}5>}۱fh%D:+siox, :HPʯΑ3AHʉn:X;c3ГC[bH BkHͧx0N;aT*G0 mPX2 ̙tht~4<.{/BBh%kA!a̮69,Y'PظdjV7*%.Άxgy/_F0u pYٓ(%X, B:N:v[IWY`d6oޠ7wЦotJ*eSu YnLԆz U˿'yGC"P$,FO\RE"&*\x[p?*f&c߫=-Z.ʯd;,Uڑ(|X ۪h5 ,x @" lY32.yr~EDr6` ZmkV(.0Nsu鹐YJ|w"*h6bm|猑 WAS!RI(A~L󡵛̺8:o@@ n:!6!:9n1AHlqCuݫ䦍k'X;}^hnܺxpo/cIaW8il ( " ;}6g䗳 ) RBt pkVY kt+^lK.c[knxX )K5cެX} W7 }{leWi&q'ǂKS^G`lJ(VȳiH A@"HB$E2"`(SNYm[ؚǂ0| GqÍ+*8O/yu-?|_qaaؓ,Y~wz+&m F[-"S)PO|+S&()  !D]dGȿ3 )>ׂ{2 oO}N6X䞋ϾZwp,=Ϗϳ<.ipa-OY"rq=鸳gxOWm}pX QTwF{lAdp "GN<@ deGipNs^#]RVl9`Cqꎷ;0YW]y7yJ _k7>VyEk>uCCՉZ*ZzvU8nAJ%AIQ*PJEAUBTBXFPDE* ฅ8D6ѭشqƷY7 ی]r^2'g?63y#U~2 ȎJ̙3c2>˾;}buCIklDIR bRB5)HMB 9b%FdC| $6Il ?,6<пCY[:f߶iuK,޷G܌ gB}_̗>z˳ |(tA$XVPF:ݟ$դphV9݆auCk=? im?\}/o~$H' ** )}F2 `N۪+]SpK"T7]J|`7+U"Ö;DT)*zz=DP,B_GET!9[W86zu*bb9BXQ,(HB>u3;4k<7w9mvۿ-ڃ{[ȄxfH%;\:f XyфH Halide-13.0.4/apps/HelloAndroidCamera2/res/layout/fragment_camera2_basic.xml000066400000000000000000000015101417234750700266640ustar00rootroot00000000000000