| #!/bin/sh | 
 | ## Copyright (c) 2023, Alliance for Open Media. All rights reserved. | 
 | ## | 
 | ## This source code is subject to the terms of the BSD 2 Clause License and | 
 | ## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License | 
 | ## was not distributed with this source code in the LICENSE file, you can | 
 | ## obtain it at www.aomedia.org/license/software. If the Alliance for Open | 
 | ## Media Patent License 1.0 was not distributed with this source code in the | 
 | ## PATENTS file, you can obtain it at www.aomedia.org/license/patent. | 
 | ## | 
 | ##  This script checks the bit exactness between C and SIMD | 
 | ##  implementations of AV1 encoder. | 
 | ## | 
 | . $(dirname $0)/tools_common.sh | 
 |  | 
 | PRESETS="good rt" | 
 | LOWBD_CIF_CLIP="yuv_raw_input" | 
 | LOWBD_480p_CLIP="yuv_480p_raw_input" | 
 | LOWBD_720p_CLIP="y4m_720p_input" | 
 | HIGHBD_CLIP="y4m_360p_10bit_input" | 
 | SC_CLIP="y4m_screen_input" | 
 | OUT_FILE_SUFFIX=".ivf" | 
 | SCRIPT_DIR=$(dirname "$0") | 
 | LIBAOM_SOURCE_DIR=$(cd ${SCRIPT_DIR}/..; pwd) | 
 |  | 
 | # Clips used in test. | 
 | YUV_RAW_INPUT="${LIBAOM_TEST_DATA_PATH}/hantro_collage_w352h288.yuv" | 
 | YUV_480P_RAW_INPUT="${LIBAOM_TEST_DATA_PATH}/niklas_640_480_30.yuv" | 
 | Y4M_360P_10BIT_INPUT="${LIBAOM_TEST_DATA_PATH}/crowd_run_360p_10_150f.y4m" | 
 | Y4M_720P_INPUT="${LIBAOM_TEST_DATA_PATH}/niklas_1280_720_30.y4m" | 
 | Y4M_SCREEN_INPUT="${LIBAOM_TEST_DATA_PATH}/wikipedia_420_360p_60f.y4m" | 
 |  | 
 | # Number of frames to test. | 
 | AV1_ENCODE_C_VS_SIMD_TEST_FRAME_LIMIT=35 | 
 |  | 
 | # Create a temporary directory for output files. | 
 | if [ -n "${TMPDIR}" ]; then | 
 |   AOM_TEST_TEMP_ROOT="${TMPDIR}" | 
 | elif [ -n "${TEMPDIR}" ]; then | 
 |   AOM_TEST_TEMP_ROOT="${TEMPDIR}" | 
 | else | 
 |   AOM_TEST_TEMP_ROOT=/tmp | 
 | fi | 
 |  | 
 | AOM_TEST_OUTPUT_DIR="${AOM_TEST_TEMP_ROOT}/av1_test_$$" | 
 |  | 
 | if ! mkdir -p "${AOM_TEST_OUTPUT_DIR}" || \ | 
 |    [ ! -d "${AOM_TEST_OUTPUT_DIR}" ]; then | 
 |   echo "${0##*/}: Cannot create output directory, giving up." | 
 |   echo "${0##*/}:   AOM_TEST_OUTPUT_DIR=${AOM_TEST_OUTPUT_DIR}" | 
 |   exit 1 | 
 | fi | 
 |  | 
 | elog() { | 
 |   echo "$@" 1>&2 | 
 | } | 
 |  | 
 | # Echoes path to $1 when it's executable and exists in ${AOM_TEST_OUTPUT_DIR}, | 
 | # or an empty string. Caller is responsible for testing the string once the | 
 | # function returns. | 
 | av1_enc_tool_path() { | 
 |   local target="$1" | 
 |   local preset="$2" | 
 |   local tool_path="${AOM_TEST_OUTPUT_DIR}/build_target_${target}/aomenc_${preset}" | 
 |  | 
 |   if [ ! -x "${tool_path}" ]; then | 
 |     tool_path="" | 
 |   fi | 
 |   echo "${tool_path}" | 
 | } | 
 |  | 
 | # Environment check: Make sure input and source directories are available. | 
 | av1_c_vs_simd_enc_verify_environment () { | 
 |   if [ ! -e "${YUV_RAW_INPUT}" ]; then | 
 |     elog "libaom test data must exist in LIBAOM_TEST_DATA_PATH." | 
 |     return 1 | 
 |   fi | 
 |   if [ ! -e "${Y4M_360P_10BIT_INPUT}" ]; then | 
 |     elog "libaom test data must exist in LIBAOM_TEST_DATA_PATH." | 
 |     return 1 | 
 |   fi | 
 |   if [ ! -e "${YUV_480P_RAW_INPUT}" ]; then | 
 |     elog "libaom test data must exist in LIBAOM_TEST_DATA_PATH." | 
 |     return 1 | 
 |   fi | 
 |   if [ ! -e "${Y4M_720P_INPUT}" ]; then | 
 |     elog "libaom test data must exist in LIBAOM_TEST_DATA_PATH." | 
 |     return 1 | 
 |   fi | 
 |   if [ ! -e "${Y4M_SCREEN_INPUT}" ]; then | 
 |     elog "libaom test data must exist in LIBAOM_TEST_DATA_PATH." | 
 |     return 1 | 
 |   fi | 
 |   if [ ! -d "$LIBAOM_SOURCE_DIR" ]; then | 
 |     elog "LIBAOM_SOURCE_DIR does not exist." | 
 |     return 1 | 
 |   fi | 
 | } | 
 |  | 
 | # This is not needed since tools_common.sh does the same cleanup. | 
 | # Keep the code here for our reference. | 
 | # cleanup() { | 
 | #  rm -rf  ${AOM_TEST_OUTPUT_DIR} | 
 | # } | 
 |  | 
 | # Echo AOM_SIMD_CAPS_MASK for different instruction set architecture. | 
 | avx2() { | 
 |    echo "0x1FF" | 
 | } | 
 |  | 
 | avx() { | 
 |    echo "0x17F" | 
 | } | 
 |  | 
 | sse4_2() { | 
 |    echo "0x13F" | 
 | } | 
 |  | 
 | sse4_1() { | 
 |    echo "0x03F" | 
 | } | 
 |  | 
 | ssse3() { | 
 |    echo "0x01F" | 
 | } | 
 |  | 
 | sse3() { | 
 |    echo "0x00F" | 
 | } | 
 |  | 
 | sse2() { | 
 |    echo "0x007" | 
 | } | 
 |  | 
 | get_bitrates() { | 
 |   local content=$1 | 
 |   local preset=$2 | 
 |  | 
 |   # Bit-rates: | 
 |   local bitrate_lowres_good="300" | 
 |   local bitrate_480p_good="500" | 
 |   local bitrate_720p_good="1000" | 
 |   local bitrate_scc_360p_good="500" | 
 |   local bitrate_lowres_rt="200" | 
 |   local bitrate_480p_rt="300" | 
 |   local bitrate_720p_rt="600" | 
 |   local bitrate_scc_360p_rt="300" | 
 |   local bitrate_hbd_360p="500" | 
 |  | 
 |   if [ "${preset}" = "good" ]; then | 
 |     if [ "${content}" = "yuv_raw_input" ]; then | 
 |       echo "${bitrate_lowres_good}" | 
 |     elif [ "${content}" = "yuv_480p_raw_input" ]; then | 
 |       echo "${bitrate_480p_good}" | 
 |     elif [ "${content}" = "y4m_720p_input" ]; then | 
 |       echo "${bitrate_720p_good}" | 
 |     elif [ "${content}" = "y4m_screen_input" ]; then | 
 |       echo "${bitrate_scc_360p_good}" | 
 |     elif [ "${content}" = "y4m_360p_10bit_input" ]; then | 
 |       echo "${bitrate_hbd_360p}" | 
 |     else | 
 |       elog "Invalid content" | 
 |     fi | 
 |   elif  [ "${preset}" = "rt" ]; then | 
 |     if [ "${content}" = "yuv_raw_input" ]; then | 
 |       echo "${bitrate_lowres_rt}" | 
 |     elif [ "${content}" = "yuv_480p_raw_input" ]; then | 
 |       echo "${bitrate_480p_rt}" | 
 |     elif [ "${content}" = "y4m_720p_input" ]; then | 
 |       echo "${bitrate_720p_rt}" | 
 |     elif [ "${content}" = "y4m_screen_input" ]; then | 
 |       echo "${bitrate_scc_360p_rt}" | 
 |     elif [ "${content}" = "y4m_360p_10bit_input" ]; then | 
 |       echo "${bitrate_hbd_360p}" | 
 |     else | 
 |       elog "Invalid content" | 
 |     fi | 
 |   else | 
 |     elog "invalid preset" | 
 |   fi | 
 | } | 
 |  | 
 | # Echo clip details to be used as input to aomenc. | 
 | yuv_raw_input() { | 
 |   echo ""${YUV_RAW_INPUT}" | 
 |        --width=352 | 
 |        --height=288 | 
 |        --bit-depth=8" | 
 | } | 
 |  | 
 | y4m_360p_10bit_input() { | 
 |   echo ""${Y4M_360P_10BIT_INPUT}" | 
 |        --bit-depth=10" | 
 | } | 
 |  | 
 | yuv_480p_raw_input() { | 
 |   echo ""${YUV_480P_RAW_INPUT}" | 
 |        --width=640 | 
 |        --height=480 | 
 |        --bit-depth=8" | 
 | } | 
 |  | 
 | y4m_720p_input() { | 
 |   echo ""${Y4M_720P_INPUT}" | 
 |        --bit-depth=8" | 
 | } | 
 |  | 
 | y4m_screen_input() { | 
 |   echo ""${Y4M_SCREEN_INPUT}" | 
 |        --tune-content=screen | 
 |        --enable-palette=1 | 
 |        --bit-depth=8" | 
 | } | 
 |  | 
 | has_x86_isa_extn() { | 
 |   instruction_set=$1 | 
 |   if ! grep -q "$instruction_set" /proc/cpuinfo; then | 
 |     # This instruction set is not supported. | 
 |     return 1 | 
 |   fi | 
 | } | 
 |  | 
 | # Echo good encode params for use with AV1 encoder. | 
 | av1_encode_good_params() { | 
 |   echo "--good \ | 
 |   --ivf \ | 
 |   --profile=0 \ | 
 |   --static-thresh=0 \ | 
 |   --threads=1 \ | 
 |   --tile-columns=0 \ | 
 |   --tile-rows=0 \ | 
 |   --verbose \ | 
 |   --end-usage=vbr \ | 
 |   --kf-max-dist=160 \ | 
 |   --kf-min-dist=0 \ | 
 |   --max-q=63 \ | 
 |   --min-q=0 \ | 
 |   --overshoot-pct=100 \ | 
 |   --undershoot-pct=100 \ | 
 |   --passes=2 \ | 
 |   --arnr-maxframes=7 \ | 
 |   --arnr-strength=5 \ | 
 |   --auto-alt-ref=1 \ | 
 |   --drop-frame=0 \ | 
 |   --frame-parallel=0 \ | 
 |   --lag-in-frames=35 \ | 
 |   --maxsection-pct=2000 \ | 
 |   --minsection-pct=0 \ | 
 |   --sharpness=0" | 
 | } | 
 |  | 
 | # Echo realtime encode params for use with AV1 encoder. | 
 | av1_encode_rt_params() { | 
 |   echo "--rt \ | 
 |   --ivf \ | 
 |   --profile=0 \ | 
 |   --static-thresh=0 \ | 
 |   --threads=1 \ | 
 |   --tile-columns=0 \ | 
 |   --tile-rows=0 \ | 
 |   --verbose \ | 
 |   --end-usage=cbr \ | 
 |   --kf-max-dist=90000 \ | 
 |   --max-q=58 \ | 
 |   --min-q=2 \ | 
 |   --overshoot-pct=50 \ | 
 |   --undershoot-pct=50 \ | 
 |   --passes=1 \ | 
 |   --aq-mode=3 \ | 
 |   --buf-initial-sz=500 \ | 
 |   --buf-optimal-sz=600 \ | 
 |   --buf-sz=1000 \ | 
 |   --coeff-cost-upd-freq=3 \ | 
 |   --dv-cost-upd-freq=3 \ | 
 |   --mode-cost-upd-freq=3 \ | 
 |   --mv-cost-upd-freq=3 \ | 
 |   --deltaq-mode=0 \ | 
 |   --enable-global-motion=0 \ | 
 |   --enable-obmc=0 \ | 
 |   --enable-order-hint=0 \ | 
 |   --enable-ref-frame-mvs=0 \ | 
 |   --enable-tpl-model=0 \ | 
 |   --enable-warped-motion=0 \ | 
 |   --lag-in-frames=0 \ | 
 |   --max-intra-rate=300 \ | 
 |   --noise-sensitivity=0" | 
 | } | 
 |  | 
 | # Configures for the given target in AOM_TEST_OUTPUT_DIR/build_target_${target} | 
 | # directory. | 
 | av1_enc_build() { | 
 |   local target="$1" | 
 |   local cmake_command="$2" | 
 |   local tmp_build_dir=${AOM_TEST_OUTPUT_DIR}/build_target_${target} | 
 |   if [ -d "$tmp_build_dir" ]; then | 
 |     rm -rf $tmp_build_dir | 
 |   fi | 
 |  | 
 |   mkdir -p $tmp_build_dir | 
 |   cd $tmp_build_dir | 
 |  | 
 |   local cmake_common_args="--fresh -DCONFIG_EXCLUDE_SIMD_MISMATCH=1 \ | 
 |            -DCMAKE_BUILD_TYPE=Release \ | 
 |            -DENABLE_CCACHE=1 \ | 
 |            '-DCMAKE_C_FLAGS_RELEASE=-O3 -g' \ | 
 |            '-DCMAKE_CXX_FLAGS_RELEASE=-O3 -g' \ | 
 |            -DENABLE_DOCS=0 -DENABLE_TESTS=0 -DENABLE_TOOLS=0" | 
 |  | 
 |   for preset in $PRESETS; do | 
 |     echo "Building target[${preset} encoding]: ${target}" | 
 |     if [ "${preset}" = "good" ]; then | 
 |       local cmake_extra_args="-DCONFIG_AV1_HIGHBITDEPTH=1" | 
 |     elif [ "${preset}" = "rt" ]; then | 
 |       local cmake_extra_args="-DCONFIG_REALTIME_ONLY=1 -DCONFIG_AV1_HIGHBITDEPTH=0" | 
 |     else | 
 |       elog "Invalid preset" | 
 |       return 1 | 
 |     fi | 
 |     if ! eval "$cmake_command" "${cmake_common_args}" "${cmake_extra_args}" \ | 
 |       ${devnull}; then | 
 |       elog "cmake failure" | 
 |       return 1 | 
 |     fi | 
 |     if ! eval make -j$(nproc) aomenc ${devnull}; then | 
 |       elog "build failure" | 
 |       return 1 | 
 |     fi | 
 |  | 
 |     mv aomenc aomenc_${preset} | 
 |   done | 
 |   echo "Done building target: ${target}" | 
 | } | 
 |  | 
 | compare_enc_output() { | 
 |   local target=$1 | 
 |   local cpu=$2 | 
 |   local clip=$3 | 
 |   local bitrate=$4 | 
 |   local preset=$5 | 
 |   if ! diff -q ${AOM_TEST_OUTPUT_DIR}/Out-generic-"${clip}"-${preset}-${bitrate}kbps-cpu${cpu}${OUT_FILE_SUFFIX} \ | 
 |        ${AOM_TEST_OUTPUT_DIR}/Out-${target}-"${clip}"-${preset}-${bitrate}kbps-cpu${cpu}${OUT_FILE_SUFFIX}; then | 
 |     elog "C vs ${target} encode mismatches for ${clip}, at ${bitrate} kbps, speed ${cpu}, ${preset} preset" | 
 |     return 1 | 
 |   fi | 
 | } | 
 |  | 
 | av1_enc_test() { | 
 |   local encoder="$1" | 
 |   local arch="$2" | 
 |   local target="$3" | 
 |   local preset="$4" | 
 |   if [ -z "$(av1_enc_tool_path "${target}"  "${preset}")" ]; then | 
 |     elog "aomenc_${preset} not found. It must exist in ${AOM_TEST_OUTPUT_DIR}/build_target_${target} path" | 
 |     return 1 | 
 |   fi | 
 |  | 
 |   if [ "${preset}" = "good" ]; then | 
 |     case "${arch}" in | 
 |       arm64) | 
 |         # Speed 0 is not tested as arm64 is run under emulation. | 
 |         local min_cpu_used=1 | 
 |         local max_cpu_used=6 | 
 |         ;; | 
 |       x86) | 
 |         # x86 has a good amount of overlap with x86-64. Only a few values are | 
 |         # tested to improve the runtime of the script. | 
 |         local min_cpu_used=2 | 
 |         local max_cpu_used=3 | 
 |         ;; | 
 |       *) | 
 |         local min_cpu_used=0 | 
 |         local max_cpu_used=6 | 
 |         ;; | 
 |     esac | 
 |     local test_params=av1_encode_good_params | 
 |   elif [ "${preset}" = "rt" ]; then | 
 |     local min_cpu_used=5 | 
 |     local max_cpu_used=11 | 
 |     local test_params=av1_encode_rt_params | 
 |   else | 
 |     elog "Invalid preset" | 
 |     return 1 | 
 |   fi | 
 |  | 
 |   for cpu in $(seq $min_cpu_used $max_cpu_used); do | 
 |     if [ "${preset}" = "good" ]; then | 
 |       if [ "${arch}" = "x86_64" -o "${arch}" = "arm64" ]; then | 
 |         if [ "${cpu}" -lt 2 ]; then | 
 |           local test_clips="${LOWBD_CIF_CLIP} ${HIGHBD_CLIP}" | 
 |         elif [ "${cpu}" -lt 5 ]; then | 
 |           local test_clips="${LOWBD_480p_CLIP} ${HIGHBD_CLIP}" | 
 |         else | 
 |           local test_clips="${LOWBD_720p_CLIP} ${HIGHBD_CLIP}" | 
 |         fi | 
 |       elif [ "${arch}" = "x86" ]; then | 
 |         local test_clips="${LOWBD_CIF_CLIP} ${HIGHBD_CLIP}" | 
 |       else | 
 |         elog "Unknown architecture: ${arch}" | 
 |         return 1 | 
 |       fi | 
 |     elif [ "${preset}" = "rt" ]; then | 
 |       if [ "${cpu}" -lt 8 ]; then | 
 |         local test_clips="${LOWBD_CIF_CLIP} ${SC_CLIP}" | 
 |       else | 
 |         local test_clips="${LOWBD_480p_CLIP} ${SC_CLIP}" | 
 |       fi | 
 |     else | 
 |       elog "Invalid preset" | 
 |       return 1 | 
 |     fi | 
 |  | 
 |     for clip in ${test_clips}; do | 
 |       local test_bitrates=$(get_bitrates ${clip} ${preset}) | 
 |       for bitrate in ${test_bitrates}; do | 
 |         eval "${encoder}" $($clip) $($test_params) \ | 
 |         "--limit=${AV1_ENCODE_C_VS_SIMD_TEST_FRAME_LIMIT}" \ | 
 |         "--cpu-used=${cpu}" "--target-bitrate=${bitrate}" "-o" \ | 
 |         ${AOM_TEST_OUTPUT_DIR}/Out-${target}-"${clip}"-${preset}-${bitrate}kbps-cpu${cpu}${OUT_FILE_SUFFIX} \ | 
 |         ${devnull} | 
 |  | 
 |         if [ "${target}" != "generic" ]; then | 
 |           if ! compare_enc_output ${target} $cpu ${clip} $bitrate ${preset}; then | 
 |             # Found a mismatch | 
 |             return 1 | 
 |           fi | 
 |         fi | 
 |       done | 
 |     done | 
 |   done | 
 | } | 
 |  | 
 | av1_test_generic() { | 
 |   local arch=$1 | 
 |   local target="generic" | 
 |   if [ $arch = "x86_64" ]; then | 
 |     local cmake_command="cmake $LIBAOM_SOURCE_DIR -DAOM_TARGET_CPU=${target}" | 
 |   elif [ $arch = "x86" ]; then | 
 |     # As AV1 encode output differs for x86 32-bit and 64-bit platforms | 
 |     # (BUG=aomedia:3479), the x86 32-bit C-only build is generated separately. | 
 |     # The cmake command line option -DENABLE_MMX=0 flag disables all SIMD | 
 |     # optimizations, and generates a C-only binary. | 
 |     local cmake_command="cmake $LIBAOM_SOURCE_DIR -DENABLE_MMX=0 \ | 
 |       -DCMAKE_TOOLCHAIN_FILE=${LIBAOM_SOURCE_DIR}/build/cmake/toolchains/i686-linux-gcc.cmake" | 
 |   fi | 
 |  | 
 |   echo "Build for: Generic ${arch}" | 
 |   if ! av1_enc_build "${target}" "${cmake_command}"; then | 
 |     return 1 | 
 |   fi | 
 |  | 
 |   for preset in $PRESETS; do | 
 |     local encoder="$(av1_enc_tool_path "${target}" "${preset}")" | 
 |     av1_enc_test $encoder "${arch}" "${target}" "${preset}" | 
 |   done | 
 | } | 
 |  | 
 | # This function encodes AV1 bitstream by enabling SSE2, SSE3, SSSE3, SSE4_1, SSE4_2, AVX, AVX2 as | 
 | # there are no functions with MMX, SSE and AVX512 specialization. | 
 | # The value of environment variable 'AOM_SIMD_CAPS_MASK' controls enabling of different instruction | 
 | # set extension optimizations. The value of the flag 'AOM_SIMD_CAPS_MASK' and the corresponding | 
 | # instruction set extension optimization enabled are as follows: | 
 | # SSE4_2 AVX2 AVX SSE4_1 SSSE3 SSE3 SSE2 SSE MMX | 
 | #   1     1    1    1      1    1    1    1   1  -> 0x1FF -> Enable AVX2 and lower variants | 
 | #   1     0    1    1      1    1    1    1   1  -> 0x17F -> Enable AVX and lower variants | 
 | #   1     0    0    1      1    1    1    1   1  -> 0x13F -> Enable SSE4_2 and lower variants | 
 | #   0     0    0    1      1    1    1    1   1  -> 0x03F -> Enable SSE4_1 and lower variants | 
 | #   0     0    0    0      1    1    1    1   1  -> 0x01F -> Enable SSSE3 and lower variants | 
 | #   0     0    0    0      0    1    1    1   1  -> 0x00F -> Enable SSE3 and lower variants | 
 | #   0     0    0    0      0    0    1    1   1  -> 0x007 -> Enable SSE2 and lower variants | 
 | #   0     0    0    0      0    0    0    1   1  -> 0x003 -> Enable SSE and lower variants | 
 | #   0     0    0    0      0    0    0    0   1  -> 0x001 -> Enable MMX | 
 | ## NOTE: In x86_64 platform, it is not possible to enable sse/mmx/c using "AOM_SIMD_CAPS_MASK" as | 
 | #  all x86_64 platforms implement sse2. | 
 | av1_test_x86() { | 
 |   local arch=$1 | 
 |  | 
 |   if ! uname -m | grep -q "x86"; then | 
 |     elog "Machine architecture is not x86 or x86_64" | 
 |     return 0 | 
 |   fi | 
 |  | 
 |   if [ $arch = "x86" ]; then | 
 |     local target="x86-linux" | 
 |     local cmake_command="cmake \ | 
 |     $LIBAOM_SOURCE_DIR \ | 
 |     -DCMAKE_TOOLCHAIN_FILE=${LIBAOM_SOURCE_DIR}/build/cmake/toolchains/i686-linux-gcc.cmake" | 
 |   elif [ $arch = "x86_64" ]; then | 
 |     local target="x86_64-linux" | 
 |     local cmake_command="cmake $LIBAOM_SOURCE_DIR" | 
 |   fi | 
 |  | 
 |   # Available x86 isa variants: "avx2 avx sse4_2 sse4_1 ssse3 sse3 sse2" | 
 |   local x86_isa_variants="avx2 sse4_2 sse2" | 
 |  | 
 |   echo "Build for x86: ${target}" | 
 |   if ! av1_enc_build "${target}" "${cmake_command}"; then | 
 |     return 1 | 
 |   fi | 
 |  | 
 |   for preset in $PRESETS; do | 
 |     local encoder="$(av1_enc_tool_path "${target}" "${preset}")" | 
 |     for isa in $x86_isa_variants; do | 
 |       # Note that if has_x86_isa_extn returns 1, it is false, and vice versa. | 
 |       if ! has_x86_isa_extn $isa; then | 
 |         echo "${isa} is not supported in this machine" | 
 |         continue | 
 |       fi | 
 |       export AOM_SIMD_CAPS_MASK=$($isa) | 
 |       if ! av1_enc_test $encoder "${arch}" "${target}" "${preset}"; then | 
 |         # Found a mismatch | 
 |         return 1 | 
 |       fi | 
 |       unset AOM_SIMD_CAPS_MASK | 
 |     done | 
 |   done | 
 | } | 
 |  | 
 | av1_test_arm() { | 
 |   local arch="arm64" | 
 |   local target="arm64-linux-gcc" | 
 |   local cmake_command="cmake $LIBAOM_SOURCE_DIR \ | 
 |         -DCMAKE_TOOLCHAIN_FILE=$LIBAOM_SOURCE_DIR/build/cmake/toolchains/${target}.cmake \ | 
 |         -DCMAKE_C_FLAGS=-Wno-maybe-uninitialized" | 
 |   echo "Build for arm64: ${target}" | 
 |   if ! av1_enc_build "${target}" "${cmake_command}"; then | 
 |     return 1 | 
 |   fi | 
 |  | 
 |   for preset in $PRESETS; do | 
 |     local encoder="$(av1_enc_tool_path "${target}" "${preset}")" | 
 |     if ! av1_enc_test "qemu-aarch64 -L /usr/aarch64-linux-gnu ${encoder}" "${arch}" "${target}" "${preset}"; then | 
 |       # Found a mismatch | 
 |       return 1 | 
 |     fi | 
 |   done | 
 | } | 
 |  | 
 | av1_c_vs_simd_enc_test () { | 
 |   # Test x86 (32 bit) | 
 |   # x86 requires the i686-linux-gnu toolchain: | 
 |   # $ sudo apt-get install g++-i686-linux-gnu | 
 |   echo "av1 test for x86 (32 bit): Started." | 
 |   # Encode 'C' only | 
 |   av1_test_generic "x86" | 
 |   # Encode with SIMD optimizations enabled | 
 |   if ! av1_test_x86 "x86"; then | 
 |     echo "av1 test for x86 (32 bit): Done, test failed." | 
 |     return 1 | 
 |   else | 
 |     echo "av1 test for x86 (32 bit): Done, all tests passed." | 
 |   fi | 
 |  | 
 |   # Test x86_64 (64 bit) | 
 |   if [ "$(eval uname -m)" = "x86_64" ]; then | 
 |     echo "av1 test for x86_64 (64 bit): Started." | 
 |     # Encode 'C' only | 
 |     av1_test_generic "x86_64" | 
 |     # Encode with SIMD optimizations enabled | 
 |     if ! av1_test_x86 "x86_64"; then | 
 |       echo "av1 test for x86_64 (64 bit): Done, test failed." | 
 |       return 1 | 
 |     else | 
 |       echo "av1 test for x86_64 (64 bit): Done, all tests passed." | 
 |     fi | 
 |   fi | 
 |  | 
 |   # Test ARM | 
 |   echo "av1_test_arm: Started." | 
 |   if ! av1_test_arm; then | 
 |     echo "av1 test for arm: Done, test failed." | 
 |     return 1 | 
 |   else | 
 |     echo "av1 test for arm: Done, all tests passed." | 
 |   fi | 
 | } | 
 |  | 
 | run_tests av1_c_vs_simd_enc_verify_environment av1_c_vs_simd_enc_test |