Vendor dav1d 1.5.3

This commit is contained in:
Basilisk-Dev 2026-05-11 09:31:45 -04:00 committed by wuggy
commit ee30135ecc
390 changed files with 325535 additions and 0 deletions

10
media/libdav1d/src/.gitignore vendored Normal file
View file

@ -0,0 +1,10 @@
/build*
/Session.vim
[._]*.swp
*~
tags
.DS_Store
/tests/argon
/tests/dav1d-test-data
*.snap
/tools/output/xxhash.h

View file

@ -0,0 +1,930 @@
stages:
- style
- build
- test
.debian-amd64-common:
image: registry.videolan.org/dav1d-debian-unstable:20250207200301
stage: build
tags:
- docker
- amd64
.debian-amd64-minimum:
image: registry.videolan.org/dav1d-debian-minimum:20250207200301
stage: build
tags:
- docker
- amd64
.debian-llvm-mingw-common:
image: registry.videolan.org/vlc-debian-llvm-msvcrt:20250305204125
stage: build
tags:
- docker
- amd64
.debian-aarch64-common:
image: registry.videolan.org/dav1d-debian-bookworm-aarch64:20250215002814
stage: build
tags:
- docker
- aarch64
.debian-armv7-common:
image: registry.videolan.org/dav1d-debian-bookworm-armv7:20250215014239
stage: build
tags:
- docker
- armv7
.debian-ppc64le-common:
image: registry.videolan.org/dav1d-debian-unstable-ppc64le:20250215003029
stage: build
tags:
- docker
- ppc64le
.android-common:
image: registry.videolan.org/vlc-debian-android:20241118101328
stage: build
tags:
- docker
- amd64
.debian-wasm-emscripten-common:
image: registry.videolan.org/vlc-debian-wasm-emscripten:20250207201514
stage: build
tags:
- docker
- amd64
style-check:
extends: .debian-amd64-common
stage: style
script:
- git grep -I -n -P "\t|\r| $" -- . ':(exclude)*/compat/*' && echo "Trailing whitespace" && exit 1
- git grep -I -n -i -e 'david' --and --not -e 'copyright' -- . ':(exclude)THANKS.md' ':(exclude).gitlab-ci.yml' && echo "Misspelled dav1d" && exit 1
- git grep -I -l -z "" -- . ':(exclude)*/compat/*' | while IFS= read -r -d '' i; do
if [ -n "$(tail -c 1 "$i")" ]; then
echo "No newline at end of $i";
exit 1;
fi;
done
- rg '[\u061c\u2000-\u200f\u2028-\u202f\u205f-\u206f]' ./ && echo "Invisible Unicode characters" && exit 1
- git remote rm upstream 2> /dev/null || true
- git remote add upstream https://code.videolan.org/videolan/dav1d.git
- git fetch -q upstream master
- for i in $(git rev-list HEAD ^upstream/master); do
echo "Checking commit message of $i";
msg="$(git log --format=%B -n 1 $i)";
if [ -n "$(echo "$msg" | awk "NR==2")" ]; then
echo "Malformed commit message in $i, second line must be empty";
exit 1;
fi;
if echo "$msg" | head -1 | grep -q '\.$'; then
echo "Malformed commit message in $i, trailing period in subject line";
exit 1;
fi;
done
x86inc-check:
extends: .debian-amd64-common
stage: style
script:
- git remote rm x86inc 2> /dev/null || true
- git remote add x86inc https://code.videolan.org/videolan/x86inc.asm.git
- git fetch -q x86inc master
- git diff --exit-code x86inc/master:x86inc.asm src/ext/x86/x86inc.asm
allow_failure: true
build-debian:
extends: .debian-amd64-common
tags:
- docker
- avx2
- amd64
script:
- meson setup build --buildtype release
-Dtrim_dsp=false
--werror
- ninja -C build
- cd build && meson test -v
artifacts:
paths:
- build/
expire_in: 1 day
build-debian-static:
extends: .debian-amd64-common
script:
- meson setup build --buildtype release
--default-library static
--werror
- ninja -C build
- cd build && meson test -v
- nm -A -g src/libdav1d.a | grep " [ABCDGRST] " | (! grep -v " _*dav1d_")
build-debian-illegal-instructions:
extends: .debian-amd64-common
tags:
- docker
- avx2
- amd64
script:
- meson setup build --buildtype debug
- ninja -C build
- cd build
- exit_code=0
- time meson test -v --suite checkasm --wrapper 'qemu-x86_64 -cpu Conroe' || exit_code=$((exit_code + $?))
- time meson test -v --suite checkasm --wrapper 'qemu-x86_64 -cpu Penryn' || exit_code=$((exit_code + $?))
- if [ $exit_code -ne 0 ]; then exit $exit_code; fi
build-debian32:
extends: .debian-amd64-common
script:
- meson setup build --buildtype release
-Dtrim_dsp=false
--werror
--cross-file package/crossfiles/i686-linux32.meson
- ninja -C build
- cd build && meson test -v
artifacts:
paths:
- build/
expire_in: 1 day
build-debian-examples:
extends: .debian-amd64-common
script:
- meson setup build --buildtype release
--werror
-Denable_examples=true
- ninja -C build
build-debian-no-tools:
extends: .debian-amd64-common
script:
- meson setup build --buildtype release
--werror
-Denable_tools=false
- ninja -C build
build-debian-bitdepth:
extends: .debian-amd64-common
script:
- meson setup build --buildtype release
--werror
-Dbitdepths=$DEPTH
- ninja -C build
parallel:
matrix:
- DEPTH: [8, 16]
build-debian-avx:
extends: .debian-amd64-common
tags:
- docker
- avx2
- amd64
variables:
CFLAGS: '-mavx'
script:
- meson setup build --buildtype debugoptimized
--werror
- ninja -C build
- cd build
- time meson test -v --suite checkasm
build-debian-minimum:
extends: .debian-amd64-minimum
script:
- meson setup build --buildtype release
--werror
-Dtrim_dsp=false
- ninja -C build
- cd build && meson test -v
build-debian-avx512:
extends: .debian-amd64-common
tags:
- docker
- amd64-avx512
variables:
CFLAGS: '-mavx'
script:
- meson setup build --buildtype debugoptimized
--werror
- ninja -C build
- cd build
- time meson test -v --suite checkasm
build-debian-clang:
extends: .debian-amd64-common
variables:
CC: clang
CC_LD: mold
script:
- meson setup build --buildtype release
--werror
-Dtrim_dsp=false
- ninja -C build
- cd build && meson test -v
build-win:
extends: .debian-amd64-common
script:
- wineserver -p && wine wineboot
- meson setup build --buildtype release
--werror
--libdir lib
--prefix "$(pwd)/build/dav1d_install"
--cross-file package/crossfiles/${CROSSFILE}.meson
-Ddefault_library=both
-Dtrim_dsp=false
- ninja -C build
- ninja -C build install
- cd build && meson test -v
- ${CROSSFILE}-nm -A -g src/libdav1d.a | grep " [ABCDGRST] " | (! grep -E -v " \.| _*dav1d_")
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
paths:
- build/dav1d_install/
expire_in: 1 week
parallel:
matrix:
- CROSSFILE: [i686-w64-mingw32, x86_64-w64-mingw32]
build-win32-unaligned-stack:
extends: .debian-llvm-mingw-common
script:
- wineserver -p && wine wineboot
- meson setup build --buildtype release
--werror
--cross-file package/crossfiles/i686-w64-mingw32.meson
-Dstack_alignment=4
-Dtrim_dsp=false
- ninja -C build
- cd build && meson test -v
build-win-arm:
extends: .debian-llvm-mingw-common
script:
- meson setup build --buildtype release
--werror
--libdir lib
--prefix "$(pwd)/build/dav1d_install"
--cross-file package/crossfiles/${CROSSFILE}.meson
-Ddefault_library=both
-Dtrim_dsp=false
- ninja -C build
- ninja -C build install
- ${CROSSFILE}-nm -A -g build/src/libdav1d.a | grep " [ABCDGRST] " | (! grep -E -v " \.| _*dav1d_")
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
paths:
- build/dav1d_install/
expire_in: 1 week
parallel:
matrix:
- CROSSFILE: [armv7-w64-mingw32, aarch64-w64-mingw32]
.build-android-common:
extends: .android-common
script:
- meson setup build --buildtype release
--werror
--libdir lib
--prefix "$(pwd)/build/dav1d_install"
--cross-file $CROSSFILE
-Ddefault_library=both
-Dtrim_dsp=false
- ninja -C build
- ninja -C build install
build-android-armv7:
extends: .build-android-common
variables:
CROSSFILE: package/crossfiles/arm-android.meson
rules:
- if: '$CI_COMMIT_BRANCH'
build-android-aarch64:
extends: .build-android-common
variables:
CROSSFILE: package/crossfiles/aarch64-android.meson
rules:
- if: '$CI_COMMIT_BRANCH'
build-android-armv7-release:
extends: build-android-armv7
rules:
- if: '$CI_COMMIT_TAG && $CI_PROJECT_PATH == "videolan/dav1d"'
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
paths:
- build/dav1d_install/
expire_in: 1 week
build-android-aarch64-release:
extends: build-android-aarch64
rules:
- if: '$CI_COMMIT_TAG && $CI_PROJECT_PATH == "videolan/dav1d"'
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
paths:
- build/dav1d_install/
expire_in: 1 week
build-debian-aarch64:
extends: .debian-aarch64-common
script:
- meson setup build --buildtype debugoptimized
--werror
- ninja -C build
- cd build && meson test -v
build-debian-aarch64-clang-5:
extends: .debian-aarch64-common
variables:
CC: clang-5.0
CFLAGS: '-integrated-as'
script:
- meson setup build --buildtype release
- ninja -C build
- cd build && meson test -v
build-debian-aarch64-clang-18:
extends: .debian-amd64-common
variables:
QEMU_LD_PREFIX: /usr/aarch64-linux-gnu/
script:
- meson setup build --buildtype release
-Dtrim_dsp=false
--werror
--cross-file package/crossfiles/aarch64-linux-clang.meson
- ninja -C build
- cd build && meson test -v
build-macos:
stage: build
tags:
- amd64
- macos
script:
- meson setup build --buildtype release
-Ddefault_library=both
-Dtrim_dsp=false
--werror
- ninja -C build
- cd build && meson test -v
build-debian-werror:
extends: .debian-aarch64-common
variables:
CC: clang
script:
- meson setup build --buildtype debug
--werror
- ninja -C build
build-debian-armv7:
extends: .debian-armv7-common
script:
- linux32 meson setup build --buildtype debugoptimized
--werror
- ninja -C build
- cd build && meson test -v
build-debian-armv7-clang-5:
extends: .debian-armv7-common
variables:
CC: clang-5.0
CFLAGS: '-integrated-as'
script:
- linux32 meson setup build --buildtype release
- ninja -C build
- cd build && meson test -v
build-debian-ppc64le:
extends: .debian-ppc64le-common
variables:
CC: gcc-13
script:
- meson setup build --buildtype release
-Dtrim_dsp=false
--werror
- ninja -C build
- cd build && meson test -v
build-debian-wasm:
extends: .debian-wasm-emscripten-common
script:
- source $EMSCRIPTEN_SDK/emsdk_env.sh
- meson setup build --buildtype release
--werror
--default-library static
--cross-file package/crossfiles/${CROSSFILE}.meson
- ninja -C build
- cd build && meson test -v
parallel:
matrix:
- CROSSFILE: [wasm32, wasm64]
build-debian-riscv64:
extends: .debian-amd64-common
variables:
QEMU_CPU: rv64,v=true,vext_spec=v1.0,vlen=256,elen=64
QEMU_LD_PREFIX: /usr/riscv64-linux-gnu/
script:
- meson setup build --buildtype release
-Dtrim_dsp=false
--werror
--cross-file package/crossfiles/${CROSSFILE}.meson
- ninja -C build
- cd build && meson test -v
parallel:
matrix:
- CROSSFILE: [riscv64-linux, riscv64-linux-clang]
build-debian-loongarch64:
extends: .debian-amd64-common
variables:
QEMU_CPU: max-loongarch-cpu
QEMU_LD_PREFIX: /opt/cross-tools/target/
script:
- meson setup build --buildtype release
-Dtrim_dsp=false
--werror
--cross-file package/crossfiles/loongarch64-linux.meson
- ninja -C build
- cd build && meson test -v
.test-common:
stage: test
cache:
key: testdata.git-20190215
paths:
- cache/dav1d-test-data.git/
before_script:
- test -d cache || mkdir cache
- test -d cache/dav1d-test-data.git && GIT_DIR=cache/dav1d-test-data.git git fetch --refmap=refs/heads/master:refs/heads/master origin master
- test -d cache/dav1d-test-data.git || git clone --bare https://code.videolan.org/videolan/dav1d-test-data.git cache/dav1d-test-data.git
- git clone cache/dav1d-test-data.git tests/dav1d-test-data
- git -C tests/dav1d-test-data describe --always --long
dependencies: []
artifacts:
when: always
reports:
junit: build/meson-logs/testlog.junit.xml
.test-asm-common:
extends:
- .debian-amd64-common
- .test-common
tags:
- docker
- amd64
- avx2
script:
- meson configure build -Dtestdata_tests=true
- ninja -C build
- cd build
- exit_code=0
- time meson test -q --suite testdata --test-args "--cpumask 0" || exit_code=$((exit_code + $?))
- time meson test -q --suite testdata --test-args "--cpumask sse2" || exit_code=$((exit_code + $?))
- time meson test -q --suite testdata --test-args "--cpumask ssse3" || exit_code=$((exit_code + $?))
- time meson test -q --suite testdata --test-args "--cpumask sse41" || exit_code=$((exit_code + $?))
- time meson test -q --suite testdata --test-args "--cpumask avx2" || exit_code=$((exit_code + $?))
- if [ $exit_code -ne 0 ]; then exit $exit_code; fi
.test-argon:
stage: test
cache:
key: argon-20230512
paths:
- cache/argon/
variables:
ARGON_URL: https://streams.videolan.org/argon/argon.tar.zst
before_script:
- test -d cache/argon || mkdir -p cache/argon
- test -f cache/argon/argon.tar.zst ||
(cd cache/argon && curl --remote-name "${ARGON_URL}" --remote-name "${ARGON_URL}.sha512sum" &&
sha512sum --check argon.tar.zst.sha512sum )
- tar -xf cache/argon/argon.tar.zst -C tests
dependencies: []
allow_failure: true
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
test-debian:
extends:
- .debian-amd64-common
- .test-common
needs: ["build-debian"]
script:
- meson setup build --buildtype release
-Dtestdata_tests=true
-Denable_seek_stress=true
-Dlogging=false
-Db_coverage=true
-Dtrim_dsp=false
- ninja -C build
- cd build && time meson test -v
- ninja coverage-html
- mv meson-logs/coveragereport ../coverage
- ninja coverage-xml
- grep -Eo 'line-rate="[^"]+"' meson-logs/coverage.xml | head -n 1 |
grep -Eo '[0-9.]+' | awk '{ print "coverage:", $1 * 100 } '
- time meson test -v --suite testdata_seek-stress --test-args "--threads 2 --framedelay 1"
- time meson test -v --suite testdata_seek-stress --test-args "--threads 2 --framedelay 2"
- time meson test -v --suite testdata --test-args "--threads=1 --negstride"
coverage: '/^coverage: (\d+.\d+)$/'
artifacts:
expose_as: 'Coverage HTML report'
paths:
- coverage/
reports:
coverage_report:
coverage_format: cobertura
path: build/meson-logs/coverage.xml
test-debian-asm:
extends:
- .test-asm-common
needs: ["build-debian"]
dependencies: ["build-debian"]
test-debian32-asm:
extends:
- .test-asm-common
needs: ["build-debian32"]
dependencies: ["build-debian32"]
test-debian-avx512:
extends:
- .debian-amd64-common
- .test-common
tags:
- docker
- amd64-avx512
variables:
CFLAGS: '-mavx'
needs: ["build-debian-avx512"]
script:
- meson setup build --buildtype release
-Dtestdata_tests=true
-Dtrim_dsp=false
- ninja -C build
- cd build && time meson test --suite testdata --test-args "--cpumask avx512icl"
- time meson test --suite testdata --test-args "--threads 2 --framedelay 2 --cpumask avx512icl"
test-debian-unaligned-stack:
extends:
- .debian-amd64-common
- .test-common
needs: ["build-debian"]
tags:
- docker
- avx2
- amd64
script:
- meson setup build --buildtype release
-Dtestdata_tests=true
-Denable_seek_stress=true
-Dlogging=false
-Dstack_alignment=16
-Dtrim_dsp=false
- ninja -C build
- cd build && time meson test -v
test-debian-asan:
extends:
- .debian-amd64-common
- .test-common
needs: ["build-debian"]
variables:
ASAN_OPTIONS: 'detect_leaks=0'
script:
- meson setup build --buildtype debugoptimized
-Dtestdata_tests=true
-Dlogging=false
-Db_sanitize=address
- ninja -C build
- cd build
- exit_code=0
- time meson test -v --setup=sanitizer --suite checkasm || exit_code=$((exit_code + $?))
- time meson test -v --setup=sanitizer --suite testdata --test-args "--cpumask 0" || exit_code=$((exit_code + $?))
- time meson test -v --setup=sanitizer --suite testdata --test-args "--cpumask 0xff" || exit_code=$((exit_code + $?))
- if [ $exit_code -ne 0 ]; then exit $exit_code; fi
test-debian-msan:
extends:
- .debian-amd64-common
- .test-common
needs: ["build-debian"]
variables:
MSAN_OPTIONS: 'exitcode=1'
CC: clang
script:
- meson setup build --buildtype debugoptimized
-Dtestdata_tests=true
-Denable_seek_stress=true
-Dlogging=false
-Db_sanitize=memory
-Db_lundef=false
-Denable_asm=false
- ninja -C build
- cd build
- exit_code=0
- time meson test -v --setup=sanitizer || exit_code=$((exit_code + $?))
- time meson test -v --setup=sanitizer --suite testdata --test-args "--frametimes /dev/null" || exit_code=$((exit_code + $?))
- if [ $exit_code -ne 0 ]; then exit $exit_code; fi
test-debian-ubsan:
extends:
- .debian-amd64-common
- .test-common
needs: ["build-debian"]
variables:
UBSAN_OPTIONS: 'print_stacktrace=1:halt_on_error=1'
CC: clang
script:
- meson setup build --buildtype debugoptimized
-Dtestdata_tests=true
-Denable_seek_stress=true
-Dlogging=false
-Db_sanitize=undefined
-Db_lundef=false
-Denable_asm=false
- ninja -C build
- cd build && time meson test -v --setup=sanitizer
test-debian-tsan:
extends:
- .debian-amd64-common
- .test-common
needs: ["build-debian"]
variables:
TSAN_OPTIONS: 'halt_on_error=1'
CC: clang
script:
- meson setup build --buildtype debugoptimized
-Dtestdata_tests=true
-Denable_seek_stress=true
-Dlogging=false
-Db_sanitize=thread
-Db_lundef=false
- ninja -C build
- cd build
- exit_code=0
- time meson test -v --setup=sanitizer --suite testdata --test-args "--threads 2 --framedelay 1" || exit_code=$((exit_code + $?))
- time meson test -v --setup=sanitizer --suite testdata --test-args "--threads 2 --framedelay 2" || exit_code=$((exit_code + $?))
- time meson test -v --setup=sanitizer --suite testdata --test-args "--threads 2 --framedelay 2 --negstride" || exit_code=$((exit_code + $?))
- time meson test -v --setup=sanitizer --suite testdata_seek-stress --test-args "--threads 2 --framedelay 1" || exit_code=$((exit_code + $?))
- time meson test -v --setup=sanitizer --suite testdata_seek-stress --test-args "--threads 2 --framedelay 2" || exit_code=$((exit_code + $?))
- time meson test -v --setup=sanitizer --suite oss-fuzz-asan --suite oss-fuzz-msan --suite oss-fuzz-ubsan || exit_code=$((exit_code + $?))
- if [ $exit_code -ne 0 ]; then exit $exit_code; fi
test-win64:
extends:
- .debian-amd64-common
- .test-common
needs: ["build-win: [x86_64-w64-mingw32]"]
tags:
- docker
- avx2
- amd64
script:
- wineserver -p && wine wineboot
- meson setup build --buildtype release
-Dtestdata_tests=true
-Dlogging=false
-Dtrim_dsp=false
--cross-file package/crossfiles/x86_64-w64-mingw32.meson
- ninja -C build
- cd build && time meson test -v
test-debian-aarch64:
extends:
- .debian-aarch64-common
- .test-common
needs: ["build-debian-aarch64"]
script:
- meson setup build --buildtype release
-Dtestdata_tests=true
-Dlogging=false
-Dtrim_dsp=false
- ninja -C build
- cd build && time meson test -v
test-debian-ppc64le:
extends:
- .debian-ppc64le-common
- .test-common
variables:
CC: gcc-13
needs: ["build-debian-ppc64le"]
script:
- meson setup build --buildtype release
-Dtestdata_tests=true
-Dlogging=false
-Dtrim_dsp=false
- ninja -C build
- cd build && time meson test -v
test-debian-riscv64:
extends:
- .debian-amd64-common
- .test-common
needs: ["build-debian-riscv64"]
script:
- meson setup build --buildtype release
-Dtestdata_tests=true
-Dlogging=false
-Dtrim_dsp=false
--cross-file package/crossfiles/riscv64-linux.meson
- ninja -C build
- cd build && time meson test -v --timeout-multiplier 10
variables:
QEMU_LD_PREFIX: /usr/riscv64-linux-gnu/
parallel:
matrix:
- QEMU_CPU: [ "rv64,v=true,vext_spec=v1.0,vlen=128,elen=64",
"rv64,v=true,vext_spec=v1.0,vlen=256,elen=64",
"rv64,v=true,vext_spec=v1.0,vlen=512,elen=64",
"rv64,v=true,vext_spec=v1.0,vlen=1024,elen=64" ]
test-debian-aarch64-qemu:
extends:
- .debian-amd64-common
- .test-common
needs: ["build-debian-aarch64"]
script:
- meson setup build --buildtype release
-Dtestdata_tests=true
-Dlogging=false
-Dtrim_dsp=false
--cross-file package/crossfiles/aarch64-linux.meson
- ninja -C build
- cd build && time meson test -v --timeout-multiplier 10
variables:
QEMU_LD_PREFIX: /usr/aarch64-linux-gnu/
parallel:
matrix:
# sve-default-vector-length sets the max vector length in bytes;
# the default is 64, allowing up to 512 bit vectors. Testing 1024
# and 2048 bit vectors requires raising this limit. The sve<n>
# option sets the active vector length in bits.
- QEMU_CPU: [ "max,sve-default-vector-length=256,sve128=on",
"max,sve-default-vector-length=256,sve256=on",
"max,sve-default-vector-length=256,sve512=on",
"max,sve-default-vector-length=256,sve1024=on",
"max,sve-default-vector-length=256,sve2048=on" ]
test-debian-armv7-clang-5:
extends:
- .debian-armv7-common
- .test-common
needs: ["build-debian-armv7-clang-5"]
variables:
CC: clang-5.0
CFLAGS: '-integrated-as'
script:
- linux32 meson setup build --buildtype release
-Dtestdata_tests=true
-Dlogging=false
-Dtrim_dsp=false
- ninja -C build
- cd build && time meson test -v
test-debian-loongarch64:
extends:
- .debian-amd64-common
- .test-common
needs: ["build-debian-loongarch64"]
variables:
QEMU_CPU: max-loongarch-cpu
QEMU_LD_PREFIX: /opt/cross-tools/target/
script:
- meson setup build --buildtype release
-Dtestdata_tests=true
-Dlogging=false
-Dtrim_dsp=false
--cross-file package/crossfiles/loongarch64-linux.meson
- ninja -C build
- cd build && time meson test -v --timeout-multiplier 10
.test-argon-script: &test-argon-script
- meson setup build --buildtype release
-Dlogging=false
-Dtrim_dsp=false
- cd build && ninja
- exit_code=0
test-debian-argon:
extends:
- .debian-amd64-common
- .test-argon
needs: ["build-debian"]
tags:
- docker
- amd64
- avx2
script:
- *test-argon-script
- ../tests/dav1d_argon.bash -t 1 -c 0 || exit_code=$((exit_code + $?))
- ../tests/dav1d_argon.bash -t 2 -c sse2 -g 0 || exit_code=$((exit_code + $?))
- ../tests/dav1d_argon.bash -t 3 -c ssse3 || exit_code=$((exit_code + $?))
- ../tests/dav1d_argon.bash -t 4 -c sse41 || exit_code=$((exit_code + $?))
- ../tests/dav1d_argon.bash -t 5 -c avx2 || exit_code=$((exit_code + $?))
- if [ $exit_code -ne 0 ]; then exit $exit_code; fi
test-debian32-argon:
extends:
- .debian-amd64-common
- .test-argon
needs: ["build-debian32"]
script:
- meson setup build --buildtype release
-Dlogging=false
-Dtrim_dsp=false
--cross-file package/crossfiles/i686-linux32.meson
- cd build && ninja
- exit_code=0
- ../tests/dav1d_argon.bash -t 2 -c sse2 || exit_code=$((exit_code + $?))
- ../tests/dav1d_argon.bash -t 2 -c ssse3 || exit_code=$((exit_code + $?))
- ../tests/dav1d_argon.bash -t 2 -c sse41 -g 0 || exit_code=$((exit_code + $?))
- if [ $exit_code -ne 0 ]; then exit $exit_code; fi
test-debian-argon-avx512:
extends:
- .debian-amd64-common
- .test-argon
needs: ["build-debian-avx512"]
tags:
- docker
- amd64-avx512
script:
- *test-argon-script
- ../tests/dav1d_argon.bash -t 2 -c avx512icl || exit_code=$((exit_code + $?))
- if [ $exit_code -ne 0 ]; then exit $exit_code; fi
test-debian-armv7-argon:
extends:
- .debian-armv7-common
- .test-argon
needs: ["build-debian-armv7"]
script:
- *test-argon-script
- ../tests/dav1d_argon.bash -t 3 -c 0 || exit_code=$((exit_code + $?))
- ../tests/dav1d_argon.bash -t 2 -c neon || exit_code=$((exit_code + $?))
- ../tests/dav1d_argon.bash -t 1 -c neon -g 0 || exit_code=$((exit_code + $?))
- if [ $exit_code -ne 0 ]; then exit $exit_code; fi
test-debian-aarch64-argon:
extends:
- .debian-aarch64-common
- .test-argon
needs: ["build-debian-aarch64"]
tags:
- docker
- aarch64
- dotprod
script:
- *test-argon-script
- ../tests/dav1d_argon.bash -t 2 -c 0 || exit_code=$((exit_code + $?))
- ../tests/dav1d_argon.bash -t 3 -c neon || exit_code=$((exit_code + $?))
- ../tests/dav1d_argon.bash -t 1 -c neon -g 0 || exit_code=$((exit_code + $?))
- ../tests/dav1d_argon.bash -t 4 -c dotprod || exit_code=$((exit_code + $?))
- if [ $exit_code -ne 0 ]; then exit $exit_code; fi
.pages-common:
extends: .debian-amd64-common
script:
- meson setup build --buildtype release
--werror
-Denable_docs=true
- ninja -C build doc/html
- mv build/doc/html public
artifacts:
paths:
- public
build-pages:
extends: .pages-common
rules:
- if: '$CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH'
pages:
extends: .pages-common
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
changes:
- include/dav1d/*
- doc/meson.build
- doc/Doxyfile.in.in

View file

@ -0,0 +1,56 @@
# dav1d contribution guide
## CoC
The [VideoLAN Code of Conduct](https://wiki.videolan.org/CoC) applies fully to this project.
## ToDo
The todo list can be found [on the wiki](https://code.videolan.org/videolan/dav1d/wikis/task-list).
## Codebase language
The codebase is developed with the following assumptions:
For the library:
- C language with C99 version, without the VLA or the Complex (*\_\_STDC_NO_COMPLEX__*) features, and without compiler extensions. Anonymous structures and unions are the only allowed compiler extensions for internal code.
- x86 asm in .asm files, using the NASM syntax,
- arm/arm64 in .S files, using the GAS syntax limited to subset llvm 5.0's internal assembler supports,
- no C++ is allowed, whatever the version.
For the tools and utils:
- C *(see above for restrictions)*
- Rust
- C++ is only allowed for the MFT.
If you want to use *Threads* or *Atomic* features, please conform to the **C11**/**POSIX** semantic and use a wrapper for older compilers/platforms *(like done in VLC)*.
Please use modern standard POSIX functions *(strscpy, asprintf, tdestroy)*, and provide a compatibility fallback *(like done in VLC)*.
We will make reasonable efforts for compilers that are a bit older, but we won't support gcc 3 or MSVC 2012.
## Authorship
Please provide a correct authorship for your commit logs, with a name and a valid email.
We will reject anonymous contributions for now. As an exception, known pseudonyms from the multimedia community are accepted.
This project is respecting **Copyright** and **Droit d'auteur**. There is no copyright attribution or CLA.
## Commit logs
Please read [How to Write a Git Commit Message](https://chris.beams.io/posts/git-commit/).
## Submit requests (WIP)
- Code,
- [Compile](https://xkcd.com/303/),
- Check your [code style](https://code.videolan.org/videolan/dav1d/wikis/Coding-style),
- Test,
- Try,
- Submit patches through merge requests,
- Check that this passes the CI.
## Patent license
You need to read, understand, and agree to the [AV1 patents license](doc/PATENTS), before committing.

View file

@ -0,0 +1,23 @@
Copyright © 2018-2025, VideoLAN and dav1d authors
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. 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.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.

460
media/libdav1d/src/NEWS Normal file
View file

@ -0,0 +1,460 @@
Changes for 1.5.3 'Sonic':
--------------------------
1.5.3 is a minor release of dav1d, focused on RISC-V and maintenance:
- Misc small optimizations
- RISC-V assembly optimizations for ipred, emu_edge and w_mask,
and VLEN 512 for blend functions
- Fix issue with ivf files with 0 frames in tools
Changes for 1.5.2 'Sonic':
--------------------------
1.5.2 is a minor release of dav1d, focused on maintenance:
- minor speed improvement in recon
- improvements on loongarch symboles visibility and asm
- mark C globals with small code model
- reduce the code size of the frame header parsing (OBU)
- minor fixes on tools and CI
- fix compilation with nasm 3.00
Changes for 1.5.1 'Sonic':
--------------------------
1.5.1 is a minor release of dav1d, focusing on optimizations and stack reduction:
- Rewrite of the looprestoration (SGR, wiener) to reduce stack usage
- Rewrite of {put,prep}_scaled functions
Now, the required stack space for dav1d should be: 62 KB on x86_64 and
58KB on arm and aarch64.
- Improvements on the SSSE3 SGR
- Improvements on ARM32/ARM64 looprestoration optimizations
- RISC-V: blend optimizations for high bitdepth
- Power9: blend optimizations for 8bpc
- Port RISC-V to POSIX/non-Linux OS
- AArch64: Add Neon implementation of load_tmvs
- Fix a rare, but possible deadlock, in flush()
Changes for 1.5.0 'Sonic':
--------------------------
1.5.0 is a major release of dav1d, that:
- WARNING: we removed some of the SSE2 optimizations, so if you care about
systems without SSSE3, you should be careful when updating!
- Add Arm OpenBSD run-time CPU feature
- Optimize index offset calculations for decode_coefs
- picture: copy HDR10+ and T35 metadata only to visible frames
- SSSE3 new optimizations for 6-tap (8bit and hbd)
- AArch64/SVE: Add HBD subpel filters using 128-bit SVE2
- AArch64: Add USMMLA Implementation for 6-tap H/HV
- AArch64: Optimize Armv8.0 NEON for HBD horizontal filters and 6-tap filters
- Power9: Optimized ITX till 16x4.
- Loongarch: numerous optimizations
- RISC-V optimizations for pal, cdef_filter, ipred, mc_blend, mc_bdir, itx
- Allow playing videos in full-screen mode in dav1dplay
Changes for 1.4.3 'Road Runner':
--------------------------------
1.4.3 is a small release focused on security issues
- AArch64: Fix potential out of bounds access in DotProd H/HV filters
- cli: Prevent buffer over-read
Changes for 1.4.2 'Road Runner':
--------------------------------
1.4.2 is a small release of dav1d, improving notably ARM, AVX-512 and PowerPC
- AVX2 optimizations for 8-tap and new variants for 6-tap
- AVX-512 optimizations for 8-tap and new variants for 6-tap
- Improve entropy decoding on ARM64
- New ARM64 optimizations for convolutions based on DotProd extension
- New ARM64 optimizations for convolutions based on i8mm extension
- New ARM64 optimizations for subpel and prep filters for i8mm
- Misc improvements on existing ARM64 optimizations, notably for put/prep
- New PowerPC9 optimizations for loopfilter
- Support for macOS kperf API for benchmarking
Changes for 1.4.1 'Road Runner':
--------------------------------
1.4.1 is a small release of dav1d, improving notably ARM and RISC-V speed
- Optimizations for 6tap filters for NEON (ARM)
- More RISC-V optimizations for itx (4x8, 8x4, 4x16, 16x4, 8x16, 16x8)
- Reduction of binary size on ARM64, ARM32 and RISC-V
- Fix out-of-bounds read in 8bpc SSE2/SSSE3 wiener_filter
- Msac optimizations
Changes for 1.4.0 'Road Runner':
--------------------------------
1.4.0 is a medium release of dav1d, focusing on new architecture support and optimizations
- AVX-512 optimizations for z1, z2, z3 in 8bit and high-bitdepth
- New architecture supported: loongarch
- Loongarch optimizations for 8bit
- New architecture supported: RISC-V
- RISC-V optimizations for itx
- Misc improvements in threading and in reducing binary size
- Fix potential integer overflow with extremely large frame sizes (CVE-2024-1580)
Changes for 1.3.0 'Tundra Peregrine Falcon (Calidus)':
------------------------------------------------------
1.3.0 is a medium release of dav1d, focus on new APIs and memory usage reduction.
- Reduce memory usage in numerous places
- ABI break in Dav1dSequenceHeader, Dav1dFrameHeader, Dav1dContentLightLevel structures
- new API function to check the API version: dav1d_version_api()
- Rewrite of the SGR functions for ARM64 to be faster
- NEON implemetation of save_tmvs for ARM32 and ARM64
- x86 palette DSP for pal_idx_finish function
Changes for 1.2.1 'Arctic Peregrine Falcon':
--------------------------------------------
1.2.1 is a small release of dav1d, adding more SIMD and fixes
- Fix a threading race on task_thread.init_done
- NEON z2 8bpc and high bit-depth optimizations
- SSSE3 z2 high bit-depth optimziations
- Fix a desynced luma/chroma planes issue with Film Grain
- Reduce memory consumption
- Improve dav1d_parse_sequence_header() speed
- OBU: Improve header parsing and fix potential overflows
- OBU: Improve ITU-T T.35 parsing speed
- Misc buildsystems, CI and headers fixes
Changes for 1.2.0 'Arctic Peregrine Falcon':
--------------------------------------------
1.2.0 is a small release of dav1d, adding more SIMD and fixes
- Improvements on attachments of props and T.35 entries on output pictures
- NEON z1/z3 high bit-depth optimizations and improvements for 8bpc
- SSSE3 z2/z3 8bpc and SSSE3 z1/z3 high bit-depth optimziations
- refmvs.save_tmvs optimizations in SSSE3/AVX2/AVX-512
- AVX-512 optimizations for high bit-depth itx (16x64, 32x64, 64x16, 64x32, 64x64)
- AVX2 optimizations for 12bpc for 16x32, 32x16, 32x32 itx
Changes for 1.1.0 'Arctic Peregrine Falcon':
--------------------------------------------
1.1.0 is an important release of dav1d, fixing numerous bugs, and adding SIMD
- New function dav1d_get_frame_delay to query the decoder frame delay
- Numerous fixes for strict conformity to the specs and samples
- NEON and AVX-512 misc fixes and improvements
- Partial AVX2 12bpc transform implementations
- AVX-512 high bit-depth cdef_filter, loopfilter, itx
- NEON z1/z3 optimization for 8bpc
- SSSE3 z1 optimization for 8bpc
"From VideoLAN with love"
Changes for 1.0.0 'Peregrine Falcon':
-------------------------------------
1.0.0 is a major release of dav1d, adding important features and bug fixes.
It notably changes, in an important way, the way threading works, by adding
an automatic thread management.
It also adds support for AVX-512 acceleration, and adds speedups to existing x86
code (from SSE2 to AVX2).
1.0.0 adds new grain API to ease acceleration on the GPU, and adds an API call
to get information of which frame failed to decode, in error cases.
Finally, 1.0.0 fixes numerous small bugs that were reported since the beginning
of the project to have a proper release.
.''.
.''. . *''* :_\/_: .
:_\/_: _\(/_ .:.*_\/_* : /\ : .'.:.'.
.''.: /\ : ./)\ ':'* /\ * : '..'. -=:o:=-
:_\/_:'.:::. ' *''* * '.\'/.' _\(/_'.':'.'
: /\ : ::::: *_\/_* -= o =- /)\ ' *
'..' ':::' * /\ * .'/.\'. '
* *..* :
* :
* 1.0.0
Changes for 0.9.2 'Golden Eagle':
---------------------------------
0.9.2 is a small update of dav1d on the 0.9.x branch:
- x86: SSE4 optimizations of inverse transforms for 10bit for all sizes
- x86: mc.resize optimizations with AVX2/SSSE3 for 10/12b
- x86: SSSE3 optimizations for cdef_filter in 10/12b and mc_w_mask_422/444 in 8b
- ARM NEON optimizations for FilmGrain Gen_grain functions
- Optimizations for splat_mv in SSE2/AVX2 and NEON
- x86: SGR improvements for SSSE3 CPUs
- x86: AVX2 optimizations for cfl_ac
Changes for 0.9.1 'Golden Eagle':
---------------------------------
0.9.1 is a middle-size revision of dav1d, adding notably 10b acceleration for SSSE3:
- 10/12b SSSE3 optimizations for mc (avg, w_avg, mask, w_mask, emu_edge),
prep/put_bilin, prep/put_8tap, ipred (dc/h/v, paeth, smooth, pal, filter), wiener,
sgr (10b), warp8x8, deblock, film_grain, cfl_ac/pred for 32bit and 64bit x86 processors
- Film grain NEON for fguv 10/12b, fgy/fguv 8b and fgy/fguv 10/12 arm32
- Fixes for filmgrain on ARM
- itx 10bit optimizations for 4x4/x8/x16, 8x4/x8/x16 for SSE4
- Misc improvements on SSE2, SSE4
Changes for 0.9.0 'Golden Eagle':
---------------------------------
0.9.0 is a major version of dav1d, adding notably 10b acceleration on x64.
Details:
- x86 (64bit) AVX2 implementation of most 10b/12b functions, which should provide
a large boost for high-bitdepth decoding on modern x86 computers and servers.
- ARM64 neon implementation of FilmGrain (4:2:0/4:2:2/4:4:4 8bit)
- New API to signal events happening during the decoding process
Changes for 0.8.2 'Eurasian Hobby':
-----------------------------------
0.8.2 is a middle-size update of the 0.8.0 branch:
- ARM32 optimizations for ipred and itx in 10/12bits,
completing the 10b/12b work on ARM64 and ARM32
- Give the post-filters their own threads
- ARM64: rewrite the wiener functions
- Speed up coefficient decoding, 0.5%-3% global decoding gain
- x86 optimizations for CDEF_filter and wiener in 10/12bit
- x86: rewrite the SGR AVX2 asm
- x86: improve msac speed on SSE2+ machines
- ARM32: improve speed of ipred and warp
- ARM64: improve speed of ipred, cdef_dir, cdef_filter, warp_motion and itx16
- ARM32/64: improve speed of looprestoration
- Add seeking, pausing to the player
- Update the player for rendering of 10b/12b
- Misc speed improvements and fixes on all platforms
- Add a xxh3 muxer in the dav1d application
Changes for 0.8.1 'Eurasian Hobby':
-----------------------------------
0.8.1 is a minor update on 0.8.0:
- Keep references to buffers valid after dav1d_close(). Fixes a regression
caused by the picture buffer pool added in 0.8.0.
- ARM32 optimizations for 10bit bitdepth for SGR
- ARM32 optimizations for 16bit bitdepth for blend/w_masl/emu_edge
- ARM64 optimizations for 10bit bitdepth for SGR
- x86 optimizations for wiener in SSE2/SSSE3/AVX2
Changes for 0.8.0 'Eurasian Hobby':
-----------------------------------
0.8.0 is a major update for dav1d:
- Improve the performance by using a picture buffer pool;
The improvements can reach 10% on some cases on Windows.
- Support for Apple ARM Silicon
- ARM32 optimizations for 8bit bitdepth for ipred paeth, smooth, cfl
- ARM32 optimizations for 10/12/16bit bitdepth for mc_avg/mask/w_avg,
put/prep 8tap/bilin, wiener and CDEF filters
- ARM64 optimizations for cfl_ac 444 for all bitdepths
- x86 optimizations for MC 8-tap, mc_scaled in AVX2
- x86 optimizations for CDEF in SSE and {put/prep}_{8tap/bilin} in SSSE3
Changes for 0.7.1 'Frigatebird':
------------------------------
0.7.1 is a minor update on 0.7.0:
- ARM32 NEON optimizations for itxfm, which can give up to 28% speedup, and MSAC
- SSE2 optimizations for prep_bilin and prep_8tap
- AVX2 optimizations for MC scaled
- Fix a clamping issue in motion vector projection
- Fix an issue on some specific Haswell CPU on ipred_z AVX2 functions
- Improvements on the dav1dplay utility player to support resizing
Changes for 0.7.0 'Frigatebird':
------------------------------
0.7.0 is a major release for dav1d:
- Faster refmv implementation gaining up to 12% speed while -25% of RAM (Single Thread)
- 10b/12b ARM64 optimizations are mostly complete:
- ipred (paeth, smooth, dc, pal, filter, cfl)
- itxfm (only 10b)
- AVX2/SSSE3 for non-4:2:0 film grain and for mc.resize
- AVX2 for cfl4:4:4
- AVX-512 CDEF filter
- ARM64 8b improvements for cfl_ac and itxfm
- ARM64 implementation for emu_edge in 8b/10b/12b
- ARM32 implementation for emu_edge in 8b
- Improvements on the dav1dplay utility player to support 10 bit,
non-4:2:0 pixel formats and film grain on the GPU
Changes for 0.6.0 'Gyrfalcon':
------------------------------
0.6.0 is a major release for dav1d:
- New ARM64 optimizations for the 10/12bit depth:
- mc_avg, mc_w_avg, mc_mask
- mc_put/mc_prep 8tap/bilin
- mc_warp_8x8
- mc_w_mask
- mc_blend
- wiener
- SGR
- loopfilter
- cdef
- New AVX-512 optimizations for prep_bilin, prep_8tap, cdef_filter, mc_avg/w_avg/mask
- New SSSE3 optimizations for film grain
- New AVX2 optimizations for msac_adapt16
- Fix rare mismatches against the reference decoder, notably because of clipping
- Improvements on ARM64 on msac, cdef, mc_blend_v and looprestoration optimizations
- Improvements on AVX2 optimizations for cdef_filter
- Improvements in the C version for itxfm, cdef_filter
Changes for 0.5.2 'Asiatic Cheetah':
------------------------------------
0.5.2 is a small release improving speed for ARM32 and adding minor features:
- ARM32 optimizations for loopfilter, ipred_dc|h|v
- Add section-5 raw OBU demuxer
- Improve the speed by reducing the L2 cache collisions
- Fix minor issues
Changes for 0.5.1 'Asiatic Cheetah':
------------------------------------
0.5.1 is a small release improving speeds and fixing minor issues
compared to 0.5.0:
- SSE2 optimizations for CDEF, wiener and warp_affine
- NEON optimizations for SGR on ARM32
- Fix mismatch issue in x86 asm in inverse identity transforms
- Fix build issue in ARM64 assembly if debug info was enabled
- Add a workaround for Xcode 11 -fstack-check bug
Changes for 0.5.0 'Asiatic Cheetah':
------------------------------------
0.5.0 is a medium release fixing regressions and minor issues,
and improving speed significantly:
- Export ITU T.35 metadata
- Speed improvements on blend_ on ARM
- Speed improvements on decode_coef and MSAC
- NEON optimizations for blend*, w_mask_, ipred functions for ARM64
- NEON optimizations for CDEF and warp on ARM32
- SSE2 optimizations for MSAC hi_tok decoding
- SSSE3 optimizations for deblocking loopfilters and warp_affine
- AVX2 optimizations for film grain and ipred_z2
- SSE4 optimizations for warp_affine
- VSX optimizations for wiener
- Fix inverse transform overflows in x86 and NEON asm
- Fix integer overflows with large frames
- Improve film grain generation to match reference code
- Improve compatibility with older binutils for ARM
- More advanced Player example in tools
Changes for 0.4.0 'Cheetah':
----------------------------
- Fix playback with unknown OBUs
- Add an option to limit the maximum frame size
- SSE2 and ARM64 optimizations for MSAC
- Improve speed on 32bits systems
- Optimization in obmc blend
- Reduce RAM usage significantly
- The initial PPC SIMD code, cdef_filter
- NEON optimizations for blend functions on ARM
- NEON optimizations for w_mask functions on ARM
- NEON optimizations for inverse transforms on ARM64
- VSX optimizations for CDEF filter
- Improve handling of malloc failures
- Simple Player example in tools
Changes for 0.3.1 'Sailfish':
------------------------------
- Fix a buffer overflow in frame-threading mode on SSSE3 CPUs
- Reduce binary size, notably on Windows
- SSSE3 optimizations for ipred_filter
- ARM optimizations for MSAC
Changes for 0.3.0 'Sailfish':
------------------------------
This is the final release for the numerous speed improvements of 0.3.0-rc.
It mostly:
- Fixes an annoying crash on SSSE3 that happened in the itx functions
Changes for 0.2.2 (0.3.0-rc) 'Antelope':
-----------------------------
- Large improvement on MSAC decoding with SSE, bringing 4-6% speed increase
The impact is important on SSSE3, SSE4 and AVX2 cpus
- SSSE3 optimizations for all blocks size in itx
- SSSE3 optimizations for ipred_paeth and ipred_cfl (420, 422 and 444)
- Speed improvements on CDEF for SSE4 CPUs
- NEON optimizations for SGR and loop filter
- Minor crashes, improvements and build changes
Changes for 0.2.1 'Antelope':
----------------------------
- SSSE3 optimization for cdef_dir
- AVX2 improvements of the existing CDEF optimizations
- NEON improvements of the existing CDEF and wiener optimizations
- Clarification about the numbering/versionning scheme
Changes for 0.2.0 'Antelope':
----------------------------
- ARM64 and ARM optimizations using NEON instructions
- SSSE3 optimizations for both 32 and 64bits
- More AVX2 assembly, reaching almost completion
- Fix installation of includes
- Rewrite inverse transforms to avoid overflows
- Snap packaging for Linux
- Updated API (ABI and API break)
- Fixes for un-decodable samples
Changes for 0.1.0 'Gazelle':
----------------------------
Initial release of dav1d, the fast and small AV1 decoder.
- Support for all features of the AV1 bitstream
- Support for all bitdepth, 8, 10 and 12bits
- Support for all chroma subsamplings 4:2:0, 4:2:2, 4:4:4 *and* grayscale
- Full acceleration for AVX2 64bits processors, making it the fastest decoder
- Partial acceleration for SSSE3 processors
- Partial acceleration for NEON processors

View file

@ -0,0 +1,168 @@
![dav1d logo](doc/dav1d_logo.png)
# dav1d
**dav1d** is an **AV1** cross-platform **d**ecoder, open-source, and focused on speed and correctness.
It is now battle-tested and production-ready and can be used everywhere.
The canonical repository URL for this repo is https://code.videolan.org/videolan/dav1d
This project was partially funded by the *Alliance for Open Media*/**AOM**.
## Goal and Features
The goal of this project is to provide a decoder for **most platforms**, and achieve the **highest speed** possible to overcome the temporary lack of AV1 hardware decoder.
It supports all features from AV1, including all subsampling and bit-depth parameters.
In the future, this project will host simple tools or simple wrappings *(like, for example, an MFT transform)*.
## License
**dav1d** is released under a very liberal license, a contrario from the other VideoLAN projects, so that it can be embedded anywhere, including non-open-source software; or even drivers, to allow the creation of hybrid decoders.
The reasoning behind this decision is the same as for libvorbis, see [RMS on vorbis](https://lwn.net/2001/0301/a/rms-ov-license.php3).
# Roadmap
The plan is the following:
### Reached
1. Complete C implementation of the decoder,
2. Provide a usable API,
3. Port to most platforms,
4. Make it fast on desktop, by writing asm for AVX2 chips.
5. Make it fast on mobile, by writing asm for ARMv8 chips,
6. Make it fast on older desktop, by writing asm for SSSE3+ chips,
7. Make high bit-depth fast on mobile, by writing asm for ARMv8 chips.
8. Make it fast on older mobile, by writing asm for ARMv7 chips,
9. Make high bit-depth fast on older mobile, by writing asm for ARMv7 chips,
10. Make high bit-depth fast on desktop, by writing asm for AVX2 chips,
11. Make high bit-depth fast on older desktop, by writing asm for SSSE3+ chips,
12. Improve threading.
### On-going
13. Improve C code base with [various tweaks](https://code.videolan.org/videolan/dav1d/wikis/task-list),
14. Accelerate for less common architectures, like PPC, SSE2, RISC-V or AVX-512.
### After
15. Use more GPU decoding, when possible.
# Contribute
Currently, we are looking for help from:
- C developers,
- asm developers,
- platform-specific developers,
- GPGPU developers,
- testers.
Our contributions guidelines are quite strict. We want to build a coherent codebase to simplify maintenance and achieve the highest possible speed.
Notably, the codebase is in pure C and asm.
We are on IRC, on the **#dav1d** channel on [*Libera.chat*](http://libera.chat/). If you do not have an IRC Client at hand, use [IRC Web Interface](https://web.libera.chat/#dav1d).
See the [contributions document](CONTRIBUTING.md).
## CLA
There is no CLA.
People will keep their copyright and their authorship rights, while adhering to the BSD 2-clause license.
VideoLAN will only have the collective work rights.
## CoC
The [VideoLAN Code of Conduct](https://wiki.videolan.org/CoC) applies to this project.
# Compile
## General compilation steps
1. Install [Meson](https://mesonbuild.com/) (0.49 or higher), [Ninja](https://ninja-build.org/), and, for x86\* targets, [nasm](https://nasm.us/) (2.14 or higher)
2. Run `mkdir build && cd build` to create a build directory and enter it
3. Run `meson setup ..` to configure meson, add `--default-library=static` if static linking is desired
4. Run `ninja` to compile
Following are modification of step 3 and 4, for specific purpose.
## Cross-Compilation for 32- or 64-bit Windows, 32-bit Linux
If you're on a linux build machine trying to compile .exe for a Windows target/host machine, configure meson like this
```
meson setup .. --cross-file=../package/crossfiles/x86_64-w64-mingw32.meson
```
or, for 32-bit:
```
meson setup .. --cross-file=../package/crossfiles/i686-w64-mingw32.meson
```
`mingw-w64` is a pre-requisite and should be installed on your linux machine via your preferred method or package manager. Note the binary name formats may differ between distributions. Verify the names, and use `alias` if certain binaries cannot be found.
For 32-bit linux, run
```
meson setup .. --cross-file=../package/crossfiles/i686-linux32.meson
```
## Build documentation
1. Make sure [doxygen](https://www.doxygen.nl/) and [graphviz](https://www.graphviz.org/) are installed.
2. Run `meson setup .. -Denable_docs=true` to configure meson to generate docs from the build directory.
3. Run `ninja doc/html` to build the docs
The result can be found in `build/doc/html/`. An online version built from master can be found [here](https://videolan.videolan.me/dav1d/).
# Run tests
1. In the root directory, run `git clone https://code.videolan.org/videolan/dav1d-test-data.git tests/dav1d-test-data` to fetch the test data repository
2. During meson configuration, specify `-Dtestdata_tests=true`
3. Run `meson test -v` after compiling
## Decoder conformance tests (optional but encouraged)
1. Download the argon conformance bitstreams from https://streams.videolan.org/argon/
2. Extract into dav1d directory by running `tar -xvf argon.tar.zst`
3. Execute tests with `tests/dav1d_argon.bash -d build/tools/dav1d -a argon`
4. Expected outcome is `2763 files successfully verified in XXmYYs (dav1d 1.x.y-zz-gHHHHHHH filmgrain=1 cpumask=-1)`
# Support
This project is partially funded by the *Alliance for Open Media*/**AOM** and is supported by TwoOrioles and VideoLabs.
These companies can provide support and integration help, should you need it.
# FAQ
## Why do you not improve libaom rather than starting a new project?
- We believe that libaom is a very good library. It was however developed for research purposes during AV1 design.
We think that an implementation written from scratch can achieve faster decoding, in the same way that *ffvp9* was faster than *libvpx*.
## Is dav1d a recursive acronym?
- Yes.
## Can I help?
- Yes. See the [contributions document](CONTRIBUTING.md).
## I am not a developer. Can I help?
- Yes. We need testers, bug reporters and documentation writers.
## What about the AV1 patent license?
- This project is an implementation of a decoder. It gives you no special rights on the AV1 patents.
Please read the [AV1 patent license](doc/PATENTS) that applies to the AV1 specification and codec.
## Will you care about <my_arch>? <my_os>?
- We do, but we don't have either the time or the knowledge. Therefore, patches and contributions welcome.

View file

@ -0,0 +1,35 @@
# The dav1d project and VideoLAN association would like to thank
## AOM
The Alliance for Open Media (AOM) for partially funding this project.
## Companies
* Two Orioles LLC, for important coding effort
* VideoLabs SAS
## Projects
* VideoLAN
* FFmpeg
* libplacebo
## Individual
And all the dav1d Authors (git shortlog -sn), including:
Henrik Gramner, Martin Storsjö, Ronald S. Bultje, Janne Grunau, James Almer,
Victorien Le Couviour--Tuffet, Matthias Dressel, Nathan E. Egge,
Jean-Baptiste Kempf, Marvin Scholz, Luc Trudeau, Niklas Haas,
Hugo Beauzée-Luyssen, Konstantin Pavlov, David Michael Barr, Steve Lhomme,
yuanhecai, Luca Barbato, Wan-Teh Chang, Kyle Siefring, B Krishnan Iyer,
Francois Cartegnie, Liwei Wang, David Conrad, Derek Buitenhuis, Jan Beich,
Michael Bradshaw, Raphaël Zumer, Xuefeng Jiang, Arpad Panyik, Christophe Gisquet,
Justin Bull, Boyuan Xiao, Dale Curtis, Emmanuel Gil Peyrot, Raphael Zumer,
Rupert Swarbrick, Thierry Foucu, Thomas Daede, jinbo, André Kempe, Colin Lee,
Jonathan Wright, Lynne, Michail Alvanos, Nico Weber, Salome Thirot, SmilingWolf,
Tristan Laurent, Tristan Matthews, Vittorio Giovara, Yannis Guyon,
Andrey Semashev, Anisse Astier, Anton Mitrofanov, Charlie Hayden, Dmitriy Sychov,
Ewout ter Hoeven, Fred Barbier, Hao Chen, Jean-Yves Avenard, Joe Drago,
Mark Shuttleworth, Matthieu Bouron, Mehdi Sabwat, Nicolas Frattaroli,
Pablo Stebler, Rostislav Pehlivanov, Sebastian Dröge, Shiz, Steinar Midtskogen,
Sylvain BERTRAND, Sylvestre Ledru, Timo Gurr, Vibhoothi,
Vignesh Venkatasubramanian, Xavier Claessens, Xu Guangxin, kossh1 and skal.

View file

@ -0,0 +1,23 @@
PROJECT_NAME = dav1d
PROJECT_NUMBER = \@VCS_TAG\@
PROJECT_BRIEF = dav1d is an AV1 decoder
OUTPUT_DIRECTORY = @DOXYGEN_OUTPUT@
STRIP_FROM_PATH = @DOXYGEN_STRIP@
OUTPUT_LANGUAGE = English
TAB_SIZE = 4
EXTRACT_ALL = YES
OPTIMIZE_OUTPUT_FOR_C = YES
DOXYFILE_ENCODING = UTF-8
TYPEDEF_HIDES_STRUCT = YES
HAVE_DOT = YES
QUIET = YES
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_AS_ERROR = FAIL_ON_WARNINGS
INPUT = @DOXYGEN_INPUT@
FILE_PATTERNS = *.h
GENERATE_HTML = YES
GENERATE_LATEX = NO

View file

@ -0,0 +1,108 @@
Alliance for Open Media Patent License 1.0
1. License Terms.
1.1. Patent License. Subject to the terms and conditions of this License, each
Licensor, on behalf of itself and successors in interest and assigns,
grants Licensee a non-sublicensable, perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as expressly stated in this
License) patent license to its Necessary Claims to make, use, sell, offer
for sale, import or distribute any Implementation.
1.2. Conditions.
1.2.1. Availability. As a condition to the grant of rights to Licensee to make,
sell, offer for sale, import or distribute an Implementation under
Section 1.1, Licensee must make its Necessary Claims available under
this License, and must reproduce this License with any Implementation
as follows:
a. For distribution in source code, by including this License in the
root directory of the source code with its Implementation.
b. For distribution in any other form (including binary, object form,
and/or hardware description code (e.g., HDL, RTL, Gate Level Netlist,
GDSII, etc.)), by including this License in the documentation, legal
notices, and/or other written materials provided with the
Implementation.
1.2.2. Additional Conditions. This license is directly from Licensor to
Licensee. Licensee acknowledges as a condition of benefiting from it
that no rights from Licensor are received from suppliers, distributors,
or otherwise in connection with this License.
1.3. Defensive Termination. If any Licensee, its Affiliates, or its agents
initiates patent litigation or files, maintains, or voluntarily
participates in a lawsuit against another entity or any person asserting
that any Implementation infringes Necessary Claims, any patent licenses
granted under this License directly to the Licensee are immediately
terminated as of the date of the initiation of action unless 1) that suit
was in response to a corresponding suit regarding an Implementation first
brought against an initiating entity, or 2) that suit was brought to
enforce the terms of this License (including intervention in a third-party
action by a Licensee).
1.4. Disclaimers. The Reference Implementation and Specification are provided
"AS IS" and without warranty. The entire risk as to implementing or
otherwise using the Reference Implementation or Specification is assumed
by the implementer and user. Licensor expressly disclaims any warranties
(express, implied, or otherwise), including implied warranties of
merchantability, non-infringement, fitness for a particular purpose, or
title, related to the material. IN NO EVENT WILL LICENSOR BE LIABLE TO
ANY OTHER PARTY FOR LOST PROFITS OR ANY FORM OF INDIRECT, SPECIAL,
INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER FROM ANY CAUSES OF
ACTION OF ANY KIND WITH RESPECT TO THIS LICENSE, WHETHER BASED ON BREACH
OF CONTRACT, TORT (INCLUDING NEGLIGENCE), OR OTHERWISE, AND WHETHER OR
NOT THE OTHER PARTRY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2. Definitions.
2.1. Affiliate. “Affiliate” means an entity that directly or indirectly
Controls, is Controlled by, or is under common Control of that party.
2.2. Control. “Control” means direct or indirect control of more than 50% of
the voting power to elect directors of that corporation, or for any other
entity, the power to direct management of such entity.
2.3. Decoder. "Decoder" means any decoder that conforms fully with all
non-optional portions of the Specification.
2.4. Encoder. "Encoder" means any encoder that produces a bitstream that can
be decoded by a Decoder only to the extent it produces such a bitstream.
2.5. Final Deliverable. “Final Deliverable” means the final version of a
deliverable approved by the Alliance for Open Media as a Final
Deliverable.
2.6. Implementation. "Implementation" means any implementation, including the
Reference Implementation, that is an Encoder and/or a Decoder. An
Implementation also includes components of an Implementation only to the
extent they are used as part of an Implementation.
2.7. License. “License” means this license.
2.8. Licensee. “Licensee” means any person or entity who exercises patent
rights granted under this License.
2.9. Licensor. "Licensor" means (i) any Licensee that makes, sells, offers
for sale, imports or distributes any Implementation, or (ii) a person
or entity that has a licensing obligation to the Implementation as a
result of its membership and/or participation in the Alliance for Open
Media working group that developed the Specification.
2.10. Necessary Claims. "Necessary Claims" means all claims of patents or
patent applications, (a) that currently or at any time in the future,
are owned or controlled by the Licensor, and (b) (i) would be an
Essential Claim as defined by the W3C Policy as of February 5, 2004
(https://www.w3.org/Consortium/Patent-Policy-20040205/#def-essential)
as if the Specification was a W3C Recommendation; or (ii) are infringed
by the Reference Implementation.
2.11. Reference Implementation. “Reference Implementation” means an Encoder
and/or Decoder released by the Alliance for Open Media as a Final
Deliverable.
2.12. Specification. “Specification” means the specification designated by
the Alliance for Open Media as a Final Deliverable for which this
License was issued.

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.3 KiB

View file

@ -0,0 +1,51 @@
# Copyright © 2018-2022, VideoLAN and dav1d authors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. 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.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
if not get_option('enable_docs')
subdir_done()
endif
doxygen = find_program('doxygen')
dot = find_program('dot')
conf_data = configuration_data()
conf_data.set('DOXYGEN_INPUT', dav1d_src_root / 'include/dav1d')
conf_data.set('DOXYGEN_STRIP', dav1d_src_root / 'include')
conf_data.set('DOXYGEN_OUTPUT', meson.current_build_dir())
doxyfile = configure_file(input: 'Doxyfile.in.in',
output: 'Doxyfile.in',
configuration: conf_data)
doxyfile_rev_target = vcs_tag(command: [
'git', '--git-dir', dav1d_git_dir, 'describe', '--long', '--always'
],
input: doxyfile,
output: 'Doxyfile'
)
custom_target('doc',
build_by_default: false,
command: [doxygen, doxyfile_rev_target],
output: ['html']
)

View file

@ -0,0 +1,792 @@
/*
* Copyright © 2019, VideoLAN and dav1d authors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include "config.h"
#include "vcs_version.h"
#include <getopt.h>
#include <stdbool.h>
#include <SDL.h>
#include "dav1d/dav1d.h"
#include "common/attributes.h"
#include "tools/input/input.h"
#include "dp_fifo.h"
#include "dp_renderer.h"
#define FRAME_OFFSET_TO_PTS(foff) \
(uint64_t)(((foff) * rd_ctx->spf) * 1000000000.0 + .5)
#define TS_TO_PTS(ts) \
(uint64_t)(((ts) * rd_ctx->timebase) * 1000000000.0 + .5)
// Selected renderer callbacks and cookie
static const Dav1dPlayRenderInfo *renderer_info = { NULL };
/**
* Render context structure
* This structure contains informations necessary
* to be shared between the decoder and the renderer
* threads.
*/
typedef struct render_context
{
Dav1dPlaySettings settings;
Dav1dSettings lib_settings;
// Renderer private data (passed to callbacks)
void *rd_priv;
// Lock to protect access to the context structure
SDL_mutex *lock;
// Timestamp of last displayed frame (in timebase unit)
int64_t last_ts;
// Timestamp of last decoded frame (in timebase unit)
int64_t current_ts;
// Ticks when last frame was received
uint32_t last_ticks;
// PTS time base
double timebase;
// Seconds per frame
double spf;
// Number of frames
uint32_t total;
// Fifo
Dav1dPlayPtrFifo *fifo;
// Custom SDL2 event types
uint32_t event_types;
// User pause state
uint8_t user_paused;
// Internal pause state
uint8_t paused;
// Start of internal pause state
uint32_t pause_start;
// Duration of internal pause state
uint32_t pause_time;
// Seek accumulator
int seek;
// Indicates if termination of the decoder thread was requested
uint8_t dec_should_terminate;
} Dav1dPlayRenderContext;
static void dp_settings_print_usage(const char *const app,
const char *const reason, ...)
{
if (reason) {
va_list args;
va_start(args, reason);
vfprintf(stderr, reason, args);
va_end(args);
fprintf(stderr, "\n\n");
}
fprintf(stderr, "Usage: %s [options]\n\n", app);
fprintf(stderr, "Supported options:\n"
" --input/-i $file: input file\n"
" --untimed/-u: ignore PTS, render as fast as possible\n"
" --threads $num: number of threads (default: 0)\n"
" --framedelay $num: maximum frame delay, capped at $threads (default: 0);\n"
" set to 1 for low-latency decoding\n"
" --highquality: enable high quality rendering\n"
" --zerocopy/-z: enable zero copy upload path\n"
" --gpugrain/-g: enable GPU grain synthesis\n"
" --fullscreen/-f: enable full screen mode\n"
" --version/-v: print version and exit\n"
" --renderer/-r: select renderer backend (default: auto)\n");
exit(1);
}
static unsigned parse_unsigned(const char *const optarg, const int option,
const char *const app)
{
char *end;
const unsigned res = (unsigned) strtoul(optarg, &end, 0);
if (*end || end == optarg)
dp_settings_print_usage(app, "Invalid argument \"%s\" for option %s; should be an integer",
optarg, option);
return res;
}
static void dp_rd_ctx_parse_args(Dav1dPlayRenderContext *rd_ctx,
const int argc, char *const *const argv)
{
int o;
Dav1dPlaySettings *settings = &rd_ctx->settings;
Dav1dSettings *lib_settings = &rd_ctx->lib_settings;
// Short options
static const char short_opts[] = "i:vuzgfr:";
enum {
ARG_THREADS = 256,
ARG_FRAME_DELAY,
ARG_HIGH_QUALITY,
};
// Long options
static const struct option long_opts[] = {
{ "input", 1, NULL, 'i' },
{ "version", 0, NULL, 'v' },
{ "untimed", 0, NULL, 'u' },
{ "threads", 1, NULL, ARG_THREADS },
{ "framedelay", 1, NULL, ARG_FRAME_DELAY },
{ "highquality", 0, NULL, ARG_HIGH_QUALITY },
{ "zerocopy", 0, NULL, 'z' },
{ "gpugrain", 0, NULL, 'g' },
{ "fullscreen", 0, NULL, 'f'},
{ "renderer", 0, NULL, 'r'},
{ NULL, 0, NULL, 0 },
};
while ((o = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
switch (o) {
case 'i':
settings->inputfile = optarg;
break;
case 'v':
fprintf(stderr, "%s\n", dav1d_version());
exit(0);
case 'u':
settings->untimed = true;
break;
case ARG_HIGH_QUALITY:
settings->highquality = true;
break;
case 'z':
settings->zerocopy = true;
break;
case 'g':
settings->gpugrain = true;
break;
case 'f':
settings->fullscreen = true;
break;
case 'r':
settings->renderer_name = optarg;
break;
case ARG_THREADS:
lib_settings->n_threads =
parse_unsigned(optarg, ARG_THREADS, argv[0]);
break;
case ARG_FRAME_DELAY:
lib_settings->max_frame_delay =
parse_unsigned(optarg, ARG_FRAME_DELAY, argv[0]);
break;
default:
dp_settings_print_usage(argv[0], NULL);
}
}
if (optind < argc)
dp_settings_print_usage(argv[0],
"Extra/unused arguments found, e.g. '%s'\n", argv[optind]);
if (!settings->inputfile)
dp_settings_print_usage(argv[0], "Input file (-i/--input) is required");
if (settings->renderer_name && strcmp(settings->renderer_name, "auto") == 0)
settings->renderer_name = NULL;
}
/**
* Destroy a Dav1dPlayRenderContext
*/
static void dp_rd_ctx_destroy(Dav1dPlayRenderContext *rd_ctx)
{
assert(rd_ctx != NULL);
renderer_info->destroy_renderer(rd_ctx->rd_priv);
dp_fifo_destroy(rd_ctx->fifo);
SDL_DestroyMutex(rd_ctx->lock);
free(rd_ctx);
}
/**
* Create a Dav1dPlayRenderContext
*
* \note The Dav1dPlayRenderContext must be destroyed
* again by using dp_rd_ctx_destroy.
*/
static Dav1dPlayRenderContext *dp_rd_ctx_create(int argc, char **argv)
{
Dav1dPlayRenderContext *rd_ctx;
// Alloc
rd_ctx = calloc(1, sizeof(Dav1dPlayRenderContext));
if (rd_ctx == NULL) {
return NULL;
}
// Parse and validate arguments
dav1d_default_settings(&rd_ctx->lib_settings);
memset(&rd_ctx->settings, 0, sizeof(rd_ctx->settings));
dp_rd_ctx_parse_args(rd_ctx, argc, argv);
// Init SDL2 library
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) {
fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError());
goto fail;
}
// Register a custom event to notify our SDL main thread
// about new frames
rd_ctx->event_types = SDL_RegisterEvents(3);
if (rd_ctx->event_types == UINT32_MAX) {
fprintf(stderr, "Failure to create custom SDL event types!\n");
goto fail;
}
rd_ctx->fifo = dp_fifo_create(5);
if (rd_ctx->fifo == NULL) {
fprintf(stderr, "Failed to create FIFO for output pictures!\n");
goto fail;
}
rd_ctx->lock = SDL_CreateMutex();
if (rd_ctx->lock == NULL) {
fprintf(stderr, "SDL_CreateMutex failed: %s\n", SDL_GetError());
goto fail;
}
// Select renderer
renderer_info = dp_get_renderer(rd_ctx->settings.renderer_name);
if (renderer_info == NULL) {
printf("No suitable renderer matching %s found.\n",
(rd_ctx->settings.renderer_name) ? rd_ctx->settings.renderer_name : "auto");
} else {
printf("Using %s renderer\n", renderer_info->name);
}
rd_ctx->rd_priv = (renderer_info) ? renderer_info->create_renderer(&rd_ctx->settings) : NULL;
if (rd_ctx->rd_priv == NULL) {
goto fail;
}
return rd_ctx;
fail:
if (rd_ctx->lock)
SDL_DestroyMutex(rd_ctx->lock);
if (rd_ctx->fifo)
dp_fifo_destroy(rd_ctx->fifo);
free(rd_ctx);
SDL_Quit();
return NULL;
}
/**
* Notify about new event
*/
static void dp_rd_ctx_post_event(Dav1dPlayRenderContext *rd_ctx, uint32_t type)
{
SDL_Event event;
SDL_zero(event);
event.type = type;
SDL_PushEvent(&event);
}
/**
* Update the decoder context with a new dav1d picture
*
* Once the decoder decoded a new picture, this call can be used
* to update the internal texture of the render context with the
* new picture.
*/
static void dp_rd_ctx_update_with_dav1d_picture(Dav1dPlayRenderContext *rd_ctx,
Dav1dPicture *dav1d_pic)
{
rd_ctx->current_ts = dav1d_pic->m.timestamp;
renderer_info->update_frame(rd_ctx->rd_priv, dav1d_pic, &rd_ctx->settings);
}
/**
* Toggle pause state
*/
static void dp_rd_ctx_toggle_pause(Dav1dPlayRenderContext *rd_ctx)
{
SDL_LockMutex(rd_ctx->lock);
rd_ctx->user_paused = !rd_ctx->user_paused;
if (rd_ctx->seek)
goto out;
rd_ctx->paused = rd_ctx->user_paused;
uint32_t now = SDL_GetTicks();
if (rd_ctx->paused)
rd_ctx->pause_start = now;
else {
rd_ctx->pause_time += now - rd_ctx->pause_start;
rd_ctx->pause_start = 0;
rd_ctx->last_ticks = now;
}
out:
SDL_UnlockMutex(rd_ctx->lock);
}
/**
* Query pause state
*/
static int dp_rd_ctx_is_paused(Dav1dPlayRenderContext *rd_ctx)
{
int ret;
SDL_LockMutex(rd_ctx->lock);
ret = rd_ctx->paused;
SDL_UnlockMutex(rd_ctx->lock);
return ret;
}
/**
* Request seeking, in seconds
*/
static void dp_rd_ctx_seek(Dav1dPlayRenderContext *rd_ctx, int sec)
{
SDL_LockMutex(rd_ctx->lock);
rd_ctx->seek += sec;
if (!rd_ctx->paused)
rd_ctx->pause_start = SDL_GetTicks();
rd_ctx->paused = 1;
SDL_UnlockMutex(rd_ctx->lock);
}
static int decode_frame(Dav1dPicture **p, Dav1dContext *c,
Dav1dData *data, DemuxerContext *in_ctx);
static inline void destroy_pic(void *a);
/**
* Seek the stream, if requested
*/
static int dp_rd_ctx_handle_seek(Dav1dPlayRenderContext *rd_ctx,
DemuxerContext *in_ctx,
Dav1dContext *c, Dav1dData *data)
{
int res = 0;
SDL_LockMutex(rd_ctx->lock);
if (!rd_ctx->seek)
goto out;
int64_t seek = rd_ctx->seek * 1000000000ULL;
uint64_t pts = TS_TO_PTS(rd_ctx->current_ts);
pts = ((int64_t)pts > -seek) ? pts + seek : 0;
int end = pts >= FRAME_OFFSET_TO_PTS(rd_ctx->total);
if (end)
pts = FRAME_OFFSET_TO_PTS(rd_ctx->total - 1);
uint64_t target_pts = pts;
dav1d_flush(c);
uint64_t shift = FRAME_OFFSET_TO_PTS(5);
while (1) {
if (shift > pts)
shift = pts;
if ((res = input_seek(in_ctx, pts - shift)))
goto out;
Dav1dSequenceHeader seq;
uint64_t cur_pts;
do {
if ((res = input_read(in_ctx, data)))
break;
cur_pts = TS_TO_PTS(data->m.timestamp);
res = dav1d_parse_sequence_header(&seq, data->data, data->sz);
} while (res && cur_pts < pts);
if (!res && cur_pts <= pts)
break;
if (shift > pts)
shift = pts;
pts -= shift;
}
if (!res) {
pts = TS_TO_PTS(data->m.timestamp);
while (pts < target_pts) {
Dav1dPicture *p;
if ((res = decode_frame(&p, c, data, in_ctx)))
break;
if (p) {
pts = TS_TO_PTS(p->m.timestamp);
if (pts < target_pts)
destroy_pic(p);
else {
dp_fifo_push(rd_ctx->fifo, p);
uint32_t type = rd_ctx->event_types + DAV1D_EVENT_SEEK_FRAME;
dp_rd_ctx_post_event(rd_ctx, type);
}
}
}
if (!res) {
rd_ctx->last_ts = data->m.timestamp - rd_ctx->spf / rd_ctx->timebase;
rd_ctx->current_ts = data->m.timestamp;
}
}
out:
rd_ctx->paused = rd_ctx->user_paused;
if (!rd_ctx->paused && rd_ctx->seek) {
uint32_t now = SDL_GetTicks();
rd_ctx->pause_time += now - rd_ctx->pause_start;
rd_ctx->pause_start = 0;
rd_ctx->last_ticks = now;
}
rd_ctx->seek = 0;
SDL_UnlockMutex(rd_ctx->lock);
if (res)
fprintf(stderr, "Error seeking, aborting\n");
return res;
}
/**
* Terminate decoder thread (async)
*/
static void dp_rd_ctx_request_shutdown(Dav1dPlayRenderContext *rd_ctx)
{
SDL_LockMutex(rd_ctx->lock);
rd_ctx->dec_should_terminate = 1;
SDL_UnlockMutex(rd_ctx->lock);
}
/**
* Query state of decoder shutdown request
*/
static int dp_rd_ctx_should_terminate(Dav1dPlayRenderContext *rd_ctx)
{
int ret = 0;
SDL_LockMutex(rd_ctx->lock);
ret = rd_ctx->dec_should_terminate;
SDL_UnlockMutex(rd_ctx->lock);
return ret;
}
/**
* Render the currently available texture
*
* Renders the currently available texture, if any.
*/
static void dp_rd_ctx_render(Dav1dPlayRenderContext *rd_ctx)
{
SDL_LockMutex(rd_ctx->lock);
// Calculate time since last frame was received
uint32_t ticks_now = SDL_GetTicks();
uint32_t ticks_diff = (rd_ctx->last_ticks != 0) ? ticks_now - rd_ctx->last_ticks : 0;
// Calculate when to display the frame
int64_t ts_diff = rd_ctx->current_ts - rd_ctx->last_ts;
int32_t pts_diff = (ts_diff * rd_ctx->timebase) * 1000.0 + .5;
int32_t wait_time = pts_diff - ticks_diff;
// In untimed mode, simply don't wait
if (rd_ctx->settings.untimed)
wait_time = 0;
// This way of timing the playback is not accurate, as there is no guarantee
// that SDL_Delay will wait for exactly the requested amount of time so in a
// accurate player this would need to be done in a better way.
if (wait_time > 0) {
SDL_Delay(wait_time);
} else if (wait_time < -10 && !rd_ctx->paused) { // Do not warn for minor time drifts
fprintf(stderr, "Frame displayed %f seconds too late\n", wait_time / 1000.0);
}
renderer_info->render(rd_ctx->rd_priv, &rd_ctx->settings);
rd_ctx->last_ts = rd_ctx->current_ts;
rd_ctx->last_ticks = SDL_GetTicks();
SDL_UnlockMutex(rd_ctx->lock);
}
static int decode_frame(Dav1dPicture **p, Dav1dContext *c,
Dav1dData *data, DemuxerContext *in_ctx)
{
int res;
// Send data packets we got from the demuxer to dav1d
if ((res = dav1d_send_data(c, data)) < 0) {
// On EAGAIN, dav1d can not consume more data and
// dav1d_get_picture needs to be called first, which
// will happen below, so just keep going in that case
// and do not error out.
if (res != DAV1D_ERR(EAGAIN)) {
dav1d_data_unref(data);
goto err;
}
}
*p = calloc(1, sizeof(**p));
// Try to get a decoded frame
if ((res = dav1d_get_picture(c, *p)) < 0) {
// In all error cases, even EAGAIN, p needs to be freed as
// it is never added to the queue and would leak.
free(*p);
*p = NULL;
// On EAGAIN, it means dav1d has not enough data to decode
// therefore this is not a decoding error but just means
// we need to feed it more data, which happens in the next
// run of the decoder loop.
if (res != DAV1D_ERR(EAGAIN))
goto err;
}
return data->sz == 0 ? input_read(in_ctx, data) : 0;
err:
fprintf(stderr, "Error decoding frame: %s\n",
strerror(-res));
return res;
}
static inline void destroy_pic(void *a)
{
Dav1dPicture *p = (Dav1dPicture *)a;
dav1d_picture_unref(p);
free(p);
}
/* Decoder thread "main" function */
static int decoder_thread_main(void *cookie)
{
Dav1dPlayRenderContext *rd_ctx = cookie;
Dav1dPicture *p;
Dav1dContext *c = NULL;
Dav1dData data;
DemuxerContext *in_ctx = NULL;
int res = 0;
unsigned total, timebase[2], fps[2];
Dav1dPlaySettings settings = rd_ctx->settings;
if ((res = input_open(&in_ctx, "ivf",
settings.inputfile,
fps, &total, timebase)) < 0)
{
fprintf(stderr, "Failed to open demuxer\n");
res = 1;
goto cleanup;
}
rd_ctx->timebase = (double)timebase[1] / timebase[0];
rd_ctx->spf = (double)fps[1] / fps[0];
rd_ctx->total = total;
if ((res = dav1d_open(&c, &rd_ctx->lib_settings))) {
fprintf(stderr, "Failed opening dav1d decoder\n");
res = 1;
goto cleanup;
}
if ((res = input_read(in_ctx, &data)) < 0) {
fprintf(stderr, "Failed demuxing input\n");
res = 1;
goto cleanup;
}
// Decoder loop
while (1) {
if (dp_rd_ctx_should_terminate(rd_ctx) ||
(res = dp_rd_ctx_handle_seek(rd_ctx, in_ctx, c, &data)) ||
(res = decode_frame(&p, c, &data, in_ctx)))
{
break;
}
else if (p) {
// Queue frame
SDL_LockMutex(rd_ctx->lock);
int seek = rd_ctx->seek;
SDL_UnlockMutex(rd_ctx->lock);
if (!seek) {
dp_fifo_push(rd_ctx->fifo, p);
uint32_t type = rd_ctx->event_types + DAV1D_EVENT_NEW_FRAME;
dp_rd_ctx_post_event(rd_ctx, type);
}
}
}
// Release remaining data
if (data.sz > 0)
dav1d_data_unref(&data);
// Do not drain in case an error occured and caused us to leave the
// decoding loop early.
if (res < 0)
goto cleanup;
// Drain decoder
// When there is no more data to feed to the decoder, for example
// because the file ended, we still need to request pictures, as
// even though we do not have more data, there can be frames decoded
// from data we sent before. So we need to call dav1d_get_picture until
// we get an EAGAIN error.
do {
if (dp_rd_ctx_should_terminate(rd_ctx))
break;
p = calloc(1, sizeof(*p));
res = dav1d_get_picture(c, p);
if (res < 0) {
free(p);
if (res != DAV1D_ERR(EAGAIN)) {
fprintf(stderr, "Error decoding frame: %s\n",
strerror(-res));
break;
}
} else {
// Queue frame
dp_fifo_push(rd_ctx->fifo, p);
uint32_t type = rd_ctx->event_types + DAV1D_EVENT_NEW_FRAME;
dp_rd_ctx_post_event(rd_ctx, type);
}
} while (res != DAV1D_ERR(EAGAIN));
cleanup:
dp_rd_ctx_post_event(rd_ctx, rd_ctx->event_types + DAV1D_EVENT_DEC_QUIT);
if (in_ctx)
input_close(in_ctx);
if (c)
dav1d_close(&c);
return (res != DAV1D_ERR(EAGAIN) && res < 0);
}
int main(int argc, char **argv)
{
SDL_Thread *decoder_thread;
// Check for version mismatch between library and tool
const char *version = dav1d_version();
if (strcmp(version, DAV1D_VERSION)) {
fprintf(stderr, "Version mismatch (library: %s, executable: %s)\n",
version, DAV1D_VERSION);
return 1;
}
// Create render context
Dav1dPlayRenderContext *rd_ctx = dp_rd_ctx_create(argc, argv);
if (rd_ctx == NULL) {
fprintf(stderr, "Failed creating render context\n");
return 5;
}
if (rd_ctx->settings.zerocopy) {
if (renderer_info->alloc_pic) {
rd_ctx->lib_settings.allocator = (Dav1dPicAllocator) {
.cookie = rd_ctx->rd_priv,
.alloc_picture_callback = renderer_info->alloc_pic,
.release_picture_callback = renderer_info->release_pic,
};
} else {
fprintf(stderr, "--zerocopy unsupported by selected renderer\n");
}
}
if (rd_ctx->settings.gpugrain) {
if (renderer_info->supports_gpu_grain) {
rd_ctx->lib_settings.apply_grain = 0;
} else {
fprintf(stderr, "--gpugrain unsupported by selected renderer\n");
}
}
// Start decoder thread
decoder_thread = SDL_CreateThread(decoder_thread_main, "Decoder thread", rd_ctx);
// Main loop
#define NUM_MAX_EVENTS 8
SDL_Event events[NUM_MAX_EVENTS];
int num_frame_events = 0;
uint32_t start_time = 0, n_out = 0;
while (1) {
int num_events = 0;
SDL_WaitEvent(NULL);
while (num_events < NUM_MAX_EVENTS && SDL_PollEvent(&events[num_events++]))
break;
for (int i = 0; i < num_events; ++i) {
SDL_Event *e = &events[i];
if (e->type == SDL_QUIT) {
dp_rd_ctx_request_shutdown(rd_ctx);
dp_fifo_flush(rd_ctx->fifo, destroy_pic);
goto out;
} else if (e->type == SDL_WINDOWEVENT) {
if (e->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
// TODO: Handle window resizes
} else if(e->window.event == SDL_WINDOWEVENT_EXPOSED) {
dp_rd_ctx_render(rd_ctx);
}
} else if (e->type == SDL_KEYDOWN) {
SDL_KeyboardEvent *kbde = (SDL_KeyboardEvent *)e;
if (kbde->keysym.sym == SDLK_SPACE) {
dp_rd_ctx_toggle_pause(rd_ctx);
} else if (kbde->keysym.sym == SDLK_ESCAPE) {
dp_rd_ctx_request_shutdown(rd_ctx);
dp_fifo_flush(rd_ctx->fifo, destroy_pic);
goto out;
} else if (kbde->keysym.sym == SDLK_LEFT ||
kbde->keysym.sym == SDLK_RIGHT)
{
if (kbde->keysym.sym == SDLK_LEFT)
dp_rd_ctx_seek(rd_ctx, -5);
else if (kbde->keysym.sym == SDLK_RIGHT)
dp_rd_ctx_seek(rd_ctx, +5);
dp_fifo_flush(rd_ctx->fifo, destroy_pic);
SDL_FlushEvent(rd_ctx->event_types + DAV1D_EVENT_NEW_FRAME);
num_frame_events = 0;
}
} else if (e->type == rd_ctx->event_types + DAV1D_EVENT_NEW_FRAME) {
num_frame_events++;
// Store current ticks for stats calculation
if (start_time == 0)
start_time = SDL_GetTicks();
} else if (e->type == rd_ctx->event_types + DAV1D_EVENT_SEEK_FRAME) {
// Dequeue frame and update the render context with it
Dav1dPicture *p = dp_fifo_shift(rd_ctx->fifo);
// Do not update textures during termination
if (!dp_rd_ctx_should_terminate(rd_ctx)) {
dp_rd_ctx_update_with_dav1d_picture(rd_ctx, p);
n_out++;
}
destroy_pic(p);
} else if (e->type == rd_ctx->event_types + DAV1D_EVENT_DEC_QUIT) {
goto out;
}
}
if (num_frame_events && !dp_rd_ctx_is_paused(rd_ctx)) {
// Dequeue frame and update the render context with it
Dav1dPicture *p = dp_fifo_shift(rd_ctx->fifo);
// Do not update textures during termination
if (!dp_rd_ctx_should_terminate(rd_ctx)) {
dp_rd_ctx_update_with_dav1d_picture(rd_ctx, p);
dp_rd_ctx_render(rd_ctx);
n_out++;
}
destroy_pic(p);
num_frame_events--;
}
}
out:;
// Print stats
uint32_t time_ms = SDL_GetTicks() - start_time - rd_ctx->pause_time;
printf("Decoded %u frames in %d seconds, avg %.02f fps\n",
n_out, time_ms / 1000, n_out/ (time_ms / 1000.0));
int decoder_ret = 0;
SDL_WaitThread(decoder_thread, &decoder_ret);
dp_rd_ctx_destroy(rd_ctx);
SDL_Quit();
return decoder_ret;
}

View file

@ -0,0 +1,147 @@
/*
* Copyright © 2019, VideoLAN and dav1d authors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include <SDL.h>
#include <assert.h>
#include "dp_fifo.h"
// FIFO structure
struct dp_fifo
{
SDL_mutex *lock;
SDL_cond *cond_change;
size_t capacity;
size_t count;
void **entries;
int push_wait;
int flush;
};
Dav1dPlayPtrFifo *dp_fifo_create(size_t capacity)
{
Dav1dPlayPtrFifo *fifo;
assert(capacity > 0);
if (capacity <= 0)
return NULL;
fifo = malloc(sizeof(*fifo));
if (fifo == NULL)
return NULL;
fifo->capacity = capacity;
fifo->count = 0;
fifo->push_wait = 0;
fifo->flush = 0;
fifo->lock = SDL_CreateMutex();
if (fifo->lock == NULL) {
free(fifo);
return NULL;
}
fifo->cond_change = SDL_CreateCond();
if (fifo->cond_change == NULL) {
SDL_DestroyMutex(fifo->lock);
free(fifo);
return NULL;
}
fifo->entries = calloc(capacity, sizeof(void*));
if (fifo->entries == NULL) {
dp_fifo_destroy(fifo);
return NULL;
}
return fifo;
}
// Destroy FIFO
void dp_fifo_destroy(Dav1dPlayPtrFifo *fifo)
{
assert(fifo->count == 0);
SDL_DestroyMutex(fifo->lock);
SDL_DestroyCond(fifo->cond_change);
free(fifo->entries);
free(fifo);
}
// Push to FIFO
void dp_fifo_push(Dav1dPlayPtrFifo *fifo, void *element)
{
SDL_LockMutex(fifo->lock);
while (fifo->count == fifo->capacity) {
fifo->push_wait = 1;
SDL_CondWait(fifo->cond_change, fifo->lock);
fifo->push_wait = 0;
if (fifo->flush) {
SDL_CondSignal(fifo->cond_change);
SDL_UnlockMutex(fifo->lock);
return;
}
}
fifo->entries[fifo->count++] = element;
if (fifo->count == 1)
SDL_CondSignal(fifo->cond_change);
SDL_UnlockMutex(fifo->lock);
}
// Helper that shifts the FIFO array
static void *dp_fifo_array_shift(void **arr, size_t len)
{
void *shifted_element = arr[0];
for (size_t i = 1; i < len; ++i)
arr[i-1] = arr[i];
return shifted_element;
}
// Get item from FIFO
void *dp_fifo_shift(Dav1dPlayPtrFifo *fifo)
{
SDL_LockMutex(fifo->lock);
while (fifo->count == 0)
SDL_CondWait(fifo->cond_change, fifo->lock);
void *res = dp_fifo_array_shift(fifo->entries, fifo->count--);
if (fifo->count == fifo->capacity - 1)
SDL_CondSignal(fifo->cond_change);
SDL_UnlockMutex(fifo->lock);
return res;
}
void dp_fifo_flush(Dav1dPlayPtrFifo *fifo, void (*destroy_elem)(void *))
{
SDL_LockMutex(fifo->lock);
fifo->flush = 1;
if (fifo->push_wait) {
SDL_CondSignal(fifo->cond_change);
SDL_CondWait(fifo->cond_change, fifo->lock);
}
while (fifo->count)
destroy_elem(fifo->entries[--fifo->count]);
fifo->flush = 0;
SDL_UnlockMutex(fifo->lock);
}

View file

@ -0,0 +1,63 @@
/*
* Copyright © 2019, VideoLAN and dav1d authors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
/*
* Dav1dPlay FIFO helper
*/
typedef struct dp_fifo Dav1dPlayPtrFifo;
/* Create a FIFO
*
* Creates a FIFO with the given capacity.
* If the capacity is reached, new inserts into the FIFO
* will block until enough space is available again.
*/
Dav1dPlayPtrFifo *dp_fifo_create(size_t capacity);
/* Destroy a FIFO
*
* The FIFO must be empty before it is destroyed!
*/
void dp_fifo_destroy(Dav1dPlayPtrFifo *fifo);
/* Shift FIFO
*
* Return the first item from the FIFO, thereby removing it from
* the FIFO and making room for new entries.
*/
void *dp_fifo_shift(Dav1dPlayPtrFifo *fifo);
/* Push to FIFO
*
* Add an item to the end of the FIFO.
* If the FIFO is full, this call will block until there is again enough
* space in the FIFO, so calling this from the "consumer" thread if no
* other thread will call dp_fifo_shift will lead to a deadlock.
*/
void dp_fifo_push(Dav1dPlayPtrFifo *fifo, void *element);
void dp_fifo_flush(Dav1dPlayPtrFifo *fifo, void (*destroy_elem)(void *));

View file

@ -0,0 +1,149 @@
/*
* Copyright © 2020, VideoLAN and dav1d authors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include <inttypes.h>
#include <string.h>
#include "dav1d/dav1d.h"
#include <SDL.h>
#if HAVE_PLACEBO
# include <libplacebo/config.h>
#endif
// Check libplacebo Vulkan rendering
#if HAVE_VULKAN && defined(SDL_VIDEO_VULKAN)
# if defined(PL_HAVE_VULKAN) && PL_HAVE_VULKAN
# define HAVE_RENDERER_PLACEBO 1
# define HAVE_PLACEBO_VULKAN 1
# endif
#endif
// Check libplacebo OpenGL rendering
#if defined(PL_HAVE_OPENGL) && PL_HAVE_OPENGL
# define HAVE_RENDERER_PLACEBO 1
# define HAVE_PLACEBO_OPENGL 1
#endif
#ifndef HAVE_RENDERER_PLACEBO
#define HAVE_RENDERER_PLACEBO 0
#endif
#ifndef HAVE_PLACEBO_VULKAN
#define HAVE_PLACEBO_VULKAN 0
#endif
#ifndef HAVE_PLACEBO_OPENGL
#define HAVE_PLACEBO_OPENGL 0
#endif
/**
* Settings structure
* Hold all settings available for the player,
* this is usually filled by parsing arguments
* from the console.
*/
typedef struct {
const char *inputfile;
const char *renderer_name;
int highquality;
int untimed;
int zerocopy;
int gpugrain;
int fullscreen;
} Dav1dPlaySettings;
#define WINDOW_WIDTH 910
#define WINDOW_HEIGHT 512
enum {
DAV1D_EVENT_NEW_FRAME,
DAV1D_EVENT_SEEK_FRAME,
DAV1D_EVENT_DEC_QUIT
};
/**
* Renderer info
*/
typedef struct rdr_info
{
// Renderer name
const char *name;
// Cookie passed to the renderer implementation callbacks
void *cookie;
// Callback to create the renderer
void* (*create_renderer)(const Dav1dPlaySettings *settings);
// Callback to destroy the renderer
void (*destroy_renderer)(void *cookie);
// Callback to the render function that renders a prevously sent frame
void (*render)(void *cookie, const Dav1dPlaySettings *settings);
// Callback to the send frame function, _may_ also unref dav1d_pic!
int (*update_frame)(void *cookie, Dav1dPicture *dav1d_pic,
const Dav1dPlaySettings *settings);
// Callback for alloc/release pictures (optional)
int (*alloc_pic)(Dav1dPicture *pic, void *cookie);
void (*release_pic)(Dav1dPicture *pic, void *cookie);
// Whether or not this renderer can apply on-GPU film grain synthesis
int supports_gpu_grain;
} Dav1dPlayRenderInfo;
extern const Dav1dPlayRenderInfo rdr_placebo_vk;
extern const Dav1dPlayRenderInfo rdr_placebo_gl;
extern const Dav1dPlayRenderInfo rdr_sdl;
// Available renderes ordered by priority
static const Dav1dPlayRenderInfo* const dp_renderers[] = {
&rdr_placebo_vk,
&rdr_placebo_gl,
&rdr_sdl,
};
static inline const Dav1dPlayRenderInfo *dp_get_renderer(const char *name)
{
for (size_t i = 0; i < (sizeof(dp_renderers)/sizeof(*dp_renderers)); ++i)
{
if (dp_renderers[i]->name == NULL)
continue;
if (name == NULL || strcmp(name, dp_renderers[i]->name) == 0) {
return dp_renderers[i];
}
}
return NULL;
}
static inline SDL_Window *dp_create_sdl_window(int window_flags)
{
SDL_Window *win;
window_flags |= SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI;
win = SDL_CreateWindow("Dav1dPlay", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
WINDOW_WIDTH, WINDOW_HEIGHT, window_flags);
if (!win)
return NULL;
SDL_SetWindowResizable(win, SDL_TRUE);
return win;
}

View file

@ -0,0 +1,437 @@
/*
* Copyright © 2020, VideoLAN and dav1d authors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include "dp_renderer.h"
#if HAVE_RENDERER_PLACEBO
#include <assert.h>
#include <libplacebo/renderer.h>
#include <libplacebo/utils/dav1d.h>
#if HAVE_PLACEBO_VULKAN
# include <libplacebo/vulkan.h>
# include <SDL_vulkan.h>
#endif
#if HAVE_PLACEBO_OPENGL
# include <libplacebo/opengl.h>
# include <SDL_opengl.h>
#endif
/**
* Renderer context for libplacebo
*/
typedef struct renderer_priv_ctx
{
// SDL window
SDL_Window *win;
// Placebo log
pl_log log;
// Placebo renderer
pl_renderer renderer;
#if HAVE_PLACEBO_VULKAN
// Placebo Vulkan handle
pl_vulkan vk;
// Placebo Vulkan instance
pl_vk_inst vk_inst;
// Vulkan surface
VkSurfaceKHR surf;
#endif
#if HAVE_PLACEBO_OPENGL
// Placebo OpenGL handle
pl_opengl gl;
// SDL OpenGL context
SDL_GLContext gl_context;
#endif
// Placebo GPU
pl_gpu gpu;
// Placebo swapchain
pl_swapchain swapchain;
// Lock protecting access to the texture
SDL_mutex *lock;
// Image to render, and planes backing them
struct pl_frame image;
pl_tex plane_tex[3];
} Dav1dPlayRendererPrivateContext;
static Dav1dPlayRendererPrivateContext*
placebo_renderer_create_common(const Dav1dPlaySettings *settings, int window_flags)
{
if (settings->fullscreen)
window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
// Create Window
SDL_Window *sdlwin = dp_create_sdl_window(window_flags | SDL_WINDOW_RESIZABLE);
if (sdlwin == NULL) {
fprintf(stderr, "Creating SDL window failed: %s\n", SDL_GetError());
return NULL;
}
SDL_ShowCursor(0);
// Alloc
Dav1dPlayRendererPrivateContext *const rd_priv_ctx =
calloc(1, sizeof(Dav1dPlayRendererPrivateContext));
if (rd_priv_ctx == NULL) {
fprintf(stderr, "Out of memory!\n");
return NULL;
}
rd_priv_ctx->win = sdlwin;
// Init libplacebo
rd_priv_ctx->log = pl_log_create(PL_API_VER, pl_log_params(
.log_cb = pl_log_color,
#ifndef NDEBUG
.log_level = PL_LOG_DEBUG,
#else
.log_level = PL_LOG_WARN,
#endif
));
if (rd_priv_ctx->log == NULL) {
fprintf(stderr, "pl_log_create failed!\n");
free(rd_priv_ctx);
return NULL;
}
// Create Mutex
rd_priv_ctx->lock = SDL_CreateMutex();
if (rd_priv_ctx->lock == NULL) {
fprintf(stderr, "SDL_CreateMutex failed: %s\n", SDL_GetError());
pl_log_destroy(&rd_priv_ctx->log);
free(rd_priv_ctx);
return NULL;
}
return rd_priv_ctx;
}
#if HAVE_PLACEBO_OPENGL
static void *placebo_renderer_create_gl(const Dav1dPlaySettings *settings)
{
SDL_Window *sdlwin = NULL;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
// Common init
Dav1dPlayRendererPrivateContext *rd_priv_ctx =
placebo_renderer_create_common(settings, SDL_WINDOW_OPENGL);
if (rd_priv_ctx == NULL)
return NULL;
sdlwin = rd_priv_ctx->win;
rd_priv_ctx->gl_context = SDL_GL_CreateContext(sdlwin);
if (!rd_priv_ctx->gl_context) {
fprintf(stderr, "Failed creating opengl context: %s\n", SDL_GetError());
exit(2);
}
SDL_GL_MakeCurrent(sdlwin, rd_priv_ctx->gl_context);
rd_priv_ctx->gl = pl_opengl_create(rd_priv_ctx->log, pl_opengl_params(
.allow_software = true,
#ifndef NDEBUG
.debug = true,
#endif
));
if (!rd_priv_ctx->gl) {
fprintf(stderr, "Failed creating opengl device!\n");
exit(2);
}
rd_priv_ctx->swapchain = pl_opengl_create_swapchain(rd_priv_ctx->gl,
pl_opengl_swapchain_params(
.swap_buffers = (void (*)(void *)) SDL_GL_SwapWindow,
.priv = sdlwin,
));
if (!rd_priv_ctx->swapchain) {
fprintf(stderr, "Failed creating opengl swapchain!\n");
exit(2);
}
int w = WINDOW_WIDTH, h = WINDOW_HEIGHT;
SDL_GL_GetDrawableSize(sdlwin, &w, &h);
if (!pl_swapchain_resize(rd_priv_ctx->swapchain, &w, &h)) {
fprintf(stderr, "Failed resizing vulkan swapchain!\n");
exit(2);
}
rd_priv_ctx->gpu = rd_priv_ctx->gl->gpu;
if (w != WINDOW_WIDTH || h != WINDOW_HEIGHT)
printf("Note: window dimensions differ (got %dx%d)\n", w, h);
return rd_priv_ctx;
}
#endif
#if HAVE_PLACEBO_VULKAN
static void *placebo_renderer_create_vk(const Dav1dPlaySettings *settings)
{
SDL_Window *sdlwin = NULL;
// Common init
Dav1dPlayRendererPrivateContext *rd_priv_ctx =
placebo_renderer_create_common(settings, SDL_WINDOW_VULKAN);
if (rd_priv_ctx == NULL)
return NULL;
sdlwin = rd_priv_ctx->win;
// Init Vulkan
unsigned num = 0;
if (!SDL_Vulkan_GetInstanceExtensions(sdlwin, &num, NULL)) {
fprintf(stderr, "Failed enumerating Vulkan extensions: %s\n", SDL_GetError());
exit(1);
}
const char **extensions = malloc(num * sizeof(const char *));
assert(extensions);
SDL_bool ok = SDL_Vulkan_GetInstanceExtensions(sdlwin, &num, extensions);
if (!ok) {
fprintf(stderr, "Failed getting Vk instance extensions\n");
exit(1);
}
if (num > 0) {
printf("Requesting %d additional Vulkan extensions:\n", num);
for (unsigned i = 0; i < num; i++)
printf(" %s\n", extensions[i]);
}
rd_priv_ctx->vk_inst = pl_vk_inst_create(rd_priv_ctx->log, pl_vk_inst_params(
.extensions = extensions,
.num_extensions = num,
));
if (!rd_priv_ctx->vk_inst) {
fprintf(stderr, "Failed creating Vulkan instance!\n");
exit(1);
}
free(extensions);
if (!SDL_Vulkan_CreateSurface(sdlwin, rd_priv_ctx->vk_inst->instance, &rd_priv_ctx->surf)) {
fprintf(stderr, "Failed creating vulkan surface: %s\n", SDL_GetError());
exit(1);
}
rd_priv_ctx->vk = pl_vulkan_create(rd_priv_ctx->log, pl_vulkan_params(
.instance = rd_priv_ctx->vk_inst->instance,
.surface = rd_priv_ctx->surf,
.allow_software = true,
));
if (!rd_priv_ctx->vk) {
fprintf(stderr, "Failed creating vulkan device!\n");
exit(2);
}
// Create swapchain
rd_priv_ctx->swapchain = pl_vulkan_create_swapchain(rd_priv_ctx->vk,
pl_vulkan_swapchain_params(
.surface = rd_priv_ctx->surf,
.present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR,
));
if (!rd_priv_ctx->swapchain) {
fprintf(stderr, "Failed creating vulkan swapchain!\n");
exit(2);
}
int w = WINDOW_WIDTH, h = WINDOW_HEIGHT;
if (!pl_swapchain_resize(rd_priv_ctx->swapchain, &w, &h)) {
fprintf(stderr, "Failed resizing vulkan swapchain!\n");
exit(2);
}
rd_priv_ctx->gpu = rd_priv_ctx->vk->gpu;
if (w != WINDOW_WIDTH || h != WINDOW_HEIGHT)
printf("Note: window dimensions differ (got %dx%d)\n", w, h);
return rd_priv_ctx;
}
#endif
static void placebo_renderer_destroy(void *cookie)
{
Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
assert(rd_priv_ctx != NULL);
pl_renderer_destroy(&(rd_priv_ctx->renderer));
pl_swapchain_destroy(&(rd_priv_ctx->swapchain));
for (int i = 0; i < 3; i++)
pl_tex_destroy(rd_priv_ctx->gpu, &(rd_priv_ctx->plane_tex[i]));
#if HAVE_PLACEBO_VULKAN
if (rd_priv_ctx->vk) {
pl_vulkan_destroy(&(rd_priv_ctx->vk));
vkDestroySurfaceKHR(rd_priv_ctx->vk_inst->instance, rd_priv_ctx->surf, NULL);
pl_vk_inst_destroy(&(rd_priv_ctx->vk_inst));
}
#endif
#if HAVE_PLACEBO_OPENGL
if (rd_priv_ctx->gl)
pl_opengl_destroy(&(rd_priv_ctx->gl));
if (rd_priv_ctx->gl_context)
SDL_GL_DeleteContext(rd_priv_ctx->gl_context);
#endif
SDL_DestroyWindow(rd_priv_ctx->win);
pl_log_destroy(&rd_priv_ctx->log);
}
static void placebo_render(void *cookie, const Dav1dPlaySettings *settings)
{
Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
assert(rd_priv_ctx != NULL);
SDL_LockMutex(rd_priv_ctx->lock);
if (!rd_priv_ctx->image.num_planes) {
SDL_UnlockMutex(rd_priv_ctx->lock);
return;
}
// Prepare rendering
if (rd_priv_ctx->renderer == NULL) {
rd_priv_ctx->renderer = pl_renderer_create(rd_priv_ctx->log, rd_priv_ctx->gpu);
}
struct pl_swapchain_frame frame;
bool ok = pl_swapchain_start_frame(rd_priv_ctx->swapchain, &frame);
if (!ok) {
SDL_UnlockMutex(rd_priv_ctx->lock);
return;
}
struct pl_frame target;
pl_frame_from_swapchain(&target, &frame);
pl_rect2df_aspect_copy(&target.crop, &rd_priv_ctx->image.crop, 0.0);
if (pl_frame_is_cropped(&target))
pl_tex_clear(rd_priv_ctx->gpu, frame.fbo, (float[4]){ 0.0 });
if (!pl_render_image(rd_priv_ctx->renderer, &rd_priv_ctx->image, &target,
settings->highquality ? &pl_render_default_params
: &pl_render_fast_params))
{
fprintf(stderr, "Failed rendering frame!\n");
pl_tex_clear(rd_priv_ctx->gpu, frame.fbo, (float[4]){ 1.0 });
}
ok = pl_swapchain_submit_frame(rd_priv_ctx->swapchain);
if (!ok) {
fprintf(stderr, "Failed submitting frame!\n");
SDL_UnlockMutex(rd_priv_ctx->lock);
return;
}
pl_swapchain_swap_buffers(rd_priv_ctx->swapchain);
SDL_UnlockMutex(rd_priv_ctx->lock);
}
static int placebo_upload_image(void *cookie, Dav1dPicture *dav1d_pic,
const Dav1dPlaySettings *settings)
{
Dav1dPlayRendererPrivateContext *p = cookie;
assert(p != NULL);
int ret = 0;
if (!dav1d_pic)
return ret;
SDL_LockMutex(p->lock);
if (!pl_upload_dav1dpicture(p->gpu, &p->image, p->plane_tex, pl_dav1d_upload_params(
.picture = dav1d_pic,
.film_grain = settings->gpugrain,
.gpu_allocated = settings->zerocopy,
.asynchronous = true,
)))
{
fprintf(stderr, "Failed uploading planes!\n");
p->image = (struct pl_frame) {0};
ret = -1;
}
SDL_UnlockMutex(p->lock);
return ret;
}
static int placebo_alloc_pic(Dav1dPicture *const pic, void *cookie)
{
Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
assert(rd_priv_ctx != NULL);
SDL_LockMutex(rd_priv_ctx->lock);
int ret = pl_allocate_dav1dpicture(pic, (void *) rd_priv_ctx->gpu);
SDL_UnlockMutex(rd_priv_ctx->lock);
return ret;
}
static void placebo_release_pic(Dav1dPicture *pic, void *cookie)
{
Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
assert(rd_priv_ctx != NULL);
SDL_LockMutex(rd_priv_ctx->lock);
pl_release_dav1dpicture(pic, (void *) rd_priv_ctx->gpu);
SDL_UnlockMutex(rd_priv_ctx->lock);
}
#if HAVE_PLACEBO_VULKAN
const Dav1dPlayRenderInfo rdr_placebo_vk = {
.name = "placebo-vk",
.create_renderer = placebo_renderer_create_vk,
.destroy_renderer = placebo_renderer_destroy,
.render = placebo_render,
.update_frame = placebo_upload_image,
.alloc_pic = placebo_alloc_pic,
.release_pic = placebo_release_pic,
.supports_gpu_grain = 1,
};
#else
const Dav1dPlayRenderInfo rdr_placebo_vk = { NULL };
#endif
#if HAVE_PLACEBO_OPENGL
const Dav1dPlayRenderInfo rdr_placebo_gl = {
.name = "placebo-gl",
.create_renderer = placebo_renderer_create_gl,
.destroy_renderer = placebo_renderer_destroy,
.render = placebo_render,
.update_frame = placebo_upload_image,
.supports_gpu_grain = 1,
};
#else
const Dav1dPlayRenderInfo rdr_placebo_gl = { NULL };
#endif
#else
const Dav1dPlayRenderInfo rdr_placebo_vk = { NULL };
const Dav1dPlayRenderInfo rdr_placebo_gl = { NULL };
#endif

View file

@ -0,0 +1,175 @@
/*
* Copyright © 2020, VideoLAN and dav1d authors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include "dp_renderer.h"
#include <assert.h>
/**
* Renderer context for SDL
*/
typedef struct renderer_priv_ctx
{
// SDL window
SDL_Window *win;
// SDL renderer
SDL_Renderer *renderer;
// Lock protecting access to the texture
SDL_mutex *lock;
// Texture to render
SDL_Texture *tex;
} Dav1dPlayRendererPrivateContext;
static void *sdl_renderer_create(const Dav1dPlaySettings *settings)
{
int window_flags = 0;
if (settings->fullscreen)
window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
SDL_Window *win = dp_create_sdl_window(window_flags);
if (win == NULL) {
fprintf(stderr, "Creating SDL window failed: %s\n", SDL_GetError());
return NULL;
}
SDL_ShowCursor(0);
// Alloc
Dav1dPlayRendererPrivateContext *rd_priv_ctx = malloc(sizeof(Dav1dPlayRendererPrivateContext));
if (rd_priv_ctx == NULL) {
fprintf(stderr, "Out of memory!\n");
return NULL;
}
rd_priv_ctx->win = win;
// Create renderer
rd_priv_ctx->renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
// Set scale quality
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
// Create Mutex
rd_priv_ctx->lock = SDL_CreateMutex();
if (rd_priv_ctx->lock == NULL) {
fprintf(stderr, "SDL_CreateMutex failed: %s\n", SDL_GetError());
free(rd_priv_ctx);
return NULL;
}
rd_priv_ctx->tex = NULL;
return rd_priv_ctx;
}
static void sdl_renderer_destroy(void *cookie)
{
Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
assert(rd_priv_ctx != NULL);
SDL_DestroyTexture(rd_priv_ctx->tex);
SDL_DestroyRenderer(rd_priv_ctx->renderer);
SDL_DestroyWindow(rd_priv_ctx->win);
SDL_DestroyMutex(rd_priv_ctx->lock);
free(rd_priv_ctx);
}
static void sdl_render(void *cookie, const Dav1dPlaySettings *settings)
{
Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
assert(rd_priv_ctx != NULL);
SDL_LockMutex(rd_priv_ctx->lock);
if (rd_priv_ctx->tex == NULL) {
SDL_UnlockMutex(rd_priv_ctx->lock);
return;
}
// Display the frame
SDL_RenderClear(rd_priv_ctx->renderer);
SDL_RenderCopy(rd_priv_ctx->renderer, rd_priv_ctx->tex, NULL, NULL);
SDL_RenderPresent(rd_priv_ctx->renderer);
SDL_UnlockMutex(rd_priv_ctx->lock);
}
static int sdl_update_texture(void *cookie, Dav1dPicture *dav1d_pic,
const Dav1dPlaySettings *settings)
{
Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
assert(rd_priv_ctx != NULL);
SDL_LockMutex(rd_priv_ctx->lock);
if (dav1d_pic == NULL) {
rd_priv_ctx->tex = NULL;
SDL_UnlockMutex(rd_priv_ctx->lock);
return 0;
}
int width = dav1d_pic->p.w;
int height = dav1d_pic->p.h;
int tex_w = width;
int tex_h = height;
enum Dav1dPixelLayout dav1d_layout = dav1d_pic->p.layout;
if (DAV1D_PIXEL_LAYOUT_I420 != dav1d_layout || dav1d_pic->p.bpc != 8) {
fprintf(stderr, "Unsupported pixel format, only 8bit 420 supported so far.\n");
exit(50);
}
SDL_Texture *texture = rd_priv_ctx->tex;
if (texture != NULL) {
SDL_QueryTexture(texture, NULL, NULL, &tex_w, &tex_h);
if (tex_w != width || tex_h != height) {
SDL_DestroyTexture(texture);
texture = NULL;
}
}
if (texture == NULL) {
texture = SDL_CreateTexture(rd_priv_ctx->renderer, SDL_PIXELFORMAT_IYUV,
SDL_TEXTUREACCESS_STREAMING, width, height);
SDL_RenderSetLogicalSize(rd_priv_ctx->renderer, width, height);
}
SDL_UpdateYUVTexture(texture, NULL,
dav1d_pic->data[0], (int)dav1d_pic->stride[0], // Y
dav1d_pic->data[1], (int)dav1d_pic->stride[1], // U
dav1d_pic->data[2], (int)dav1d_pic->stride[1] // V
);
rd_priv_ctx->tex = texture;
SDL_UnlockMutex(rd_priv_ctx->lock);
return 0;
}
const Dav1dPlayRenderInfo rdr_sdl = {
.name = "sdl",
.create_renderer = sdl_renderer_create,
.destroy_renderer = sdl_renderer_destroy,
.render = sdl_render,
.update_frame = sdl_update_texture
};

View file

@ -0,0 +1,78 @@
# Copyright © 2018, VideoLAN and dav1d authors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. 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.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
#
# Build definition for the dav1d examples
#
# Leave subdir if examples are disabled
if not get_option('enable_examples')
subdir_done()
endif
# dav1d player sources
dav1dplay_sources = files(
'dav1dplay.c',
'dp_fifo.c',
'dp_renderer_placebo.c',
'dp_renderer_sdl.c',
)
sdl2_dependency = dependency('sdl2', version: '>= 2.0.1', required: true)
if sdl2_dependency.found()
dav1dplay_deps = [sdl2_dependency, libm_dependency]
dav1dplay_cflags = []
placebo_dependency = dependency('libplacebo', version: '>= 4.160.0', required: false)
have_vulkan = false
have_placebo = placebo_dependency.found()
if have_placebo
dav1dplay_deps += placebo_dependency
# If libplacebo is found, we might be able to use Vulkan
# with it, in which case we need the Vulkan library too.
vulkan_dependency = dependency('vulkan', required: false)
if vulkan_dependency.found()
dav1dplay_deps += vulkan_dependency
have_vulkan = true
endif
endif
dav1dplay_cflags += '-DHAVE_PLACEBO=' + (have_placebo ? '1' : '0')
dav1dplay_cflags += '-DHAVE_VULKAN=' + (have_vulkan ? '1' : '0')
dav1dplay = executable('dav1dplay',
dav1dplay_sources,
rev_target,
link_with : [libdav1d, dav1d_input_objs],
include_directories : [dav1d_inc_dirs],
dependencies : [getopt_dependency, dav1dplay_deps],
install : true,
c_args : dav1dplay_cflags,
)
endif

View file

@ -0,0 +1,4 @@
exclude = .*/tests/.*
exclude = .*/tools/.*
exclude = .*/include/common/dump.h
gcov-ignore-parse-errors = negative_hits.warn

View file

@ -0,0 +1,213 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2018, Two Orioles, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#ifndef DAV1D_COMMON_ATTRIBUTES_H
#define DAV1D_COMMON_ATTRIBUTES_H
#include "config.h"
#include <stddef.h>
#include <assert.h>
#ifndef __has_attribute
#define __has_attribute(x) 0
#endif
#ifndef __has_feature
#define __has_feature(x) 0
#endif
#ifdef __GNUC__
#define ATTR_ALIAS __attribute__((may_alias))
#if defined(__MINGW32__) && !defined(__clang__)
#define ATTR_FORMAT_PRINTF(fmt, attr) __attribute__((__format__(__gnu_printf__, fmt, attr)))
#else
#define ATTR_FORMAT_PRINTF(fmt, attr) __attribute__((__format__(__printf__, fmt, attr)))
#endif
#define COLD __attribute__((cold))
#else
#define ATTR_ALIAS
#define ATTR_FORMAT_PRINTF(fmt, attr)
#define COLD
#endif
#if ARCH_X86_64
/* x86-64 needs 32- and 64-byte alignment for AVX2 and AVX-512. */
#define ALIGN_64_VAL 64
#define ALIGN_32_VAL 32
#define ALIGN_16_VAL 16
#elif ARCH_AARCH64 || ARCH_ARM || ARCH_LOONGARCH || ARCH_PPC64LE || ARCH_X86_32
/* ARM doesn't benefit from anything more than 16-byte alignment. */
#define ALIGN_64_VAL 16
#define ALIGN_32_VAL 16
#define ALIGN_16_VAL 16
#else
/* No need for extra alignment on platforms without assembly. */
#define ALIGN_64_VAL 8
#define ALIGN_32_VAL 8
#define ALIGN_16_VAL 8
#endif
/*
* API for variables, struct members (ALIGN()) like:
* uint8_t var[1][2][3][4]
* becomes:
* ALIGN(uint8_t var[1][2][3][4], alignment).
*/
#ifdef _MSC_VER
#define ALIGN(ll, a) \
__declspec(align(a)) ll
#else
#define ALIGN(line, align) \
line __attribute__((aligned(align)))
#endif
/*
* API for stack alignment (ALIGN_STK_$align()) of variables like:
* uint8_t var[1][2][3][4]
* becomes:
* ALIGN_STK_$align(uint8_t, var, 1, [2][3][4])
*/
#define ALIGN_STK_64(type, var, sz1d, sznd) \
ALIGN(type var[sz1d]sznd, ALIGN_64_VAL)
#define ALIGN_STK_32(type, var, sz1d, sznd) \
ALIGN(type var[sz1d]sznd, ALIGN_32_VAL)
#define ALIGN_STK_16(type, var, sz1d, sznd) \
ALIGN(type var[sz1d]sznd, ALIGN_16_VAL)
/*
* Forbid inlining of a function:
* static NOINLINE void func() {}
*/
#ifdef _MSC_VER
#define NOINLINE __declspec(noinline)
#elif __has_attribute(noclone)
#define NOINLINE __attribute__((noinline, noclone))
#else
#define NOINLINE __attribute__((noinline))
#endif
#ifdef _MSC_VER
#define ALWAYS_INLINE __forceinline
#else
#define ALWAYS_INLINE __attribute__((always_inline)) inline
#endif
#if (defined(__ELF__) || defined(__MACH__) || (defined(_WIN32) && defined(__clang__))) && __has_attribute(visibility)
#define EXTERN extern __attribute__((visibility("hidden")))
#else
#define EXTERN extern
#endif
#if ARCH_X86_64 && __has_attribute(model)
#define ATTR_MCMODEL_SMALL __attribute__((model("small")))
#else
#define ATTR_MCMODEL_SMALL
#endif
#ifdef __clang__
#define NO_SANITIZE(x) __attribute__((no_sanitize(x)))
#else
#define NO_SANITIZE(x)
#endif
#if defined(NDEBUG) && (defined(__GNUC__) || defined(__clang__))
#undef assert
#define assert(x) do { if (!(x)) __builtin_unreachable(); } while (0)
#elif defined(NDEBUG) && defined(_MSC_VER)
#undef assert
#define assert __assume
#endif
#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__)
# define dav1d_uninit(x) x=x
#else
# define dav1d_uninit(x) x
#endif
#if defined(_MSC_VER) && !defined(__clang__)
#include <intrin.h>
static inline int ctz(const unsigned int mask) {
unsigned long idx;
_BitScanForward(&idx, mask);
return idx;
}
static inline int clz(const unsigned int mask) {
unsigned long leading_zero = 0;
_BitScanReverse(&leading_zero, mask);
return (31 - leading_zero);
}
#ifdef _WIN64
static inline int clzll(const unsigned long long mask) {
unsigned long leading_zero = 0;
_BitScanReverse64(&leading_zero, mask);
return (63 - leading_zero);
}
#else /* _WIN64 */
static inline int clzll(const unsigned long long mask) {
if (mask >> 32)
return clz((unsigned)(mask >> 32));
else
return clz((unsigned)mask) + 32;
}
#endif /* _WIN64 */
#else /* !_MSC_VER */
static inline int ctz(const unsigned int mask) {
return __builtin_ctz(mask);
}
static inline int clz(const unsigned int mask) {
return __builtin_clz(mask);
}
static inline int clzll(const unsigned long long mask) {
return __builtin_clzll(mask);
}
#endif /* !_MSC_VER */
#ifndef static_assert
#define CHECK_OFFSET(type, field, name) \
struct check_##type##_##field { int x[(name == offsetof(type, field)) ? 1 : -1]; }
#define CHECK_SIZE(type, size) \
struct check_##type##_size { int x[(size == sizeof(type)) ? 1 : -1]; }
#else
#define CHECK_OFFSET(type, field, name) \
static_assert(name == offsetof(type, field), #field)
#define CHECK_SIZE(type, size) \
static_assert(size == sizeof(type), #type)
#endif
#ifdef _MSC_VER
#define PACKED(...) __pragma(pack(push, 1)) __VA_ARGS__ __pragma(pack(pop))
#else
#define PACKED(...) __VA_ARGS__ __attribute__((__packed__))
#endif
#endif /* DAV1D_COMMON_ATTRIBUTES_H */

View file

@ -0,0 +1,93 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2018, Two Orioles, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#ifndef DAV1D_COMMON_BITDEPTH_H
#define DAV1D_COMMON_BITDEPTH_H
#include <stdint.h>
#include <string.h>
#include "common/attributes.h"
#if !defined(BITDEPTH)
typedef uint8_t pixel; /* can't be void due to pointer-to-array usage */
typedef void coef;
#define HIGHBD_DECL_SUFFIX /* nothing */
#define HIGHBD_CALL_SUFFIX /* nothing */
#define HIGHBD_TAIL_SUFFIX /* nothing */
#elif BITDEPTH == 8
typedef uint8_t pixel;
typedef int16_t coef;
#define PIXEL_TYPE uint8_t
#define COEF_TYPE int16_t
#define pixel_copy memcpy
#define pixel_set memset
#define iclip_pixel iclip_u8
#define PIX_HEX_FMT "%02x"
#define bitfn(x) x##_8bpc
#define BF(x, suffix) x##_8bpc_##suffix
#define PXSTRIDE(x) (x)
#define highbd_only(x)
#define HIGHBD_DECL_SUFFIX /* nothing */
#define HIGHBD_CALL_SUFFIX /* nothing */
#define HIGHBD_TAIL_SUFFIX /* nothing */
#define bitdepth_from_max(x) 8
#define BITDEPTH_MAX 0xff
#elif BITDEPTH == 16
typedef uint16_t pixel;
typedef int32_t coef;
#define PIXEL_TYPE uint16_t
#define COEF_TYPE int32_t
#define pixel_copy(a, b, c) memcpy(a, b, (c) << 1)
static inline void pixel_set(pixel *const dst, const int val, const int num) {
for (int n = 0; n < num; n++)
dst[n] = val;
}
#define PIX_HEX_FMT "%03x"
#define iclip_pixel(x) iclip(x, 0, bitdepth_max)
#define HIGHBD_DECL_SUFFIX , const int bitdepth_max
#define HIGHBD_CALL_SUFFIX , f->bitdepth_max
#define HIGHBD_TAIL_SUFFIX , bitdepth_max
#define bitdepth_from_max(bitdepth_max) (32 - clz(bitdepth_max))
#define BITDEPTH_MAX bitdepth_max
#define bitfn(x) x##_16bpc
#define BF(x, suffix) x##_16bpc_##suffix
static inline ptrdiff_t PXSTRIDE(const ptrdiff_t x) {
assert(!(x & 1));
return x >> 1;
}
#define highbd_only(x) x
#else
#error invalid value for bitdepth
#endif
#define bytefn(x) bitfn(x)
#define bitfn_decls(name, ...) \
name##_8bpc(__VA_ARGS__); \
name##_16bpc(__VA_ARGS__)
#endif /* DAV1D_COMMON_BITDEPTH_H */

View file

@ -0,0 +1,92 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2018, Two Orioles, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#ifndef DAV1D_COMMON_DUMP_H
#define DAV1D_COMMON_DUMP_H
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include "common/bitdepth.h"
static inline void append_plane_to_file(const pixel *buf, ptrdiff_t stride,
int w, int h, const char *const file)
{
FILE *const f = fopen(file, "ab");
while (h--) {
fwrite(buf, w * sizeof(pixel), 1, f);
buf += PXSTRIDE(stride);
}
fclose(f);
}
static inline void hex_fdump(FILE *out, const pixel *buf, ptrdiff_t stride,
int w, int h, const char *what)
{
fprintf(out, "%s\n", what);
while (h--) {
int x;
for (x = 0; x < w; x++)
fprintf(out, " " PIX_HEX_FMT, buf[x]);
buf += PXSTRIDE(stride);
fprintf(out, "\n");
}
}
static inline void hex_dump(const pixel *buf, ptrdiff_t stride,
int w, int h, const char *what)
{
hex_fdump(stdout, buf, stride, w, h, what);
}
static inline void coef_dump(const coef *buf, const int w, const int h,
const int len, const char *what)
{
int y;
printf("%s\n", what);
for (y = 0; y < h; y++) {
int x;
for (x = 0; x < w; x++)
printf(" %*d", len, buf[x]);
buf += w;
printf("\n");
}
}
static inline void ac_dump(const int16_t *buf, int w, int h, const char *what)
{
printf("%s\n", what);
while (h--) {
for (int x = 0; x < w; x++)
printf(" %03d", buf[x]);
buf += w;
printf("\n");
}
}
#endif /* DAV1D_COMMON_DUMP_H */

View file

@ -0,0 +1,45 @@
/*
* Copyright © 2021, VideoLAN and dav1d authors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#ifndef DAV1D_COMMON_FRAME_H
#define DAV1D_COMMON_FRAME_H
/*
* Checks whether Dav1dFrameType == INTER || == SWITCH
* Both are defined as odd numbers {1, 3} and therefore have the LSB set.
* See also: AV1 spec 6.8.2
*/
#define IS_INTER_OR_SWITCH(frame_header) \
((frame_header)->frame_type & 1)
/*
* Checks whether Dav1dFrameType == KEY || == INTRA
* See also: AV1 spec 6.8.2
*/
#define IS_KEY_OR_INTRA(frame_header) \
(!IS_INTER_OR_SWITCH(frame_header))
#endif /* DAV1D_COMMON_FRAME_H */

View file

@ -0,0 +1,84 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2018, Two Orioles, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#ifndef DAV1D_COMMON_INTOPS_H
#define DAV1D_COMMON_INTOPS_H
#include <stdint.h>
#include "common/attributes.h"
static inline int imax(const int a, const int b) {
return a > b ? a : b;
}
static inline int imin(const int a, const int b) {
return a < b ? a : b;
}
static inline unsigned umax(const unsigned a, const unsigned b) {
return a > b ? a : b;
}
static inline unsigned umin(const unsigned a, const unsigned b) {
return a < b ? a : b;
}
static inline int iclip(const int v, const int min, const int max) {
return v < min ? min : v > max ? max : v;
}
static inline int iclip_u8(const int v) {
return iclip(v, 0, 255);
}
static inline int apply_sign(const int v, const int s) {
return s < 0 ? -v : v;
}
static inline int apply_sign64(const int v, const int64_t s) {
return s < 0 ? -v : v;
}
static inline int ulog2(const unsigned v) {
return 31 ^ clz(v);
}
static inline int u64log2(const uint64_t v) {
return 63 ^ clzll(v);
}
static inline unsigned inv_recenter(const unsigned r, const unsigned v) {
if (v > (r << 1))
return v;
else if ((v & 1) == 0)
return (v >> 1) + r;
else
return r - ((v + 1) >> 1);
}
#endif /* DAV1D_COMMON_INTOPS_H */

View file

@ -0,0 +1,61 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2018, Two Orioles, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#ifndef DAV1D_COMMON_VALIDATE_H
#define DAV1D_COMMON_VALIDATE_H
#include <stdio.h>
#include <stdlib.h>
#if defined(NDEBUG)
#define debug_print(...) do {} while (0)
#define debug_abort() do {} while (0)
#else
#define debug_print(...) fprintf(stderr, __VA_ARGS__)
#define debug_abort abort
#endif
#define validate_input_or_ret_with_msg(x, r, ...) \
if (!(x)) { \
debug_print("Input validation check \'%s\' failed in %s!\n", \
#x, __func__); \
debug_print(__VA_ARGS__); \
debug_abort(); \
return r; \
}
#define validate_input_or_ret(x, r) \
if (!(x)) { \
debug_print("Input validation check \'%s\' failed in %s!\n", \
#x, __func__); \
debug_abort(); \
return r; \
}
#define validate_input(x) validate_input_or_ret(x, )
#endif /* DAV1D_COMMON_VALIDATE_H */

View file

@ -0,0 +1,51 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#ifndef GCCVER_STDATOMIC_H_
#define GCCVER_STDATOMIC_H_
#if !defined(__cplusplus)
typedef int atomic_int;
typedef unsigned int atomic_uint;
#define memory_order_relaxed __ATOMIC_RELAXED
#define memory_order_acquire __ATOMIC_ACQUIRE
#define atomic_init(p_a, v) do { *(p_a) = (v); } while(0)
#define atomic_store(p_a, v) __atomic_store_n(p_a, v, __ATOMIC_SEQ_CST)
#define atomic_load(p_a) __atomic_load_n(p_a, __ATOMIC_SEQ_CST)
#define atomic_load_explicit(p_a, mo) __atomic_load_n(p_a, mo)
#define atomic_fetch_add(p_a, inc) __atomic_fetch_add(p_a, inc, __ATOMIC_SEQ_CST)
#define atomic_fetch_add_explicit(p_a, inc, mo) __atomic_fetch_add(p_a, inc, mo)
#define atomic_fetch_sub(p_a, dec) __atomic_fetch_sub(p_a, dec, __ATOMIC_SEQ_CST)
#define atomic_exchange(p_a, v) __atomic_exchange_n(p_a, v, __ATOMIC_SEQ_CST)
#define atomic_fetch_or(p_a, v) __atomic_fetch_or(p_a, v, __ATOMIC_SEQ_CST)
#define atomic_compare_exchange_strong(p_a, expected, desired) __atomic_compare_exchange_n(p_a, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
#endif /* !defined(__cplusplus) */
#endif /* GCCVER_STDATOMIC_H_ */

View file

@ -0,0 +1,97 @@
#ifndef __GETOPT_H__
/**
* DISCLAIMER
* This file has no copyright assigned and is placed in the Public Domain.
* This file is part of the mingw-w64 runtime package.
*
* The mingw-w64 runtime package and its code is distributed in the hope that it
* will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR
* IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to
* warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#define __GETOPT_H__
/* All the headers include this file. */
#ifdef _WIN32
#include <crtdefs.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
extern int optind; /* index of first non-option in argv */
extern int optopt; /* single option character, as parsed */
extern int opterr; /* flag to enable built-in diagnostics... */
/* (user may set to zero, to suppress) */
extern char *optarg; /* pointer to argument of current option */
extern int getopt(int nargc, char * const *nargv, const char *options);
#ifdef _BSD_SOURCE
/*
* BSD adds the non-standard `optreset' feature, for reinitialisation
* of `getopt' parsing. We support this feature, for applications which
* proclaim their BSD heritage, before including this header; however,
* to maintain portability, developers are advised to avoid it.
*/
# define optreset __mingw_optreset
extern int optreset;
#endif
#ifdef __cplusplus
}
#endif
/*
* POSIX requires the `getopt' API to be specified in `unistd.h';
* thus, `unistd.h' includes this header. However, we do not want
* to expose the `getopt_long' or `getopt_long_only' APIs, when
* included in this manner. Thus, close the standard __GETOPT_H__
* declarations block, and open an additional __GETOPT_LONG_H__
* specific block, only when *not* __UNISTD_H_SOURCED__, in which
* to declare the extended API.
*/
#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__)
#define __GETOPT_LONG_H__
#ifdef __cplusplus
extern "C" {
#endif
struct option /* specification for a long form option... */
{
const char *name; /* option name, without leading hyphens */
int has_arg; /* does it take an argument? */
int *flag; /* where to save its status, or NULL */
int val; /* its associated status value */
};
enum /* permitted values for its `has_arg' field... */
{
no_argument = 0, /* option never takes an argument */
required_argument, /* option always requires an argument */
optional_argument /* option may take an argument */
};
extern int getopt_long(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx);
extern int getopt_long_only(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx);
/*
* Previous MinGW implementation had...
*/
#ifndef HAVE_DECL_GETOPT
/*
* ...for the long form API only; keep this for compatibility.
*/
# define HAVE_DECL_GETOPT 1
#endif
#ifdef __cplusplus
}
#endif
#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */
#endif /* !defined(__GETOPT_H__) */

View file

@ -0,0 +1,82 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#ifndef MSCVER_STDATOMIC_H_
#define MSCVER_STDATOMIC_H_
#if !defined(__cplusplus) && defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4067) /* newline for __has_include_next */
#if defined(__clang__) && __has_include_next(<stdatomic.h>)
/* use the clang stdatomic.h with clang-cl*/
# include_next <stdatomic.h>
#else /* ! stdatomic.h */
#include <windows.h>
#include "common/attributes.h"
typedef volatile LONG atomic_int;
typedef volatile ULONG atomic_uint;
typedef enum {
memory_order_relaxed,
memory_order_acquire
} msvc_atomic_memory_order;
#define atomic_init(p_a, v) do { *(p_a) = (v); } while(0)
#define atomic_store(p_a, v) InterlockedExchange((LONG*)p_a, v)
#define atomic_load(p_a) InterlockedCompareExchange((LONG*)p_a, 0, 0)
#define atomic_exchange(p_a, v) InterlockedExchange(p_a, v)
#define atomic_load_explicit(p_a, mo) atomic_load(p_a)
static inline int atomic_compare_exchange_strong_int(LONG *obj, LONG *expected,
LONG desired)
{
LONG orig = *expected;
*expected = InterlockedCompareExchange(obj, desired, orig);
return *expected == orig;
}
#define atomic_compare_exchange_strong(p_a, expected, desired) atomic_compare_exchange_strong_int((LONG *)p_a, (LONG *)expected, (LONG)desired)
/*
* TODO use a special call to increment/decrement
* using InterlockedIncrement/InterlockedDecrement
*/
#define atomic_fetch_add(p_a, inc) InterlockedExchangeAdd(p_a, inc)
#define atomic_fetch_sub(p_a, dec) InterlockedExchangeAdd(p_a, -(dec))
#define atomic_fetch_or(p_a, v) InterlockedOr(p_a, v)
#define atomic_fetch_add_explicit(p_a, inc, mo) atomic_fetch_add(p_a, inc)
#endif /* ! stdatomic.h */
#pragma warning(pop)
#endif /* !defined(__cplusplus) && defined(_MSC_VER) */
#endif /* MSCVER_STDATOMIC_H_ */

View file

@ -0,0 +1,94 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2018, Two Orioles, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#ifndef DAV1D_COMMON_H
#define DAV1D_COMMON_H
#include <errno.h>
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef DAV1D_API
#if defined _WIN32
#if defined DAV1D_BUILDING_DLL
#define DAV1D_API __declspec(dllexport)
#else
#define DAV1D_API
#endif
#else
#if __GNUC__ >= 4
#define DAV1D_API __attribute__ ((visibility ("default")))
#else
#define DAV1D_API
#endif
#endif
#endif
#if EPERM > 0
#define DAV1D_ERR(e) (-(e)) ///< Negate POSIX error code.
#else
#define DAV1D_ERR(e) (e)
#endif
/**
* A reference-counted object wrapper for a user-configurable pointer.
*/
typedef struct Dav1dUserData {
const uint8_t *data; ///< data pointer
struct Dav1dRef *ref; ///< allocation origin
} Dav1dUserData;
/**
* Input packet metadata which are copied from the input data used to
* decode each image into the matching structure of the output image
* returned back to the user. Since these are metadata fields, they
* can be used for other purposes than the documented ones, they will
* still be passed from input data to output picture without being
* used internally.
*/
typedef struct Dav1dDataProps {
int64_t timestamp; ///< container timestamp of input data, INT64_MIN if unknown (default)
int64_t duration; ///< container duration of input data, 0 if unknown (default)
int64_t offset; ///< stream offset of input data, -1 if unknown (default)
size_t size; ///< packet size, default Dav1dData.sz
struct Dav1dUserData user_data; ///< user-configurable data, default NULL members
} Dav1dDataProps;
/**
* Release reference to a Dav1dDataProps.
*/
DAV1D_API void dav1d_data_props_unref(Dav1dDataProps *props);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* DAV1D_COMMON_H */

View file

@ -0,0 +1,117 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2018, Two Orioles, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#ifndef DAV1D_DATA_H
#define DAV1D_DATA_H
#include <stddef.h>
#include <stdint.h>
#include "common.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct Dav1dData {
const uint8_t *data; ///< data pointer
size_t sz; ///< data size
struct Dav1dRef *ref; ///< allocation origin
Dav1dDataProps m; ///< user provided metadata passed to the output picture
} Dav1dData;
/**
* Allocate data.
*
* @param data Input context.
* @param sz Size of the data that should be allocated.
*
* @return Pointer to the allocated buffer on success. NULL on error.
*/
DAV1D_API uint8_t * dav1d_data_create(Dav1dData *data, size_t sz);
/**
* Wrap an existing data array.
*
* @param data Input context.
* @param buf The data to be wrapped.
* @param sz Size of the data.
* @param free_callback Function to be called when we release our last
* reference to this data. In this callback, $buf will be
* the $buf argument to this function, and $cookie will
* be the $cookie input argument to this function.
* @param cookie Opaque parameter passed to free_callback().
*
* @return 0 on success. A negative DAV1D_ERR value on error.
*/
DAV1D_API int dav1d_data_wrap(Dav1dData *data, const uint8_t *buf, size_t sz,
void (*free_callback)(const uint8_t *buf, void *cookie),
void *cookie);
/**
* Wrap a user-provided data pointer into a reference counted object.
*
* data->m.user_data field will initialized to wrap the provided $user_data
* pointer.
*
* $free_callback will be called on the same thread that released the last
* reference. If frame threading is used, make sure $free_callback is
* thread-safe.
*
* @param data Input context.
* @param user_data The user data to be wrapped.
* @param free_callback Function to be called when we release our last
* reference to this data. In this callback, $user_data
* will be the $user_data argument to this function, and
* $cookie will be the $cookie input argument to this
* function.
* @param cookie Opaque parameter passed to $free_callback.
*
* @return 0 on success. A negative DAV1D_ERR value on error.
*/
DAV1D_API int dav1d_data_wrap_user_data(Dav1dData *data,
const uint8_t *user_data,
void (*free_callback)(const uint8_t *user_data,
void *cookie),
void *cookie);
/**
* Free the data reference.
*
* The reference count for data->m.user_data will be decremented (if it has been
* initialized with dav1d_data_wrap_user_data). The $data object will be memset
* to 0.
*
* @param data Input context.
*/
DAV1D_API void dav1d_data_unref(Dav1dData *data);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* DAV1D_DATA_H */

View file

@ -0,0 +1,329 @@
/*
* Copyright © 2018-2021, VideoLAN and dav1d authors
* Copyright © 2018, Two Orioles, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#ifndef DAV1D_H
#define DAV1D_H
#include <errno.h>
#include <stdarg.h>
#include "common.h"
#include "picture.h"
#include "data.h"
#include "version.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct Dav1dContext Dav1dContext;
typedef struct Dav1dRef Dav1dRef;
#define DAV1D_MAX_THREADS 256
#define DAV1D_MAX_FRAME_DELAY 256
typedef struct Dav1dLogger {
void *cookie; ///< Custom data to pass to the callback.
/**
* Logger callback. May be NULL to disable logging.
*
* @param cookie Custom pointer passed to all calls.
* @param format The vprintf compatible format string.
* @param ap List of arguments referenced by the format string.
*/
void (*callback)(void *cookie, const char *format, va_list ap);
} Dav1dLogger;
enum Dav1dInloopFilterType {
DAV1D_INLOOPFILTER_NONE = 0,
DAV1D_INLOOPFILTER_DEBLOCK = 1 << 0,
DAV1D_INLOOPFILTER_CDEF = 1 << 1,
DAV1D_INLOOPFILTER_RESTORATION = 1 << 2,
DAV1D_INLOOPFILTER_ALL = DAV1D_INLOOPFILTER_DEBLOCK |
DAV1D_INLOOPFILTER_CDEF |
DAV1D_INLOOPFILTER_RESTORATION,
};
enum Dav1dDecodeFrameType {
DAV1D_DECODEFRAMETYPE_ALL = 0, ///< decode and return all frames
DAV1D_DECODEFRAMETYPE_REFERENCE = 1,///< decode and return frames referenced by other frames only
DAV1D_DECODEFRAMETYPE_INTRA = 2, ///< decode and return intra frames only (includes keyframes)
DAV1D_DECODEFRAMETYPE_KEY = 3, ///< decode and return keyframes only
};
typedef struct Dav1dSettings {
int n_threads; ///< number of threads (0 = number of logical cores in host system, default 0)
int max_frame_delay; ///< Set to 1 for low-latency decoding (0 = ceil(sqrt(n_threads)), default 0)
int apply_grain; ///< whether to apply film grain on output frames (default 1)
int operating_point; ///< select an operating point for scalable AV1 bitstreams (0 - 31, default 0)
int all_layers; ///< output all spatial layers of a scalable AV1 biststream (default 1)
unsigned frame_size_limit; ///< maximum frame size, in pixels (0 = unlimited, default 0)
Dav1dPicAllocator allocator; ///< Picture allocator callback.
Dav1dLogger logger; ///< Logger callback.
int strict_std_compliance; ///< whether to abort decoding on standard compliance violations
///< that don't affect actual bitstream decoding (e.g. inconsistent
///< or invalid metadata, default 0)
int output_invisible_frames; ///< output invisibly coded frames (in coding order) in addition
///< to all visible frames. Because of show-existing-frame, this
///< means some frames may appear twice (once when coded,
///< once when shown, default 0)
enum Dav1dInloopFilterType inloop_filters; ///< postfilters to enable during decoding (default
///< DAV1D_INLOOPFILTER_ALL)
enum Dav1dDecodeFrameType decode_frame_type; ///< frame types to decode (default
///< DAV1D_DECODEFRAMETYPE_ALL)
uint8_t reserved[16]; ///< reserved for future use
} Dav1dSettings;
/**
* Get library version.
*/
DAV1D_API const char *dav1d_version(void);
/**
* Get library API version.
*
* @return A value in the format 0x00XXYYZZ, where XX is the major version,
* YY the minor version, and ZZ the patch version.
* @see DAV1D_API_MAJOR, DAV1D_API_MINOR, DAV1D_API_PATCH
*/
DAV1D_API unsigned dav1d_version_api(void);
/**
* Initialize settings to default values.
*
* @param s Input settings context.
*/
DAV1D_API void dav1d_default_settings(Dav1dSettings *s);
/**
* Allocate and open a decoder instance.
*
* @param c_out The decoder instance to open. *c_out will be set to the
* allocated context.
* @param s Input settings context.
*
* @note The context must be freed using dav1d_close() when decoding is
* finished.
*
* @return 0 on success, or < 0 (a negative DAV1D_ERR code) on error.
*/
DAV1D_API int dav1d_open(Dav1dContext **c_out, const Dav1dSettings *s);
/**
* Parse a Sequence Header OBU from bitstream data.
*
* @param out Output Sequence Header.
* @param buf The data to be parser.
* @param sz Size of the data.
*
* @return
* 0: Success, and out is filled with the parsed Sequence Header
* OBU parameters.
* DAV1D_ERR(ENOENT): No Sequence Header OBUs were found in the buffer.
* Other negative DAV1D_ERR codes: Invalid data in the buffer, invalid passed-in
* arguments, and other errors during parsing.
*
* @note It is safe to feed this function data containing other OBUs than a
* Sequence Header, as they will simply be ignored. If there is more than
* one Sequence Header OBU present, only the last will be returned.
*/
DAV1D_API int dav1d_parse_sequence_header(Dav1dSequenceHeader *out,
const uint8_t *buf, const size_t sz);
/**
* Feed bitstream data to the decoder, in the form of one or multiple AV1
* Open Bitstream Units (OBUs).
*
* @param c Input decoder instance.
* @param in Input bitstream data. On success, ownership of the reference is
* passed to the library.
*
* @return
* 0: Success, and the data was consumed.
* DAV1D_ERR(EAGAIN): The data can't be consumed. dav1d_get_picture() should
* be called to get one or more frames before the function
* can consume new data.
* Other negative DAV1D_ERR codes: Error during decoding or because of invalid
* passed-in arguments. The reference remains
* owned by the caller.
*/
DAV1D_API int dav1d_send_data(Dav1dContext *c, Dav1dData *in);
/**
* Return a decoded picture.
*
* @param c Input decoder instance.
* @param out Output frame. The caller assumes ownership of the returned
* reference.
*
* @return
* 0: Success, and a frame is returned.
* DAV1D_ERR(EAGAIN): Not enough data to output a frame. dav1d_send_data()
* should be called with new input.
* Other negative DAV1D_ERR codes: Error during decoding or because of invalid
* passed-in arguments.
*
* @note To drain buffered frames from the decoder (i.e. on end of stream),
* call this function until it returns DAV1D_ERR(EAGAIN).
*
* @code{.c}
* Dav1dData data = { 0 };
* Dav1dPicture p = { 0 };
* int res;
*
* read_data(&data);
* do {
* res = dav1d_send_data(c, &data);
* // Keep going even if the function can't consume the current data
* packet. It eventually will after one or more frames have been
* returned in this loop.
* if (res < 0 && res != DAV1D_ERR(EAGAIN))
* free_and_abort();
* res = dav1d_get_picture(c, &p);
* if (res < 0) {
* if (res != DAV1D_ERR(EAGAIN))
* free_and_abort();
* } else
* output_and_unref_picture(&p);
* // Stay in the loop as long as there's data to consume.
* } while (data.sz || read_data(&data) == SUCCESS);
*
* // Handle EOS by draining all buffered frames.
* do {
* res = dav1d_get_picture(c, &p);
* if (res < 0) {
* if (res != DAV1D_ERR(EAGAIN))
* free_and_abort();
* } else
* output_and_unref_picture(&p);
* } while (res == 0);
* @endcode
*/
DAV1D_API int dav1d_get_picture(Dav1dContext *c, Dav1dPicture *out);
/**
* Apply film grain to a previously decoded picture. If the picture contains no
* film grain metadata, then this function merely returns a new reference.
*
* @param c Input decoder instance.
* @param out Output frame. The caller assumes ownership of the returned
* reference.
* @param in Input frame. No ownership is transferred.
*
* @return
* 0: Success, and a frame is returned.
* Other negative DAV1D_ERR codes: Error due to lack of memory or because of
* invalid passed-in arguments.
*
* @note If `Dav1dSettings.apply_grain` is true, film grain was already applied
* by `dav1d_get_picture`, and so calling this function leads to double
* application of film grain. Users should only call this when needed.
*/
DAV1D_API int dav1d_apply_grain(Dav1dContext *c, Dav1dPicture *out,
const Dav1dPicture *in);
/**
* Close a decoder instance and free all associated memory.
*
* @param c_out The decoder instance to close. *c_out will be set to NULL.
*/
DAV1D_API void dav1d_close(Dav1dContext **c_out);
/**
* Flush all delayed frames in decoder and clear internal decoder state,
* to be used when seeking.
*
* @param c Input decoder instance.
*
* @note Decoding will start only after a valid sequence header OBU is
* delivered to dav1d_send_data().
*
*/
DAV1D_API void dav1d_flush(Dav1dContext *c);
enum Dav1dEventFlags {
/**
* The last returned picture contains a reference to a new Sequence Header,
* either because it's the start of a new coded sequence, or the decoder was
* flushed before it was generated.
*/
DAV1D_EVENT_FLAG_NEW_SEQUENCE = 1 << 0,
/**
* The last returned picture contains a reference to a Sequence Header with
* new operating parameters information for the current coded sequence.
*/
DAV1D_EVENT_FLAG_NEW_OP_PARAMS_INFO = 1 << 1,
};
/**
* Fetch a combination of DAV1D_EVENT_FLAG_* event flags generated by the decoding
* process.
*
* @param c Input decoder instance.
* @param flags Where to write the flags.
*
* @return 0 on success, or < 0 (a negative DAV1D_ERR code) on error.
*
* @note Calling this function will clear all the event flags currently stored in
* the decoder.
*
*/
DAV1D_API int dav1d_get_event_flags(Dav1dContext *c, enum Dav1dEventFlags *flags);
/**
* Retrieve the user-provided metadata associated with the input data packet
* for the last decoding error reported to the user, i.e. a negative return
* value (not EAGAIN) from dav1d_send_data() or dav1d_get_picture().
*
* @param c Input decoder instance.
* @param out Output Dav1dDataProps. On success, the caller assumes ownership of
* the returned reference.
*
* @return 0 on success, or < 0 (a negative DAV1D_ERR code) on error.
*/
DAV1D_API int dav1d_get_decode_error_data_props(Dav1dContext *c, Dav1dDataProps *out);
/**
* Get the decoder delay, which is the number of internally buffered frames, not
* including reference frames.
* This value is guaranteed to be >= 1 and <= max_frame_delay.
*
* @param s Input settings context.
*
* @return Decoder frame delay on success, or < 0 (a negative DAV1D_ERR code) on
* error.
*
* @note The returned delay is valid only for a Dav1dContext initialized with the
* provided Dav1dSettings.
*/
DAV1D_API int dav1d_get_frame_delay(const Dav1dSettings *s);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* DAV1D_H */

View file

@ -0,0 +1,440 @@
/*
* Copyright © 2018-2020, VideoLAN and dav1d authors
* Copyright © 2018, Two Orioles, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#ifndef DAV1D_HEADERS_H
#define DAV1D_HEADERS_H
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
// Constants from Section 3. "Symbols and abbreviated terms"
#define DAV1D_MAX_CDEF_STRENGTHS 8
#define DAV1D_MAX_OPERATING_POINTS 32
#define DAV1D_MAX_TILE_COLS 64
#define DAV1D_MAX_TILE_ROWS 64
#define DAV1D_MAX_SEGMENTS 8
#define DAV1D_NUM_REF_FRAMES 8
#define DAV1D_PRIMARY_REF_NONE 7
#define DAV1D_REFS_PER_FRAME 7
#define DAV1D_TOTAL_REFS_PER_FRAME (DAV1D_REFS_PER_FRAME + 1)
enum Dav1dObuType {
DAV1D_OBU_SEQ_HDR = 1,
DAV1D_OBU_TD = 2,
DAV1D_OBU_FRAME_HDR = 3,
DAV1D_OBU_TILE_GRP = 4,
DAV1D_OBU_METADATA = 5,
DAV1D_OBU_FRAME = 6,
DAV1D_OBU_REDUNDANT_FRAME_HDR = 7,
DAV1D_OBU_PADDING = 15,
};
enum Dav1dTxfmMode {
DAV1D_TX_4X4_ONLY,
DAV1D_TX_LARGEST,
DAV1D_TX_SWITCHABLE,
DAV1D_N_TX_MODES,
};
enum Dav1dFilterMode {
DAV1D_FILTER_8TAP_REGULAR,
DAV1D_FILTER_8TAP_SMOOTH,
DAV1D_FILTER_8TAP_SHARP,
DAV1D_N_SWITCHABLE_FILTERS,
DAV1D_FILTER_BILINEAR = DAV1D_N_SWITCHABLE_FILTERS,
DAV1D_N_FILTERS,
DAV1D_FILTER_SWITCHABLE = DAV1D_N_FILTERS,
};
enum Dav1dAdaptiveBoolean {
DAV1D_OFF = 0,
DAV1D_ON = 1,
DAV1D_ADAPTIVE = 2,
};
enum Dav1dRestorationType {
DAV1D_RESTORATION_NONE,
DAV1D_RESTORATION_SWITCHABLE,
DAV1D_RESTORATION_WIENER,
DAV1D_RESTORATION_SGRPROJ,
};
enum Dav1dWarpedMotionType {
DAV1D_WM_TYPE_IDENTITY,
DAV1D_WM_TYPE_TRANSLATION,
DAV1D_WM_TYPE_ROT_ZOOM,
DAV1D_WM_TYPE_AFFINE,
};
typedef struct Dav1dWarpedMotionParams {
enum Dav1dWarpedMotionType type;
int32_t matrix[6];
union {
struct {
int16_t alpha, beta, gamma, delta;
} p;
int16_t abcd[4];
} u;
} Dav1dWarpedMotionParams;
enum Dav1dPixelLayout {
DAV1D_PIXEL_LAYOUT_I400, ///< monochrome
DAV1D_PIXEL_LAYOUT_I420, ///< 4:2:0 planar
DAV1D_PIXEL_LAYOUT_I422, ///< 4:2:2 planar
DAV1D_PIXEL_LAYOUT_I444, ///< 4:4:4 planar
};
enum Dav1dFrameType {
DAV1D_FRAME_TYPE_KEY = 0, ///< Key Intra frame
DAV1D_FRAME_TYPE_INTER = 1, ///< Inter frame
DAV1D_FRAME_TYPE_INTRA = 2, ///< Non key Intra frame
DAV1D_FRAME_TYPE_SWITCH = 3, ///< Switch Inter frame
};
enum Dav1dColorPrimaries {
DAV1D_COLOR_PRI_BT709 = 1,
DAV1D_COLOR_PRI_UNKNOWN = 2,
DAV1D_COLOR_PRI_BT470M = 4,
DAV1D_COLOR_PRI_BT470BG = 5,
DAV1D_COLOR_PRI_BT601 = 6,
DAV1D_COLOR_PRI_SMPTE240 = 7,
DAV1D_COLOR_PRI_FILM = 8,
DAV1D_COLOR_PRI_BT2020 = 9,
DAV1D_COLOR_PRI_XYZ = 10,
DAV1D_COLOR_PRI_SMPTE431 = 11,
DAV1D_COLOR_PRI_SMPTE432 = 12,
DAV1D_COLOR_PRI_EBU3213 = 22,
DAV1D_COLOR_PRI_RESERVED = 255,
};
enum Dav1dTransferCharacteristics {
DAV1D_TRC_BT709 = 1,
DAV1D_TRC_UNKNOWN = 2,
DAV1D_TRC_BT470M = 4,
DAV1D_TRC_BT470BG = 5,
DAV1D_TRC_BT601 = 6,
DAV1D_TRC_SMPTE240 = 7,
DAV1D_TRC_LINEAR = 8,
DAV1D_TRC_LOG100 = 9, ///< logarithmic (100:1 range)
DAV1D_TRC_LOG100_SQRT10 = 10, ///< lograithmic (100*sqrt(10):1 range)
DAV1D_TRC_IEC61966 = 11,
DAV1D_TRC_BT1361 = 12,
DAV1D_TRC_SRGB = 13,
DAV1D_TRC_BT2020_10BIT = 14,
DAV1D_TRC_BT2020_12BIT = 15,
DAV1D_TRC_SMPTE2084 = 16, ///< PQ
DAV1D_TRC_SMPTE428 = 17,
DAV1D_TRC_HLG = 18, ///< hybrid log/gamma (BT.2100 / ARIB STD-B67)
DAV1D_TRC_RESERVED = 255,
};
enum Dav1dMatrixCoefficients {
DAV1D_MC_IDENTITY = 0,
DAV1D_MC_BT709 = 1,
DAV1D_MC_UNKNOWN = 2,
DAV1D_MC_FCC = 4,
DAV1D_MC_BT470BG = 5,
DAV1D_MC_BT601 = 6,
DAV1D_MC_SMPTE240 = 7,
DAV1D_MC_SMPTE_YCGCO = 8,
DAV1D_MC_BT2020_NCL = 9,
DAV1D_MC_BT2020_CL = 10,
DAV1D_MC_SMPTE2085 = 11,
DAV1D_MC_CHROMAT_NCL = 12, ///< Chromaticity-derived
DAV1D_MC_CHROMAT_CL = 13,
DAV1D_MC_ICTCP = 14,
DAV1D_MC_RESERVED = 255,
};
enum Dav1dChromaSamplePosition {
DAV1D_CHR_UNKNOWN = 0,
DAV1D_CHR_VERTICAL = 1, ///< Horizontally co-located with luma(0, 0)
///< sample, between two vertical samples
DAV1D_CHR_COLOCATED = 2, ///< Co-located with luma(0, 0) sample
};
typedef struct Dav1dContentLightLevel {
uint16_t max_content_light_level;
uint16_t max_frame_average_light_level;
} Dav1dContentLightLevel;
typedef struct Dav1dMasteringDisplay {
uint16_t primaries[3][2]; ///< 0.16 fixed point
uint16_t white_point[2]; ///< 0.16 fixed point
uint32_t max_luminance; ///< 24.8 fixed point
uint32_t min_luminance; ///< 18.14 fixed point
} Dav1dMasteringDisplay;
typedef struct Dav1dITUTT35 {
uint8_t country_code;
uint8_t country_code_extension_byte;
size_t payload_size;
uint8_t *payload;
} Dav1dITUTT35;
typedef struct Dav1dSequenceHeader {
/**
* Stream profile, 0 for 8-10 bits/component 4:2:0 or monochrome;
* 1 for 8-10 bits/component 4:4:4; 2 for 4:2:2 at any bits/component,
* or 12 bits/component at any chroma subsampling.
*/
uint8_t profile;
/**
* Maximum dimensions for this stream. In non-scalable streams, these
* are often the actual dimensions of the stream, although that is not
* a normative requirement.
*/
int max_width, max_height;
enum Dav1dPixelLayout layout; ///< format of the picture
enum Dav1dColorPrimaries pri; ///< color primaries (av1)
enum Dav1dTransferCharacteristics trc; ///< transfer characteristics (av1)
enum Dav1dMatrixCoefficients mtrx; ///< matrix coefficients (av1)
enum Dav1dChromaSamplePosition chr; ///< chroma sample position (av1)
/**
* 0, 1 and 2 mean 8, 10 or 12 bits/component, respectively. This is not
* exactly the same as 'hbd' from the spec; the spec's hbd distinguishes
* between 8 (0) and 10-12 (1) bits/component, and another element
* (twelve_bit) to distinguish between 10 and 12 bits/component. To get
* the spec's hbd, use !!our_hbd, and to get twelve_bit, use hbd == 2.
*/
uint8_t hbd;
/**
* Pixel data uses JPEG pixel range ([0,255] for 8bits) instead of
* MPEG pixel range ([16,235] for 8bits luma, [16,240] for 8bits chroma).
*/
uint8_t color_range;
uint8_t num_operating_points;
struct Dav1dSequenceHeaderOperatingPoint {
uint8_t major_level, minor_level;
uint8_t initial_display_delay;
uint16_t idc;
uint8_t tier;
uint8_t decoder_model_param_present;
uint8_t display_model_param_present;
} operating_points[DAV1D_MAX_OPERATING_POINTS];
uint8_t still_picture;
uint8_t reduced_still_picture_header;
uint8_t timing_info_present;
uint32_t num_units_in_tick;
uint32_t time_scale;
uint8_t equal_picture_interval;
uint32_t num_ticks_per_picture;
uint8_t decoder_model_info_present;
uint8_t encoder_decoder_buffer_delay_length;
uint32_t num_units_in_decoding_tick;
uint8_t buffer_removal_delay_length;
uint8_t frame_presentation_delay_length;
uint8_t display_model_info_present;
uint8_t width_n_bits, height_n_bits;
uint8_t frame_id_numbers_present;
uint8_t delta_frame_id_n_bits;
uint8_t frame_id_n_bits;
uint8_t sb128;
uint8_t filter_intra;
uint8_t intra_edge_filter;
uint8_t inter_intra;
uint8_t masked_compound;
uint8_t warped_motion;
uint8_t dual_filter;
uint8_t order_hint;
uint8_t jnt_comp;
uint8_t ref_frame_mvs;
enum Dav1dAdaptiveBoolean screen_content_tools;
enum Dav1dAdaptiveBoolean force_integer_mv;
uint8_t order_hint_n_bits;
uint8_t super_res;
uint8_t cdef;
uint8_t restoration;
uint8_t ss_hor, ss_ver, monochrome;
uint8_t color_description_present;
uint8_t separate_uv_delta_q;
uint8_t film_grain_present;
// Dav1dSequenceHeaders of the same sequence are required to be
// bit-identical until this offset. See 7.5 "Ordering of OBUs":
// Within a particular coded video sequence, the contents of
// sequence_header_obu must be bit-identical each time the
// sequence header appears except for the contents of
// operating_parameters_info.
struct Dav1dSequenceHeaderOperatingParameterInfo {
uint32_t decoder_buffer_delay;
uint32_t encoder_buffer_delay;
uint8_t low_delay_mode;
} operating_parameter_info[DAV1D_MAX_OPERATING_POINTS];
} Dav1dSequenceHeader;
typedef struct Dav1dSegmentationData {
int16_t delta_q;
int8_t delta_lf_y_v, delta_lf_y_h, delta_lf_u, delta_lf_v;
int8_t ref;
uint8_t skip;
uint8_t globalmv;
} Dav1dSegmentationData;
typedef struct Dav1dSegmentationDataSet {
Dav1dSegmentationData d[DAV1D_MAX_SEGMENTS];
uint8_t preskip;
int8_t last_active_segid;
} Dav1dSegmentationDataSet;
typedef struct Dav1dLoopfilterModeRefDeltas {
int8_t mode_delta[2 /* is_zeromv */];
int8_t ref_delta[DAV1D_TOTAL_REFS_PER_FRAME];
} Dav1dLoopfilterModeRefDeltas;
typedef struct Dav1dFilmGrainData {
unsigned seed;
int num_y_points;
uint8_t y_points[14][2 /* value, scaling */];
int chroma_scaling_from_luma;
int num_uv_points[2];
uint8_t uv_points[2][10][2 /* value, scaling */];
int scaling_shift;
int ar_coeff_lag;
int8_t ar_coeffs_y[24];
int8_t ar_coeffs_uv[2][25 + 3 /* padding for alignment purposes */];
uint64_t ar_coeff_shift;
int grain_scale_shift;
int uv_mult[2];
int uv_luma_mult[2];
int uv_offset[2];
int overlap_flag;
int clip_to_restricted_range;
} Dav1dFilmGrainData;
typedef struct Dav1dFrameHeader {
struct {
Dav1dFilmGrainData data;
uint8_t present, update;
} film_grain; ///< film grain parameters
enum Dav1dFrameType frame_type; ///< type of the picture
int width[2 /* { coded_width, superresolution_upscaled_width } */], height;
uint8_t frame_offset; ///< frame number
uint8_t temporal_id; ///< temporal id of the frame for SVC
uint8_t spatial_id; ///< spatial id of the frame for SVC
uint8_t show_existing_frame;
uint8_t existing_frame_idx;
uint32_t frame_id;
uint32_t frame_presentation_delay;
uint8_t show_frame;
uint8_t showable_frame;
uint8_t error_resilient_mode;
uint8_t disable_cdf_update;
uint8_t allow_screen_content_tools;
uint8_t force_integer_mv;
uint8_t frame_size_override;
uint8_t primary_ref_frame;
uint8_t buffer_removal_time_present;
struct Dav1dFrameHeaderOperatingPoint {
uint32_t buffer_removal_time;
} operating_points[DAV1D_MAX_OPERATING_POINTS];
uint8_t refresh_frame_flags;
int render_width, render_height;
struct {
uint8_t width_scale_denominator;
uint8_t enabled;
} super_res;
uint8_t have_render_size;
uint8_t allow_intrabc;
uint8_t frame_ref_short_signaling;
int8_t refidx[DAV1D_REFS_PER_FRAME];
uint8_t hp;
enum Dav1dFilterMode subpel_filter_mode;
uint8_t switchable_motion_mode;
uint8_t use_ref_frame_mvs;
uint8_t refresh_context;
struct {
uint8_t uniform;
uint8_t n_bytes;
uint8_t min_log2_cols, max_log2_cols, log2_cols, cols;
uint8_t min_log2_rows, max_log2_rows, log2_rows, rows;
uint16_t col_start_sb[DAV1D_MAX_TILE_COLS + 1];
uint16_t row_start_sb[DAV1D_MAX_TILE_ROWS + 1];
uint16_t update;
} tiling;
struct {
uint8_t yac;
int8_t ydc_delta;
int8_t udc_delta, uac_delta, vdc_delta, vac_delta;
uint8_t qm, qm_y, qm_u, qm_v;
} quant;
struct {
uint8_t enabled, update_map, temporal, update_data;
Dav1dSegmentationDataSet seg_data;
uint8_t lossless[DAV1D_MAX_SEGMENTS], qidx[DAV1D_MAX_SEGMENTS];
} segmentation;
struct {
struct {
uint8_t present;
uint8_t res_log2;
} q;
struct {
uint8_t present;
uint8_t res_log2;
uint8_t multi;
} lf;
} delta;
uint8_t all_lossless;
struct {
uint8_t level_y[2 /* dir */];
uint8_t level_u, level_v;
uint8_t mode_ref_delta_enabled;
uint8_t mode_ref_delta_update;
Dav1dLoopfilterModeRefDeltas mode_ref_deltas;
uint8_t sharpness;
} loopfilter;
struct {
uint8_t damping;
uint8_t n_bits;
uint8_t y_strength[DAV1D_MAX_CDEF_STRENGTHS];
uint8_t uv_strength[DAV1D_MAX_CDEF_STRENGTHS];
} cdef;
struct {
enum Dav1dRestorationType type[3 /* plane */];
uint8_t unit_size[2 /* y, uv */];
} restoration;
enum Dav1dTxfmMode txfm_mode;
uint8_t switchable_comp_refs;
uint8_t skip_mode_allowed, skip_mode_enabled;
int8_t skip_mode_refs[2];
uint8_t warp_motion;
uint8_t reduced_txtp_set;
Dav1dWarpedMotionParams gmv[DAV1D_REFS_PER_FRAME];
} Dav1dFrameHeader;
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* DAV1D_HEADERS_H */

View file

@ -0,0 +1,36 @@
# Copyright © 2019, VideoLAN and dav1d authors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. 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.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
dav1d_api_headers = [
'common.h',
'data.h',
'dav1d.h',
'headers.h',
'picture.h',
'version.h',
]
# install headers
install_headers(dav1d_api_headers,
subdir : 'dav1d')

View file

@ -0,0 +1,157 @@
/*
* Copyright © 2018-2020, VideoLAN and dav1d authors
* Copyright © 2018, Two Orioles, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#ifndef DAV1D_PICTURE_H
#define DAV1D_PICTURE_H
#include <stddef.h>
#include <stdint.h>
#include "common.h"
#include "headers.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Number of bytes to align AND pad picture memory buffers by, so that SIMD
* implementations can over-read by a few bytes, and use aligned read/write
* instructions. */
#define DAV1D_PICTURE_ALIGNMENT 64
typedef struct Dav1dPictureParameters {
int w; ///< width (in pixels)
int h; ///< height (in pixels)
enum Dav1dPixelLayout layout; ///< format of the picture
int bpc; ///< bits per pixel component (8 or 10)
} Dav1dPictureParameters;
typedef struct Dav1dPicture {
Dav1dSequenceHeader *seq_hdr;
Dav1dFrameHeader *frame_hdr;
/**
* Pointers to planar image data (Y is [0], U is [1], V is [2]). The data
* should be bytes (for 8 bpc) or words (for 10 bpc). In case of words
* containing 10 bpc image data, the pixels should be located in the LSB
* bits, so that values range between [0, 1023]; the upper bits should be
* zero'ed out.
*/
void *data[3];
/**
* Number of bytes between 2 lines in data[] for luma [0] or chroma [1].
*/
ptrdiff_t stride[2];
Dav1dPictureParameters p;
Dav1dDataProps m;
/**
* High Dynamic Range Content Light Level metadata applying to this picture,
* as defined in section 5.8.3 and 6.7.3
*/
Dav1dContentLightLevel *content_light;
/**
* High Dynamic Range Mastering Display Color Volume metadata applying to
* this picture, as defined in section 5.8.4 and 6.7.4
*/
Dav1dMasteringDisplay *mastering_display;
/**
* Array of ITU-T T.35 metadata as defined in section 5.8.2 and 6.7.2
*/
Dav1dITUTT35 *itut_t35;
/**
* Number of ITU-T T35 metadata entries in the array
*/
size_t n_itut_t35;
uintptr_t reserved[4]; ///< reserved for future use
struct Dav1dRef *frame_hdr_ref; ///< Dav1dFrameHeader allocation origin
struct Dav1dRef *seq_hdr_ref; ///< Dav1dSequenceHeader allocation origin
struct Dav1dRef *content_light_ref; ///< Dav1dContentLightLevel allocation origin
struct Dav1dRef *mastering_display_ref; ///< Dav1dMasteringDisplay allocation origin
struct Dav1dRef *itut_t35_ref; ///< Dav1dITUTT35 allocation origin
uintptr_t reserved_ref[4]; ///< reserved for future use
struct Dav1dRef *ref; ///< Frame data allocation origin
void *allocator_data; ///< pointer managed by the allocator
} Dav1dPicture;
typedef struct Dav1dPicAllocator {
void *cookie; ///< custom data to pass to the allocator callbacks.
/**
* Allocate the picture buffer based on the Dav1dPictureParameters.
*
* The data[0], data[1] and data[2] must be DAV1D_PICTURE_ALIGNMENT byte
* aligned and with a pixel width/height multiple of 128 pixels. Any
* allocated memory area should also be padded by DAV1D_PICTURE_ALIGNMENT
* bytes.
* data[1] and data[2] must share the same stride[1].
*
* This function will be called on the main thread (the thread which calls
* dav1d_get_picture()).
*
* @param pic The picture to allocate the buffer for. The callback needs to
* fill the picture data[0], data[1], data[2], stride[0] and
* stride[1].
* The allocator can fill the pic allocator_data pointer with
* a custom pointer that will be passed to
* release_picture_callback().
* @param cookie Custom pointer passed to all calls.
*
* @note No fields other than data, stride and allocator_data must be filled
* by this callback.
* @return 0 on success. A negative DAV1D_ERR value on error.
*/
int (*alloc_picture_callback)(Dav1dPicture *pic, void *cookie);
/**
* Release the picture buffer.
*
* If frame threading is used, this function may be called by the main
* thread (the thread which calls dav1d_get_picture()) or any of the frame
* threads and thus must be thread-safe. If frame threading is not used,
* this function will only be called on the main thread.
*
* @param pic The picture that was filled by alloc_picture_callback().
* @param cookie Custom pointer passed to all calls.
*/
void (*release_picture_callback)(Dav1dPicture *pic, void *cookie);
} Dav1dPicAllocator;
/**
* Release reference to a picture.
*/
DAV1D_API void dav1d_picture_unref(Dav1dPicture *p);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* DAV1D_PICTURE_H */

View file

@ -0,0 +1,50 @@
/*
* Copyright © 2019-2024, VideoLAN and dav1d authors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#ifndef DAV1D_VERSION_H
#define DAV1D_VERSION_H
#ifdef __cplusplus
extern "C" {
#endif
#define DAV1D_API_VERSION_MAJOR 7
#define DAV1D_API_VERSION_MINOR 0
#define DAV1D_API_VERSION_PATCH 0
/**
* Extract version components from the value returned by
* dav1d_version_int()
*/
#define DAV1D_API_MAJOR(v) (((v) >> 16) & 0xFF)
#define DAV1D_API_MINOR(v) (((v) >> 8) & 0xFF)
#define DAV1D_API_PATCH(v) (((v) >> 0) & 0xFF)
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* DAV1D_VERSION_H */

View file

@ -0,0 +1,34 @@
# Copyright © 2018, VideoLAN and dav1d authors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. 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.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
# Revision file (vcs_version.h) generation
dav1d_git_dir = join_paths(dav1d_src_root, '.git')
rev_target = vcs_tag(command: [
'git', '--git-dir', dav1d_git_dir, 'describe', '--long', '--always'
],
input: 'vcs_version.h.in',
output: 'vcs_version.h'
)
subdir('dav1d')

View file

@ -0,0 +1,2 @@
/* auto-generated, do not edit */
#define DAV1D_VERSION "@VCS_TAG@"

View file

@ -0,0 +1,610 @@
# Copyright © 2018-2024, VideoLAN and dav1d authors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. 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.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
project('dav1d', ['c'],
version: '1.5.3',
default_options: ['c_std=c99',
'warning_level=2',
'buildtype=release',
'b_ndebug=if-release'],
meson_version: '>= 0.49.0')
dav1d_src_root = meson.current_source_dir()
cc = meson.get_compiler('c')
# Configuratin data for config.h
cdata = configuration_data()
# Configuration data for config.asm
cdata_asm = configuration_data()
# Include directories
dav1d_inc_dirs = include_directories(['.', 'include/dav1d', 'include'])
dav1d_api_version_major = cc.get_define('DAV1D_API_VERSION_MAJOR',
prefix: '#include "dav1d/version.h"',
include_directories: dav1d_inc_dirs).strip()
dav1d_api_version_minor = cc.get_define('DAV1D_API_VERSION_MINOR',
prefix: '#include "dav1d/version.h"',
include_directories: dav1d_inc_dirs).strip()
dav1d_api_version_revision = cc.get_define('DAV1D_API_VERSION_PATCH',
prefix: '#include "dav1d/version.h"',
include_directories: dav1d_inc_dirs).strip()
dav1d_soname_version = '@0@.@1@.@2@'.format(dav1d_api_version_major,
dav1d_api_version_minor,
dav1d_api_version_revision)
#
# Option handling
#
# Bitdepth option
dav1d_bitdepths = get_option('bitdepths')
foreach bitdepth : ['8', '16']
cdata.set10('CONFIG_@0@BPC'.format(bitdepth), dav1d_bitdepths.contains(bitdepth))
endforeach
# ASM option
is_asm_enabled = (get_option('enable_asm') == true and
(host_machine.cpu_family() == 'aarch64' or
host_machine.cpu_family().startswith('arm') or
host_machine.cpu() == 'ppc64le' or
host_machine.cpu_family().startswith('riscv') or
host_machine.cpu_family().startswith('loongarch') or
host_machine.cpu_family() == 'x86' or
(host_machine.cpu_family() == 'x86_64' and cc.get_define('__ILP32__').strip() == '')))
cdata.set10('HAVE_ASM', is_asm_enabled)
if is_asm_enabled and get_option('b_sanitize') == 'memory'
error('asm causes false positive with memory sanitizer. Use \'-Denable_asm=false\'.')
endif
cdata.set10('TRIM_DSP_FUNCTIONS', get_option('trim_dsp') == 'true' or
(get_option('trim_dsp') == 'if-release' and get_option('buildtype') == 'release'))
# Logging option
cdata.set10('CONFIG_LOG', get_option('logging'))
cdata.set10('CONFIG_MACOS_KPERF', get_option('macos_kperf'))
#
# OS/Compiler checks and defines
#
# Arguments in test_args will be used even on feature tests
test_args = []
optional_arguments = []
optional_link_arguments = []
if host_machine.system() in ['linux', 'gnu', 'emscripten']
test_args += '-D_GNU_SOURCE'
add_project_arguments('-D_GNU_SOURCE', language: 'c')
endif
have_clock_gettime = false
have_posix_memalign = false
have_memalign = false
have_aligned_alloc = false
if host_machine.system() == 'windows'
cdata.set('_WIN32_WINNT', '0x0601')
cdata.set('UNICODE', 1) # Define to 1 for Unicode (Wide Chars) APIs
cdata.set('_UNICODE', 1) # Define to 1 for Unicode (Wide Chars) APIs
cdata.set('__USE_MINGW_ANSI_STDIO', 1) # Define to force use of MinGW printf
cdata.set('_CRT_DECLARE_NONSTDC_NAMES', 1) # Define to get off_t from sys/types.h on MSVC
if cc.has_function('fseeko', prefix : '#include <stdio.h>', args : test_args)
cdata.set('_FILE_OFFSET_BITS', 64) # Not set by default by Meson on Windows
else
cdata.set('fseeko', '_fseeki64')
cdata.set('ftello', '_ftelli64')
endif
if host_machine.cpu_family() == 'x86_64'
if cc.get_argument_syntax() != 'msvc'
optional_link_arguments += '-Wl,--dynamicbase,--nxcompat,--tsaware,--high-entropy-va'
endif
elif host_machine.cpu_family() == 'x86' or host_machine.cpu_family() == 'arm'
if cc.get_argument_syntax() == 'msvc'
optional_link_arguments += '/largeaddressaware'
else
optional_link_arguments += '-Wl,--dynamicbase,--nxcompat,--tsaware,--large-address-aware'
endif
endif
# On Windows, we use a compatibility layer to emulate pthread
thread_dependency = []
thread_compat_dep = declare_dependency(sources : files('src/win32/thread.c'))
rt_dependency = []
rc_version_array = meson.project_version().split('.')
winmod = import('windows')
rc_data = configuration_data()
rc_data.set('PROJECT_VERSION_MAJOR', rc_version_array[0])
rc_data.set('PROJECT_VERSION_MINOR', rc_version_array[1])
rc_data.set('PROJECT_VERSION_REVISION', rc_version_array[2])
rc_data.set('API_VERSION_MAJOR', dav1d_api_version_major)
rc_data.set('API_VERSION_MINOR', dav1d_api_version_minor)
rc_data.set('API_VERSION_REVISION', dav1d_api_version_revision)
rc_data.set('COPYRIGHT_YEARS', '2018-2025')
else
thread_dependency = dependency('threads')
thread_compat_dep = []
rt_dependency = []
if cc.has_function('clock_gettime', prefix : '#include <time.h>', args : test_args)
have_clock_gettime = true
elif host_machine.system() not in ['darwin', 'ios', 'tvos']
rt_dependency = cc.find_library('rt', required: false)
if not cc.has_function('clock_gettime', prefix : '#include <time.h>', args : test_args, dependencies : rt_dependency)
error('clock_gettime not found')
endif
have_clock_gettime = true
endif
have_posix_memalign = cc.has_function('posix_memalign', prefix : '#include <stdlib.h>', args : test_args)
have_memalign = cc.has_function('memalign', prefix : '#include <malloc.h>', args : test_args)
have_aligned_alloc = cc.has_function('aligned_alloc', prefix : '#include <stdlib.h>', args : test_args)
endif
cdata.set10('HAVE_CLOCK_GETTIME', have_clock_gettime)
cdata.set10('HAVE_POSIX_MEMALIGN', have_posix_memalign)
cdata.set10('HAVE_MEMALIGN', have_memalign)
cdata.set10('HAVE_ALIGNED_ALLOC', have_aligned_alloc)
# check for fseeko on android. It is not always available if _FILE_OFFSET_BITS is defined to 64
have_fseeko = true
if host_machine.system() == 'android'
if not cc.has_function('fseeko', prefix : '#include <stdio.h>', args : test_args)
if cc.has_function('fseeko', prefix : '#include <stdio.h>', args : test_args + ['-U_FILE_OFFSET_BITS'])
warning('Files larger than 2 gigabytes might not be supported in the dav1d CLI tool.')
add_project_arguments('-U_FILE_OFFSET_BITS', language: 'c')
elif get_option('enable_tools')
error('dav1d CLI tool needs fseeko()')
else
have_fseeko = false
endif
endif
endif
libdl_dependency = []
have_dlsym = false
if host_machine.system() == 'linux'
libdl_dependency = cc.find_library('dl', required : false)
have_dlsym = cc.has_function('dlsym', prefix : '#include <dlfcn.h>', args : test_args, dependencies : libdl_dependency)
endif
cdata.set10('HAVE_DLSYM', have_dlsym)
libm_dependency = cc.find_library('m', required: false)
# Header checks
stdatomic_dependencies = []
if not cc.check_header('stdatomic.h')
if cc.get_id() == 'msvc'
# we have a custom replacement for MSVC
stdatomic_dependencies += declare_dependency(
include_directories : include_directories('include/compat/msvc'),
)
elif cc.compiles('''int main() { int v = 0; return __atomic_fetch_add(&v, 1, __ATOMIC_SEQ_CST); }''',
name : 'GCC-style atomics', args : test_args)
stdatomic_dependencies += declare_dependency(
include_directories : include_directories('include/compat/gcc'),
)
else
error('Atomics not supported')
endif
endif
if host_machine.cpu_family().startswith('wasm')
# enable atomics + bulk-memory features
stdatomic_dependencies += thread_dependency.partial_dependency(compile_args: true)
endif
cdata.set10('HAVE_SYS_TYPES_H', cc.check_header('sys/types.h'))
cdata.set10('HAVE_UNISTD_H', cc.check_header('unistd.h'))
cdata.set10('HAVE_IO_H', cc.check_header('io.h'))
have_pthread_np = cc.check_header('pthread_np.h')
cdata.set10('HAVE_PTHREAD_NP_H', have_pthread_np)
test_args += '-DHAVE_PTHREAD_NP_H=' + (have_pthread_np ? '1' : '0')
# Function checks
if not cc.has_function('getopt_long', prefix : '#include <getopt.h>', args : test_args)
getopt_dependency = declare_dependency(
sources: files('tools/compat/getopt.c'),
include_directories : include_directories('include/compat'),
)
else
getopt_dependency = []
endif
have_getauxval = false
have_elf_aux_info = false
if (host_machine.cpu_family() == 'aarch64' or
host_machine.cpu_family().startswith('arm') or
host_machine.cpu_family().startswith('loongarch') or
host_machine.cpu() == 'ppc64le' or
host_machine.cpu_family().startswith('riscv'))
have_getauxval = cc.has_function('getauxval', prefix : '#include <sys/auxv.h>', args : test_args)
have_elf_aux_info = cc.has_function('elf_aux_info', prefix : '#include <sys/auxv.h>', args : test_args)
endif
cdata.set10('HAVE_GETAUXVAL', have_getauxval)
cdata.set10('HAVE_ELF_AUX_INFO', have_elf_aux_info)
pthread_np_prefix = '''
#include <pthread.h>
#if HAVE_PTHREAD_NP_H
#include <pthread_np.h>
#endif
'''
cdata.set10('HAVE_PTHREAD_GETAFFINITY_NP', cc.has_function('pthread_getaffinity_np', prefix : pthread_np_prefix, args : test_args, dependencies : thread_dependency))
cdata.set10('HAVE_PTHREAD_SETAFFINITY_NP', cc.has_function('pthread_setaffinity_np', prefix : pthread_np_prefix, args : test_args, dependencies : thread_dependency))
cdata.set10('HAVE_PTHREAD_SETNAME_NP', cc.has_function('pthread_setname_np', prefix : pthread_np_prefix, args : test_args, dependencies : thread_dependency))
cdata.set10('HAVE_PTHREAD_SET_NAME_NP', cc.has_function('pthread_set_name_np', prefix : pthread_np_prefix, args : test_args, dependencies : thread_dependency))
cdata.set10('HAVE_C11_GENERIC', cc.compiles('int x = _Generic(0, default: 0);', name: '_Generic', args: test_args))
# Compiler flag tests
if cc.has_argument('-fvisibility=hidden')
add_project_arguments('-fvisibility=hidden', language: 'c')
else
warning('Compiler does not support -fvisibility=hidden, all symbols will be public!')
endif
# Compiler flags that should be set
# But when the compiler does not supports them
# it is not an error and silently tolerated
if cc.get_argument_syntax() != 'msvc'
optional_arguments += [
'-Wundef',
'-Werror=vla',
'-Wno-maybe-uninitialized',
'-Wno-missing-field-initializers',
'-Wno-unused-parameter',
'-Wstrict-prototypes',
'-Werror=missing-prototypes',
'-Wshorten-64-to-32',
]
if host_machine.cpu_family() == 'x86'
optional_arguments += [
'-msse2',
'-mfpmath=sse',
]
endif
else
optional_arguments += [
'-wd4028', # parameter different from declaration
'-wd4090', # broken with arrays of pointers
'-wd4996' # use of POSIX functions
]
endif
if (get_option('buildtype') != 'debug' and get_option('buildtype') != 'plain')
optional_arguments += '-fomit-frame-pointer'
optional_arguments += '-ffast-math'
endif
if (host_machine.system() in ['darwin', 'ios', 'tvos'] and cc.get_id() == 'clang' and
cc.version().startswith('11'))
# Workaround for Xcode 11 -fstack-check bug, see #301
optional_arguments += '-fno-stack-check'
endif
if (host_machine.cpu_family() == 'aarch64' or host_machine.cpu_family().startswith('arm'))
optional_arguments += '-fno-align-functions'
endif
add_project_arguments(cc.get_supported_arguments(optional_arguments), language : 'c')
add_project_link_arguments(cc.get_supported_link_arguments(optional_link_arguments), language : 'c')
# libFuzzer related things
fuzzing_engine = get_option('fuzzing_engine')
if fuzzing_engine == 'libfuzzer'
if not cc.has_argument('-fsanitize=fuzzer')
error('fuzzing_engine libfuzzer requires "-fsanitize=fuzzer"')
endif
fuzzer_args = ['-fsanitize=fuzzer-no-link', '-fsanitize=fuzzer']
add_project_arguments(cc.first_supported_argument(fuzzer_args), language : 'c')
endif
cdata.set10('ENDIANNESS_BIG', host_machine.endian() == 'big')
if host_machine.cpu_family().startswith('x86')
if get_option('stack_alignment') > 0
stack_alignment = get_option('stack_alignment')
elif host_machine.cpu_family() == 'x86_64' or host_machine.system() in ['linux', 'darwin', 'ios', 'tvos']
stack_alignment = 16
else
stack_alignment = 4
endif
cdata_asm.set('STACK_ALIGNMENT', stack_alignment)
endif
#
# ASM specific stuff
#
use_gaspp = false
if (is_asm_enabled and
(host_machine.cpu_family() == 'aarch64' or
host_machine.cpu_family().startswith('arm')) and
cc.get_argument_syntax() == 'msvc' and
(cc.get_id() != 'clang-cl' or meson.version().version_compare('<0.58.0')))
gaspp = find_program('gas-preprocessor.pl')
use_gaspp = true
gaspp_args = [
'-as-type', 'armasm',
'-arch', host_machine.cpu_family(),
'--',
host_machine.cpu_family() == 'aarch64' ? 'armasm64' : 'armasm',
'-nologo',
'-I@0@'.format(dav1d_src_root),
'-I@0@/'.format(meson.current_build_dir()),
]
gaspp_gen = generator(gaspp,
output: '@BASENAME@.obj',
arguments: gaspp_args + [
'@INPUT@',
'-c',
'-o', '@OUTPUT@'
])
endif
cdata.set10('ARCH_AARCH64', host_machine.cpu_family() == 'aarch64' or host_machine.cpu() == 'arm64')
cdata.set10('ARCH_ARM', host_machine.cpu_family().startswith('arm') and host_machine.cpu() != 'arm64')
have_as_func = false
have_as_arch = false
aarch64_extensions = {
'dotprod': 'udot v0.4s, v0.16b, v0.16b',
'i8mm': 'usdot v0.4s, v0.16b, v0.16b',
'sve': 'whilelt p0.s, x0, x1',
'sve2': 'sqrdmulh z0.s, z0.s, z0.s',
}
supported_aarch64_archexts = []
supported_aarch64_instructions = []
if (is_asm_enabled and
(host_machine.cpu_family() == 'aarch64' or
host_machine.cpu_family().startswith('arm')))
as_func_code = '''__asm__ (
".func meson_test"
".endfunc"
);
'''
have_as_func = cc.compiles(as_func_code)
# fedora package build infrastructure uses a gcc specs file to enable
# '-fPIE' by default. The chosen way only adds '-fPIE' to the C compiler
# with integrated preprocessor. It is not added to the standalone
# preprocessor or the preprocessing stage of '.S' files. So we have to
# compile code to check if we have to define PIC for the arm asm to
# avoid absolute relocations when building for example checkasm.
check_pic_code = '''
#if defined(PIC)
#error "PIC already defined"
#elif !(defined(__PIC__) || defined(__pic__))
#error "no pic"
#endif
'''
if cc.compiles(check_pic_code)
cdata.set('PIC', '3')
endif
if host_machine.cpu_family() == 'aarch64'
have_as_arch = cc.compiles('''__asm__ (".arch armv8-a");''')
as_arch_str = ''
if have_as_arch
as_arch_level = 'armv8-a'
# Check what .arch levels are supported. In principle, we only
# want to detect up to armv8.2-a here (binutils requires that
# in order to enable i8mm). However, older Clang versions
# (before Clang 17, and Xcode versions up to and including 15.0)
# didn't support controlling dotprod/i8mm extensions via
# .arch_extension, therefore try to enable a high enough .arch
# level as well, to implicitly make them available via that.
foreach arch : ['armv8.2-a', 'armv8.4-a', 'armv8.6-a']
if cc.compiles('__asm__ (".arch ' + arch + '\\n");')
as_arch_level = arch
endif
endforeach
# Clang versions before 17 also had a bug
# (https://github.com/llvm/llvm-project/issues/32220)
# causing a plain ".arch <level>" to not have any effect unless it
# had an extra "+<feature>" included - but it was activated on the
# next ".arch_extension" directive instead. Check if we can include
# "+crc" as dummy feature to make the .arch directive behave as
# expected and take effect right away.
if cc.compiles('__asm__ (".arch ' + as_arch_level + '+crc\\n");')
as_arch_level = as_arch_level + '+crc'
endif
cdata.set('AS_ARCH_LEVEL', as_arch_level)
as_arch_str = '".arch ' + as_arch_level + '\\n"'
endif
if use_gaspp
python3 = import('python').find_installation()
endif
foreach name, instr : aarch64_extensions
if use_gaspp
f = configure_file(
command: [python3, '-c', 'import sys; print(sys.argv[1])', '@0@'.format(instr)],
output: 'test-@0@.S'.format(name),
capture: true)
r = run_command(gaspp, gaspp_args, f, '-c', '-o', meson.current_build_dir() / 'test-' + name + '.obj', check: false)
message('Checking for gaspp/armasm64 ' + name.to_upper() + ': ' + (r.returncode() == 0 ? 'YES' : 'NO'))
if r.returncode() == 0
supported_aarch64_instructions += name
endif
else
# Test for support for the various extensions. First test if
# the assembler supports the .arch_extension directive for
# enabling/disabling the extension, then separately check whether
# the instructions themselves are supported. Even if .arch_extension
# isn't supported, we may be able to assemble the instructions
# if the .arch level includes support for them.
code = '__asm__ (' + as_arch_str
code += '".arch_extension ' + name + '\\n"'
code += ');'
supports_archext = cc.compiles(code)
code = '__asm__ (' + as_arch_str
if supports_archext
supported_aarch64_archexts += name
code += '".arch_extension ' + name + '\\n"'
endif
code += '"' + instr + '\\n"'
code += ');'
if cc.compiles(code, name: name.to_upper())
supported_aarch64_instructions += name
endif
endif
endforeach
endif
endif
cdata.set10('HAVE_AS_FUNC', have_as_func)
cdata.set10('HAVE_AS_ARCH_DIRECTIVE', have_as_arch)
foreach name, _ : aarch64_extensions
cdata.set10('HAVE_AS_ARCHEXT_' + name.to_upper() + '_DIRECTIVE', name in supported_aarch64_archexts)
cdata.set10('HAVE_' + name.to_upper(), name in supported_aarch64_instructions)
endforeach
cdata.set10('ARCH_X86', host_machine.cpu_family().startswith('x86'))
cdata.set10('ARCH_X86_64', host_machine.cpu_family() == 'x86_64')
cdata.set10('ARCH_X86_32', host_machine.cpu_family() == 'x86')
if host_machine.cpu_family().startswith('x86')
cdata_asm.set('private_prefix', 'dav1d')
cdata_asm.set10('ARCH_X86_64', host_machine.cpu_family() == 'x86_64')
cdata_asm.set10('ARCH_X86_32', host_machine.cpu_family() == 'x86')
cdata_asm.set10('PIC', true)
# Convert SSE asm into (128-bit) AVX when compiler flags are set to use AVX instructions
cdata_asm.set10('FORCE_VEX_ENCODING', cc.get_define('__AVX__').strip() != '')
endif
cdata.set10('ARCH_PPC64LE', host_machine.cpu() == 'ppc64le')
cdata.set10('ARCH_RISCV', host_machine.cpu_family().startswith('riscv'))
cdata.set10('ARCH_RV32', host_machine.cpu_family() == 'riscv32')
cdata.set10('ARCH_RV64', host_machine.cpu_family() == 'riscv64')
cdata.set10('ARCH_LOONGARCH', host_machine.cpu_family().startswith('loongarch'))
cdata.set10('ARCH_LOONGARCH32', host_machine.cpu_family() == 'loongarch32')
cdata.set10('ARCH_LOONGARCH64', host_machine.cpu_family() == 'loongarch64')
# meson's cc.symbols_have_underscore_prefix() is unfortunately unrelieably
# when additional flags like '-fprofile-instr-generate' are passed via CFLAGS
# see following meson issue https://github.com/mesonbuild/meson/issues/5482
if (host_machine.system() in ['darwin', 'ios', 'tvos'] or
(host_machine.system() == 'windows' and host_machine.cpu_family() == 'x86'))
cdata.set10('PREFIX', true)
cdata_asm.set10('PREFIX', true)
endif
if is_asm_enabled and host_machine.cpu_family().startswith('x86')
# NASM compiler support
nasm = find_program('nasm')
# check NASM version
if nasm.found()
nasm_r = run_command(nasm, '-v', check: true)
out = nasm_r.stdout().strip().split()
if out[1].to_lower() == 'version'
if out[2].version_compare('<2.14')
error('nasm 2.14 or later is required, found nasm @0@'.format(out[2]))
endif
else
error('unexpected nasm version string: @0@'.format(nasm_r.stdout()))
endif
endif
# Generate config.asm
config_asm_target = configure_file(output: 'config.asm', output_format: 'nasm', configuration: cdata_asm)
if host_machine.system() == 'windows'
nasm_format = 'win'
elif host_machine.system() in ['darwin', 'ios', 'tvos']
nasm_format = 'macho'
else
nasm_format = 'elf'
endif
if host_machine.cpu_family() == 'x86_64'
nasm_format += '64'
else
nasm_format += '32'
endif
nasm_gen = generator(nasm,
output: '@BASENAME@.obj',
depfile: '@BASENAME@.obj.ndep',
arguments: [
'-f', nasm_format,
'-I', '@0@/src/'.format(dav1d_src_root),
'-I', '@0@/'.format(meson.current_build_dir()),
'-MQ', '@OUTPUT@', '-MF', '@DEPFILE@',
'@EXTRA_ARGS@',
'@INPUT@',
'-o', '@OUTPUT@'
])
endif
if is_asm_enabled and host_machine.cpu_family().startswith('riscv')
as_option_code = '''__asm__ (
".option arch, +v\n"
"vsetivli zero, 0, e8, m1, ta, ma"
);
'''
if not cc.compiles(as_option_code, name : 'RISC-V Vector')
error('Compiler doesn\'t support \'.option arch\' asm directive. Update to binutils>=2.38 or clang>=17 or use \'-Denable_asm=false\'.')
endif
endif
# Generate config.h
config_h_target = configure_file(output: 'config.h', configuration: cdata)
#
# Include subdir meson.build files
# The order is important!
subdir('include')
subdir('doc')
subdir('src')
subdir('tools')
subdir('examples')
subdir('tests')

View file

@ -0,0 +1,75 @@
# General options
option('bitdepths',
type: 'array',
choices: ['8', '16'],
description: 'Enable only specified bitdepths')
option('enable_asm',
type: 'boolean',
value: true,
description: 'Build asm files, if available')
option('enable_tools',
type: 'boolean',
value: true,
description: 'Build dav1d cli tools')
option('enable_examples',
type: 'boolean',
value: false,
description: 'Build dav1d examples')
option('enable_tests',
type: 'boolean',
value: true,
description: 'Build dav1d tests')
option('enable_seek_stress',
type: 'boolean',
value: false,
description: 'Build seek_stress test tool')
option('enable_docs',
type: 'boolean',
value: false,
description: 'Build dav1d documentation')
option('logging',
type: 'boolean',
value: true,
description: 'Print error log messages using the provided callback function')
option('testdata_tests',
type: 'boolean',
value: false,
description: 'Run tests requiring the test data repository')
option('fuzzing_engine',
type: 'combo',
choices : ['none', 'libfuzzer', 'oss-fuzz'],
value: 'none',
description: 'Select the fuzzing engine')
option('fuzzer_ldflags',
type: 'string',
description: 'Extra LDFLAGS used during linking of fuzzing binaries')
option('stack_alignment',
type: 'integer',
value: 0)
option('xxhash_muxer',
type : 'feature',
value : 'auto')
option('trim_dsp',
type: 'combo',
choices: ['true', 'false', 'if-release'],
value: 'if-release',
description: 'Eliminate redundant DSP functions where possible')
option('macos_kperf',
type: 'boolean',
value: false,
description: 'Use the private macOS kperf API for benchmarking')

View file

@ -0,0 +1,15 @@
[binaries]
c = 'aarch64-linux-android21-clang'
cpp = 'aarch64-linux-android21-clang++'
ar = 'llvm-ar'
strip = 'llvm-strip'
pkgconfig = 'pkg-config'
[properties]
needs_exe_wrapper = true
[host_machine]
system = 'android'
cpu_family = 'aarch64'
cpu = 'aarch64'
endian = 'little'

View file

@ -0,0 +1,16 @@
[binaries]
c = 'clang'
cpp = 'clang++'
ar = 'aarch64-linux-gnu-ar'
strip = 'aarch64-linux-gnu-strip'
exe_wrapper = 'qemu-aarch64'
[properties]
c_args = '-target aarch64-linux-gnu'
c_link_args = '-target aarch64-linux-gnu'
[host_machine]
system = 'linux'
cpu_family = 'aarch64'
cpu = 'aarch64'
endian = 'little'

View file

@ -0,0 +1,12 @@
[binaries]
c = 'aarch64-linux-gnu-gcc'
cpp = 'aarch64-linux-gnu-g++'
ar = 'aarch64-linux-gnu-ar'
strip = 'aarch64-linux-gnu-strip'
exe_wrapper = 'qemu-aarch64'
[host_machine]
system = 'linux'
cpu_family = 'aarch64'
cpu = 'aarch64'
endian = 'little'

View file

@ -0,0 +1,16 @@
[binaries]
c = 'aarch64-w64-mingw32-clang'
cpp = 'aarch64-w64-mingw32-clang++'
ar = 'aarch64-w64-mingw32-ar'
strip = 'aarch64-w64-mingw32-strip'
pkgconfig = 'pkg-config'
windres = 'aarch64-w64-mingw32-windres'
[properties]
c_link_args = ['-static-libgcc']
[host_machine]
system = 'windows'
cpu_family = 'aarch64'
cpu = 'aarch64'
endian = 'little'

View file

@ -0,0 +1,15 @@
[binaries]
c = 'armv7a-linux-androideabi21-clang'
cpp = 'armv7a-linux-androideabi21-clang++'
ar = 'llvm-ar'
strip = 'llvm-strip'
pkgconfig = 'pkg-config'
[properties]
needs_exe_wrapper = true
[host_machine]
system = 'android'
cpu_family = 'arm'
cpu = 'arm'
endian = 'little'

View file

@ -0,0 +1,27 @@
[binaries]
c = ['clang', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk']
cpp = ['clang++', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk']
objc = ['clang', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk']
objcpp = ['clang++', '-arch', 'arm64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk']
ar = 'ar'
strip = 'strip'
[built-in options]
c_args = ['-miphoneos-version-min=11.0']
cpp_args = ['-miphoneos-version-min=11.0']
c_link_args = ['-miphoneos-version-min=11.0']
cpp_link_args = ['-miphoneos-version-min=11.0']
objc_args = ['-miphoneos-version-min=11.0']
objcpp_args = ['-miphoneos-version-min=11.0']
[properties]
root = '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer'
needs_exe_wrapper = true
[host_machine]
system = 'darwin'
subsystem = 'ios'
kernel = 'xnu'
cpu_family = 'aarch64'
cpu = 'aarch64'
endian = 'little'

View file

@ -0,0 +1,16 @@
[binaries]
c = 'armv7-w64-mingw32-clang'
cpp = 'armv7-w64-mingw32-clang++'
ar = 'armv7-w64-mingw32-ar'
strip = 'armv7-w64-mingw32-strip'
pkgconfig = 'pkg-config'
windres = 'armv7-w64-mingw32-windres'
[properties]
c_link_args = ['-static-libgcc']
[host_machine]
system = 'windows'
cpu_family = 'arm'
cpu = 'armv7'
endian = 'little'

View file

@ -0,0 +1,15 @@
[binaries]
c = 'gcc'
cpp = 'g++'
ar = 'ar'
strip = 'strip'
[properties]
c_link_args = ['-m32', '-Wl,-z,text']
c_args = ['-m32']
[host_machine]
system = 'linux'
cpu_family = 'x86'
cpu = 'i686'
endian = 'little'

View file

@ -0,0 +1,16 @@
[binaries]
c = 'i686-w64-mingw32-gcc'
cpp = 'i686-w64-mingw32-g++'
ar = 'i686-w64-mingw32-ar'
strip = 'i686-w64-mingw32-strip'
windres = 'i686-w64-mingw32-windres'
exe_wrapper = 'wine'
[properties]
c_link_args = ['-static-libgcc']
[host_machine]
system = 'windows'
cpu_family = 'x86'
cpu = 'i686'
endian = 'little'

View file

@ -0,0 +1,13 @@
[binaries]
c = 'loongarch64-unknown-linux-gnu-gcc'
cpp = 'loongarch64-unknown-linux-gnu-c++'
ar = 'loongarch64-unknown-linux-gnu-ar'
strip = 'loongarch64-unknown-linux-gnu-strip'
pkgconfig = 'pkg-config'
exe_wrapper = 'qemu-loongarch64'
[host_machine]
system = 'linux'
cpu_family = 'loongarch64'
cpu = 'loongarch64'
endian = 'little'

View file

@ -0,0 +1,16 @@
[binaries]
c = 'clang'
cpp = 'clang++'
ar = 'riscv64-linux-gnu-ar'
strip = 'riscv64-linux-gnu-strip'
exe_wrapper = 'qemu-riscv64'
[properties]
c_args = '-target riscv64-linux-gnu'
c_link_args = '-target riscv64-linux-gnu'
[host_machine]
system = 'linux'
cpu_family = 'riscv64'
cpu = 'riscv64'
endian = 'little'

View file

@ -0,0 +1,12 @@
[binaries]
c = 'riscv64-linux-gnu-gcc'
cpp = 'riscv64-linux-gnu-g++'
ar = 'riscv64-linux-gnu-ar'
strip = 'riscv64-linux-gnu-strip'
exe_wrapper = 'qemu-riscv64'
[host_machine]
system = 'linux'
cpu_family = 'riscv64'
cpu = 'riscv64'
endian = 'little'

View file

@ -0,0 +1,15 @@
[binaries]
c = 'emcc'
cpp = 'em++'
ar = 'emar'
strip = 'emstrip'
exe_wrapper = 'node'
[properties]
c_link_args = ['-sEXPORT_ALL=1']
[host_machine]
system = 'emscripten'
cpu_family = 'wasm32'
cpu = 'wasm32'
endian = 'little'

View file

@ -0,0 +1,15 @@
[binaries]
c = 'emcc'
cpp = 'em++'
ar = 'emar'
strip = 'emstrip'
exe_wrapper = 'node'
[properties]
c_link_args = ['-sEXPORT_ALL=1']
[host_machine]
system = 'emscripten'
cpu_family = 'wasm64'
cpu = 'wasm64'
endian = 'little'

View file

@ -0,0 +1,15 @@
[binaries]
c = 'i686-linux-android19-clang'
cpp = 'i686-linux-android19-clang++'
ar = 'llvm-ar'
strip = 'llvm-strip'
pkgconfig = 'pkg-config'
[properties]
needs_exe_wrapper = true
[host_machine]
system = 'android'
cpu_family = 'x86'
cpu = 'i686'
endian = 'little'

View file

@ -0,0 +1,15 @@
[binaries]
c = 'x86_64-linux-android21-clang'
cpp = 'x86_64-linux-android21-clang++'
ar = 'llvm-ar'
strip = 'llvm-strip'
pkgconfig = 'pkg-config'
[properties]
needs_exe_wrapper = true
[host_machine]
system = 'android'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'

View file

@ -0,0 +1,27 @@
[binaries]
c = ['clang', '-arch', 'x86_64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk']
cpp = ['clang++', '-arch', 'x86_64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk']
objc = ['clang', '-arch', 'x86_64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk']
objcpp = ['clang++', '-arch', 'x86_64', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk']
ar = 'ar'
strip = 'strip'
[built-in options]
c_args = ['-miphoneos-version-min=11.0']
cpp_args = ['-miphoneos-version-min=11.0']
c_link_args = ['-miphoneos-version-min=11.0']
cpp_link_args = ['-miphoneos-version-min=11.0']
objc_args = ['-miphoneos-version-min=11.0']
objcpp_args = ['-miphoneos-version-min=11.0']
[properties]
root = '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer'
needs_exe_wrapper = true
[host_machine]
system = 'darwin'
subsystem = 'ios-simulator'
kernel = 'xnu'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'

View file

@ -0,0 +1,16 @@
[binaries]
c = 'x86_64-w64-mingw32-gcc'
cpp = 'x86_64-w64-mingw32-g++'
ar = 'x86_64-w64-mingw32-ar'
strip = 'x86_64-w64-mingw32-strip'
windres = 'x86_64-w64-mingw32-windres'
exe_wrapper = 'wine'
[properties]
c_link_args = ['-static-libgcc']
[host_machine]
system = 'windows'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'

View file

@ -0,0 +1,24 @@
name: dav1d
base: core18
version: git
version-script: git describe HEAD --always
summary: AV1 decoder from VideoLAN
description: |
A small and fast AV1 decoder from the people who brought you VLC.
grade: stable
confinement: strict # use 'strict' once you have the right plugs and slots
apps:
dav1d:
command: usr/bin/dav1d
plugs: [ 'home' ]
parts:
dav1d:
plugin: meson
source: ../../
build-packages: [ 'nasm' ]
meson-parameters:
- --prefix=/usr
- --buildtype=release

View file

@ -0,0 +1,540 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2019, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include "src/arm/asm.S"
#include "util.S"
#include "cdef_tmpl.S"
// n1 = s0/d0
// w1 = d0/q0
// n2 = s4/d2
// w2 = d2/q1
.macro pad_top_bottom s1, s2, w, stride, n1, w1, n2, w2, align, ret
tst r7, #1 // CDEF_HAVE_LEFT
beq 2f
// CDEF_HAVE_LEFT
tst r7, #2 // CDEF_HAVE_RIGHT
beq 1f
// CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
ldrh r12, [\s1, #-2]
vldr \n1, [\s1]
vdup.16 d4, r12
ldrh r12, [\s1, #\w]
vmov.16 d4[1], r12
ldrh r12, [\s2, #-2]
vldr \n2, [\s2]
vmov.16 d4[2], r12
ldrh r12, [\s2, #\w]
vmovl.u8 q0, d0
vmov.16 d4[3], r12
vmovl.u8 q1, d2
vmovl.u8 q2, d4
vstr s8, [r0, #-4]
vst1.16 {\w1}, [r0, :\align]
vstr s9, [r0, #2*\w]
add r0, r0, #2*\stride
vstr s10, [r0, #-4]
vst1.16 {\w2}, [r0, :\align]
vstr s11, [r0, #2*\w]
.if \ret
pop {r4-r8,pc}
.else
add r0, r0, #2*\stride
b 3f
.endif
1:
// CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
ldrh r12, [\s1, #-2]
vldr \n1, [\s1]
vdup.16 d4, r12
ldrh r12, [\s2, #-2]
vldr \n2, [\s2]
vmovl.u8 q0, d0
vmov.16 d4[1], r12
vmovl.u8 q1, d2
vmovl.u8 q2, d4
vstr s8, [r0, #-4]
vst1.16 {\w1}, [r0, :\align]
vstr s12, [r0, #2*\w]
add r0, r0, #2*\stride
vstr s9, [r0, #-4]
vst1.16 {\w2}, [r0, :\align]
vstr s12, [r0, #2*\w]
.if \ret
pop {r4-r8,pc}
.else
add r0, r0, #2*\stride
b 3f
.endif
2:
// !CDEF_HAVE_LEFT
tst r7, #2 // CDEF_HAVE_RIGHT
beq 1f
// !CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
vldr \n1, [\s1]
ldrh r12, [\s1, #\w]
vldr \n2, [\s2]
vdup.16 d4, r12
ldrh r12, [\s2, #\w]
vmovl.u8 q0, d0
vmov.16 d4[1], r12
vmovl.u8 q1, d2
vmovl.u8 q2, d4
vstr s12, [r0, #-4]
vst1.16 {\w1}, [r0, :\align]
vstr s8, [r0, #2*\w]
add r0, r0, #2*\stride
vstr s12, [r0, #-4]
vst1.16 {\w2}, [r0, :\align]
vstr s9, [r0, #2*\w]
.if \ret
pop {r4-r8,pc}
.else
add r0, r0, #2*\stride
b 3f
.endif
1:
// !CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
vldr \n1, [\s1]
vldr \n2, [\s2]
vmovl.u8 q0, d0
vmovl.u8 q1, d2
vstr s12, [r0, #-4]
vst1.16 {\w1}, [r0, :\align]
vstr s12, [r0, #2*\w]
add r0, r0, #2*\stride
vstr s12, [r0, #-4]
vst1.16 {\w2}, [r0, :\align]
vstr s12, [r0, #2*\w]
.if \ret
pop {r4-r8,pc}
.else
add r0, r0, #2*\stride
.endif
3:
.endm
.macro load_n_incr dst, src, incr, w
.if \w == 4
vld1.32 {\dst\()[0]}, [\src, :32], \incr
.else
vld1.8 {\dst\()}, [\src, :64], \incr
.endif
.endm
// void dav1d_cdef_paddingX_8bpc_neon(uint16_t *tmp, const pixel *src,
// ptrdiff_t src_stride, const pixel (*left)[2],
// const pixel *const top,
// const pixel *const bottom, int h,
// enum CdefEdgeFlags edges);
// n1 = s0/d0
// w1 = d0/q0
// n2 = s4/d2
// w2 = d2/q1
.macro padding_func w, stride, n1, w1, n2, w2, align
function cdef_padding\w\()_8bpc_neon, export=1
push {r4-r8,lr}
ldrd r4, r5, [sp, #24]
ldrd r6, r7, [sp, #32]
cmp r7, #0xf // fully edged
beq cdef_padding\w\()_edged_8bpc_neon
vmov.i16 q3, #0x8000
tst r7, #4 // CDEF_HAVE_TOP
bne 1f
// !CDEF_HAVE_TOP
sub r12, r0, #2*(2*\stride+2)
vmov.i16 q2, #0x8000
vst1.16 {q2,q3}, [r12]!
.if \w == 8
vst1.16 {q2,q3}, [r12]!
.endif
b 3f
1:
// CDEF_HAVE_TOP
add r8, r4, r2
sub r0, r0, #2*(2*\stride)
pad_top_bottom r4, r8, \w, \stride, \n1, \w1, \n2, \w2, \align, 0
// Middle section
3:
tst r7, #1 // CDEF_HAVE_LEFT
beq 2f
// CDEF_HAVE_LEFT
tst r7, #2 // CDEF_HAVE_RIGHT
beq 1f
// CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
0:
vld1.16 {d2[]}, [r3, :16]!
ldrh r12, [r1, #\w]
load_n_incr d0, r1, r2, \w
subs r6, r6, #1
vmov.16 d2[1], r12
vmovl.u8 q0, d0
vmovl.u8 q1, d2
vstr s4, [r0, #-4]
vst1.16 {\w1}, [r0, :\align]
vstr s5, [r0, #2*\w]
add r0, r0, #2*\stride
bgt 0b
b 3f
1:
// CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
vld1.16 {d2[]}, [r3, :16]!
load_n_incr d0, r1, r2, \w
subs r6, r6, #1
vmovl.u8 q0, d0
vmovl.u8 q1, d2
vstr s4, [r0, #-4]
vst1.16 {\w1}, [r0, :\align]
vstr s12, [r0, #2*\w]
add r0, r0, #2*\stride
bgt 1b
b 3f
2:
tst r7, #2 // CDEF_HAVE_RIGHT
beq 1f
// !CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
0:
ldrh r12, [r1, #\w]
load_n_incr d0, r1, r2, \w
vdup.16 d2, r12
subs r6, r6, #1
vmovl.u8 q0, d0
vmovl.u8 q1, d2
vstr s12, [r0, #-4]
vst1.16 {\w1}, [r0, :\align]
vstr s4, [r0, #2*\w]
add r0, r0, #2*\stride
bgt 0b
b 3f
1:
// !CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
load_n_incr d0, r1, r2, \w
subs r6, r6, #1
vmovl.u8 q0, d0
vstr s12, [r0, #-4]
vst1.16 {\w1}, [r0, :\align]
vstr s12, [r0, #2*\w]
add r0, r0, #2*\stride
bgt 1b
3:
tst r7, #8 // CDEF_HAVE_BOTTOM
bne 1f
// !CDEF_HAVE_BOTTOM
sub r12, r0, #4
vmov.i16 q2, #0x8000
vst1.16 {q2,q3}, [r12]!
.if \w == 8
vst1.16 {q2,q3}, [r12]!
.endif
pop {r4-r8,pc}
1:
// CDEF_HAVE_BOTTOM
add r8, r5, r2
pad_top_bottom r5, r8, \w, \stride, \n1, \w1, \n2, \w2, \align, 1
endfunc
.endm
padding_func 8, 16, d0, q0, d2, q1, 128
padding_func 4, 8, s0, d0, s4, d2, 64
// void cdef_paddingX_edged_8bpc_neon(uint16_t *tmp, const pixel *src,
// ptrdiff_t src_stride, const pixel (*left)[2],
// const pixel *const top,
// const pixel *const bottom, int h,
// enum CdefEdgeFlags edges);
.macro padding_func_edged w, stride, reg, align
function cdef_padding\w\()_edged_8bpc_neon
sub r0, r0, #(2*\stride)
ldrh r12, [r4, #-2]
vldr \reg, [r4]
add r8, r4, r2
strh r12, [r0, #-2]
ldrh r12, [r4, #\w]
vstr \reg, [r0]
strh r12, [r0, #\w]
ldrh r12, [r8, #-2]
vldr \reg, [r8]
strh r12, [r0, #\stride-2]
ldrh r12, [r8, #\w]
vstr \reg, [r0, #\stride]
strh r12, [r0, #\stride+\w]
add r0, r0, #2*\stride
0:
ldrh r12, [r3], #2
vldr \reg, [r1]
str r12, [r0, #-2]
ldrh r12, [r1, #\w]
add r1, r1, r2
subs r6, r6, #1
vstr \reg, [r0]
str r12, [r0, #\w]
add r0, r0, #\stride
bgt 0b
ldrh r12, [r5, #-2]
vldr \reg, [r5]
add r8, r5, r2
strh r12, [r0, #-2]
ldrh r12, [r5, #\w]
vstr \reg, [r0]
strh r12, [r0, #\w]
ldrh r12, [r8, #-2]
vldr \reg, [r8]
strh r12, [r0, #\stride-2]
ldrh r12, [r8, #\w]
vstr \reg, [r0, #\stride]
strh r12, [r0, #\stride+\w]
pop {r4-r8,pc}
endfunc
.endm
padding_func_edged 8, 16, d0, 64
padding_func_edged 4, 8, s0, 32
tables
filter 8, 8
filter 4, 8
find_dir 8
.macro load_px_8 d11, d12, d21, d22, w
.if \w == 8
add r6, r2, r9 // x + off
sub r9, r2, r9 // x - off
vld1.8 {\d11}, [r6] // p0
add r6, r6, #16 // += stride
vld1.8 {\d21}, [r9] // p1
add r9, r9, #16 // += stride
vld1.8 {\d12}, [r6] // p0
vld1.8 {\d22}, [r9] // p1
.else
add r6, r2, r9 // x + off
sub r9, r2, r9 // x - off
vld1.32 {\d11[0]}, [r6] // p0
add r6, r6, #8 // += stride
vld1.32 {\d21[0]}, [r9] // p1
add r9, r9, #8 // += stride
vld1.32 {\d11[1]}, [r6] // p0
add r6, r6, #8 // += stride
vld1.32 {\d21[1]}, [r9] // p1
add r9, r9, #8 // += stride
vld1.32 {\d12[0]}, [r6] // p0
add r6, r6, #8 // += stride
vld1.32 {\d22[0]}, [r9] // p1
add r9, r9, #8 // += stride
vld1.32 {\d12[1]}, [r6] // p0
vld1.32 {\d22[1]}, [r9] // p1
.endif
.endm
.macro handle_pixel_8 s1, s2, thresh_vec, shift, tap, min
.if \min
vmin.u8 q3, q3, \s1
vmax.u8 q4, q4, \s1
vmin.u8 q3, q3, \s2
vmax.u8 q4, q4, \s2
.endif
vabd.u8 q8, q0, \s1 // abs(diff)
vabd.u8 q11, q0, \s2 // abs(diff)
vshl.u8 q9, q8, \shift // abs(diff) >> shift
vshl.u8 q12, q11, \shift // abs(diff) >> shift
vqsub.u8 q9, \thresh_vec, q9 // clip = imax(0, threshold - (abs(diff) >> shift))
vqsub.u8 q12, \thresh_vec, q12// clip = imax(0, threshold - (abs(diff) >> shift))
vcgt.u8 q10, q0, \s1 // px > p0
vcgt.u8 q13, q0, \s2 // px > p1
vmin.u8 q9, q9, q8 // imin(abs(diff), clip)
vmin.u8 q12, q12, q11 // imin(abs(diff), clip)
vneg.s8 q8, q9 // -imin()
vneg.s8 q11, q12 // -imin()
vbsl q10, q8, q9 // constrain() = imax(imin(diff, clip), -clip)
vdup.8 d18, \tap // taps[k]
vbsl q13, q11, q12 // constrain() = imax(imin(diff, clip), -clip)
vmlal.s8 q1, d20, d18 // sum += taps[k] * constrain()
vmlal.s8 q1, d26, d18 // sum += taps[k] * constrain()
vmlal.s8 q2, d21, d18 // sum += taps[k] * constrain()
vmlal.s8 q2, d27, d18 // sum += taps[k] * constrain()
.endm
// void cdef_filterX_edged_neon(pixel *dst, ptrdiff_t dst_stride,
// const uint16_t *tmp, int pri_strength,
// int sec_strength, int dir, int damping,
// int h, size_t edges);
.macro filter_func_8 w, pri, sec, min, suffix
function cdef_filter\w\suffix\()_edged_neon
.if \pri
movrel_local r8, pri_taps
and r9, r3, #1
add r8, r8, r9, lsl #1
.endif
movrel_local r9, directions\w
add r5, r9, r5, lsl #1
vmov.u8 d17, #7
vdup.8 d16, r6 // damping
vmov.8 d8[0], r3
vmov.8 d8[1], r4
vclz.i8 d8, d8 // clz(threshold)
vsub.i8 d8, d17, d8 // ulog2(threshold)
vqsub.u8 d8, d16, d8 // shift = imax(0, damping - ulog2(threshold))
vneg.s8 d8, d8 // -shift
.if \sec
vdup.8 q6, d8[1]
.endif
.if \pri
vdup.8 q5, d8[0]
.endif
1:
.if \w == 8
add r12, r2, #16
vld1.8 {d0}, [r2, :64] // px
vld1.8 {d1}, [r12, :64] // px
.else
add r12, r2, #8
vld1.32 {d0[0]}, [r2, :32] // px
add r9, r2, #2*8
vld1.32 {d0[1]}, [r12, :32] // px
add r12, r12, #2*8
vld1.32 {d1[0]}, [r9, :32] // px
vld1.32 {d1[1]}, [r12, :32] // px
.endif
vmov.u8 q1, #0 // sum
vmov.u8 q2, #0 // sum
.if \min
vmov.u16 q3, q0 // min
vmov.u16 q4, q0 // max
.endif
// Instead of loading sec_taps 2, 1 from memory, just set it
// to 2 initially and decrease for the second round.
// This is also used as loop counter.
mov lr, #2 // sec_taps[0]
2:
.if \pri
ldrsb r9, [r5] // off1
load_px_8 d28, d29, d30, d31, \w
.endif
.if \sec
add r5, r5, #4 // +2*2
ldrsb r9, [r5] // off2
.endif
.if \pri
ldrb r12, [r8] // *pri_taps
vdup.8 q7, r3 // threshold
handle_pixel_8 q14, q15, q7, q5, r12, \min
.endif
.if \sec
load_px_8 d28, d29, d30, d31, \w
add r5, r5, #8 // +2*4
ldrsb r9, [r5] // off3
vdup.8 q7, r4 // threshold
handle_pixel_8 q14, q15, q7, q6, lr, \min
load_px_8 d28, d29, d30, d31, \w
handle_pixel_8 q14, q15, q7, q6, lr, \min
sub r5, r5, #11 // r5 -= 2*(2+4); r5 += 1;
.else
add r5, r5, #1 // r5 += 1
.endif
subs lr, lr, #1 // sec_tap-- (value)
.if \pri
add r8, r8, #1 // pri_taps++ (pointer)
.endif
bne 2b
vshr.s16 q14, q1, #15 // -(sum < 0)
vshr.s16 q15, q2, #15 // -(sum < 0)
vadd.i16 q1, q1, q14 // sum - (sum < 0)
vadd.i16 q2, q2, q15 // sum - (sum < 0)
vrshr.s16 q1, q1, #4 // (8 + sum - (sum < 0)) >> 4
vrshr.s16 q2, q2, #4 // (8 + sum - (sum < 0)) >> 4
vaddw.u8 q1, q1, d0 // px + (8 + sum ...) >> 4
vaddw.u8 q2, q2, d1 // px + (8 + sum ...) >> 4
vqmovun.s16 d0, q1
vqmovun.s16 d1, q2
.if \min
vmin.u8 q0, q0, q4
vmax.u8 q0, q0, q3 // iclip(px + .., min, max)
.endif
.if \w == 8
vst1.8 {d0}, [r0, :64], r1
add r2, r2, #2*16 // tmp += 2*tmp_stride
subs r7, r7, #2 // h -= 2
vst1.8 {d1}, [r0, :64], r1
.else
vst1.32 {d0[0]}, [r0, :32], r1
add r2, r2, #4*8 // tmp += 4*tmp_stride
vst1.32 {d0[1]}, [r0, :32], r1
subs r7, r7, #4 // h -= 4
vst1.32 {d1[0]}, [r0, :32], r1
vst1.32 {d1[1]}, [r0, :32], r1
.endif
// Reset pri_taps and directions back to the original point
sub r5, r5, #2
.if \pri
sub r8, r8, #2
.endif
bgt 1b
vpop {q4-q7}
pop {r4-r9,pc}
endfunc
.endm
.macro filter_8 w
filter_func_8 \w, pri=1, sec=0, min=0, suffix=_pri
filter_func_8 \w, pri=0, sec=1, min=0, suffix=_sec
filter_func_8 \w, pri=1, sec=1, min=1, suffix=_pri_sec
.endm
filter_8 8
filter_8 4

View file

@ -0,0 +1,233 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2020, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include "src/arm/asm.S"
#include "util.S"
#include "cdef_tmpl.S"
// r1 = d0/q0
// r2 = d2/q1
.macro pad_top_bot_16 s1, s2, w, stride, r1, r2, align, ret
tst r7, #1 // CDEF_HAVE_LEFT
beq 2f
// CDEF_HAVE_LEFT
tst r7, #2 // CDEF_HAVE_RIGHT
beq 1f
// CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
vldr s8, [\s1, #-4]
vld1.16 {\r1}, [\s1, :\align]
vldr s9, [\s1, #2*\w]
vldr s10, [\s2, #-4]
vld1.16 {\r2}, [\s2, :\align]
vldr s11, [\s2, #2*\w]
vstr s8, [r0, #-4]
vst1.16 {\r1}, [r0, :\align]
vstr s9, [r0, #2*\w]
add r0, r0, #2*\stride
vstr s10, [r0, #-4]
vst1.16 {\r2}, [r0, :\align]
vstr s11, [r0, #2*\w]
.if \ret
pop {r4-r8,pc}
.else
add r0, r0, #2*\stride
b 3f
.endif
1:
// CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
vldr s8, [\s1, #-4]
vld1.16 {\r1}, [\s1, :\align]
vldr s9, [\s2, #-4]
vld1.16 {\r2}, [\s2, :\align]
vstr s8, [r0, #-4]
vst1.16 {\r1}, [r0, :\align]
vstr s12, [r0, #2*\w]
add r0, r0, #2*\stride
vstr s9, [r0, #-4]
vst1.16 {\r2}, [r0, :\align]
vstr s12, [r0, #2*\w]
.if \ret
pop {r4-r8,pc}
.else
add r0, r0, #2*\stride
b 3f
.endif
2:
// !CDEF_HAVE_LEFT
tst r7, #2 // CDEF_HAVE_RIGHT
beq 1f
// !CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
vld1.16 {\r1}, [\s1, :\align]
vldr s8, [\s1, #2*\w]
vld1.16 {\r2}, [\s2, :\align]
vldr s9, [\s2, #2*\w]
vstr s12, [r0, #-4]
vst1.16 {\r1}, [r0, :\align]
vstr s8, [r0, #2*\w]
add r0, r0, #2*\stride
vstr s12, [r0, #-4]
vst1.16 {\r2}, [r0, :\align]
vstr s9, [r0, #2*\w]
.if \ret
pop {r4-r8,pc}
.else
add r0, r0, #2*\stride
b 3f
.endif
1:
// !CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
vld1.16 {\r1}, [\s1, :\align]
vld1.16 {\r2}, [\s2, :\align]
vstr s12, [r0, #-4]
vst1.16 {\r1}, [r0, :\align]
vstr s12, [r0, #2*\w]
add r0, r0, #2*\stride
vstr s12, [r0, #-4]
vst1.16 {\r2}, [r0, :\align]
vstr s12, [r0, #2*\w]
.if \ret
pop {r4-r8,pc}
.else
add r0, r0, #2*\stride
.endif
3:
.endm
// void dav1d_cdef_paddingX_16bpc_neon(uint16_t *tmp, const pixel *src,
// ptrdiff_t src_stride, const pixel (*left)[2],
// const pixel *const top,
// const pixel *const bottom, int h,
// enum CdefEdgeFlags edges);
// r1 = d0/q0
// r2 = d2/q1
.macro padding_func_16 w, stride, r1, r2, align
function cdef_padding\w\()_16bpc_neon, export=1
push {r4-r8,lr}
ldrd r4, r5, [sp, #24]
ldrd r6, r7, [sp, #32]
vmov.i16 q3, #0x8000
tst r7, #4 // CDEF_HAVE_TOP
bne 1f
// !CDEF_HAVE_TOP
sub r12, r0, #2*(2*\stride+2)
vmov.i16 q2, #0x8000
vst1.16 {q2,q3}, [r12]!
.if \w == 8
vst1.16 {q2,q3}, [r12]!
.endif
b 3f
1:
// CDEF_HAVE_TOP
add r8, r4, r2
sub r0, r0, #2*(2*\stride)
pad_top_bot_16 r4, r8, \w, \stride, \r1, \r2, \align, 0
// Middle section
3:
tst r7, #1 // CDEF_HAVE_LEFT
beq 2f
// CDEF_HAVE_LEFT
tst r7, #2 // CDEF_HAVE_RIGHT
beq 1f
// CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
0:
vld1.32 {d2[]}, [r3, :32]!
vldr s5, [r1, #2*\w]
vld1.16 {\r1}, [r1, :\align], r2
subs r6, r6, #1
vstr s4, [r0, #-4]
vst1.16 {\r1}, [r0, :\align]
vstr s5, [r0, #2*\w]
add r0, r0, #2*\stride
bgt 0b
b 3f
1:
// CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
vld1.32 {d2[]}, [r3, :32]!
vld1.16 {\r1}, [r1, :\align], r2
subs r6, r6, #1
vstr s4, [r0, #-4]
vst1.16 {\r1}, [r0, :\align]
vstr s12, [r0, #2*\w]
add r0, r0, #2*\stride
bgt 1b
b 3f
2:
tst r7, #2 // CDEF_HAVE_RIGHT
beq 1f
// !CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
0:
vldr s4, [r1, #2*\w]
vld1.16 {\r1}, [r1, :\align], r2
subs r6, r6, #1
vstr s12, [r0, #-4]
vst1.16 {\r1}, [r0, :\align]
vstr s4, [r0, #2*\w]
add r0, r0, #2*\stride
bgt 0b
b 3f
1:
// !CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
vld1.16 {\r1}, [r1, :\align], r2
subs r6, r6, #1
vstr s12, [r0, #-4]
vst1.16 {\r1}, [r0, :\align]
vstr s12, [r0, #2*\w]
add r0, r0, #2*\stride
bgt 1b
3:
tst r7, #8 // CDEF_HAVE_BOTTOM
bne 1f
// !CDEF_HAVE_BOTTOM
sub r12, r0, #4
vmov.i16 q2, #0x8000
vst1.16 {q2,q3}, [r12]!
.if \w == 8
vst1.16 {q2,q3}, [r12]!
.endif
pop {r4-r8,pc}
1:
// CDEF_HAVE_BOTTOM
add r8, r5, r2
pad_top_bot_16 r5, r8, \w, \stride, \r1, \r2, \align, 1
endfunc
.endm
padding_func_16 8, 16, q0, q1, 128
padding_func_16 4, 8, d0, d2, 64
tables
filter 8, 16
filter 4, 16
find_dir 16

View file

@ -0,0 +1,515 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2020, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include "src/arm/asm.S"
#include "util.S"
.macro dir_table w, stride
const directions\w
.byte -1 * \stride + 1, -2 * \stride + 2
.byte 0 * \stride + 1, -1 * \stride + 2
.byte 0 * \stride + 1, 0 * \stride + 2
.byte 0 * \stride + 1, 1 * \stride + 2
.byte 1 * \stride + 1, 2 * \stride + 2
.byte 1 * \stride + 0, 2 * \stride + 1
.byte 1 * \stride + 0, 2 * \stride + 0
.byte 1 * \stride + 0, 2 * \stride - 1
// Repeated, to avoid & 7
.byte -1 * \stride + 1, -2 * \stride + 2
.byte 0 * \stride + 1, -1 * \stride + 2
.byte 0 * \stride + 1, 0 * \stride + 2
.byte 0 * \stride + 1, 1 * \stride + 2
.byte 1 * \stride + 1, 2 * \stride + 2
.byte 1 * \stride + 0, 2 * \stride + 1
endconst
.endm
.macro tables
dir_table 8, 16
dir_table 4, 8
const pri_taps
.byte 4, 2, 3, 3
endconst
.endm
.macro load_px d11, d12, d21, d22, w
.if \w == 8
add r6, r2, r9, lsl #1 // x + off
sub r9, r2, r9, lsl #1 // x - off
vld1.16 {\d11,\d12}, [r6] // p0
vld1.16 {\d21,\d22}, [r9] // p1
.else
add r6, r2, r9, lsl #1 // x + off
sub r9, r2, r9, lsl #1 // x - off
vld1.16 {\d11}, [r6] // p0
add r6, r6, #2*8 // += stride
vld1.16 {\d21}, [r9] // p1
add r9, r9, #2*8 // += stride
vld1.16 {\d12}, [r6] // p0
vld1.16 {\d22}, [r9] // p1
.endif
.endm
.macro handle_pixel s1, s2, thresh_vec, shift, tap, min
.if \min
vmin.u16 q2, q2, \s1
vmax.s16 q3, q3, \s1
vmin.u16 q2, q2, \s2
vmax.s16 q3, q3, \s2
.endif
vabd.u16 q8, q0, \s1 // abs(diff)
vabd.u16 q11, q0, \s2 // abs(diff)
vshl.u16 q9, q8, \shift // abs(diff) >> shift
vshl.u16 q12, q11, \shift // abs(diff) >> shift
vqsub.u16 q9, \thresh_vec, q9 // clip = imax(0, threshold - (abs(diff) >> shift))
vqsub.u16 q12, \thresh_vec, q12// clip = imax(0, threshold - (abs(diff) >> shift))
vsub.i16 q10, \s1, q0 // diff = p0 - px
vsub.i16 q13, \s2, q0 // diff = p1 - px
vneg.s16 q8, q9 // -clip
vneg.s16 q11, q12 // -clip
vmin.s16 q10, q10, q9 // imin(diff, clip)
vmin.s16 q13, q13, q12 // imin(diff, clip)
vdup.16 q9, \tap // taps[k]
vmax.s16 q10, q10, q8 // constrain() = imax(imin(diff, clip), -clip)
vmax.s16 q13, q13, q11 // constrain() = imax(imin(diff, clip), -clip)
vmla.i16 q1, q10, q9 // sum += taps[k] * constrain()
vmla.i16 q1, q13, q9 // sum += taps[k] * constrain()
.endm
// void dav1d_cdef_filterX_Ybpc_neon(pixel *dst, ptrdiff_t dst_stride,
// const uint16_t *tmp, int pri_strength,
// int sec_strength, int dir, int damping,
// int h, size_t edges);
.macro filter_func w, bpc, pri, sec, min, suffix
function cdef_filter\w\suffix\()_\bpc\()bpc_neon
.if \bpc == 8
cmp r8, #0xf
beq cdef_filter\w\suffix\()_edged_neon
.endif
.if \pri
.if \bpc == 16
clz r9, r9
sub r9, r9, #24 // -bitdepth_min_8
neg r9, r9 // bitdepth_min_8
.endif
movrel_local r8, pri_taps
.if \bpc == 16
lsr r9, r3, r9 // pri_strength >> bitdepth_min_8
and r9, r9, #1 // (pri_strength >> bitdepth_min_8) & 1
.else
and r9, r3, #1
.endif
add r8, r8, r9, lsl #1
.endif
movrel_local r9, directions\w
add r5, r9, r5, lsl #1
vmov.u16 d17, #15
vdup.16 d16, r6 // damping
.if \pri
vdup.16 q5, r3 // threshold
.endif
.if \sec
vdup.16 q7, r4 // threshold
.endif
vmov.16 d8[0], r3
vmov.16 d8[1], r4
vclz.i16 d8, d8 // clz(threshold)
vsub.i16 d8, d17, d8 // ulog2(threshold)
vqsub.u16 d8, d16, d8 // shift = imax(0, damping - ulog2(threshold))
vneg.s16 d8, d8 // -shift
.if \sec
vdup.16 q6, d8[1]
.endif
.if \pri
vdup.16 q4, d8[0]
.endif
1:
.if \w == 8
vld1.16 {q0}, [r2, :128] // px
.else
add r12, r2, #2*8
vld1.16 {d0}, [r2, :64] // px
vld1.16 {d1}, [r12, :64] // px
.endif
vmov.u16 q1, #0 // sum
.if \min
vmov.u16 q2, q0 // min
vmov.u16 q3, q0 // max
.endif
// Instead of loading sec_taps 2, 1 from memory, just set it
// to 2 initially and decrease for the second round.
// This is also used as loop counter.
mov lr, #2 // sec_taps[0]
2:
.if \pri
ldrsb r9, [r5] // off1
load_px d28, d29, d30, d31, \w
.endif
.if \sec
add r5, r5, #4 // +2*2
ldrsb r9, [r5] // off2
.endif
.if \pri
ldrb r12, [r8] // *pri_taps
handle_pixel q14, q15, q5, q4, r12, \min
.endif
.if \sec
load_px d28, d29, d30, d31, \w
add r5, r5, #8 // +2*4
ldrsb r9, [r5] // off3
handle_pixel q14, q15, q7, q6, lr, \min
load_px d28, d29, d30, d31, \w
handle_pixel q14, q15, q7, q6, lr, \min
sub r5, r5, #11 // r5 -= 2*(2+4); r5 += 1;
.else
add r5, r5, #1 // r5 += 1
.endif
subs lr, lr, #1 // sec_tap-- (value)
.if \pri
add r8, r8, #1 // pri_taps++ (pointer)
.endif
bne 2b
vshr.s16 q14, q1, #15 // -(sum < 0)
vadd.i16 q1, q1, q14 // sum - (sum < 0)
vrshr.s16 q1, q1, #4 // (8 + sum - (sum < 0)) >> 4
vadd.i16 q0, q0, q1 // px + (8 + sum ...) >> 4
.if \min
vmin.s16 q0, q0, q3
vmax.s16 q0, q0, q2 // iclip(px + .., min, max)
.endif
.if \bpc == 8
vmovn.u16 d0, q0
.endif
.if \w == 8
add r2, r2, #2*16 // tmp += tmp_stride
subs r7, r7, #1 // h--
.if \bpc == 8
vst1.8 {d0}, [r0, :64], r1
.else
vst1.16 {q0}, [r0, :128], r1
.endif
.else
.if \bpc == 8
vst1.32 {d0[0]}, [r0, :32], r1
.else
vst1.16 {d0}, [r0, :64], r1
.endif
add r2, r2, #2*16 // tmp += 2*tmp_stride
subs r7, r7, #2 // h -= 2
.if \bpc == 8
vst1.32 {d0[1]}, [r0, :32], r1
.else
vst1.16 {d1}, [r0, :64], r1
.endif
.endif
// Reset pri_taps and directions back to the original point
sub r5, r5, #2
.if \pri
sub r8, r8, #2
.endif
bgt 1b
vpop {q4-q7}
pop {r4-r9,pc}
endfunc
.endm
.macro filter w, bpc
filter_func \w, \bpc, pri=1, sec=0, min=0, suffix=_pri
filter_func \w, \bpc, pri=0, sec=1, min=0, suffix=_sec
filter_func \w, \bpc, pri=1, sec=1, min=1, suffix=_pri_sec
function cdef_filter\w\()_\bpc\()bpc_neon, export=1
push {r4-r9,lr}
vpush {q4-q7}
ldrd r4, r5, [sp, #92]
ldrd r6, r7, [sp, #100]
.if \bpc == 16
ldrd r8, r9, [sp, #108]
.else
ldr r8, [sp, #108]
.endif
cmp r3, #0 // pri_strength
bne 1f
b cdef_filter\w\()_sec_\bpc\()bpc_neon // only sec
1:
cmp r4, #0 // sec_strength
bne 1f
b cdef_filter\w\()_pri_\bpc\()bpc_neon // only pri
1:
b cdef_filter\w\()_pri_sec_\bpc\()bpc_neon // both pri and sec
endfunc
.endm
const div_table, align=4
.short 840, 420, 280, 210, 168, 140, 120, 105
endconst
const alt_fact, align=4
.short 420, 210, 140, 105, 105, 105, 105, 105, 140, 210, 420, 0
endconst
.macro cost_alt dest, s1, s2, s3, s4, s5, s6
vmull.s16 q1, \s1, \s1 // sum_alt[n]*sum_alt[n]
vmull.s16 q2, \s2, \s2
vmull.s16 q3, \s3, \s3
vmull.s16 q5, \s4, \s4 // sum_alt[n]*sum_alt[n]
vmull.s16 q12, \s5, \s5
vmull.s16 q6, \s6, \s6 // q6 overlaps the first \s1-\s2 here
vmul.i32 q1, q1, q13 // sum_alt[n]^2*fact
vmla.i32 q1, q2, q14
vmla.i32 q1, q3, q15
vmul.i32 q5, q5, q13 // sum_alt[n]^2*fact
vmla.i32 q5, q12, q14
vmla.i32 q5, q6, q15
vadd.i32 d2, d2, d3
vadd.i32 d3, d10, d11
vpadd.i32 \dest, d2, d3 // *cost_ptr
.endm
.macro find_best s1, s2, s3
.ifnb \s2
vmov.32 lr, \s2
.endif
cmp r12, r1 // cost[n] > best_cost
itt gt
movgt r0, r3 // best_dir = n
movgt r1, r12 // best_cost = cost[n]
.ifnb \s2
add r3, r3, #1 // n++
cmp lr, r1 // cost[n] > best_cost
vmov.32 r12, \s3
itt gt
movgt r0, r3 // best_dir = n
movgt r1, lr // best_cost = cost[n]
add r3, r3, #1 // n++
.endif
.endm
// int dav1d_cdef_find_dir_Xbpc_neon(const pixel *img, const ptrdiff_t stride,
// unsigned *const var)
.macro find_dir bpc
function cdef_find_dir_\bpc\()bpc_neon, export=1
push {lr}
vpush {q4-q7}
.if \bpc == 16
clz r3, r3 // clz(bitdepth_max)
sub lr, r3, #24 // -bitdepth_min_8
.endif
sub sp, sp, #32 // cost
mov r3, #8
vmov.u16 q1, #0 // q0-q1 sum_diag[0]
vmov.u16 q3, #0 // q2-q3 sum_diag[1]
vmov.u16 q5, #0 // q4-q5 sum_hv[0-1]
vmov.u16 q8, #0 // q6,d16 sum_alt[0]
// q7,d17 sum_alt[1]
vmov.u16 q9, #0 // q9,d22 sum_alt[2]
vmov.u16 q11, #0
vmov.u16 q10, #0 // q10,d23 sum_alt[3]
.irpc i, 01234567
.if \bpc == 8
vld1.8 {d30}, [r0, :64], r1
vmov.u8 d31, #128
vsubl.u8 q15, d30, d31 // img[x] - 128
.else
vld1.16 {q15}, [r0, :128], r1
vdup.16 q14, lr // -bitdepth_min_8
vshl.u16 q15, q15, q14
vmov.u16 q14, #128
vsub.i16 q15, q15, q14 // img[x] - 128
.endif
vmov.u16 q14, #0
.if \i == 0
vmov q0, q15 // sum_diag[0]
.else
vext.8 q12, q14, q15, #(16-2*\i)
vext.8 q13, q15, q14, #(16-2*\i)
vadd.i16 q0, q0, q12 // sum_diag[0]
vadd.i16 q1, q1, q13 // sum_diag[0]
.endif
vrev64.16 q13, q15
vswp d26, d27 // [-x]
.if \i == 0
vmov q2, q13 // sum_diag[1]
.else
vext.8 q12, q14, q13, #(16-2*\i)
vext.8 q13, q13, q14, #(16-2*\i)
vadd.i16 q2, q2, q12 // sum_diag[1]
vadd.i16 q3, q3, q13 // sum_diag[1]
.endif
vpadd.u16 d26, d30, d31 // [(x >> 1)]
vmov.u16 d27, #0
vpadd.u16 d24, d26, d28
vpadd.u16 d24, d24, d28 // [y]
vmov.u16 r12, d24[0]
vadd.i16 q5, q5, q15 // sum_hv[1]
.if \i < 4
vmov.16 d8[\i], r12 // sum_hv[0]
.else
vmov.16 d9[\i-4], r12 // sum_hv[0]
.endif
.if \i == 0
vmov.u16 q6, q13 // sum_alt[0]
.else
vext.8 q12, q14, q13, #(16-2*\i)
vext.8 q14, q13, q14, #(16-2*\i)
vadd.i16 q6, q6, q12 // sum_alt[0]
vadd.i16 d16, d16, d28 // sum_alt[0]
.endif
vrev64.16 d26, d26 // [-(x >> 1)]
vmov.u16 q14, #0
.if \i == 0
vmov q7, q13 // sum_alt[1]
.else
vext.8 q12, q14, q13, #(16-2*\i)
vext.8 q13, q13, q14, #(16-2*\i)
vadd.i16 q7, q7, q12 // sum_alt[1]
vadd.i16 d17, d17, d26 // sum_alt[1]
.endif
.if \i < 6
vext.8 q12, q14, q15, #(16-2*(3-(\i/2)))
vext.8 q13, q15, q14, #(16-2*(3-(\i/2)))
vadd.i16 q9, q9, q12 // sum_alt[2]
vadd.i16 d22, d22, d26 // sum_alt[2]
.else
vadd.i16 q9, q9, q15 // sum_alt[2]
.endif
.if \i == 0
vmov q10, q15 // sum_alt[3]
.elseif \i == 1
vadd.i16 q10, q10, q15 // sum_alt[3]
.else
vext.8 q12, q14, q15, #(16-2*(\i/2))
vext.8 q13, q15, q14, #(16-2*(\i/2))
vadd.i16 q10, q10, q12 // sum_alt[3]
vadd.i16 d23, d23, d26 // sum_alt[3]
.endif
.endr
vmov.u32 q15, #105
vmull.s16 q12, d8, d8 // sum_hv[0]*sum_hv[0]
vmlal.s16 q12, d9, d9
vmull.s16 q13, d10, d10 // sum_hv[1]*sum_hv[1]
vmlal.s16 q13, d11, d11
vadd.s32 d8, d24, d25
vadd.s32 d9, d26, d27
vpadd.s32 d8, d8, d9 // cost[2,6] (s16, s17)
vmul.i32 d8, d8, d30 // cost[2,6] *= 105
vrev64.16 q1, q1
vrev64.16 q3, q3
vext.8 q1, q1, q1, #10 // sum_diag[0][14-n]
vext.8 q3, q3, q3, #10 // sum_diag[1][14-n]
vstr s16, [sp, #2*4] // cost[2]
vstr s17, [sp, #6*4] // cost[6]
movrel_local r12, div_table
vld1.16 {q14}, [r12, :128]
vmull.s16 q5, d0, d0 // sum_diag[0]*sum_diag[0]
vmull.s16 q12, d1, d1
vmlal.s16 q5, d2, d2
vmlal.s16 q12, d3, d3
vmull.s16 q0, d4, d4 // sum_diag[1]*sum_diag[1]
vmull.s16 q1, d5, d5
vmlal.s16 q0, d6, d6
vmlal.s16 q1, d7, d7
vmovl.u16 q13, d28 // div_table
vmovl.u16 q14, d29
vmul.i32 q5, q5, q13 // cost[0]
vmla.i32 q5, q12, q14
vmul.i32 q0, q0, q13 // cost[4]
vmla.i32 q0, q1, q14
vadd.i32 d10, d10, d11
vadd.i32 d0, d0, d1
vpadd.i32 d0, d10, d0 // cost[0,4] = s0,s1
movrel_local r12, alt_fact
vld1.16 {d29, d30, d31}, [r12, :64] // div_table[2*m+1] + 105
vstr s0, [sp, #0*4] // cost[0]
vstr s1, [sp, #4*4] // cost[4]
vmovl.u16 q13, d29 // div_table[2*m+1] + 105
vmovl.u16 q14, d30
vmovl.u16 q15, d31
cost_alt d14, d12, d13, d16, d14, d15, d17 // cost[1], cost[3]
cost_alt d15, d18, d19, d22, d20, d21, d23 // cost[5], cost[7]
vstr s28, [sp, #1*4] // cost[1]
vstr s29, [sp, #3*4] // cost[3]
mov r0, #0 // best_dir
vmov.32 r1, d0[0] // best_cost
mov r3, #1 // n
vstr s30, [sp, #5*4] // cost[5]
vstr s31, [sp, #7*4] // cost[7]
vmov.32 r12, d14[0]
find_best d14[0], d8[0], d14[1]
find_best d14[1], d0[1], d15[0]
find_best d15[0], d8[1], d15[1]
find_best d15[1]
eor r3, r0, #4 // best_dir ^4
ldr r12, [sp, r3, lsl #2]
sub r1, r1, r12 // best_cost - cost[best_dir ^ 4]
lsr r1, r1, #10
str r1, [r2] // *var
add sp, sp, #32
vpop {q4-q7}
pop {pc}
endfunc
.endm

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,868 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2019, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include "src/arm/asm.S"
#include "util.S"
.macro loop_filter wd
function lpf_8_wd\wd\()_neon
vabd.u8 d0, d22, d23 // abs(p1 - p0)
vabd.u8 d1, d25, d24 // abs(q1 - q0)
vabd.u8 d2, d23, d24 // abs(p0 - q0)
vabd.u8 d3, d22, d25 // abs(p1 - q1)
.if \wd >= 6
vabd.u8 d4, d21, d22 // abs(p2 - p1)
vabd.u8 d5, d26, d25 // abs(q2 - q1)
.endif
.if \wd >= 8
vabd.u8 d6, d20, d21 // abs(p3 - p2)
vabd.u8 d7, d27, d26 // abs(q3 - q3)
.endif
.if \wd >= 6
vmax.u8 d4, d4, d5
.endif
vqadd.u8 d2, d2, d2 // abs(p0 - q0) * 2
.if \wd >= 8
vmax.u8 d6, d6, d7
.endif
vshr.u8 d3, d3, #1
.if \wd >= 8
vmax.u8 d4, d4, d6
.endif
.if \wd >= 6
vand d4, d4, d14
.endif
vmax.u8 d0, d0, d1 // max(abs(p1 - p0), abs(q1 - q0))
vqadd.u8 d2, d2, d3 // abs(p0 - q0) * 2 + abs(p1 - q1) >> 1
.if \wd >= 6
vmax.u8 d4, d0, d4
vcge.u8 d1, d11, d4 // max(abs(p1 - p0), abs(q1 - q0), abs(), abs(), ...) <= I
.else
vcge.u8 d1, d11, d0 // max(abs(p1 - p0), abs(q1 - q0)) <= I
.endif
vcge.u8 d2, d10, d2 // abs(p0 - q0) * 2 + abs(p1 - q1) >> 1 <= E
vand d1, d1, d2 // fm
vand d1, d1, d13 // fm && wd >= 4
.if \wd >= 6
vand d14, d14, d1 // fm && wd > 4
.endif
.if \wd >= 16
vand d15, d15, d1 // fm && wd == 16
.endif
vmov r10, r11, d1
orrs r10, r10, r11
beq 9f // if (!fm || wd < 4) return;
.if \wd >= 6
vmov.i8 d10, #1
vabd.u8 d2, d21, d23 // abs(p2 - p0)
vabd.u8 d3, d22, d23 // abs(p1 - p0)
vabd.u8 d4, d25, d24 // abs(q1 - q0)
vabd.u8 d5, d26, d24 // abs(q2 - q0)
.if \wd >= 8
vabd.u8 d6, d20, d23 // abs(p3 - p0)
vabd.u8 d7, d27, d24 // abs(q3 - q0)
.endif
vmax.u8 d2, d2, d3
vmax.u8 d4, d4, d5
.if \wd >= 8
vmax.u8 d6, d6, d7
.endif
vmax.u8 d2, d2, d4
.if \wd >= 8
vmax.u8 d2, d2, d6
.endif
.if \wd == 16
vabd.u8 d3, d17, d23 // abs(p6 - p0)
vabd.u8 d4, d18, d23 // abs(p5 - p0)
vabd.u8 d5, d19, d23 // abs(p4 - p0)
.endif
vcge.u8 d2, d10, d2 // flat8in
.if \wd == 16
vabd.u8 d6, d28, d24 // abs(q4 - q0)
vabd.u8 d7, d29, d24 // abs(q5 - q0)
vabd.u8 d8, d30, d24 // abs(q6 - q0)
.endif
vand d14, d2, d14 // flat8in && fm && wd > 4
vbic d1, d1, d14 // fm && wd >= 4 && !flat8in
.if \wd == 16
vmax.u8 d3, d3, d4
vmax.u8 d5, d5, d6
.endif
vmov r10, r11, d1
.if \wd == 16
vmax.u8 d7, d7, d8
vmax.u8 d3, d3, d5
vmax.u8 d3, d3, d7
vcge.u8 d3, d10, d3 // flat8out
.endif
orrs r10, r10, r11
.if \wd == 16
vand d15, d15, d3 // flat8out && fm && wd == 16
vand d15, d15, d14 // flat8out && flat8in && fm && wd == 16
vbic d14, d14, d15 // flat8in && fm && wd >= 4 && !flat8out
.endif
beq 1f // skip wd == 4 case
.endif
vsubl.u8 q1, d22, d25 // p1 - q1
vcgt.u8 d0, d0, d12 // hev
vqmovn.s16 d2, q1
vand d4, d2, d0 // if (hev) iclip_diff(p1 - q1)
vbic d0, d1, d0 // (fm && wd >= 4 && !hev)
vsubl.u8 q1, d24, d23
vmov.i16 q3, #3
vmul.i16 q1, q1, q3
vmov.i8 d6, #4
vaddw.s8 q1, q1, d4
vmov.i8 d7, #3
vqmovn.s16 d2, q1 // f
vqadd.s8 d4, d6, d2 // imin(f + 4, 127)
vqadd.s8 d5, d7, d2 // imin(f + 3, 127)
vshr.s8 d4, d4, #3 // f1
vshr.s8 d5, d5, #3 // f2
vmovl.u8 q1, d23 // p0
vmovl.u8 q3, d24 // q0
vaddw.s8 q1, q1, d5
vsubw.s8 q3, q3, d4
vrshr.s8 d4, d4, #1 // (f1 + 1) >> 1
vqmovun.s16 d2, q1 // out p0
vqmovun.s16 d6, q3 // out q0
vbit d23, d2, d1 // if (fm && wd >= 4)
vmovl.u8 q1, d22 // p1
vbit d24, d6, d1 // if (fm && wd >= 4)
vmovl.u8 q3, d25 // q1
vaddw.s8 q1, q1, d4
vsubw.s8 q3, q3, d4
vqmovun.s16 d2, q1 // out p1
vqmovun.s16 d6, q3 // out q1
vbit d22, d2, d0 // if (fm && wd >= 4 && !hev)
vbit d25, d6, d0 // if (fm && wd >= 4 && !hev)
1:
.if \wd == 6
vmov r10, r11, d14
orrs r10, r10, r11
beq 2f // skip if there's no flat8in
vaddl.u8 q0, d21, d21 // p2 * 2
vaddl.u8 q1, d21, d22 // p2 + p1
vaddl.u8 q2, d22, d23 // p1 + p0
vaddl.u8 q3, d23, d24 // p0 + q0
vadd.i16 q4, q0, q1
vadd.i16 q5, q2, q3
vaddl.u8 q6, d24, d25 // q0 + q1
vadd.i16 q4, q4, q5
vsub.i16 q6, q6, q0
vaddl.u8 q5, d25, d26 // q1 + q2
vrshrn.i16 d0, q4, #3 // out p1
vadd.i16 q4, q4, q6
vsub.i16 q5, q5, q1
vaddl.u8 q6, d26, d26 // q2 + q2
vrshrn.i16 d1, q4, #3 // out p0
vadd.i16 q4, q4, q5
vsub.i16 q6, q6, q2
vrshrn.i16 d2, q4, #3 // out q0
vbit d22, d0, d14 // p1 if (flat8in)
vadd.i16 q4, q4, q6
vbit d23, d1, d14 // p0 if (flat8in)
vrshrn.i16 d3, q4, #3 // out q1
vbit d24, d2, d14 // q0 if (flat8in)
vbit d25, d3, d14 // q1 if (flat8in)
.elseif \wd >= 8
vmov r10, r11, d14
orrs r10, r10, r11
.if \wd == 8
beq 8f // skip if there's no flat8in
.else
beq 2f // skip if there's no flat8in
.endif
vaddl.u8 q0, d20, d21 // p3 + p2
vaddl.u8 q1, d22, d25 // p1 + q1
vaddl.u8 q2, d20, d22 // p3 + p1
vaddl.u8 q3, d23, d26 // p0 + q2
vadd.i16 q4, q0, q0 // 2 * (p3 + p2)
vaddw.u8 q4, q4, d23 // + p0
vaddw.u8 q4, q4, d24 // + q0
vadd.i16 q4, q4, q2 // + p3 + p1
vsub.i16 q1, q1, q0 // p1 + q1 - p3 - p2
vsub.i16 q3, q3, q2 // p0 + q2 - p3 - p1
vrshrn.i16 d10, q4, #3 // out p2
vadd.i16 q4, q4, q1
vaddl.u8 q0, d20, d23 // p3 + p0
vaddl.u8 q1, d24, d27 // q0 + q3
vrshrn.i16 d11, q4, #3 // out p1
vadd.i16 q4, q4, q3
vsub.i16 q1, q1, q0 // q0 + q3 - p3 - p0
vaddl.u8 q2, d21, d24 // p2 + q0
vaddl.u8 q3, d25, d27 // q1 + q3
vrshrn.i16 d12, q4, #3 // out p0
vadd.i16 q4, q4, q1
vsub.i16 q3, q3, q2 // q1 + q3 - p2 - q0
vaddl.u8 q0, d22, d25 // p1 + q1
vaddl.u8 q1, d26, d27 // q2 + q3
vrshrn.i16 d13, q4, #3 // out q0
vadd.i16 q4, q4, q3
vsub.i16 q1, q1, q0 // q2 + q3 - p1 - q1
vrshrn.i16 d0, q4, #3 // out q1
vadd.i16 q4, q4, q1
vbit d21, d10, d14
vbit d22, d11, d14
vbit d23, d12, d14
vrshrn.i16 d1, q4, #3 // out q2
vbit d24, d13, d14
vbit d25, d0, d14
vbit d26, d1, d14
.endif
2:
.if \wd == 16
vmov r10, r11, d15
orrs r10, r10, r11
bne 1f // check if flat8out is needed
vmov r10, r11, d14
orrs r10, r10, r11
beq 8f // if there was no flat8in, just write the inner 4 pixels
b 7f // if flat8in was used, write the inner 6 pixels
1:
vaddl.u8 q1, d17, d17 // p6 + p6
vaddl.u8 q2, d17, d18 // p6 + p5
vaddl.u8 q3, d17, d19 // p6 + p4
vaddl.u8 q4, d17, d20 // p6 + p3
vadd.i16 q6, q1, q2
vadd.i16 q5, q3, q4
vaddl.u8 q3, d17, d21 // p6 + p2
vadd.i16 q6, q6, q5
vaddl.u8 q4, d17, d22 // p6 + p1
vaddl.u8 q5, d18, d23 // p5 + p0
vadd.i16 q3, q3, q4
vaddl.u8 q4, d19, d24 // p4 + q0
vadd.i16 q6, q6, q3
vadd.i16 q5, q5, q4
vaddl.u8 q3, d20, d25 // p3 + q1
vadd.i16 q6, q6, q5
vsub.i16 q3, q3, q1
vaddl.u8 q1, d21, d26 // p2 + q2
vrshrn.i16 d0, q6, #4 // out p5
vadd.i16 q6, q6, q3 // - (p6 + p6) + (p3 + q1)
vsub.i16 q1, q1, q2
vaddl.u8 q2, d22, d27 // p1 + q3
vaddl.u8 q3, d17, d19 // p6 + p4
vrshrn.i16 d1, q6, #4 // out p4
vadd.i16 q6, q6, q1 // - (p6 + p5) + (p2 + q2)
vsub.i16 q2, q2, q3
vaddl.u8 q3, d23, d28 // p0 + q4
vaddl.u8 q4, d17, d20 // p6 + p3
vrshrn.i16 d2, q6, #4 // out p3
vadd.i16 q6, q6, q2 // - (p6 + p4) + (p1 + q3)
vsub.i16 q3, q3, q4
vaddl.u8 q4, d24, d29 // q0 + q5
vaddl.u8 q2, d17, d21 // p6 + p2
vrshrn.i16 d3, q6, #4 // out p2
vadd.i16 q6, q6, q3 // - (p6 + p3) + (p0 + q4)
vsub.i16 q4, q4, q2
vaddl.u8 q3, d25, d30 // q1 + q6
vaddl.u8 q5, d17, d22 // p6 + p1
vrshrn.i16 d4, q6, #4 // out p1
vadd.i16 q6, q6, q4 // - (p6 + p2) + (q0 + q5)
vsub.i16 q3, q3, q5
vaddl.u8 q4, d26, d30 // q2 + q6
vbif d0, d18, d15 // out p5
vaddl.u8 q5, d18, d23 // p5 + p0
vrshrn.i16 d5, q6, #4 // out p0
vadd.i16 q6, q6, q3 // - (p6 + p1) + (q1 + q6)
vsub.i16 q4, q4, q5
vaddl.u8 q5, d27, d30 // q3 + q6
vbif d1, d19, d15 // out p4
vaddl.u8 q9, d19, d24 // p4 + q0
vrshrn.i16 d6, q6, #4 // out q0
vadd.i16 q6, q6, q4 // - (p5 + p0) + (q2 + q6)
vsub.i16 q5, q5, q9
vaddl.u8 q4, d28, d30 // q4 + q6
vbif d2, d20, d15 // out p3
vaddl.u8 q9, d20, d25 // p3 + q1
vrshrn.i16 d7, q6, #4 // out q1
vadd.i16 q6, q6, q5 // - (p4 + q0) + (q3 + q6)
vsub.i16 q9, q4, q9
vaddl.u8 q5, d29, d30 // q5 + q6
vbif d3, d21, d15 // out p2
vaddl.u8 q10, d21, d26 // p2 + q2
vrshrn.i16 d8, q6, #4 // out q2
vadd.i16 q6, q6, q9 // - (p3 + q1) + (q4 + q6)
vsub.i16 q5, q5, q10
vaddl.u8 q9, d30, d30 // q6 + q6
vbif d4, d22, d15 // out p1
vaddl.u8 q10, d22, d27 // p1 + q3
vrshrn.i16 d9, q6, #4 // out q3
vadd.i16 q6, q6, q5 // - (p2 + q2) + (q5 + q6)
vsub.i16 q9, q9, q10
vbif d5, d23, d15 // out p0
vrshrn.i16 d10, q6, #4 // out q4
vadd.i16 q6, q6, q9 // - (p1 + q3) + (q6 + q6)
vrshrn.i16 d11, q6, #4 // out q5
vbif d6, d24, d15 // out q0
vbif d7, d25, d15 // out q1
vbif d8, d26, d15 // out q2
vbif d9, d27, d15 // out q3
vbif d10, d28, d15 // out q4
vbif d11, d29, d15 // out q5
.endif
bx lr
.if \wd == 16
7:
// Return to a shorter epilogue, writing only the inner 6 pixels
bx r8
.endif
.if \wd >= 8
8:
// Return to a shorter epilogue, writing only the inner 4 pixels
bx r9
.endif
9:
// Return directly without writing back any pixels
bx r12
endfunc
.endm
loop_filter 16
loop_filter 8
loop_filter 6
loop_filter 4
.macro lpf_8_wd16
adr r8, 7f + CONFIG_THUMB
adr r9, 8f + CONFIG_THUMB
bl lpf_8_wd16_neon
.endm
.macro lpf_8_wd8
adr r9, 8f + CONFIG_THUMB
bl lpf_8_wd8_neon
.endm
.macro lpf_8_wd6
bl lpf_8_wd6_neon
.endm
.macro lpf_8_wd4
bl lpf_8_wd4_neon
.endm
function lpf_v_4_8_neon
mov r12, lr
sub r10, r0, r1, lsl #1
vld1.8 {d22}, [r10, :64], r1 // p1
vld1.8 {d24}, [r0, :64], r1 // q0
vld1.8 {d23}, [r10, :64], r1 // p0
vld1.8 {d25}, [r0, :64], r1 // q1
sub r0, r0, r1, lsl #1
lpf_8_wd4
sub r10, r0, r1, lsl #1
vst1.8 {d22}, [r10, :64], r1 // p1
vst1.8 {d24}, [r0, :64], r1 // q0
vst1.8 {d23}, [r10, :64], r1 // p0
vst1.8 {d25}, [r0, :64], r1 // q1
sub r0, r0, r1, lsl #1
bx r12
endfunc
function lpf_h_4_8_neon
mov r12, lr
sub r10, r0, #2
add r0, r10, r1, lsl #2
vld1.32 {d22[0]}, [r10], r1
vld1.32 {d22[1]}, [r0], r1
vld1.32 {d23[0]}, [r10], r1
vld1.32 {d23[1]}, [r0], r1
vld1.32 {d24[0]}, [r10], r1
vld1.32 {d24[1]}, [r0], r1
vld1.32 {d25[0]}, [r10], r1
vld1.32 {d25[1]}, [r0], r1
add r0, r0, #2
transpose_4x8b q11, q12, d22, d23, d24, d25
lpf_8_wd4
sub r10, r0, r1, lsl #3
sub r10, r10, #2
transpose_4x8b q11, q12, d22, d23, d24, d25
add r0, r10, r1, lsl #2
vst1.32 {d22[0]}, [r10], r1
vst1.32 {d22[1]}, [r0], r1
vst1.32 {d23[0]}, [r10], r1
vst1.32 {d23[1]}, [r0], r1
vst1.32 {d24[0]}, [r10], r1
vst1.32 {d24[1]}, [r0], r1
vst1.32 {d25[0]}, [r10], r1
vst1.32 {d25[1]}, [r0], r1
add r0, r0, #2
bx r12
endfunc
function lpf_v_6_8_neon
mov r12, lr
sub r10, r0, r1, lsl #1
sub r10, r10, r1
vld1.8 {d21}, [r10, :64], r1 // p2
vld1.8 {d24}, [r0, :64], r1 // q0
vld1.8 {d22}, [r10, :64], r1 // p1
vld1.8 {d25}, [r0, :64], r1 // q1
vld1.8 {d23}, [r10, :64], r1 // p0
vld1.8 {d26}, [r0, :64], r1 // q2
sub r0, r0, r1, lsl #1
sub r0, r0, r1
lpf_8_wd6
sub r10, r0, r1, lsl #1
vst1.8 {d22}, [r10, :64], r1 // p1
vst1.8 {d24}, [r0, :64], r1 // q0
vst1.8 {d23}, [r10, :64], r1 // p0
vst1.8 {d25}, [r0, :64], r1 // q1
sub r0, r0, r1, lsl #1
bx r12
endfunc
function lpf_h_6_8_neon
mov r12, lr
sub r10, r0, #4
add r0, r10, r1, lsl #2
vld1.8 {d20}, [r10], r1
vld1.8 {d24}, [r0], r1
vld1.8 {d21}, [r10], r1
vld1.8 {d25}, [r0], r1
vld1.8 {d22}, [r10], r1
vld1.8 {d26}, [r0], r1
vld1.8 {d23}, [r10], r1
vld1.8 {d27}, [r0], r1
add r0, r0, #4
transpose_8x8b q10, q11, q12, q13, d20, d21, d22, d23, d24, d25, d26, d27
lpf_8_wd6
sub r10, r0, r1, lsl #3
sub r10, r10, #2
transpose_4x8b q11, q12, d22, d23, d24, d25
add r0, r10, r1, lsl #2
vst1.32 {d22[0]}, [r10], r1
vst1.32 {d22[1]}, [r0], r1
vst1.32 {d23[0]}, [r10], r1
vst1.32 {d23[1]}, [r0], r1
vst1.32 {d24[0]}, [r10], r1
vst1.32 {d24[1]}, [r0], r1
vst1.32 {d25[0]}, [r10], r1
vst1.32 {d25[1]}, [r0], r1
add r0, r0, #2
bx r12
endfunc
function lpf_v_8_8_neon
mov r12, lr
sub r10, r0, r1, lsl #2
vld1.8 {d20}, [r10, :64], r1 // p3
vld1.8 {d24}, [r0, :64], r1 // q0
vld1.8 {d21}, [r10, :64], r1 // p2
vld1.8 {d25}, [r0, :64], r1 // q1
vld1.8 {d22}, [r10, :64], r1 // p1
vld1.8 {d26}, [r0, :64], r1 // q2
vld1.8 {d23}, [r10, :64], r1 // p0
vld1.8 {d27}, [r0, :64], r1 // q3
sub r0, r0, r1, lsl #2
lpf_8_wd8
sub r10, r0, r1, lsl #1
sub r10, r10, r1
vst1.8 {d21}, [r10, :64], r1 // p2
vst1.8 {d24}, [r0, :64], r1 // q0
vst1.8 {d22}, [r10, :64], r1 // p1
vst1.8 {d25}, [r0, :64], r1 // q1
vst1.8 {d23}, [r10, :64], r1 // p0
vst1.8 {d26}, [r0, :64], r1 // q2
sub r0, r0, r1, lsl #1
sub r0, r0, r1
bx r12
8:
sub r10, r0, r1, lsl #1
vst1.8 {d22}, [r10, :64], r1 // p1
vst1.8 {d24}, [r0, :64], r1 // q0
vst1.8 {d23}, [r10, :64], r1 // p0
vst1.8 {d25}, [r0, :64], r1 // q1
sub r0, r0, r1, lsl #1
bx r12
endfunc
function lpf_h_8_8_neon
mov r12, lr
sub r10, r0, #4
add r0, r10, r1, lsl #2
vld1.8 {d20}, [r10], r1
vld1.8 {d24}, [r0], r1
vld1.8 {d21}, [r10], r1
vld1.8 {d25}, [r0], r1
vld1.8 {d22}, [r10], r1
vld1.8 {d26}, [r0], r1
vld1.8 {d23}, [r10], r1
vld1.8 {d27}, [r0], r1
add r0, r0, #4
transpose_8x8b q10, q11, q12, q13, d20, d21, d22, d23, d24, d25, d26, d27
lpf_8_wd8
sub r10, r0, r1, lsl #3
sub r10, r10, #4
transpose_8x8b q10, q11, q12, q13, d20, d21, d22, d23, d24, d25, d26, d27
add r0, r10, r1, lsl #2
vst1.8 {d20}, [r10], r1
vst1.8 {d24}, [r0], r1
vst1.8 {d21}, [r10], r1
vst1.8 {d25}, [r0], r1
vst1.8 {d22}, [r10], r1
vst1.8 {d26}, [r0], r1
vst1.8 {d23}, [r10], r1
vst1.8 {d27}, [r0], r1
add r0, r0, #4
bx r12
8:
sub r10, r0, r1, lsl #3
sub r10, r10, #2
transpose_4x8b q11, q12, d22, d23, d24, d25
add r0, r10, r1, lsl #2
vst1.32 {d22[0]}, [r10], r1
vst1.32 {d22[1]}, [r0], r1
vst1.32 {d23[0]}, [r10], r1
vst1.32 {d23[1]}, [r0], r1
vst1.32 {d24[0]}, [r10], r1
vst1.32 {d24[1]}, [r0], r1
vst1.32 {d25[0]}, [r10], r1
vst1.32 {d25[1]}, [r0], r1
add r0, r0, #2
bx r12
endfunc
function lpf_v_16_8_neon
mov r12, lr
sub r10, r0, r1, lsl #3
add r10, r10, r1
vld1.8 {d17}, [r10, :64], r1 // p6
vld1.8 {d24}, [r0, :64], r1 // q0
vld1.8 {d18}, [r10, :64], r1 // p5
vld1.8 {d25}, [r0, :64], r1 // q1
vld1.8 {d19}, [r10, :64], r1 // p4
vld1.8 {d26}, [r0, :64], r1 // q2
vld1.8 {d20}, [r10, :64], r1 // p3
vld1.8 {d27}, [r0, :64], r1 // q3
vld1.8 {d21}, [r10, :64], r1 // p2
vld1.8 {d28}, [r0, :64], r1 // q4
vld1.8 {d22}, [r10, :64], r1 // p1
vld1.8 {d29}, [r0, :64], r1 // q5
vld1.8 {d23}, [r10, :64], r1 // p0
vld1.8 {d30}, [r0, :64], r1 // q6
sub r0, r0, r1, lsl #3
add r0, r0, r1
lpf_8_wd16
sub r10, r0, r1, lsl #2
sub r10, r10, r1, lsl #1
vst1.8 {d0}, [r10, :64], r1 // p5
vst1.8 {d6}, [r0, :64], r1 // q0
vst1.8 {d1}, [r10, :64], r1 // p4
vst1.8 {d7}, [r0, :64], r1 // q1
vst1.8 {d2}, [r10, :64], r1 // p3
vst1.8 {d8}, [r0, :64], r1 // q2
vst1.8 {d3}, [r10, :64], r1 // p2
vst1.8 {d9}, [r0, :64], r1 // q3
vst1.8 {d4}, [r10, :64], r1 // p1
vst1.8 {d10}, [r0, :64], r1 // q4
vst1.8 {d5}, [r10, :64], r1 // p0
vst1.8 {d11}, [r0, :64], r1 // q5
sub r0, r0, r1, lsl #2
sub r0, r0, r1, lsl #1
bx r12
7:
sub r10, r0, r1
sub r10, r10, r1, lsl #1
vst1.8 {d21}, [r10, :64], r1 // p2
vst1.8 {d24}, [r0, :64], r1 // q0
vst1.8 {d22}, [r10, :64], r1 // p1
vst1.8 {d25}, [r0, :64], r1 // q1
vst1.8 {d23}, [r10, :64], r1 // p0
vst1.8 {d26}, [r0, :64], r1 // q2
sub r0, r0, r1, lsl #1
sub r0, r0, r1
bx r12
8:
sub r10, r0, r1, lsl #1
vst1.8 {d22}, [r10, :64], r1 // p1
vst1.8 {d24}, [r0, :64], r1 // q0
vst1.8 {d23}, [r10, :64], r1 // p0
vst1.8 {d25}, [r0, :64], r1 // q1
sub r0, r0, r1, lsl #1
bx r12
endfunc
function lpf_h_16_8_neon
mov r12, lr
sub r10, r0, #8
vld1.8 {d16}, [r10, :64], r1
vld1.8 {d24}, [r0, :64], r1
vld1.8 {d17}, [r10, :64], r1
vld1.8 {d25}, [r0, :64], r1
vld1.8 {d18}, [r10, :64], r1
vld1.8 {d26}, [r0, :64], r1
vld1.8 {d19}, [r10, :64], r1
vld1.8 {d27}, [r0, :64], r1
vld1.8 {d20}, [r10, :64], r1
vld1.8 {d28}, [r0, :64], r1
vld1.8 {d21}, [r10, :64], r1
vld1.8 {d29}, [r0, :64], r1
vld1.8 {d22}, [r10, :64], r1
vld1.8 {d30}, [r0, :64], r1
vld1.8 {d23}, [r10, :64], r1
vld1.8 {d31}, [r0, :64], r1
transpose_8x8b q8, q9, q10, q11, d16, d17, d18, d19, d20, d21, d22, d23
transpose_8x8b q12, q13, q14, q15, d24, d25, d26, d27, d28, d29, d30, d31
lpf_8_wd16
sub r0, r0, r1, lsl #3
sub r10, r0, #8
transpose_8x8b q8, q0, q1, q2, d16, d17, d0, d1, d2, d3, d4, d5
transpose_8x8b q3, q4, q5, q15, d6, d7, d8, d9, d10, d11, d30, d31
vst1.8 {d16}, [r10, :64], r1
vst1.8 {d6}, [r0, :64], r1
vst1.8 {d17}, [r10, :64], r1
vst1.8 {d7}, [r0, :64], r1
vst1.8 {d0}, [r10, :64], r1
vst1.8 {d8}, [r0, :64], r1
vst1.8 {d1}, [r10, :64], r1
vst1.8 {d9}, [r0, :64], r1
vst1.8 {d2}, [r10, :64], r1
vst1.8 {d10}, [r0, :64], r1
vst1.8 {d3}, [r10, :64], r1
vst1.8 {d11}, [r0, :64], r1
vst1.8 {d4}, [r10, :64], r1
vst1.8 {d30}, [r0, :64], r1
vst1.8 {d5}, [r10, :64], r1
vst1.8 {d31}, [r0, :64], r1
bx r12
7:
sub r10, r0, r1, lsl #3
sub r10, r10, #4
transpose_8x8b q10, q11, q12, q13, d20, d21, d22, d23, d24, d25, d26, d27
add r0, r10, r1, lsl #2
vst1.8 {d20}, [r10], r1
vst1.8 {d24}, [r0], r1
vst1.8 {d21}, [r10], r1
vst1.8 {d25}, [r0], r1
vst1.8 {d22}, [r10], r1
vst1.8 {d26}, [r0], r1
vst1.8 {d23}, [r10], r1
vst1.8 {d27}, [r0], r1
add r0, r0, #4
bx r12
8:
sub r10, r0, r1, lsl #3
sub r10, r10, #2
transpose_4x8b q11, q12, d22, d23, d24, d25
add r0, r10, r1, lsl #2
vst1.32 {d22[0]}, [r10], r1
vst1.32 {d22[1]}, [r0], r1
vst1.32 {d23[0]}, [r10], r1
vst1.32 {d23[1]}, [r0], r1
vst1.32 {d24[0]}, [r10], r1
vst1.32 {d24[1]}, [r0], r1
vst1.32 {d25[0]}, [r10], r1
vst1.32 {d25[1]}, [r0], r1
add r0, r0, #2
bx r12
endfunc
// void dav1d_lpf_v_sb_y_8bpc_neon(pixel *dst, const ptrdiff_t stride,
// const uint32_t *const vmask,
// const uint8_t (*l)[4], ptrdiff_t b4_stride,
// const Av1FilterLUT *lut, const int w)
.macro lpf_func dir, type
function lpf_\dir\()_sb_\type\()_8bpc_neon, export=1
push {r4-r11,lr}
vpush {q4-q7}
ldrd r4, r5, [sp, #100]
ldrd r6, r7, [r2] // vmask[0], vmask[1]
.ifc \type, y
ldr r2, [r2, #8] // vmask[2]
.endif
add r5, r5, #128 // Move to sharp part of lut
.ifc \type, y
orr r7, r7, r2 // vmask[1] |= vmask[2]
.endif
.ifc \dir, v
sub r4, r3, r4, lsl #2
.else
sub r3, r3, #4
lsl r4, r4, #2
.endif
orr r6, r6, r7 // vmask[0] |= vmask[1]
1:
tst r6, #0x03
.ifc \dir, v
vld1.8 {d0}, [r4]!
vld1.8 {d1}, [r3]!
.else
vld2.32 {d0[0], d1[0]}, [r3], r4
vld2.32 {d0[1], d1[1]}, [r3], r4
.endif
beq 7f // if (!(vm & bits)) continue;
vld1.8 {d5[]}, [r5] // sharp[0]
add r5, r5, #8
vmov.i32 d2, #0xff
vdup.32 d13, r6 // vmask[0]
vand d0, d0, d2 // Keep only lowest byte in each 32 bit word
vand d1, d1, d2
vtst.8 d3, d1, d2 // Check for nonzero values in l[0][0]
vmov.i8 d4, #1
vld1.8 {d6[]}, [r5] // sharp[1]
sub r5, r5, #8
vbif d1, d0, d3 // if (!l[0][0]) L = l[offset][0]
vtst.32 d2, d1, d2 // L != 0
vmul.i32 d1, d1, d4 // L
.ifc \type, y
vdup.32 d15, r2 // vmask[2]
.endif
vdup.32 d14, r7 // vmask[1]
vmov r10, r11, d2
orrs r10, r10, r11
beq 7f // if (!L) continue;
vneg.s8 d5, d5 // -sharp[0]
movrel_local r10, word_12
vshr.u8 d12, d1, #4 // H
vld1.32 {d16}, [r10, :64]
vshl.s8 d3, d1, d5 // L >> sharp[0]
.ifc \type, y
vtst.32 d15, d15, d16 // if (vmask[2] & bits)
.endif
vmov.i8 d7, #2
vmin.u8 d3, d3, d6 // imin(L >> sharp[0], sharp[1])
vadd.i8 d0, d1, d7 // L + 2
vmax.u8 d11, d3, d4 // imax(imin(), 1) = limit = I
vadd.u8 d0, d0, d0 // 2*(L + 2)
vtst.32 d14, d14, d16 // if (vmask[1] & bits)
vadd.i8 d10, d0, d11 // 2*(L + 2) + limit = E
vtst.32 d13, d13, d16 // if (vmask[0] & bits)
vand d13, d13, d2 // vmask[0] &= L != 0
.ifc \type, y
tst r2, #0x03
beq 2f
// wd16
bl lpf_\dir\()_16_8_neon
b 8f
2:
.endif
tst r7, #0x03
beq 3f
.ifc \type, y
// wd8
bl lpf_\dir\()_8_8_neon
.else
// wd6
bl lpf_\dir\()_6_8_neon
.endif
b 8f
3:
// wd4
bl lpf_\dir\()_4_8_neon
.ifc \dir, h
b 8f
7:
// For dir h, the functions above increment r0.
// If the whole function is skipped, increment it here instead.
add r0, r0, r1, lsl #3
.else
7:
.endif
8:
lsrs r6, r6, #2 // vmask[0] >>= 2
lsr r7, r7, #2 // vmask[1] >>= 2
.ifc \type, y
lsr r2, r2, #2 // vmask[2] >>= 2
.endif
.ifc \dir, v
add r0, r0, #8
.else
// For dir h, r0 is returned incremented
.endif
bne 1b
vpop {q4-q7}
pop {r4-r11,pc}
endfunc
.endm
lpf_func v, y
lpf_func h, y
lpf_func v, uv
lpf_func h, uv
const word_12, align=4
.word 1, 2
endconst

View file

@ -0,0 +1,859 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2020, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include "src/arm/asm.S"
#include "util.S"
.macro loop_filter wd
function lpf_4_wd\wd\()_neon
vabd.u16 d0, d22, d23 // abs(p1 - p0)
vabd.u16 d1, d25, d24 // abs(q1 - q0)
vabd.u16 d2, d23, d24 // abs(p0 - q0)
vabd.u16 d3, d22, d25 // abs(p1 - q1)
.if \wd >= 6
vabd.u16 d4, d21, d22 // abs(p2 - p1)
vabd.u16 d5, d26, d25 // abs(q2 - q1)
.endif
.if \wd >= 8
vabd.u16 d6, d20, d21 // abs(p3 - p2)
vabd.u16 d7, d27, d26 // abs(q3 - q3)
.endif
.if \wd >= 6
vmax.u16 d4, d4, d5
.endif
vqadd.u16 d2, d2, d2 // abs(p0 - q0) * 2
.if \wd >= 8
vmax.u16 d6, d6, d7
.endif
vshr.u16 d3, d3, #1
.if \wd >= 8
vmax.u16 d4, d4, d6
.endif
vmax.u16 d0, d0, d1 // max(abs(p1 - p0), abs(q1 - q0))
vqadd.u16 d2, d2, d3 // abs(p0 - q0) * 2 + abs(p1 - q1) >> 1
.if \wd >= 6
vmax.u16 d4, d0, d4
vcge.u16 d1, d11, d4 // max(abs(p1 - p0), abs(q1 - q0), abs(), abs(), ...) <= I
.else
vcge.u16 d1, d11, d0 // max(abs(p1 - p0), abs(q1 - q0)) <= I
.endif
vcge.u16 d2, d10, d2 // abs(p0 - q0) * 2 + abs(p1 - q1) >> 1 <= E
vand d1, d1, d2 // fm && wd >= 4 (implicit)
.if \wd >= 6
vmov d14, d1 // fm && wd > 4 (implicit)
.endif
.if \wd >= 16
vmov d15, d1 // fm && wd == 16 (implicit)
.endif
vmov r10, r11, d1
orrs r10, r10, r11
beq 9f // if (!fm || wd < 4) return;
.if \wd >= 6
vmov.i16 d10, #1
vabd.u16 d2, d21, d23 // abs(p2 - p0)
vabd.u16 d3, d22, d23 // abs(p1 - p0)
vabd.u16 d4, d25, d24 // abs(q1 - q0)
vabd.u16 d5, d26, d24 // abs(q2 - q0)
vdup.16 d9, r9 // bitdepth_min_8
.if \wd >= 8
vabd.u16 d6, d20, d23 // abs(p3 - p0)
vabd.u16 d7, d27, d24 // abs(q3 - q0)
.endif
vmax.u16 d2, d2, d3
vmax.u16 d4, d4, d5
.if \wd >= 8
vmax.u16 d6, d6, d7
.endif
vmax.u16 d2, d2, d4
vshl.u16 d10, d10, d9 // F = 1 << bitdepth_min_8
.if \wd >= 8
vmax.u16 d2, d2, d6
.endif
.if \wd == 16
vabd.u16 d3, d17, d23 // abs(p6 - p0)
vabd.u16 d4, d18, d23 // abs(p5 - p0)
vabd.u16 d5, d19, d23 // abs(p4 - p0)
.endif
vcge.u16 d2, d10, d2 // flat8in
.if \wd == 16
vabd.u16 d6, d28, d24 // abs(q4 - q0)
vabd.u16 d7, d29, d24 // abs(q5 - q0)
vabd.u16 d8, d30, d24 // abs(q6 - q0)
.endif
vand d14, d2, d14 // flat8in && fm && wd > 4
vbic d1, d1, d14 // fm && wd >= 4 && !flat8in
.if \wd == 16
vmax.u16 d3, d3, d4
vmax.u16 d5, d5, d6
.endif
vmov r10, r11, d1
.if \wd == 16
vmax.u16 d7, d7, d8
vmax.u16 d3, d3, d5
vmax.u16 d3, d3, d7
vcge.u16 d3, d10, d3 // flat8out
.endif
orrs r10, r10, r11
.if \wd == 16
vand d15, d15, d3 // flat8out && fm && wd == 16
vand d15, d15, d14 // flat8out && flat8in && fm && wd == 16
vbic d14, d14, d15 // flat8in && fm && wd >= 4 && !flat8out
.endif
beq 1f // skip wd == 4 case
.endif
vdup.16 d3, r8 // bitdepth_max
vsub.u16 d2, d22, d25 // p1 - q1
vshr.u16 d3, d3, #1 // 128 << bitdepth_min_8 - 1
vcgt.u16 d0, d0, d12 // hev
vmvn d9, d3 // - 128 * (1 << bitdepth_min_8)
vmin.s16 d2, d2, d3 // iclip_diff(p1 - q1)
vmax.s16 d2, d2, d9 // iclip_diff(p1 - q1)
vand d4, d2, d0 // if (hev) iclip_diff(p1 - q1)
vsub.u16 d2, d24, d23
vmov.i16 d6, #3
vbic d0, d1, d0 // (fm && wd >= 4 && !hev)
vmul.i16 d2, d2, d6
vmov.i16 d7, #4
vadd.i16 d2, d2, d4
vmin.s16 d2, d2, d3 // f = iclip_diff()
vmax.s16 d2, d2, d9 // f = iclip_diff()
vqadd.s16 d4, d7, d2 // f + 4
vqadd.s16 d5, d6, d2 // f + 3
vmin.s16 d4, d4, d3 // imin(f + 4, 128 << bitdepth_min_8 - 1)
vmin.s16 d5, d5, d3 // imin(f + 3, 128 << bitdepth_min_8 - 1)
vshr.s16 d4, d4, #3 // f1
vshr.s16 d5, d5, #3 // f2
vmov.i16 d9, #0
vdup.16 d3, r8 // bitdepth_max
vqadd.s16 d2, d23, d5 // p0 + f2
vqsub.s16 d6, d24, d4 // q0 - f1
vrshr.s16 d4, d4, #1 // (f1 + 1) >> 1
vmin.s16 d2, d2, d3 // out p0 = iclip_pixel()
vmin.s16 d6, d6, d3 // out q0 = iclip_pixel()
vmax.s16 d2, d2, d9 // out p0 = iclip_pixel()
vmax.s16 d6, d6, d9 // out q0 = iclip_pixel()
vbit d23, d2, d1 // if (fm && wd >= 4)
vbit d24, d6, d1 // if (fm && wd >= 4)
vqadd.s16 d2, d22, d4 // p1 + f
vqsub.s16 d6, d25, d4 // q1 - f
vmin.s16 d2, d2, d3 // out p1 = iclip_pixel()
vmin.s16 d6, d6, d3 // out q1 = iclip_pixel()
vmax.s16 d2, d2, d9 // out p1 = iclip_pixel()
vmax.s16 d6, d6, d9 // out q1 = iclip_pixel()
vbit d22, d2, d0 // if (fm && wd >= 4 && !hev)
vbit d25, d6, d0 // if (fm && wd >= 4 && !hev)
1:
.if \wd == 6
vmov r10, r11, d14
orrs r10, r10, r11
beq 2f // skip if there's no flat8in
vadd.i16 d0, d21, d21 // p2 * 2
vadd.i16 d2, d21, d22 // p2 + p1
vadd.i16 d4, d22, d23 // p1 + p0
vadd.i16 d6, d23, d24 // p0 + q0
vadd.i16 d8, d0, d2
vadd.i16 d10, d4, d6
vadd.i16 d12, d24, d25 // q0 + q1
vadd.i16 d8, d8, d10
vsub.i16 d12, d12, d0
vadd.i16 d10, d25, d26 // q1 + q2
vrshr.u16 d0, d8, #3 // out p1
vadd.i16 d8, d8, d12
vsub.i16 d10, d10, d2
vadd.i16 d12, d26, d26 // q2 + q2
vrshr.u16 d1, d8, #3 // out p0
vadd.i16 d8, d8, d10
vsub.i16 d12, d12, d4
vrshr.u16 d2, d8, #3 // out q0
vbit d22, d0, d14 // p1 if (flat8in)
vadd.i16 d8, d8, d12
vbit d23, d1, d14 // p0 if (flat8in)
vrshr.u16 d3, d8, #3 // out q1
vbit d24, d2, d14 // q0 if (flat8in)
vbit d25, d3, d14 // q1 if (flat8in)
.elseif \wd >= 8
vmov r10, r11, d14
orrs r10, r10, r11
.if \wd == 8
beq 8f // skip if there's no flat8in
.else
beq 2f // skip if there's no flat8in
.endif
vadd.i16 d0, d20, d21 // p3 + p2
vadd.i16 d2, d22, d25 // p1 + q1
vadd.i16 d4, d20, d22 // p3 + p1
vadd.i16 d6, d23, d26 // p0 + q2
vadd.i16 d8, d0, d0 // 2 * (p3 + p2)
vadd.i16 d9, d23, d24 // p0 + q0
vadd.i16 d8, d8, d4 // + p3 + p1
vsub.i16 d2, d2, d0 // p1 + q1 - p3 - p2
vadd.i16 d8, d8, d9 // + p0 + q0
vsub.i16 d6, d6, d4 // p0 + q2 - p3 - p1
vrshr.u16 d10, d8, #3 // out p2
vadd.i16 d8, d8, d2
vadd.i16 d0, d20, d23 // p3 + p0
vadd.i16 d2, d24, d27 // q0 + q3
vrshr.u16 d11, d8, #3 // out p1
vadd.i16 d8, d8, d6
vsub.i16 d2, d2, d0 // q0 + q3 - p3 - p0
vadd.i16 d4, d21, d24 // p2 + q0
vadd.i16 d6, d25, d27 // q1 + q3
vrshr.u16 d12, d8, #3 // out p0
vadd.i16 d8, d8, d2
vsub.i16 d6, d6, d4 // q1 + q3 - p2 - q0
vadd.i16 d0, d22, d25 // p1 + q1
vadd.i16 d2, d26, d27 // q2 + q3
vrshr.u16 d13, d8, #3 // out q0
vadd.i16 d8, d8, d6
vsub.i16 d2, d2, d0 // q2 + q3 - p1 - q1
vrshr.u16 d0, d8, #3 // out q1
vadd.i16 d8, d8, d2
vbit d21, d10, d14
vbit d22, d11, d14
vbit d23, d12, d14
vrshr.u16 d1, d8, #3 // out q2
vbit d24, d13, d14
vbit d25, d0, d14
vbit d26, d1, d14
.endif
2:
.if \wd == 16
vmov r10, r11, d15
orrs r10, r10, r11
bne 1f // check if flat8out is needed
vmov r10, r11, d14
orrs r10, r10, r11
beq 8f // if there was no flat8in, just write the inner 4 pixels
b 7f // if flat8in was used, write the inner 6 pixels
1:
vadd.i16 d2, d17, d17 // p6 + p6
vadd.i16 d4, d17, d18 // p6 + p5
vadd.i16 d6, d17, d19 // p6 + p4
vadd.i16 d8, d17, d20 // p6 + p3
vadd.i16 d12, d2, d4
vadd.i16 d10, d6, d8
vadd.i16 d6, d17, d21 // p6 + p2
vadd.i16 d12, d12, d10
vadd.i16 d8, d17, d22 // p6 + p1
vadd.i16 d10, d18, d23 // p5 + p0
vadd.i16 d6, d6, d8
vadd.i16 d8, d19, d24 // p4 + q0
vadd.i16 d12, d12, d6
vadd.i16 d10, d10, d8
vadd.i16 d6, d20, d25 // p3 + q1
vadd.i16 d12, d12, d10
vsub.i16 d6, d6, d2
vadd.i16 d2, d21, d26 // p2 + q2
vrshr.u16 d0, d12, #4 // out p5
vadd.i16 d12, d12, d6 // - (p6 + p6) + (p3 + q1)
vsub.i16 d2, d2, d4
vadd.i16 d4, d22, d27 // p1 + q3
vadd.i16 d6, d17, d19 // p6 + p4
vrshr.u16 d1, d12, #4 // out p4
vadd.i16 d12, d12, d2 // - (p6 + p5) + (p2 + q2)
vsub.i16 d4, d4, d6
vadd.i16 d6, d23, d28 // p0 + q4
vadd.i16 d8, d17, d20 // p6 + p3
vrshr.u16 d2, d12, #4 // out p3
vadd.i16 d12, d12, d4 // - (p6 + p4) + (p1 + q3)
vsub.i16 d6, d6, d8
vadd.i16 d8, d24, d29 // q0 + q5
vadd.i16 d4, d17, d21 // p6 + p2
vrshr.u16 d3, d12, #4 // out p2
vadd.i16 d12, d12, d6 // - (p6 + p3) + (p0 + q4)
vsub.i16 d8, d8, d4
vadd.i16 d6, d25, d30 // q1 + q6
vadd.i16 d10, d17, d22 // p6 + p1
vrshr.u16 d4, d12, #4 // out p1
vadd.i16 d12, d12, d8 // - (p6 + p2) + (q0 + q5)
vsub.i16 d6, d6, d10
vadd.i16 d8, d26, d30 // q2 + q6
vbif d0, d18, d15 // out p5
vadd.i16 d10, d18, d23 // p5 + p0
vrshr.u16 d5, d12, #4 // out p0
vadd.i16 d12, d12, d6 // - (p6 + p1) + (q1 + q6)
vsub.i16 d8, d8, d10
vadd.i16 d10, d27, d30 // q3 + q6
vbif d1, d19, d15 // out p4
vadd.i16 d18, d19, d24 // p4 + q0
vrshr.u16 d6, d12, #4 // out q0
vadd.i16 d12, d12, d8 // - (p5 + p0) + (q2 + q6)
vsub.i16 d10, d10, d18
vadd.i16 d8, d28, d30 // q4 + q6
vbif d2, d20, d15 // out p3
vadd.i16 d18, d20, d25 // p3 + q1
vrshr.u16 d7, d12, #4 // out q1
vadd.i16 d12, d12, d10 // - (p4 + q0) + (q3 + q6)
vsub.i16 d18, d8, d18
vadd.i16 d10, d29, d30 // q5 + q6
vbif d3, d21, d15 // out p2
vadd.i16 d20, d21, d26 // p2 + q2
vrshr.u16 d8, d12, #4 // out q2
vadd.i16 d12, d12, d18 // - (p3 + q1) + (q4 + q6)
vsub.i16 d10, d10, d20
vadd.i16 d18, d30, d30 // q6 + q6
vbif d4, d22, d15 // out p1
vadd.i16 d20, d22, d27 // p1 + q3
vrshr.u16 d9, d12, #4 // out q3
vadd.i16 d12, d12, d10 // - (p2 + q2) + (q5 + q6)
vsub.i16 d18, d18, d20
vbif d5, d23, d15 // out p0
vrshr.u16 d10, d12, #4 // out q4
vadd.i16 d12, d12, d18 // - (p1 + q3) + (q6 + q6)
vrshr.u16 d11, d12, #4 // out q5
vbif d6, d24, d15 // out q0
vbif d7, d25, d15 // out q1
vbif d8, d26, d15 // out q2
vbif d9, d27, d15 // out q3
vbif d10, d28, d15 // out q4
vbif d11, d29, d15 // out q5
.endif
bx lr
.if \wd == 16
7:
// Return to a shorter epilogue, writing only the inner 6 pixels
bx r6
.endif
.if \wd >= 8
8:
// Return to a shorter epilogue, writing only the inner 4 pixels
bx r7
.endif
9:
// Return directly without writing back any pixels
bx r12
endfunc
.endm
loop_filter 16
loop_filter 8
loop_filter 6
loop_filter 4
.macro lpf_4_wd16
adr r6, 7f + CONFIG_THUMB
adr r7, 8f + CONFIG_THUMB
bl lpf_4_wd16_neon
.endm
.macro lpf_4_wd8
adr r7, 8f + CONFIG_THUMB
bl lpf_4_wd8_neon
.endm
.macro lpf_4_wd6
bl lpf_4_wd6_neon
.endm
.macro lpf_4_wd4
bl lpf_4_wd4_neon
.endm
function lpf_v_4_4_neon
mov r12, lr
sub r10, r0, r1, lsl #1
vld1.16 {d22}, [r10, :64], r1 // p1
vld1.16 {d24}, [r0, :64], r1 // q0
vld1.16 {d23}, [r10, :64], r1 // p0
vld1.16 {d25}, [r0, :64], r1 // q1
sub r0, r0, r1, lsl #1
lpf_4_wd4
sub r10, r0, r1, lsl #1
vst1.16 {d22}, [r10, :64], r1 // p1
vst1.16 {d24}, [r0, :64], r1 // q0
vst1.16 {d23}, [r10, :64], r1 // p0
vst1.16 {d25}, [r0, :64], r1 // q1
sub r0, r0, r1, lsl #1
bx r12
endfunc
function lpf_h_4_4_neon
mov r12, lr
sub r10, r0, #4
add r0, r10, r1, lsl #1
vld1.16 {d22}, [r10], r1
vld1.16 {d24}, [r0], r1
vld1.16 {d23}, [r10], r1
vld1.16 {d25}, [r0], r1
add r0, r0, #4
transpose_4x4h q11, q12, d22, d23, d24, d25
lpf_4_wd4
sub r10, r0, r1, lsl #2
sub r10, r10, #4
transpose_4x4h q11, q12, d22, d23, d24, d25
add r0, r10, r1, lsl #1
vst1.16 {d22}, [r10], r1
vst1.16 {d24}, [r0], r1
vst1.16 {d23}, [r10], r1
vst1.16 {d25}, [r0], r1
add r0, r0, #4
bx r12
endfunc
function lpf_v_6_4_neon
mov r12, lr
sub r10, r0, r1, lsl #1
sub r10, r10, r1
vld1.16 {d21}, [r10, :64], r1 // p2
vld1.16 {d24}, [r0, :64], r1 // q0
vld1.16 {d22}, [r10, :64], r1 // p1
vld1.16 {d25}, [r0, :64], r1 // q1
vld1.16 {d23}, [r10, :64], r1 // p0
vld1.16 {d26}, [r0, :64], r1 // q2
sub r0, r0, r1, lsl #1
sub r0, r0, r1
lpf_4_wd6
sub r10, r0, r1, lsl #1
vst1.16 {d22}, [r10, :64], r1 // p1
vst1.16 {d24}, [r0, :64], r1 // q0
vst1.16 {d23}, [r10, :64], r1 // p0
vst1.16 {d25}, [r0, :64], r1 // q1
sub r0, r0, r1, lsl #1
bx r12
endfunc
function lpf_h_6_4_neon
mov r12, lr
sub r10, r0, #8
vld1.16 {d20}, [r10, :64], r1
vld1.16 {d24}, [r0, :64], r1
vld1.16 {d21}, [r10, :64], r1
vld1.16 {d25}, [r0, :64], r1
vld1.16 {d22}, [r10, :64], r1
vld1.16 {d26}, [r0, :64], r1
vld1.16 {d23}, [r10, :64], r1
vld1.16 {d27}, [r0, :64], r1
transpose_4x4h q10, q11, d20, d21, d22, d23
transpose_4x4h q12, q13, d24, d25, d26, d27
lpf_4_wd6
sub r0, r0, #4
transpose_4x4h q11, q12, d22, d23, d24, d25
sub r10, r0, r1, lsl #2
sub r0, r0, r1, lsl #1
vst1.16 {d22}, [r10], r1
vst1.16 {d24}, [r0], r1
vst1.16 {d23}, [r10], r1
vst1.16 {d25}, [r0], r1
add r0, r0, #4
bx r12
endfunc
function lpf_v_8_4_neon
mov r12, lr
sub r10, r0, r1, lsl #2
vld1.16 {d20}, [r10, :64], r1 // p3
vld1.16 {d24}, [r0, :64], r1 // q0
vld1.16 {d21}, [r10, :64], r1 // p2
vld1.16 {d25}, [r0, :64], r1 // q1
vld1.16 {d22}, [r10, :64], r1 // p1
vld1.16 {d26}, [r0, :64], r1 // q2
vld1.16 {d23}, [r10, :64], r1 // p0
vld1.16 {d27}, [r0, :64], r1 // q3
sub r0, r0, r1, lsl #2
lpf_4_wd8
sub r10, r0, r1, lsl #1
sub r10, r10, r1
vst1.16 {d21}, [r10, :64], r1 // p2
vst1.16 {d24}, [r0, :64], r1 // q0
vst1.16 {d22}, [r10, :64], r1 // p1
vst1.16 {d25}, [r0, :64], r1 // q1
vst1.16 {d23}, [r10, :64], r1 // p0
vst1.16 {d26}, [r0, :64], r1 // q2
sub r0, r0, r1, lsl #1
sub r0, r0, r1
bx r12
8:
sub r10, r0, r1, lsl #1
vst1.16 {d22}, [r10, :64], r1 // p1
vst1.16 {d24}, [r0, :64], r1 // q0
vst1.16 {d23}, [r10, :64], r1 // p0
vst1.16 {d25}, [r0, :64], r1 // q1
sub r0, r0, r1, lsl #1
bx r12
endfunc
function lpf_h_8_4_neon
mov r12, lr
sub r10, r0, #8
vld1.16 {d20}, [r10, :64], r1
vld1.16 {d24}, [r0, :64], r1
vld1.16 {d21}, [r10, :64], r1
vld1.16 {d25}, [r0, :64], r1
vld1.16 {d22}, [r10, :64], r1
vld1.16 {d26}, [r0, :64], r1
vld1.16 {d23}, [r10, :64], r1
vld1.16 {d27}, [r0, :64], r1
transpose_4x4h q10, q11, d20, d21, d22, d23
transpose_4x4h q12, q13, d24, d25, d26, d27
lpf_4_wd8
sub r0, r0, r1, lsl #2
transpose_4x4h q10, q11, d20, d21, d22, d23
transpose_4x4h q12, q13, d24, d25, d26, d27
sub r10, r0, #8
vst1.16 {d20}, [r10, :64], r1
vst1.16 {d24}, [r0, :64], r1
vst1.16 {d21}, [r10, :64], r1
vst1.16 {d25}, [r0, :64], r1
vst1.16 {d22}, [r10, :64], r1
vst1.16 {d26}, [r0, :64], r1
vst1.16 {d23}, [r10, :64], r1
vst1.16 {d27}, [r0, :64], r1
bx r12
8:
sub r0, r0, #4
transpose_4x4h q11, q12, d22, d23, d24, d25
sub r10, r0, r1, lsl #2
sub r0, r0, r1, lsl #1
vst1.16 {d22}, [r10], r1
vst1.16 {d24}, [r0], r1
vst1.16 {d23}, [r10], r1
vst1.16 {d25}, [r0], r1
add r0, r0, #4
bx r12
endfunc
function lpf_v_16_4_neon
mov r12, lr
sub r10, r0, r1, lsl #3
add r10, r10, r1
vld1.16 {d17}, [r10, :64], r1 // p6
vld1.16 {d24}, [r0, :64], r1 // q0
vld1.16 {d18}, [r10, :64], r1 // p5
vld1.16 {d25}, [r0, :64], r1 // q1
vld1.16 {d19}, [r10, :64], r1 // p4
vld1.16 {d26}, [r0, :64], r1 // q2
vld1.16 {d20}, [r10, :64], r1 // p3
vld1.16 {d27}, [r0, :64], r1 // q3
vld1.16 {d21}, [r10, :64], r1 // p2
vld1.16 {d28}, [r0, :64], r1 // q4
vld1.16 {d22}, [r10, :64], r1 // p1
vld1.16 {d29}, [r0, :64], r1 // q5
vld1.16 {d23}, [r10, :64], r1 // p0
vld1.16 {d30}, [r0, :64], r1 // q6
sub r0, r0, r1, lsl #3
add r0, r0, r1
lpf_4_wd16
sub r10, r0, r1, lsl #2
sub r10, r10, r1, lsl #1
vst1.16 {d0}, [r10, :64], r1 // p5
vst1.16 {d6}, [r0, :64], r1 // q0
vst1.16 {d1}, [r10, :64], r1 // p4
vst1.16 {d7}, [r0, :64], r1 // q1
vst1.16 {d2}, [r10, :64], r1 // p3
vst1.16 {d8}, [r0, :64], r1 // q2
vst1.16 {d3}, [r10, :64], r1 // p2
vst1.16 {d9}, [r0, :64], r1 // q3
vst1.16 {d4}, [r10, :64], r1 // p1
vst1.16 {d10}, [r0, :64], r1 // q4
vst1.16 {d5}, [r10, :64], r1 // p0
vst1.16 {d11}, [r0, :64], r1 // q5
sub r0, r0, r1, lsl #2
sub r0, r0, r1, lsl #1
bx r12
7:
sub r10, r0, r1
sub r10, r10, r1, lsl #1
vst1.16 {d21}, [r10, :64], r1 // p2
vst1.16 {d24}, [r0, :64], r1 // q0
vst1.16 {d22}, [r10, :64], r1 // p1
vst1.16 {d25}, [r0, :64], r1 // q1
vst1.16 {d23}, [r10, :64], r1 // p0
vst1.16 {d26}, [r0, :64], r1 // q2
sub r0, r0, r1, lsl #1
sub r0, r0, r1
bx r12
8:
sub r10, r0, r1, lsl #1
vst1.16 {d22}, [r10, :64], r1 // p1
vst1.16 {d24}, [r0, :64], r1 // q0
vst1.16 {d23}, [r10, :64], r1 // p0
vst1.16 {d25}, [r0, :64], r1 // q1
sub r0, r0, r1, lsl #1
bx r12
endfunc
function lpf_h_16_4_neon
mov r12, lr
sub r10, r0, #16
sub r0, r0, #8
vld1.16 {d16}, [r10, :64], r1
vld1.16 {d20}, [r0, :64], r1
vld1.16 {d17}, [r10, :64], r1
vld1.16 {d21}, [r0, :64], r1
vld1.16 {d18}, [r10, :64], r1
vld1.16 {d22}, [r0, :64], r1
vld1.16 {d19}, [r10, :64], r1
vld1.16 {d23}, [r0, :64], r1
sub r10, r10, r1, lsl #2
sub r0, r0, r1, lsl #2
add r10, r10, #16
add r0, r0, #16
vld1.16 {d24}, [r10, :64], r1
vld1.16 {d28}, [r0, :64], r1
vld1.16 {d25}, [r10, :64], r1
vld1.16 {d29}, [r0, :64], r1
vld1.16 {d26}, [r10, :64], r1
vld1.16 {d30}, [r0, :64], r1
vld1.16 {d27}, [r10, :64], r1
vld1.16 {d31}, [r0, :64], r1
sub r0, r0, #8
transpose_4x4h q8, q9, d16, d17, d18, d19
transpose_4x4h q10, q11, d20, d21, d22, d23
transpose_4x4h q12, q13, d24, d25, d26, d27
transpose_4x4h q14, q15, d28, d29, d30, d31
lpf_4_wd16
sub r0, r0, r1, lsl #2
transpose_4x4h q8, q0, d16, d17, d0, d1
transpose_4x4h q1, q2, d2, d3, d4, d5
transpose_4x4h q3, q4, d6, d7, d8, d9
transpose_4x4h q5, q15, d10, d11, d30, d31
sub r10, r0, #16
sub r0, r0, #8
vst1.16 {d16}, [r10, :64], r1
vst1.16 {d2}, [r0, :64], r1
vst1.16 {d17}, [r10, :64], r1
vst1.16 {d3}, [r0, :64], r1
vst1.16 {d0}, [r10, :64], r1
vst1.16 {d4}, [r0, :64], r1
vst1.16 {d1}, [r10, :64], r1
vst1.16 {d5}, [r0, :64], r1
sub r10, r10, r1, lsl #2
sub r0, r0, r1, lsl #2
add r10, r10, #16
add r0, r0, #16
vst1.16 {d6}, [r10, :64], r1
vst1.16 {d10}, [r0, :64], r1
vst1.16 {d7}, [r10, :64], r1
vst1.16 {d11}, [r0, :64], r1
vst1.16 {d8}, [r10, :64], r1
vst1.16 {d30}, [r0, :64], r1
vst1.16 {d9}, [r10, :64], r1
vst1.16 {d31}, [r0, :64], r1
sub r0, r0, #8
bx r12
7:
sub r0, r0, r1, lsl #2
transpose_4x4h q10, q11, d20, d21, d22, d23
transpose_4x4h q12, q13, d24, d25, d26, d27
sub r10, r0, #8
vst1.16 {d20}, [r10, :64], r1
vst1.16 {d24}, [r0, :64], r1
vst1.16 {d21}, [r10, :64], r1
vst1.16 {d25}, [r0, :64], r1
vst1.16 {d22}, [r10, :64], r1
vst1.16 {d26}, [r0, :64], r1
vst1.16 {d23}, [r10, :64], r1
vst1.16 {d27}, [r0, :64], r1
bx r12
8:
sub r0, r0, #4
transpose_4x4h q11, q12, d22, d23, d24, d25
sub r10, r0, r1, lsl #2
sub r0, r0, r1, lsl #1
vst1.16 {d22}, [r10], r1
vst1.16 {d24}, [r0], r1
vst1.16 {d23}, [r10], r1
vst1.16 {d25}, [r0], r1
add r0, r0, #4
bx r12
endfunc
// void dav1d_lpf_v_sb_y_16bpc_neon(pixel *dst, const ptrdiff_t stride,
// const uint32_t *const vmask,
// const uint8_t (*l)[4], ptrdiff_t b4_stride,
// const Av1FilterLUT *lut, const int w,
// const int bitdepth_max)
.macro lpf_func dir, type
function lpf_\dir\()_sb_\type\()_16bpc_neon, export=1
push {r4-r11,lr}
vpush {q4-q7}
ldrd r4, r5, [sp, #100]
ldr r8, [sp, #112] // bitdepth_max; the 'w' parameter isn't loaded
sub sp, sp, #8
clz r9, r8
rsb r9, r9, #24 // bitdepth_min_8
ldrd r6, r7, [r2] // vmask[0], vmask[1]
.ifc \type, y
ldr r2, [r2, #8] // vmask[2]
.endif
add r5, r5, #128 // Move to sharp part of lut
.ifc \type, y
orr r7, r7, r2 // vmask[1] |= vmask[2]
.endif
.ifc \dir, v
sub r4, r3, r4, lsl #2
.else
sub r3, r3, #4
lsl r4, r4, #2
.endif
orr r6, r6, r7 // vmask[0] |= vmask[1]
1:
tst r6, #0x01
strd r6, r7, [sp]
.ifc \dir, v
ldrb r10, [r4], #4
ldrb r11, [r3], #4
.else
ldrb r10, [r3]
ldrb r11, [r3, #4]
add r3, r3, r4
.endif
beq 7f // if (!(vm & bits)) continue;
orrs r12, r10, r11
vdup.16 d31, r9 // bitdepth_min_8
beq 7f // if (!(l[0][0] | l[offset][0])) continue;
cmp r11, #0 // Check for nonzero values in l[0][0]
ldrb r6, [r5], #8 // sharp[0]
it eq
moveq r11, r10 // if (!l[0][0]) L = l[offset][0]
ldrb r12, [r5] // sharp[1]
lsr r6, r11, r6 // L >> sharp[0]
sub r5, r5, #8
cmp r12, r6
lsr r10, r11, #4 // H
add r11, r11, #2 // L + 2
it lt
movlt r6, r12 // imin(L >> sharp[0], sharp[1])
add r11, r11, r11 // 2*(L + 2)
cmp r6, #1
lsl r10, r10, r9 // H << bitdepth_min_8
it lt
movlt r6, #1 // imax(imin(), 1) = limit = I
vdup.16 d12, r10 // H << bitdepth_min_8
add r11, r11, r6 // 2*(L + 2) + limit = E
lsl r6, r6, r9 // I << bitdepth_min_8
lsl r11, r11, r9 // E << bitdepth_min_8
vdup.16 d11, r6 // I << bitdepth_min_8
vdup.16 d10, r11 // E << bitdepth_min_8
.ifc \type, y
tst r2, #0x01
beq 2f
// wd16
bl lpf_\dir\()_16_4_neon
b 8f
2:
.endif
tst r7, #0x01
beq 3f
.ifc \type, y
// wd8
bl lpf_\dir\()_8_4_neon
.else
// wd6
bl lpf_\dir\()_6_4_neon
.endif
b 8f
3:
// wd4
bl lpf_\dir\()_4_4_neon
.ifc \dir, h
b 8f
7:
// For dir h, the functions above increment r0.
// If the whole function is skipped, increment it here instead.
add r0, r0, r1, lsl #2
.else
7:
.endif
8:
ldrd r6, r7, [sp]
.ifc \type, y
lsr r2, r2, #1 // vmask[2] >>= 1
.endif
.ifc \dir, v
add r0, r0, #8
.else
// For dir h, r0 is returned incremented
.endif
lsrs r6, r6, #1 // vmask[0] >>= 1
lsr r7, r7, #1 // vmask[1] >>= 1
bne 1b
add sp, sp, #8
vpop {q4-q7}
pop {r4-r11,pc}
endfunc
.endm
lpf_func v, y
lpf_func h, y
lpf_func v, uv
lpf_func h, uv

View file

@ -0,0 +1,729 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2019, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include "src/arm/asm.S"
#include "util.S"
const right_ext_mask_buf
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
right_ext_mask:
.byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
.byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
.byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
.byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
endconst
// void dav1d_wiener_filter_h_8bpc_neon(int16_t *dst, const pixel (*left)[4],
// const pixel *src, const int16_t fh[8],
// const int w,
// const enum LrEdgeFlags edges);
function wiener_filter_h_8bpc_neon, export=1
push {r4-r5,lr}
ldrd r4, r5, [sp, #12]
vld1.16 {q0}, [r3, :128]
movw r12, #(1 << 14) - (1 << 2)
vdup.16 q14, r12
vmov.s16 q15, #2048
// Set up the src pointers to include the left edge, for LR_HAVE_LEFT, left == NULL
tst r5, #1 // LR_HAVE_LEFT
beq 1f
// LR_HAVE_LEFT
cmp r1, #0
bne 0f
// left == NULL
sub r2, r2, #3
vld1.8 {q2}, [r2]!
b 2f
0:
// LR_HAVE_LEFT, left != NULL
vld1.8 {q2}, [r2]!
vld1.32 {d3[1]}, [r1]
// Move r2 back to account for the last 3 bytes we loaded earlier,
// which we'll shift out.
sub r2, r2, #3
vext.8 q2, q1, q2, #13
b 2f
1:
vld1.8 {q2}, [r2]!
// !LR_HAVE_LEFT, fill q1 with the leftmost byte
// and shift q2 to have 3x the first byte at the front.
vdup.8 q1, d4[0]
// Move r2 back to account for the last 3 bytes we loaded before,
// which we shifted out.
sub r2, r2, #3
vext.8 q2, q1, q2, #13
2:
vmovl.u8 q1, d4
vmovl.u8 q2, d5
tst r5, #2 // LR_HAVE_RIGHT
bne 4f
3: // !LR_HAVE_RIGHT
// Check whether we need to pad the right edge
cmp r4, #11
bge 4f // If w >= 11, all used input pixels are valid
// 1 <= w < 11, w+3 pixels valid in q1-q2. For w=9 or w=10,
// this ends up called again; it's not strictly needed in those
// cases (we pad enough here), but keeping the code as simple as possible.
// The padding pixel is q1/2.h[w+2]. r2 points at the next input, ie
// q1/2.h[16]. Thus read from r2[w-14] to find the padding pixel.
sub r12, r4, #14
// Insert padding in q1/2.h[w+3] onwards; fuse the +3 (*2) into the
// buffer pointer.
movrel_local r3, right_ext_mask, -6
ldrb r12, [r2, r12]
sub r3, r3, r4, lsl #1
vdup.16 q13, r12
vld1.8 {q10, q11}, [r3]
vbit q1, q13, q10
vbit q2, q13, q11
4: // Loop horizontally
vext.8 q10, q1, q2, #4
vext.8 q11, q1, q2, #8
vext.8 q9, q1, q2, #2
vext.8 q12, q1, q2, #10
vext.8 q13, q1, q2, #12
vext.8 q8, q1, q2, #6
vadd.i16 q10, q10, q11
vadd.i16 q9, q9, q12
vadd.i16 q13, q13, q1
vshl.s16 q1, q8, #7
vmul.s16 q3, q8, d0[3]
vmla.s16 q3, q10, d1[0]
vmla.s16 q3, q9, d1[1]
vmla.s16 q3, q13, d1[2]
vsub.s16 q1, q1, q14
vqadd.s16 q3, q3, q1
vshr.s16 q3, q3, #3
vadd.s16 q3, q3, q15
subs r4, r4, #8
vst1.16 {q3}, [r0, :128]!
ble 9f
vmov q1, q2
vld1.8 {d4}, [r2]!
tst r5, #2 // LR_HAVE_RIGHT
vmovl.u8 q2, d4
bne 4b // If we don't need to pad, just keep filtering.
b 3b // If we need to pad, check how many pixels we have left.
9:
pop {r4-r5,pc}
endfunc
// void dav1d_wiener_filter_v_8bpc_neon(pixel *dst, int16_t **ptrs,
// const int16_t fv[8], const int w);
function wiener_filter_v_8bpc_neon, export=1
push {r4-r9,lr}
vpush {q4-q6}
vld1.16 {q0}, [r2, :128]
ldrd r4, r5, [r1]
ldrd r6, r7, [r1, #8]
ldrd r8, r9, [r1, #16]
1:
vld1.16 {q1, q2}, [r4, :128]!
vld1.16 {q8, q9}, [r9, :128]!
vld1.16 {q5, q6}, [r5, :128]!
vld1.16 {q10, q11}, [r6, :128]!
vld1.16 {q12, q13}, [r8, :128]!
vld1.16 {q14, q15}, [r7, :128]!
subs r3, r3, #16
vadd.i16 q1, q1, q8
vadd.i16 q2, q2, q9
vadd.i16 q5, q5, q8
vadd.i16 q6, q6, q9
vadd.i16 q10, q10, q12
vadd.i16 q11, q11, q13
vmull.s16 q3, d28, d0[3]
vmlal.s16 q3, d2, d0[0]
vmlal.s16 q3, d10, d0[1]
vmlal.s16 q3, d20, d0[2]
vmull.s16 q4, d29, d0[3]
vmlal.s16 q4, d3, d0[0]
vmlal.s16 q4, d11, d0[1]
vmlal.s16 q4, d21, d0[2]
vmull.s16 q8, d30, d0[3]
vmlal.s16 q8, d4, d0[0]
vmlal.s16 q8, d12, d0[1]
vmlal.s16 q8, d22, d0[2]
vmull.s16 q9, d31, d0[3]
vmlal.s16 q9, d5, d0[0]
vmlal.s16 q9, d13, d0[1]
vmlal.s16 q9, d23, d0[2]
vqrshrun.s32 d6, q3, #11
vqrshrun.s32 d7, q4, #11
vqrshrun.s32 d16, q8, #11
vqrshrun.s32 d17, q9, #11
vqmovun.s16 d6, q3
vqmovun.s16 d7, q8
vst1.8 {q3}, [r0, :128]!
bgt 1b
// Shift the pointers, but only update the first 5; the 6th pointer is
// kept as it was before (and the 7th is implicitly identical to the
// 6th).
ldrd r4, r5, [r1, #4]
ldrd r6, r7, [r1, #12]
ldr r8, [r1, #20]
strd r4, r5, [r1]
strd r6, r7, [r1, #8]
str r8, [r1, #16]
vpop {q4-q6}
pop {r4-r9,pc}
endfunc
// void dav1d_wiener_filter_hv_8bpc_neon(pixel *dst, const pixel (*left)[4],
// const pixel *src,
// const int16_t filter[2][8],
// const int w,
// const enum LrEdgeFlags edges,
// int16_t **ptrs);
function wiener_filter_hv_8bpc_neon, export=1
push {r4-r11,lr}
vpush {q4-q7}
ldrd r4, r5, [sp, #100]
ldr lr, [sp, #108]
vld1.16 {q0, q1}, [r3, :128]
movw r12, #(1 << 14) - (1 << 2)
vdup.16 q14, r12
vmov.s16 q15, #2048
ldrd r6, r7, [lr]
ldrd r8, r9, [lr, #8]
ldrd r10, r11, [lr, #16]
ldr r12, [lr, #24]
// Set up the src pointers to include the left edge, for LR_HAVE_LEFT, left == NULL
tst r5, #1 // LR_HAVE_LEFT
beq 1f
// LR_HAVE_LEFT
cmp r1, #0
bne 0f
// left == NULL
sub r2, r2, #3
vld1.8 {q2}, [r2]!
b 2f
0:
// LR_HAVE_LEFT, left != NULL
vld1.8 {q2}, [r2]!
vld1.32 {d3[1]}, [r1]
// Move r2 back to account for the last 3 bytes we loaded earlier,
// which we'll shift out.
sub r2, r2, #3
vext.8 q2, q1, q2, #13
b 2f
1:
vld1.8 {q2}, [r2]!
// !LR_HAVE_LEFT, fill q1 with the leftmost byte
// and shift q2 to have 3x the first byte at the front.
vdup.8 q3, d4[0]
// Move r2 back to account for the last 3 bytes we loaded before,
// which we shifted out.
sub r2, r2, #3
vext.8 q2, q3, q2, #13
2:
vmovl.u8 q3, d5
vmovl.u8 q2, d4
tst r5, #2 // LR_HAVE_RIGHT
bne 4f
3: // !LR_HAVE_RIGHT
// Check whether we need to pad the right edge
cmp r4, #11
bge 4f // If w >= 11, all used input pixels are valid
// 1 <= w < 11, w+3 pixels valid in q1-q2. For w=9 or w=10,
// this ends up called again; it's not strictly needed in those
// cases (we pad enough here), but keeping the code as simple as possible.
// The padding pixel is q1/2.h[w+2]. r2 points at the next input, ie
// q1/2.h[16]. Thus read from r2[w-14] to find the padding pixel.
sub lr, r4, #14
// Insert padding in q1/2.h[w+3] onwards; fuse the +3 (*2) into the
// buffer pointer.
movrel_local r3, right_ext_mask, -6
ldrb lr, [r2, lr]
sub r3, r3, r4, lsl #1
vdup.16 q13, lr
vld1.8 {q10, q11}, [r3]
vbit q2, q13, q10
vbit q3, q13, q11
4: // Loop horizontally
vext.8 q10, q2, q3, #4
vext.8 q11, q2, q3, #8
vext.8 q9, q2, q3, #2
vext.8 q12, q2, q3, #10
vext.8 q13, q2, q3, #12
vext.8 q8, q2, q3, #6
vadd.i16 q10, q10, q11
vadd.i16 q9, q9, q12
vadd.i16 q13, q13, q2
vld1.16 {q6}, [r7, :128]!
vshl.s16 q2, q8, #7
vld1.16 {q11}, [r11, :128]!
vsub.s16 q2, q2, q14
vld1.16 {q7}, [r8, :128]!
vmul.s16 q4, q8, d0[3]
vmla.s16 q4, q10, d1[0]
vmla.s16 q4, q9, d1[1]
vmla.s16 q4, q13, d1[2]
vld1.16 {q10}, [r10, :128]!
vqadd.s16 q4, q4, q2
vld1.16 {q9}, [r9, :128]!
vshr.s16 q4, q4, #3
vld1.16 {q5}, [r6, :128]!
vadd.s16 q4, q4, q15
vadd.s16 q6, q6, q11
vadd.s16 q7, q7, q10
vadd.s16 q5, q5, q4
vmull.s16 q8, d18, d2[3]
vmlal.s16 q8, d12, d2[1]
vmlal.s16 q8, d14, d2[2]
vmlal.s16 q8, d10, d2[0]
vmull.s16 q9, d19, d2[3]
vmlal.s16 q9, d13, d2[1]
vmlal.s16 q9, d15, d2[2]
vmlal.s16 q9, d11, d2[0]
vqrshrun.s32 d16, q8, #11
vqrshrun.s32 d17, q9, #11
vst1.16 {q4}, [r12, :128]!
vqmovun.s16 d16, q8
subs r4, r4, #8
vst1.8 {d16}, [r0, :64]!
ble 9f
vmov q2, q3
vld1.8 {d6}, [r2]!
tst r5, #2 // LR_HAVE_RIGHT
vmovl.u8 q3, d6
bne 4b // If we don't need to pad, just keep filtering.
b 3b // If we need to pad, check how many pixels we have left.
9:
// Reload ptrs from arguments on the stack
ldr lr, [sp, #108]
// Rotate the window of pointers. Shift the 6 pointers downwards one step.
ldrd r6, r7, [lr, #4]
ldrd r8, r9, [lr, #12]
ldrd r10, r11, [lr, #20]
strd r6, r7, [lr]
strd r8, r9, [lr, #8]
strd r10, r11, [lr, #16]
// The topmost pointer, ptrs[6], which isn't used as input, is set to
// ptrs[0], which will be used as output for the next _hv call.
// At the start of the filtering, the caller may set ptrs[6] to the
// right next buffer to fill in, instead.
str r6, [lr, #24]
vpop {q4-q7}
pop {r4-r11,pc}
endfunc
#include "looprestoration_tmpl.S"
// void dav1d_sgr_box3_row_h_8bpc_neon(int32_t *sumsq, int16_t *sum,
// const pixel (*left)[4],
// const pixel *src, const int w,
// const enum LrEdgeFlags edges);
function sgr_box3_row_h_8bpc_neon, export=1
push {r4-r5,lr}
ldrd r4, r5, [sp, #12]
add r4, r4, #2 // w += 2
tst r5, #1 // LR_HAVE_LEFT
beq 1f
cmp r2, #0
bne 0f
// LR_HAVE_LEFT && left == NULL
sub r3, r3, #2
vld1.8 {q0}, [r3]!
b 2f
0:
// LR_HAVE_LEFT, left != NULL
vld1.8 {q0}, [r3]!
vld1.32 {d3[]}, [r2]
// Move r3 back to account for the last 2 bytes we loaded earlier,
// which we'll shift out.
sub r3, r3, #2
vext.8 q0, q1, q0, #14
b 2f
1:
vld1.8 {q0}, [r3]!
// !LR_HAVE_LEFT, fill q1 with the leftmost byte
// and shift q0 to have 2x the first byte at the front.
vdup.8 q1, d0[0]
// Move r3 back to account for the last 2 bytes we loaded before,
// which we shifted out.
sub r3, r3, #2
vext.8 q0, q1, q0, #14
2:
vmull.u8 q1, d0, d0
vmull.u8 q2, d1, d1
tst r5, #2 // LR_HAVE_RIGHT
bne 4f
// If we'll need to pad the right edge, load that byte to pad with
// here since we can find it pretty easily from here.
sub lr, r4, #(2 + 16 - 2 + 1)
ldrb lr, [r3, lr]
// Fill q14 with the right padding pixel
vdup.8 q14, lr
3: // !LR_HAVE_RIGHT
// Check whether we need to pad the right edge
cmp r4, #10
bge 4f // If w >= 10, all used input pixels are valid
// 1 <= w < 10, w pixels valid in q0. For w=9, this ends up called
// again; it's not strictly needed in those cases (we pad enough here),
// but keeping the code as simple as possible.
// Insert padding in q0.b[w] onwards
movrel_local lr, right_ext_mask
sub lr, lr, r4
vld1.8 {q13}, [lr]
vbit q0, q14, q13
// Update the precalculated squares
vmull.u8 q1, d0, d0
vmull.u8 q2, d1, d1
4: // Loop horizontally
vext.8 d16, d0, d1, #1
vext.8 d17, d0, d1, #2
vaddl.u8 q3, d0, d16
vext.8 q9, q1, q2, #2
vaddw.u8 q3, q3, d17
vext.8 q10, q1, q2, #4
vaddl.u16 q12, d2, d18
vaddl.u16 q13, d3, d19
vaddw.u16 q12, q12, d20
vaddw.u16 q13, q13, d21
subs r4, r4, #8
vst1.16 {q3}, [r1, :128]!
vst1.32 {q12, q13}, [r0, :128]!
ble 9f
tst r5, #2 // LR_HAVE_RIGHT
vld1.8 {d6}, [r3]!
vmov q1, q2
vext.8 q0, q0, q3, #8
vmull.u8 q2, d6, d6
bne 4b // If we don't need to pad, just keep summing.
b 3b // If we need to pad, check how many pixels we have left.
9:
pop {r4-r5,pc}
endfunc
// void dav1d_sgr_box5_row_h_8bpc_neon(int32_t *sumsq, int16_t *sum,
// const pixel (*left)[4],
// const pixel *src, const int w,
// const enum LrEdgeFlags edges);
function sgr_box5_row_h_8bpc_neon, export=1
push {r4-r5,lr}
ldrd r4, r5, [sp, #12]
add r4, r4, #2 // w += 2
tst r5, #1 // LR_HAVE_LEFT
beq 1f
cmp r2, #0
bne 0f
// LR_HAVE_LEFT && left == NULL
sub r3, r3, #3
vld1.8 {q0}, [r3]!
b 2f
0:
// LR_HAVE_LEFT, left != NULL
vld1.8 {q0}, [r3]!
vld1.32 {d3[]}, [r2]
// Move r3 back to account for the last 3 bytes we loaded earlier,
// which we'll shift out.
sub r3, r3, #3
vext.8 q0, q1, q0, #13
b 2f
1:
vld1.8 {q0}, [r3]!
// !LR_HAVE_LEFT, fill q1 with the leftmost byte
// and shift q0 to have 3x the first byte at the front.
vdup.8 q1, d0[0]
// Move r3 back to account for the last 3 bytes we loaded before,
// which we shifted out.
sub r3, r3, #3
vext.8 q0, q1, q0, #13
2:
vmull.u8 q1, d0, d0
vmull.u8 q2, d1, d1
tst r5, #2 // LR_HAVE_RIGHT
bne 4f
// If we'll need to pad the right edge, load that byte to pad with
// here since we can find it pretty easily from here.
sub lr, r4, #(2 + 16 - 3 + 1)
ldrb lr, [r3, lr]
// Fill q14 with the right padding pixel
vdup.8 q14, lr
3: // !LR_HAVE_RIGHT
// Check whether we need to pad the right edge
cmp r4, #11
bge 4f // If w >= 11, all used input pixels are valid
// 1 <= w < 11, w+1 pixels valid in q0. For w=9 or w=10,
// this ends up called again; it's not strictly needed in those
// cases (we pad enough here), but keeping the code as simple as possible.
// Insert padding in q0.b[w+1] onwards; fuse the +1 into the
// buffer pointer.
movrel_local lr, right_ext_mask, -1
sub lr, lr, r4
vld1.8 {q13}, [lr]
vbit q0, q14, q13
// Update the precalculated squares
vmull.u8 q1, d0, d0
vmull.u8 q2, d1, d1
4: // Loop horizontally
vext.8 d16, d0, d1, #1
vext.8 d17, d0, d1, #2
vext.8 d18, d0, d1, #3
vext.8 d19, d0, d1, #4
vaddl.u8 q3, d0, d16
vaddl.u8 q12, d17, d18
vaddw.u8 q3, q3, d19
vadd.u16 q3, q3, q12
vext.8 q8, q1, q2, #2
vext.8 q9, q1, q2, #4
vext.8 q10, q1, q2, #6
vext.8 q11, q1, q2, #8
vaddl.u16 q12, d2, d16
vaddl.u16 q13, d3, d17
vaddl.u16 q8, d18, d20
vaddl.u16 q9, d19, d21
vaddw.u16 q12, q12, d22
vaddw.u16 q13, q13, d23
vadd.i32 q12, q12, q8
vadd.i32 q13, q13, q9
subs r4, r4, #8
vst1.16 {q3}, [r1, :128]!
vst1.32 {q12, q13}, [r0, :128]!
ble 9f
tst r5, #2 // LR_HAVE_RIGHT
vld1.8 {d6}, [r3]!
vmov q1, q2
vext.8 q0, q0, q3, #8
vmull.u8 q2, d6, d6
bne 4b // If we don't need to pad, just keep summing.
b 3b // If we need to pad, check how many pixels we have left.
9:
pop {r4-r5,pc}
endfunc
// void dav1d_sgr_box35_row_h_8bpc_neon(int32_t *sumsq3, int16_t *sum3,
// int32_t *sumsq5, int16_t *sum5,
// const pixel (*left)[4],
// const pixel *src, const int w,
// const enum LrEdgeFlags edges);
function sgr_box35_row_h_8bpc_neon, export=1
push {r4-r7,lr}
ldrd r4, r5, [sp, #20]
ldrd r6, r7, [sp, #28]
add r6, r6, #2 // w += 2
tst r7, #1 // LR_HAVE_LEFT
beq 1f
cmp r4, #0
bne 0f
// LR_HAVE_LEFT && left == NULL
sub r5, r5, #3
vld1.8 {q0}, [r5]!
b 2f
0:
// LR_HAVE_LEFT, left != NULL
vld1.8 {q0}, [r5]!
vld1.32 {d3[]}, [r4]
// Move r3 back to account for the last 3 bytes we loaded earlier,
// which we'll shift out.
sub r5, r5, #3
vext.8 q0, q1, q0, #13
b 2f
1:
vld1.8 {q0}, [r5]!
// !LR_HAVE_LEFT, fill q1 with the leftmost byte
// and shift q0 to have 3x the first byte at the front.
vdup.8 q1, d0[0]
// Move r3 back to account for the last 3 bytes we loaded before,
// which we shifted out.
sub r5, r5, #3
vext.8 q0, q1, q0, #13
2:
vmull.u8 q1, d0, d0
vmull.u8 q2, d1, d1
tst r7, #2 // LR_HAVE_RIGHT
bne 4f
// If we'll need to pad the right edge, load that byte to pad with
// here since we can find it pretty easily from here.
sub lr, r6, #(2 + 16 - 3 + 1)
ldrb lr, [r5, lr]
// Fill q14 with the right padding pixel
vdup.8 q14, lr
3: // !LR_HAVE_RIGHT
// Check whether we need to pad the right edge
cmp r6, #11
bge 4f // If w >= 11, all used input pixels are valid
// 1 <= w < 11, w+1 pixels valid in q0. For w=9 or w=10,
// this ends up called again; it's not strictly needed in those
// cases (we pad enough here), but keeping the code as simple as possible.
// Insert padding in q0.b[w+1] onwards; fuse the +1 into the
// buffer pointer.
movrel_local lr, right_ext_mask, -1
sub lr, lr, r6
vld1.8 {q13}, [lr]
vbit q0, q14, q13
// Update the precalculated squares
vmull.u8 q1, d0, d0
vmull.u8 q2, d1, d1
4: // Loop horizontally
vext.8 d16, d0, d1, #1
vext.8 d17, d0, d1, #2
vext.8 d18, d0, d1, #3
vext.8 d19, d0, d1, #4
vaddl.u8 q3, d16, d17
vaddl.u8 q12, d0, d19
vaddw.u8 q3, q3, d18
vext.8 q8, q1, q2, #2
vext.8 q9, q1, q2, #4
vext.8 q10, q1, q2, #6
vext.8 q11, q1, q2, #8
vst1.16 {q3}, [r1, :128]!
vadd.u16 q3, q3, q12
vaddl.u16 q12, d16, d18
vaddl.u16 q13, d17, d19
vaddl.u16 q8, d2, d22
vaddl.u16 q9, d3, d23
vaddw.u16 q12, q12, d20
vaddw.u16 q13, q13, d21
vst1.32 {q12, q13}, [r0, :128]!
vadd.i32 q12, q12, q8
vadd.i32 q13, q13, q9
subs r6, r6, #8
vst1.16 {q3}, [r3, :128]!
vst1.32 {q12, q13}, [r2, :128]!
ble 9f
tst r7, #2 // LR_HAVE_RIGHT
vld1.8 {d6}, [r5]!
vmov q1, q2
vext.8 q0, q0, q3, #8
vmull.u8 q2, d6, d6
bne 4b // If we don't need to pad, just keep summing.
b 3b // If we need to pad, check how many pixels we have left.
9:
pop {r4-r7,pc}
endfunc
sgr_funcs 8

View file

@ -0,0 +1,757 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2020, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include "src/arm/asm.S"
#include "util.S"
const right_ext_mask_buf
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
right_ext_mask:
.byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
.byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
.byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
.byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
endconst
// void dav1d_wiener_filter_h_16bpc_neon(int16_t *dst, const pixel (*left)[4],
// const pixel *src, const int16_t fh[8],
// const int w,
// enum LrEdgeFlags edges,
// const int bitdepth_max);
function wiener_filter_h_16bpc_neon, export=1
push {r4-r6,lr}
ldrd r4, r5, [sp, #16]
ldr r6, [sp, #24] // bitdepth_max
vld1.16 {q0}, [r3, :128]
clz r6, r6
vmov.i32 q14, #1
sub r12, r6, #38 // -(bitdepth + 6)
sub r6, r6, #25 // -round_bits_h
neg r12, r12 // bitdepth + 6
vdup.32 q1, r12
vdup.32 q13, r6 // -round_bits_h
vmov.i16 q15, #8192
vshl.u32 q14, q14, q1 // 1 << (bitdepth + 6)
vmvn.i16 q12, #0x8000 // 0x7fff = (1 << 15) - 1
// Set up the src pointers to include the left edge, for LR_HAVE_LEFT, left == NULL
tst r5, #1 // LR_HAVE_LEFT
beq 1f
// LR_HAVE_LEFT
cmp r1, #0
bne 0f
// left == NULL
sub r2, r2, #6
vld1.16 {q2, q3}, [r2]!
b 2f
0:
// LR_HAVE_LEFT, left != NULL
vld1.16 {q2, q3}, [r2]!
vld1.16 {d3}, [r1]!
// Move r2 back to account for the last 3 pixels we loaded earlier,
// which we'll shift out.
sub r2, r2, #6
vext.8 q3, q2, q3, #10
vext.8 q2, q1, q2, #10
b 2f
1:
vld1.16 {q2, q3}, [r2]!
// !LR_HAVE_LEFT, fill q1 with the leftmost pixel
// and shift q2/q3 to have 3x the first pixel at the front.
vdup.16 q1, d4[0]
// Move r2 back to account for the last 3 pixels we loaded before,
// which we shifted out.
sub r2, r2, #6
vext.8 q3, q2, q3, #10
vext.8 q2, q1, q2, #10
2:
tst r5, #2 // LR_HAVE_RIGHT
bne 4f
3: // !LR_HAVE_RIGHT
// Check whether we need to pad the right edge
cmp r4, #11
bge 4f // If w >= 11, all used input pixels are valid
// 1 <= w < 11, w+3 pixels valid in q2-q3. For w=9 or w=10,
// this ends up called again; it's not strictly needed in those
// cases (we pad enough here), but keeping the code as simple as possible.
// The padding pixel is q1/2.h[w+2]. r2 points at the next input, ie
// q1/2.h[16]. Thus read from r2[w-14] to find the padding pixel.
sub r12, r4, #14
lsl r12, r12, #1
// Insert padding in q2/3.h[w+3] onwards; fuse the +3 (*2) into the
// buffer pointer.
movrel_local r3, right_ext_mask, -6
ldrh r12, [r2, r12]
sub r3, r3, r4, lsl #1
vdup.16 q11, r12
vld1.8 {q9, q10}, [r3]
vbit q2, q11, q9
vbit q3, q11, q10
4: // Loop horizontally
vext.8 q9, q2, q3, #4
vext.8 q10, q2, q3, #8
vext.8 q8, q2, q3, #2
vext.8 q11, q2, q3, #10
vadd.i16 q10, q10, q9
vadd.i16 q11, q11, q8
vext.8 q8, q2, q3, #12
vext.8 q9, q2, q3, #6
vadd.i16 q2, q2, q8
vmull.s16 q8, d18, d0[3]
vmlal.s16 q8, d20, d1[0]
vmlal.s16 q8, d22, d1[1]
vmlal.s16 q8, d4, d1[2]
vmull.s16 q9, d19, d0[3]
vmlal.s16 q9, d21, d1[0]
vmlal.s16 q9, d23, d1[1]
vmlal.s16 q9, d5, d1[2]
vadd.i32 q8, q8, q14
vadd.i32 q9, q9, q14
vrshl.s32 q8, q8, q13
vrshl.s32 q9, q9, q13
vqmovun.s32 d16, q8
vqmovun.s32 d17, q9
vmin.u16 q8, q8, q12
vsub.i16 q8, q8, q15
subs r4, r4, #8
vst1.16 {q8}, [r0, :128]!
ble 9f
vmov q2, q3
tst r5, #2 // LR_HAVE_RIGHT
vld1.16 {q3}, [r2]!
bne 4b // If we don't need to pad, just keep filtering.
b 3b // If we need to pad, check how many pixels we have left.
9:
pop {r4-r6,pc}
endfunc
// void dav1d_wiener_filter_v_16bpc_neon(pixel *dst, int16_t **ptrs,
// const int16_t fv[8], const int w,
// const int bitdepth_max);
function wiener_filter_v_16bpc_neon, export=1
push {r4-r9,lr}
vpush {q4-q7}
ldr lr, [sp, #92] // bitdepth_max
vld1.16 {q0}, [r2, :128]
vdup.16 q2, lr
clz lr, lr
sub lr, lr, #11 // round_bits_v
vdup.32 q1, lr
ldrd r4, r5, [r1]
ldrd r6, r7, [r1, #8]
ldrd r8, r9, [r1, #16]
vneg.s32 q1, q1 // -round_bits_v
1:
vld1.16 {q4, q5}, [r4, :128]!
vld1.16 {q6, q7}, [r5, :128]!
vld1.16 {q8, q9}, [r6, :128]!
vld1.16 {q10, q11}, [r7, :128]!
vld1.16 {q12, q13}, [r8, :128]!
vld1.16 {q14, q15}, [r9, :128]!
subs r3, r3, #16
vmull.s16 q3, d8, d0[0]
vmlal.s16 q3, d12, d0[1]
vmlal.s16 q3, d16, d0[2]
vmlal.s16 q3, d20, d0[3]
vmlal.s16 q3, d24, d1[0]
vmlal.s16 q3, d28, d1[1]
vmlal.s16 q3, d28, d1[2]
vmull.s16 q4, d9, d0[0]
vmlal.s16 q4, d13, d0[1]
vmlal.s16 q4, d17, d0[2]
vmlal.s16 q4, d21, d0[3]
vmlal.s16 q4, d25, d1[0]
vmlal.s16 q4, d29, d1[1]
vmlal.s16 q4, d29, d1[2]
vmull.s16 q6, d10, d0[0]
vmlal.s16 q6, d14, d0[1]
vmlal.s16 q6, d18, d0[2]
vmlal.s16 q6, d22, d0[3]
vmlal.s16 q6, d26, d1[0]
vmlal.s16 q6, d30, d1[1]
vmlal.s16 q6, d30, d1[2]
vmull.s16 q5, d11, d0[0]
vmlal.s16 q5, d15, d0[1]
vmlal.s16 q5, d19, d0[2]
vmlal.s16 q5, d23, d0[3]
vmlal.s16 q5, d27, d1[0]
vmlal.s16 q5, d31, d1[1]
vmlal.s16 q5, d31, d1[2]
vrshl.s32 q3, q3, q1 // round_bits_v
vrshl.s32 q4, q4, q1
vrshl.s32 q6, q6, q1
vrshl.s32 q5, q5, q1
vqmovun.s32 d6, q3
vqmovun.s32 d7, q4
vqmovun.s32 d8, q6
vqmovun.s32 d9, q5
vmin.u16 q3, q3, q2 // bitdepth_max
vmin.u16 q4, q4, q2
vst1.16 {q3, q4}, [r0, :128]!
bgt 1b
// Shift the pointers, but only update the first 5; the 6th pointer is
// kept as it was before (and the 7th is implicitly identical to the
// 6th).
ldrd r4, r5, [r1, #4]
ldrd r6, r7, [r1, #12]
ldr r8, [r1, #20]
strd r4, r5, [r1]
strd r6, r7, [r1, #8]
str r8, [r1, #16]
vpop {q4-q7}
pop {r4-r9,pc}
endfunc
// void dav1d_wiener_filter_hv_16bpc_neon(pixel *dst, const pixel (*left)[4],
// const pixel *src,
// const int16_t filter[2][8],
// const int w,
// const enum LrEdgeFlags edges,
// int16_t **ptrs,
// const int bitdepth_max);
function wiener_filter_hv_16bpc_neon, export=1
push {r4-r11,lr}
vpush {q4-q7}
ldrd r4, r5, [sp, #100]
ldrd r6, r7, [sp, #108]
vld1.16 {q0, q1}, [r3, :128]
vdup.16 q11, r7 // bitdepth_max
clz r7, r7
vmov.i32 q14, #1
sub r12, r7, #38 // -(bitdepth + 6)
sub lr, r7, #11 // round_bits_v
sub r7, r7, #25 // -round_bits_h
neg r12, r12 // bitdepth + 6
vdup.32 q2, r12
vdup.32 q13, r7 // -round_bits_h
vdup.32 q10, lr // round_bits_v
mov lr, r6
vmov.i16 q15, #8192
vshl.u32 q14, q14, q2 // 1 << (bitdepth + 6)
vneg.s32 q10, q10 // -round_bits_v
ldrd r6, r7, [lr]
ldrd r8, r9, [lr, #8]
ldrd r10, r11, [lr, #16]
ldr r12, [lr, #24]
// Set up the src pointers to include the left edge, for LR_HAVE_LEFT, left == NULL
tst r5, #1 // LR_HAVE_LEFT
beq 1f
// LR_HAVE_LEFT
cmp r1, #0
bne 0f
// left == NULL
sub r2, r2, #6
vld1.16 {q2, q3}, [r2]!
b 2f
0:
// LR_HAVE_LEFT, left != NULL
vld1.16 {q2, q3}, [r2]!
vld1.16 {d9}, [r1]!
// Move r2 back to account for the last 3 pixels we loaded earlier,
// which we'll shift out.
sub r2, r2, #6
vext.8 q3, q2, q3, #10
vext.8 q2, q4, q2, #10
b 2f
1:
vld1.16 {q2, q3}, [r2]!
// !LR_HAVE_LEFT, fill q1 with the leftmost pixel
// and shift q2/q3 to have 3x the first pixel at the front.
vdup.16 q4, d4[0]
// Move r2 back to account for the last 3 pixels we loaded before,
// which we shifted out.
sub r2, r2, #6
vext.8 q3, q2, q3, #10
vext.8 q2, q4, q2, #10
2:
tst r5, #2 // LR_HAVE_RIGHT
bne 4f
3: // !LR_HAVE_RIGHT
// Check whether we need to pad the right edge
cmp r4, #11
bge 4f // If w >= 11, all used input pixels are valid
// 1 <= w < 11, w+3 pixels valid in q2-q3. For w=9 or w=10,
// this ends up called again; it's not strictly needed in those
// cases (we pad enough here), but keeping the code as simple as possible.
// The padding pixel is q1/2.h[w+2]. r2 points at the next input, ie
// q1/2.h[16]. Thus read from r2[w-14] to find the padding pixel.
sub lr, r4, #14
lsl lr, lr, #1
// Insert padding in q2/3.h[w+3] onwards; fuse the +3 (*2) into the
// buffer pointer.
movrel_local r3, right_ext_mask, -6
ldrh lr, [r2, lr]
sub r3, r3, r4, lsl #1
vdup.16 q4, lr
vld1.8 {q8, q9}, [r3]
vbit q2, q4, q8
vbit q3, q4, q9
4: // Loop horizontally
vext.8 q5, q2, q3, #4
vext.8 q6, q2, q3, #8
vext.8 q4, q2, q3, #2
vext.8 q7, q2, q3, #10
vadd.i16 q6, q6, q5
vadd.i16 q7, q7, q4
vext.8 q4, q2, q3, #12
vext.8 q5, q2, q3, #6
vadd.i16 q2, q2, q4
vld1.16 {q4}, [r6, :128]!
vmull.s16 q8, d10, d0[3]
vmlal.s16 q8, d12, d1[0]
vmlal.s16 q8, d14, d1[1]
vmlal.s16 q8, d4, d1[2]
vmull.s16 q9, d11, d0[3]
vmlal.s16 q9, d13, d1[0]
vmlal.s16 q9, d15, d1[1]
vmlal.s16 q9, d5, d1[2]
vld1.16 {q5}, [r7, :128]!
vmvn.i16 q12, #0x8000 // 0x7fff = (1 << 15) - 1
vadd.i32 q8, q8, q14
vadd.i32 q9, q9, q14
vld1.16 {q6}, [r8, :128]!
vrshl.s32 q8, q8, q13
vrshl.s32 q9, q9, q13
vqmovun.s32 d16, q8
vqmovun.s32 d17, q9
vld1.16 {q7}, [r9, :128]!
vmin.u16 q8, q8, q12
vld1.16 {q9}, [r10, :128]!
vsub.i16 q8, q8, q15
vld1.16 {q2}, [r11, :128]!
vmull.s16 q12, d8, d2[0]
vmlal.s16 q12, d10, d2[1]
vmlal.s16 q12, d12, d2[2]
vmlal.s16 q12, d14, d2[3]
vmlal.s16 q12, d18, d3[0]
vmlal.s16 q12, d4, d3[1]
vmlal.s16 q12, d16, d3[2]
vmull.s16 q4, d9, d2[0]
vmlal.s16 q4, d11, d2[1]
vmlal.s16 q4, d13, d2[2]
vmlal.s16 q4, d15, d2[3]
vmlal.s16 q4, d19, d3[0]
vmlal.s16 q4, d5, d3[1]
vmlal.s16 q4, d17, d3[2]
vrshl.s32 q12, q12, q10 // round_bits_v
vrshl.s32 q4, q4, q10
vqmovun.s32 d24, q12
vqmovun.s32 d25, q4
vst1.16 {q8}, [r12, :128]!
vmin.u16 q12, q12, q11 // bitdepth_max
subs r4, r4, #8
vst1.16 {q12}, [r0, :128]!
ble 9f
vmov q2, q3
tst r5, #2 // LR_HAVE_RIGHT
vld1.16 {q3}, [r2]!
bne 4b // If we don't need to pad, just keep filtering.
b 3b // If we need to pad, check how many pixels we have left.
9:
// Reload ptrs from arguments on the stack
ldr lr, [sp, #108]
// Rotate the window of pointers. Shift the 6 pointers downwards one step.
ldrd r6, r7, [lr, #4]
ldrd r8, r9, [lr, #12]
ldrd r10, r11, [lr, #20]
strd r6, r7, [lr]
strd r8, r9, [lr, #8]
strd r10, r11, [lr, #16]
// The topmost pointer, ptrs[6], which isn't used as input, is set to
// ptrs[0], which will be used as output for the next _hv call.
// At the start of the filtering, the caller may set ptrs[6] to the
// right next buffer to fill in, instead.
str r6, [lr, #24]
vpop {q4-q7}
pop {r4-r11,pc}
endfunc
#include "looprestoration_tmpl.S"
// void dav1d_sgr_box3_row_h_16bpc_neon(int32_t *sumsq, int16_t *sum,
// const pixel (*left)[4],
// const pixel *src, const int w,
// const enum LrEdgeFlags edges);
function sgr_box3_row_h_16bpc_neon, export=1
push {r4-r5,lr}
ldrd r4, r5, [sp, #12]
add r4, r4, #2 // w += 2
tst r5, #1 // LR_HAVE_LEFT
beq 1f
cmp r2, #0
bne 0f
// LR_HAVE_LEFT && left == NULL
sub r3, r3, #4
vld1.8 {q0, q1}, [r3]!
b 2f
0:
// LR_HAVE_LEFT, left != NULL
vld1.8 {q0, q1}, [r3]!
vld1.16 {d5}, [r2]
// Move r3 back to account for the last 2 pixels we loaded earlier,
// which we'll shift out.
sub r3, r3, #4
vext.8 q1, q0, q1, #12
vext.8 q0, q2, q0, #12
b 2f
1:
vld1.8 {q0, q1}, [r3]!
// !LR_HAVE_LEFT, fill q1 with the leftmost pixel
// and shift q0/q1 to have 2x the first pixel at the front.
vdup.16 q2, d0[0]
// Move r3 back to account for the last 2 pixels we loaded before,
// which we shifted out.
sub r3, r3, #4
vext.8 q1, q0, q1, #12
vext.8 q0, q2, q0, #12
2:
tst r5, #2 // LR_HAVE_RIGHT
bne 4f
// If we'll need to pad the right edge, load that pixel to pad with
// here since we can find it pretty easily from here.
sub lr, r4, #(2 + 16 - 2 + 1)
lsl lr, lr, #1
ldrh lr, [r3, lr]
// Fill q14 with the right padding pixel
vdup.16 q14, lr
3: // !LR_HAVE_RIGHT
// Check whether we need to pad the right edge
cmp r4, #10
bge 4f // If w >= 10, all used input pixels are valid
// 1 <= w < 10, w pixels valid in q0-q1. For w=9, this ends up called
// again; it's not strictly needed in those cases (we pad enough here),
// but keeping the code as simple as possible.
// Insert padding in q0.h[w] onwards
movrel_local lr, right_ext_mask
sub lr, lr, r4, lsl #1
vld1.8 {q12, q13}, [lr]
vbit q0, q14, q12
vbit q1, q14, q13
4: // Loop horizontally
vext.8 q8, q0, q1, #2
vext.8 q9, q0, q1, #4
vadd.i16 q2, q0, q8
vmull.u16 q12, d0, d0
vmlal.u16 q12, d16, d16
vmlal.u16 q12, d18, d18
vadd.i16 q2, q2, q9
vmull.u16 q13, d1, d1
vmlal.u16 q13, d17, d17
vmlal.u16 q13, d19, d19
subs r4, r4, #8
vst1.16 {q2}, [r1, :128]!
vst1.32 {q12, q13}, [r0, :128]!
ble 9f
tst r5, #2 // LR_HAVE_RIGHT
vmov q0, q1
vld1.16 {q1}, [r3]!
bne 4b // If we don't need to pad, just keep summing.
b 3b // If we need to pad, check how many pixels we have left.
9:
pop {r4-r5,pc}
endfunc
// void dav1d_sgr_box5_row_h_16bpc_neon(int32_t *sumsq, int16_t *sum,
// const pixel (*left)[4],
// const pixel *src, const int w,
// const enum LrEdgeFlags edges);
function sgr_box5_row_h_16bpc_neon, export=1
push {r4-r5,lr}
ldrd r4, r5, [sp, #12]
add r4, r4, #2 // w += 2
tst r5, #1 // LR_HAVE_LEFT
beq 1f
cmp r2, #0
bne 0f
// LR_HAVE_LEFT && left == NULL
sub r3, r3, #6
vld1.8 {q0, q1}, [r3]!
b 2f
0:
// LR_HAVE_LEFT, left != NULL
vld1.8 {q0, q1}, [r3]!
vld1.16 {d5}, [r2]
// Move r3 back to account for the last 2 pixels we loaded earlier,
// which we'll shift out.
sub r3, r3, #6
vext.8 q1, q0, q1, #10
vext.8 q0, q2, q0, #10
b 2f
1:
vld1.8 {q0, q1}, [r3]!
// !LR_HAVE_LEFT, fill q1 with the leftmost pixel
// and shift q0/q1 to have 3x the first pixel at the front.
vdup.16 q2, d0[0]
// Move r3 back to account for the last 3 pixels we loaded before,
// which we shifted out.
sub r3, r3, #6
vext.8 q1, q0, q1, #10
vext.8 q0, q2, q0, #10
2:
tst r5, #2 // LR_HAVE_RIGHT
bne 4f
// If we'll need to pad the right edge, load that pixel to pad with
// here since we can find it pretty easily from here.
sub lr, r4, #(2 + 16 - 3 + 1)
lsl lr, lr, #1
ldrh lr, [r3, lr]
// Fill q14 with the right padding pixel
vdup.16 q14, lr
3: // !LR_HAVE_RIGHT
// Check whether we need to pad the right edge
cmp r4, #11
bge 4f // If w >= 11, all used input pixels are valid
// 1 <= w < 11, w+1 pixels valid in q0-q1. For w=9 or w=10,
// this ends up called again; it's not strictly needed in those
// cases (we pad enough here), but keeping the code as simple as possible.
// Insert padding in q0.h[w+1] onwards; fuse the +1 into the
// buffer pointer.
movrel_local lr, right_ext_mask, -2
sub lr, lr, r4, lsl #1
vld1.8 {q12, q13}, [lr]
vbit q0, q14, q12
vbit q1, q14, q13
4: // Loop horizontally
vext.8 q8, q0, q1, #2
vext.8 q9, q0, q1, #4
vadd.i16 q2, q0, q8
vmull.u16 q12, d0, d0
vmlal.u16 q12, d16, d16
vmlal.u16 q12, d18, d18
vadd.i16 q2, q2, q9
vmull.u16 q13, d1, d1
vmlal.u16 q13, d17, d17
vmlal.u16 q13, d19, d19
vext.8 q8, q0, q1, #6
vext.8 q9, q0, q1, #8
vadd.i16 q2, q2, q8
vmlal.u16 q12, d16, d16
vmlal.u16 q12, d1, d1
vadd.i16 q2, q2, q9
vmlal.u16 q13, d17, d17
vmlal.u16 q13, d19, d19
subs r4, r4, #8
vst1.16 {q2}, [r1, :128]!
vst1.32 {q12, q13}, [r0, :128]!
ble 9f
tst r5, #2 // LR_HAVE_RIGHT
vmov q0, q1
vld1.16 {q1}, [r3]!
bne 4b // If we don't need to pad, just keep summing.
b 3b // If we need to pad, check how many pixels we have left.
9:
pop {r4-r5,pc}
endfunc
// void dav1d_sgr_box35_row_h_16bpc_neon(int32_t *sumsq3, int16_t *sum3,
// int32_t *sumsq5, int16_t *sum5,
// const pixel (*left)[4],
// const pixel *src, const int w,
// const enum LrEdgeFlags edges);
function sgr_box35_row_h_16bpc_neon, export=1
push {r4-r7,lr}
ldrd r4, r5, [sp, #20]
ldrd r6, r7, [sp, #28]
add r6, r6, #2 // w += 2
tst r7, #1 // LR_HAVE_LEFT
beq 1f
cmp r4, #0
bne 0f
// LR_HAVE_LEFT && left == NULL
sub r5, r5, #6
vld1.8 {q0, q1}, [r5]!
b 2f
0:
// LR_HAVE_LEFT, left != NULL
vld1.8 {q0, q1}, [r5]!
vld1.16 {d5}, [r4]
// Move r3 back to account for the last 2 pixels we loaded earlier,
// which we'll shift out.
sub r5, r5, #6
vext.8 q1, q0, q1, #10
vext.8 q0, q2, q0, #10
b 2f
1:
vld1.8 {q0, q1}, [r5]!
// !LR_HAVE_LEFT, fill q1 with the leftmost pixel
// and shift q0/q1 to have 3x the first pixel at the front.
vdup.16 q2, d0[0]
// Move r3 back to account for the last 3 pixels we loaded before,
// which we shifted out.
sub r5, r5, #6
vext.8 q1, q0, q1, #10
vext.8 q0, q2, q0, #10
2:
tst r7, #2 // LR_HAVE_RIGHT
bne 4f
// If we'll need to pad the right edge, load that pixel to pad with
// here since we can find it pretty easily from here.
sub lr, r6, #(2 + 16 - 3 + 1)
lsl lr, lr, #1
ldrh lr, [r5, lr]
// Fill q14 with the right padding pixel
vdup.16 q14, lr
3: // !LR_HAVE_RIGHT
// Check whether we need to pad the right edge
cmp r6, #11
bge 4f // If w >= 11, all used input pixels are valid
// 1 <= w < 11, w+1 pixels valid in q0-q1. For w=9 or w=10,
// this ends up called again; it's not strictly needed in those
// cases (we pad enough here), but keeping the code as simple as possible.
// Insert padding in q0.h[w+1] onwards; fuse the +1 into the
// buffer pointer.
movrel_local lr, right_ext_mask, -2
sub lr, lr, r6, lsl #1
vld1.8 {q12, q13}, [lr]
vbit q0, q14, q12
vbit q1, q14, q13
4: // Loop horizontally
vext.8 q8, q0, q1, #2
vext.8 q9, q0, q1, #4
vext.8 q10, q0, q1, #6
vext.8 q11, q0, q1, #8
vadd.i16 q2, q8, q9
vadd.i16 q3, q0, q11
vadd.i16 q2, q2, q10
vmull.u16 q12, d16, d16
vmlal.u16 q12, d18, d18
vmlal.u16 q12, d20, d20
vmull.u16 q13, d17, d17
vmlal.u16 q13, d19, d19
vmlal.u16 q13, d21, d21
vadd.i16 q3, q3, q2
vst1.16 {q2}, [r1, :128]!
vst1.32 {q12, q13}, [r0, :128]!
vmlal.u16 q12, d0, d0
vmlal.u16 q12, d22, d22
vmlal.u16 q13, d1, d1
vmlal.u16 q13, d23, d23
subs r6, r6, #8
vst1.16 {q3}, [r3, :128]!
vst1.32 {q12, q13}, [r2, :128]!
ble 9f
tst r7, #2 // LR_HAVE_RIGHT
vmov q0, q1
vld1.16 {q1}, [r5]!
bne 4b // If we don't need to pad, just keep summing.
b 3b // If we need to pad, check how many pixels we have left.
9:
pop {r4-r7,pc}
endfunc
sgr_funcs 16

View file

@ -0,0 +1,216 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2019, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include "src/arm/asm.S"
#include "util.S"
// void dav1d_sgr_box3_row_v_neon(int32_t **sumsq, int16_t **sum,
// int32_t *sumsq_out, int16_t *sum_out,
// const int w);
function sgr_box3_row_v_neon, export=1
push {r4-r9,lr}
ldr r4, [sp, #28]
ldrd r6, r7, [r0]
ldr r0, [r0, #8]
add r4, r4, #2
ldrd r8, r9, [r1]
ldr r1, [r1, #8]
1:
vld1.32 {q8, q9}, [r6]!
vld1.32 {q10, q11}, [r7]!
vld1.16 {q14}, [r8]!
vld1.16 {q15}, [r9]!
subs r4, r4, #8
vadd.i32 q8, q8, q10
vadd.i32 q9, q9, q11
vld1.32 {q12, q13}, [r0]!
vadd.i16 q14, q14, q15
vld1.16 {q15}, [r1]!
vadd.i32 q8, q8, q12
vadd.i32 q9, q9, q13
vadd.i16 q14, q14, q15
vst1.32 {q8, q9}, [r2]!
vst1.16 {q14}, [r3]!
bgt 1b
pop {r4-r9,pc}
endfunc
// void dav1d_sgr_box5_row_v_neon(int32_t **sumsq, int16_t **sum,
// int32_t *sumsq_out, int16_t *sum_out,
// const int w);
function sgr_box5_row_v_neon, export=1
push {r4-r11,lr}
ldr lr, [sp, #36]
ldrd r4, r5, [r0]
ldrd r6, r7, [r0, #8]
ldr r0, [r0, #16]
add lr, lr, #2
ldrd r8, r9, [r1]
ldrd r10, r11, [r1, #8]
ldr r1, [r1, #16]
1:
vld1.32 {q8, q9}, [r4]!
vld1.32 {q10, q11}, [r5]!
vld1.32 {q12, q13}, [r6]!
vld1.32 {q14, q15}, [r7]!
vld1.16 {q0}, [r8]!
vld1.16 {q1}, [r9]!
vld1.16 {q2}, [r10]!
vld1.16 {q3}, [r11]!
subs lr, lr, #8
vadd.i32 q8, q8, q10
vadd.i32 q9, q9, q11
vadd.i32 q12, q12, q14
vadd.i32 q13, q13, q15
vld1.32 {q14, q15}, [r0]!
vadd.i16 q0, q0, q1
vadd.i16 q2, q2, q3
vld1.16 {q3}, [r1]!
vadd.i32 q8, q8, q12
vadd.i32 q9, q9, q13
vadd.i16 q0, q0, q2
vadd.i32 q8, q8, q14
vadd.i32 q9, q9, q15
vadd.i16 q0, q0, q3
vst1.32 {q8, q9}, [r2]!
vst1.16 {q0}, [r3]!
bgt 1b
pop {r4-r11,pc}
endfunc
// void dav1d_sgr_calc_row_ab1_neon(int32_t *a, int16_t *b,
// const int w, const int strength,
// const int bitdepth_max);
// void dav1d_sgr_calc_row_ab2_neon(int32_t *a, int16_t *b,
// const int w, const int strength,
// const int bitdepth_max);
function sgr_calc_row_ab1_neon, export=1
push {r4-r7,lr}
vpush {q4-q7}
ldr r4, [sp, #84]
clz r6, r4
vmov.i32 q15, #9 // n
movw r5, #455
b sgr_calc_ab_neon
endfunc
function sgr_calc_row_ab2_neon, export=1
push {r4-r7,lr}
vpush {q4-q7}
ldr r4, [sp, #84]
clz r6, r4
vmov.i32 q15, #25 // n
mov r5, #164
endfunc
function sgr_calc_ab_neon
movrel r12, X(sgr_x_by_x)
sub r6, r6, #24 // -bitdepth_min_8
vld1.8 {q8, q9}, [r12, :128]!
add r7, r6, r6 // -2*bitdepth_min_8
vmov.i8 q11, #5
vmov.i8 d10, #55 // idx of last 5
vld1.8 {q10}, [r12, :128]
vmov.i8 d11, #72 // idx of last 4
vmov.i8 d12, #101 // idx of last 3
vmov.i8 d13, #169 // idx of last 2
vmov.i8 d14, #254 // idx of last 1
vmov.i8 d15, #32 // elements consumed in first vtbl
add r2, r2, #2 // w += 2
vdup.32 q12, r3
vsub.i8 q8, q8, q11
vsub.i8 q9, q9, q11
vsub.i8 q10, q10, q11
vdup.32 q13, r7 // -2*bitdepth_min_8
1:
vld1.32 {q0, q1}, [r0, :128] // a
vld1.16 {q2}, [r1, :128] // b
vdup.16 q14, r6 // -bitdepth_min_8
subs r2, r2, #8
vrshl.s32 q0, q0, q13
vrshl.s32 q1, q1, q13
vrshl.s16 q4, q2, q14
vmul.i32 q0, q0, q15 // a * n
vmul.i32 q1, q1, q15 // a * n
vmull.u16 q3, d8, d8 // b * b
vmull.u16 q4, d9, d9 // b * b
vqsub.u32 q0, q0, q3 // imax(a * n - b * b, 0)
vqsub.u32 q1, q1, q4 // imax(a * n - b * b, 0)
vmul.i32 q0, q0, q12 // p * s
vmul.i32 q1, q1, q12 // p * s
vqshrn.u32 d0, q0, #16
vqshrn.u32 d1, q1, #16
vqrshrn.u16 d0, q0, #4 // imin(z, 255)
vcgt.u8 d2, d0, d10 // = -1 if sgr_x_by_x[d0] < 5
vcgt.u8 d3, d0, d11 // = -1 if sgr_x_by_x[d0] < 4
vtbl.8 d1, {q8, q9}, d0
vcgt.u8 d6, d0, d12 // = -1 if sgr_x_by_x[d0] < 3
vsub.i8 d9, d0, d15 // indices for vtbx
vcgt.u8 d7, d0, d13 // = -1 if sgr_x_by_x[d0] < 2
vadd.i8 d2, d2, d3
vtbx.8 d1, {q10}, d9
vcgt.u8 d8, d0, d14 // = -1 if sgr_x_by_x[d0] < 1
vadd.i8 d6, d6, d7
vadd.i8 d8, d8, d22
vadd.i8 d2, d2, d6
vadd.i8 d1, d1, d8
vadd.i8 d1, d1, d2
vmovl.u8 q0, d1 // x
vdup.32 q14, r5 // one_by_x
vmull.u16 q1, d0, d4 // x * BB[i]
vmull.u16 q2, d1, d5 // x * BB[i]
vmul.i32 q1, q1, q14 // x * BB[i] * sgr_one_by_x
vmul.i32 q2, q2, q14 // x * BB[i] * sgr_one_by_x
vrshr.s32 q1, q1, #12 // AA[i]
vrshr.s32 q2, q2, #12 // AA[i]
vst1.32 {q1, q2}, [r0, :128]!
vst1.16 {q0}, [r1, :128]!
bgt 1b
vpop {q4-q7}
pop {r4-r7,pc}
endfunc

View file

@ -0,0 +1,410 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2019, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include "src/arm/asm.S"
#define FILTER_OUT_STRIDE 384
.macro sgr_funcs bpc
// void dav1d_sgr_finish_filter_row1_Xbpc_neon(int16_t *tmp,
// const pixel *src,
// const int32_t **a, const int16_t **b,
// const int w);
function sgr_finish_filter_row1_\bpc\()bpc_neon, export=1
push {r4-r11,lr}
vpush {q4-q7}
ldr r4, [sp, #100]
ldrd r6, r7, [r2]
ldr r2, [r2, #8]
ldrd r8, r9, [r3]
ldr r3, [r3, #8]
vmov.i16 q14, #3
vmov.i32 q15, #3
1:
vld1.16 {q0}, [r8, :128]!
vld1.16 {q1}, [r9, :128]!
vld1.16 {q2}, [r3, :128]!
vld1.32 {q8, q9}, [r6, :128]!
vld1.32 {q10, q11}, [r7, :128]!
vld1.32 {q12, q13}, [r2, :128]!
2:
subs r4, r4, #4
vext.8 d6, d0, d1, #2 // -stride
vext.8 d7, d2, d3, #2 // 0
vext.8 d8, d4, d5, #2 // +stride
vext.8 d9, d0, d1, #4 // +1-stride
vext.8 d10, d2, d3, #4 // +1
vext.8 d11, d4, d5, #4 // +1+stride
vadd.i16 d2, d2, d6 // -1, -stride
vadd.i16 d7, d7, d8 // 0, +stride
vadd.i16 d0, d0, d9 // -1-stride, +1-stride
vadd.i16 d2, d2, d7
vadd.i16 d4, d4, d11 // -1+stride, +1+stride
vadd.i16 d2, d2, d10 // +1
vadd.i16 d0, d0, d4
vext.8 q3, q8, q9, #4 // -stride
vshl.i16 d2, d2, #2
vext.8 q4, q8, q9, #8 // +1-stride
vext.8 q5, q10, q11, #4 // 0
vext.8 q6, q10, q11, #8 // +1
vmla.i16 d2, d0, d28 // * 3 -> a
vadd.i32 q3, q3, q10 // -stride, -1
vadd.i32 q8, q8, q4 // -1-stride, +1-stride
vadd.i32 q5, q5, q6 // 0, +1
vadd.i32 q8, q8, q12 // -1+stride
vadd.i32 q3, q3, q5
vext.8 q7, q12, q13, #4 // +stride
vext.8 q10, q12, q13, #8 // +1+stride
.if \bpc == 8
vld1.32 {d24[0]}, [r1, :32]! // src
.else
vld1.16 {d24}, [r1, :64]! // src
.endif
vadd.i32 q3, q3, q7 // +stride
vadd.i32 q8, q8, q10 // +1+stride
vshl.i32 q3, q3, #2
vmla.i32 q3, q8, q15 // * 3 -> b
.if \bpc == 8
vmovl.u8 q12, d24 // src
.endif
vmov d0, d1
vmlsl.u16 q3, d2, d24 // b - a * src
vmov d2, d3
vrshrn.i32 d6, q3, #9
vmov d4, d5
vst1.16 {d6}, [r0]!
ble 3f
vmov q8, q9
vmov q10, q11
vmov q12, q13
vld1.16 {d1}, [r8, :64]!
vld1.16 {d3}, [r9, :64]!
vld1.16 {d5}, [r3, :64]!
vld1.32 {q9}, [r6, :128]!
vld1.32 {q11}, [r7, :128]!
vld1.32 {q13}, [r2, :128]!
b 2b
3:
vpop {q4-q7}
pop {r4-r11,pc}
endfunc
// void dav1d_sgr_finish_filter2_2rows_Xbpc_neon(int16_t *tmp,
// const pixel *src, const ptrdiff_t stride,
// const int32_t **a, const int16_t **b,
// const int w, const int h);
function sgr_finish_filter2_2rows_\bpc\()bpc_neon, export=1
push {r4-r11,lr}
vpush {q4-q7}
ldrd r4, r5, [sp, #100]
ldr r6, [sp, #108]
ldrd r8, r9, [r3]
ldrd r10, r11, [r4]
mov r7, #2*FILTER_OUT_STRIDE
add r2, r1, r2
add r7, r7, r0
mov lr, r5
1:
vld1.16 {q0, q1}, [r10, :128]!
vld1.16 {q2, q3}, [r11, :128]!
vld1.32 {q8, q9}, [r8, :128]!
vld1.32 {q11, q12}, [r9, :128]!
vld1.32 {q10}, [r8, :128]!
vld1.32 {q13}, [r9, :128]!
2:
vmov.i16 q14, #5
vmov.i16 q15, #6
subs r5, r5, #8
vext.8 q4, q0, q1, #4 // +1-stride
vext.8 q5, q2, q3, #4 // +1+stride
vext.8 q6, q0, q1, #2 // -stride
vext.8 q7, q2, q3, #2 // +stride
vadd.i16 q0, q0, q4 // -1-stride, +1-stride
vadd.i16 q5, q2, q5 // -1+stride, +1+stride
vadd.i16 q2, q6, q7 // -stride, +stride
vadd.i16 q0, q0, q5
vext.8 q4, q8, q9, #8 // +1-stride
vext.8 q5, q9, q10, #8
vext.8 q6, q11, q12, #8 // +1+stride
vext.8 q7, q12, q13, #8
vmul.i16 q0, q0, q14 // * 5
vmla.i16 q0, q2, q15 // * 6
vadd.i32 q4, q4, q8 // -1-stride, +1-stride
vadd.i32 q5, q5, q9
vadd.i32 q6, q6, q11 // -1+stride, +1+stride
vadd.i32 q7, q7, q12
vadd.i32 q4, q4, q6
vadd.i32 q5, q5, q7
vext.8 q6, q8, q9, #4 // -stride
vext.8 q7, q9, q10, #4
vext.8 q8, q11, q12, #4 // +stride
vext.8 q11, q12, q13, #4
.if \bpc == 8
vld1.8 {d4}, [r1, :64]!
.else
vld1.8 {q2}, [r1, :128]!
.endif
vmov.i32 q14, #5
vmov.i32 q15, #6
vadd.i32 q6, q6, q8 // -stride, +stride
vadd.i32 q7, q7, q11
vmul.i32 q4, q4, q14 // * 5
vmla.i32 q4, q6, q15 // * 6
vmul.i32 q5, q5, q14 // * 5
vmla.i32 q5, q7, q15 // * 6
.if \bpc == 8
vmovl.u8 q2, d4
.endif
vmlsl.u16 q4, d0, d4 // b - a * src
vmlsl.u16 q5, d1, d5 // b - a * src
vmov q0, q1
vrshrn.i32 d8, q4, #9
vrshrn.i32 d9, q5, #9
vmov q2, q3
vst1.16 {q4}, [r0, :128]!
ble 3f
vmov q8, q10
vmov q11, q13
vld1.16 {q1}, [r10, :128]!
vld1.16 {q3}, [r11, :128]!
vld1.32 {q9, q10}, [r8, :128]!
vld1.32 {q12, q13}, [r9, :128]!
b 2b
3:
subs r6, r6, #1
ble 0f
mov r5, lr
ldrd r8, r9, [r3]
ldrd r10, r11, [r4]
mov r0, r7
mov r1, r2
vld1.32 {q8, q9}, [r9, :128]!
vld1.16 {q0, q1}, [r11, :128]!
vld1.32 {q10}, [r9, :128]!
vmov.i16 q12, #5
vmov.i16 q13, #6
4:
subs r5, r5, #8
vext.8 q3, q0, q1, #4 // +1
vext.8 q2, q0, q1, #2 // 0
vadd.i16 q0, q0, q3 // -1, +1
vext.8 q4, q8, q9, #4 // 0
vext.8 q5, q9, q10, #4
vext.8 q6, q8, q9, #8 // +1
vext.8 q7, q9, q10, #8
vmul.i16 q2, q2, q13 // * 6
vmla.i16 q2, q0, q12 // * 5 -> a
.if \bpc == 8
vld1.8 {d22}, [r1, :64]!
.else
vld1.16 {q11}, [r1, :128]!
.endif
vadd.i32 q8, q8, q6 // -1, +1
vadd.i32 q9, q9, q7
.if \bpc == 8
vmovl.u8 q11, d22
.endif
vmul.i32 q4, q4, q15 // * 6
vmla.i32 q4, q8, q14 // * 5 -> b
vmul.i32 q5, q5, q15 // * 6
vmla.i32 q5, q9, q14 // * 5 -> b
vmlsl.u16 q4, d4, d22 // b - a * src
vmlsl.u16 q5, d5, d23
vmov q0, q1
vrshrn.i32 d8, q4, #8
vrshrn.i32 d9, q5, #8
vmov q8, q10
vst1.16 {q4}, [r0, :128]!
ble 5f
vld1.16 {q1}, [r11, :128]!
vld1.32 {q9, q10}, [r9, :128]!
b 4b
5:
0:
vpop {q4-q7}
pop {r4-r11,pc}
endfunc
// void dav1d_sgr_weighted_row1_Xbpc_neon(pixel *dst,
// const int16_t *t1, const int w,
// const int w1, const int bitdepth_max);
function sgr_weighted_row1_\bpc\()bpc_neon, export=1
push {lr}
.if \bpc == 16
ldr lr, [sp, #4]
.endif
vdup.16 d31, r3
.if \bpc == 16
vmov.i16 q13, #0
vdup.16 q14, lr
.endif
1:
.if \bpc == 8
vld1.8 {d0}, [r0, :64]
.else
vld1.16 {q0}, [r0, :128]
.endif
vld1.16 {q1}, [r1, :128]!
subs r2, r2, #8
vmull.s16 q2, d2, d31 // v
vmull.s16 q3, d3, d31 // v
vrshrn.i32 d4, q2, #11
vrshrn.i32 d5, q3, #11
.if \bpc == 8
vaddw.u8 q2, q2, d0
vqmovun.s16 d2, q2
vst1.8 {d2}, [r0, :64]!
.else
vadd.i16 q2, q2, q0
vmax.s16 q2, q2, q13
vmin.u16 q2, q2, q14
vst1.16 {q2}, [r0, :128]!
.endif
bgt 1b
0:
pop {pc}
endfunc
// void dav1d_sgr_weighted2_Xbpc_neon(pixel *dst, const ptrdiff_t stride,
// const int16_t *t1, const int16_t *t2,
// const int w, const int h,
// const int16_t wt[2], const int bitdepth_max);
function sgr_weighted2_\bpc\()bpc_neon, export=1
push {r4-r8,lr}
ldrd r4, r5, [sp, #24]
.if \bpc == 8
ldr r6, [sp, #32]
.else
ldrd r6, r7, [sp, #32]
.endif
cmp r5, #2
add r8, r0, r1
add r12, r2, #2*FILTER_OUT_STRIDE
add lr, r3, #2*FILTER_OUT_STRIDE
vld2.16 {d30[], d31[]}, [r6] // wt[0], wt[1]
.if \bpc == 16
vdup.16 q14, r7
.endif
blt 2f
1:
.if \bpc == 8
vld1.8 {d0}, [r0, :64]
vld1.8 {d16}, [r8, :64]
.else
vld1.16 {q0}, [r0, :128]
vld1.16 {q8}, [r8, :128]
.endif
vld1.16 {q1}, [r2, :128]!
vld1.16 {q9}, [r12, :128]!
vld1.16 {q2}, [r3, :128]!
vld1.16 {q10}, [lr, :128]!
subs r4, r4, #8
vmull.s16 q3, d2, d30 // wt[0] * t1
vmlal.s16 q3, d4, d31 // wt[1] * t2
vmull.s16 q12, d3, d30 // wt[0] * t1
vmlal.s16 q12, d5, d31 // wt[1] * t2
vmull.s16 q11, d18, d30 // wt[0] * t1
vmlal.s16 q11, d20, d31 // wt[1] * t2
vmull.s16 q13, d19, d30 // wt[0] * t1
vmlal.s16 q13, d21, d31 // wt[1] * t2
vrshrn.i32 d6, q3, #11
vrshrn.i32 d7, q12, #11
vrshrn.i32 d22, q11, #11
vrshrn.i32 d23, q13, #11
.if \bpc == 8
vaddw.u8 q3, q3, d0
vaddw.u8 q11, q11, d16
vqmovun.s16 d6, q3
vqmovun.s16 d22, q11
vst1.8 {d6}, [r0, :64]!
vst1.8 {d22}, [r8, :64]!
.else
vmov.i16 q13, #0
vadd.i16 q3, q3, q0
vadd.i16 q11, q11, q8
vmax.s16 q3, q3, q13
vmax.s16 q11, q11, q13
vmin.u16 q3, q3, q14
vmin.u16 q11, q11, q14
vst1.16 {q3}, [r0, :128]!
vst1.16 {q11}, [r8, :128]!
.endif
bgt 1b
b 0f
2:
.if \bpc == 8
vld1.8 {d0}, [r0, :64]
.else
vld1.16 {q0}, [r0, :128]
.endif
vld1.16 {q1}, [r2, :128]!
vld1.16 {q2}, [r3, :128]!
subs r4, r4, #8
vmull.s16 q3, d2, d30 // wt[0] * t1
vmlal.s16 q3, d4, d31 // wt[1] * t2
vmull.s16 q11, d3, d30 // wt[0] * t1
vmlal.s16 q11, d5, d31 // wt[1] * t2
vrshrn.i32 d6, q3, #11
vrshrn.i32 d7, q11, #11
.if \bpc == 8
vaddw.u8 q3, q3, d0
vqmovun.s16 d6, q3
vst1.8 {d6}, [r0, :64]!
.else
vmov.i16 q13, #0
vadd.i16 q3, q3, q0
vmax.s16 q3, q3, q13
vmin.u16 q3, q3, q14
vst1.16 {q3}, [r0, :128]!
.endif
bgt 2b
0:
pop {r4-r8,pc}
endfunc
.endm

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,588 @@
/*
* Copyright © 2019, VideoLAN and dav1d authors
* Copyright © 2020, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include "src/arm/asm.S"
#include "util.S"
#define BUF_POS 0
#define BUF_END 4
#define DIF 8
#define RNG 12
#define CNT 16
#define ALLOW_UPDATE_CDF 20
const coeffs
.short 60, 56, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0
.short 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
endconst
const bits, align=4
.short 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
.short 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000
endconst
.macro vld1_align_n d0, q0, q1, src, n
.if \n == 4
vld1.16 {\d0}, [\src, :64]
.elseif \n == 8
vld1.16 {\q0}, [\src, :128]
.else
vld1.16 {\q0, \q1}, [\src, :128]
.endif
.endm
.macro vld1_n d0, q0, q1, src, n
.if \n == 4
vld1.16 {\d0}, [\src]
.elseif \n == 8
vld1.16 {\q0}, [\src]
.else
vld1.16 {\q0, \q1}, [\src]
.endif
.endm
.macro vst1_align_n d0, q0, q1, src, n
.if \n == 4
vst1.16 {\d0}, [\src, :64]
.elseif \n == 8
vst1.16 {\q0}, [\src, :128]
.else
vst1.16 {\q0, \q1}, [\src, :128]
.endif
.endm
.macro vst1_n d0, q0, q1, src, n
.if \n == 4
vst1.16 {\d0}, [\src]
.elseif \n == 8
vst1.16 {\q0}, [\src]
.else
vst1.16 {\q0, \q1}, [\src]
.endif
.endm
.macro vshr_n d0, d1, d2, s0, s1, s2, s3, s4, s5, n
.if \n == 4
vshr.u16 \d0, \s0, \s3
.else
vshr.u16 \d1, \s1, \s4
.if \n == 16
vshr.u16 \d2, \s2, \s5
.endif
.endif
.endm
.macro vadd_n d0, d1, d2, s0, s1, s2, s3, s4, s5, n
.if \n == 4
vadd.i16 \d0, \s0, \s3
.else
vadd.i16 \d1, \s1, \s4
.if \n == 16
vadd.i16 \d2, \s2, \s5
.endif
.endif
.endm
.macro vsub_n d0, d1, d2, s0, s1, s2, s3, s4, s5, n
.if \n == 4
vsub.i16 \d0, \s0, \s3
.else
vsub.i16 \d1, \s1, \s4
.if \n == 16
vsub.i16 \d2, \s2, \s5
.endif
.endif
.endm
.macro vand_n d0, d1, d2, s0, s1, s2, s3, s4, s5, n
.if \n == 4
vand \d0, \s0, \s3
.else
vand \d1, \s1, \s4
.if \n == 16
vand \d2, \s2, \s5
.endif
.endif
.endm
.macro vcge_n d0, d1, d2, s0, s1, s2, s3, s4, s5, n
.if \n == 4
vcge.u16 \d0, \s0, \s3
.else
vcge.u16 \d1, \s1, \s4
.if \n == 16
vcge.u16 \d2, \s2, \s5
.endif
.endif
.endm
.macro vrhadd_n d0, d1, d2, s0, s1, s2, s3, s4, s5, n
.if \n == 4
vrhadd.u16 \d0, \s0, \s3
.else
vrhadd.u16 \d1, \s1, \s4
.if \n == 16
vrhadd.u16 \d2, \s2, \s5
.endif
.endif
.endm
.macro vshl_n d0, d1, d2, s0, s1, s2, s3, s4, s5, n
.if \n == 4
vshl.s16 \d0, \s0, \s3
.else
vshl.s16 \d1, \s1, \s4
.if \n == 16
vshl.s16 \d2, \s2, \s5
.endif
.endif
.endm
.macro vqdmulh_n d0, d1, d2, s0, s1, s2, s3, s4, s5, n
.if \n == 4
vqdmulh.s16 \d0, \s0, \s3
.else
vqdmulh.s16 \d1, \s1, \s4
.if \n == 16
vqdmulh.s16 \d2, \s2, \s5
.endif
.endif
.endm
// unsigned dav1d_msac_decode_symbol_adapt4_neon(MsacContext *s, uint16_t *cdf,
// size_t n_symbols);
function msac_decode_symbol_adapt4_neon, export=1
.macro decode_update n
push {r4-r10,lr}
sub sp, sp, #48
add r8, r0, #RNG
vld1_align_n d0, q0, q1, r1, \n // cdf
vld1.16 {d16[]}, [r8, :16] // rng
movrel_local r9, coeffs, 30
vmov.i16 d30, #0x7f00 // 0x7f00
sub r9, r9, r2, lsl #1
vmvn.i16 q14, #0x3f // 0xffc0
add r8, sp, #14
vand d22, d16, d30 // rng & 0x7f00
vst1.16 {d16[0]}, [r8, :16] // store original u = s->rng
vand_n d4, q2, q3, d0, q0, q1, d28, q14, q14, \n // cdf & 0xffc0
.if \n > 4
vmov d23, d22
.endif
vld1_n d16, q8, q9, r9, \n // EC_MIN_PROB * (n_symbols - ret)
vqdmulh_n d20, q10, q11, d4, q2, q3, d22, q11, q11, \n // ((cdf >> EC_PROB_SHIFT) * (r - 128)) >> 1
add r8, r0, #DIF + 2
vadd_n d16, q8, q9, d4, q2, q3, d16, q8, q9, \n // v = cdf + EC_MIN_PROB * (n_symbols - ret)
.if \n == 4
vmov.i16 d17, #0
.endif
vadd_n d16, q8, q9, d20, q10, q11, d16, q8, q9, \n // v = ((cdf >> EC_PROB_SHIFT) * r) >> 1 + EC_MIN_PROB * (n_symbols - ret)
add r9, sp, #16
vld1.16 {d20[]}, [r8, :16] // dif >> (EC_WIN_SIZE - 16)
movrel_local r8, bits
vst1_n q8, q8, q9, r9, \n // store v values to allow indexed access
vmov d21, d20
vld1_align_n q12, q12, q13, r8, \n
.if \n == 16
vmov q11, q10
.endif
vcge_n q2, q2, q3, q10, q10, q11, q8, q8, q9, \n // c >= v
vand_n q10, q10, q11, q2, q2, q3, q12, q12, q13, \n // One bit per halfword set in the mask
.if \n == 16
vadd.i16 q10, q10, q11
.endif
vadd.i16 d20, d20, d21 // Aggregate mask bits
ldr r4, [r0, #ALLOW_UPDATE_CDF]
vpadd.i16 d20, d20, d20
lsl r10, r2, #1
vpadd.i16 d20, d20, d20
vmov.u16 r3, d20[0]
cmp r4, #0
rbit r3, r3
clz lr, r3 // ret
beq L(renorm)
// update_cdf
ldrh r3, [r1, r10] // count = cdf[n_symbols]
vmov.i8 q10, #0xff
.if \n == 16
mov r4, #-5
.else
mvn r12, r2
mov r4, #-4
cmn r12, #3 // set C if n_symbols <= 2
.endif
vrhadd_n d16, q8, q9, d20, q10, q10, d4, q2, q3, \n // i >= val ? -1 : 32768
.if \n == 16
sub r4, r4, r3, lsr #4 // -((count >> 4) + 5)
.else
lsr r12, r3, #4 // count >> 4
sbc r4, r4, r12 // -((count >> 4) + (n_symbols > 2) + 4)
.endif
vsub_n d16, q8, q9, d16, q8, q9, d0, q0, q1, \n // (32768 - cdf[i]) or (-1 - cdf[i])
.if \n == 4
vdup.16 d20, r4 // -rate
.else
vdup.16 q10, r4 // -rate
.endif
sub r3, r3, r3, lsr #5 // count - (count == 32)
vsub_n d0, q0, q1, d0, q0, q1, d4, q2, q3, \n // cdf + (i >= val ? 1 : 0)
vshl_n d16, q8, q9, d16, q8, q9, d20, q10, q10, \n // ({32768,-1} - cdf[i]) >> rate
add r3, r3, #1 // count + (count < 32)
vadd_n d0, q0, q1, d0, q0, q1, d16, q8, q9, \n // cdf + (32768 - cdf[i]) >> rate
vst1_align_n d0, q0, q1, r1, \n
strh r3, [r1, r10]
.endm
decode_update 4
L(renorm):
add r8, sp, #16
add r8, r8, lr, lsl #1
ldrh r3, [r8] // v
ldrh r4, [r8, #-2] // u
ldr r6, [r0, #CNT]
ldr r7, [r0, #DIF]
sub r4, r4, r3 // rng = u - v
clz r5, r4 // clz(rng)
eor r5, r5, #16 // d = clz(rng) ^ 16
sub r7, r7, r3, lsl #16 // dif - (v << 16)
L(renorm2):
lsl r4, r4, r5 // rng << d
subs r6, r6, r5 // cnt -= d
lsl r7, r7, r5 // (dif - (v << 16)) << d
str r4, [r0, #RNG]
bhs 4f
// refill
ldr r3, [r0, #BUF_POS] // BUF_POS
ldr r4, [r0, #BUF_END] // BUF_END
add r5, r3, #4
subs r5, r5, r4
bhi 6f
ldr r8, [r3] // next_bits
rsb r5, r6, #16
add r4, r6, #16 // shift_bits = cnt + 16
mvn r8, r8
lsr r5, r5, #3 // num_bytes_read
rev r8, r8 // next_bits = bswap(next_bits)
lsr r8, r8, r4 // next_bits >>= shift_bits
2: // refill_end
add r3, r3, r5
add r6, r6, r5, lsl #3 // cnt += num_bits_read
str r3, [r0, #BUF_POS]
3: // refill_end2
orr r7, r7, r8 // dif |= next_bits
4: // end
str r6, [r0, #CNT]
str r7, [r0, #DIF]
mov r0, lr
add sp, sp, #48
pop {r4-r10,pc}
5: // pad_with_ones
add r8, r6, #-240
lsr r8, r8, r8
b 3b
6: // refill_eob
cmp r3, r4
bhs 5b
ldr r8, [r4, #-4]
lsl r5, r5, #3
lsr r8, r8, r5
add r5, r6, #16
mvn r8, r8
sub r4, r4, r3 // num_bytes_left
rev r8, r8
lsr r8, r8, r5
rsb r5, r6, #16
lsr r5, r5, #3
cmp r5, r4
it hs
movhs r5, r4
b 2b
endfunc
function msac_decode_symbol_adapt8_neon, export=1
decode_update 8
b L(renorm)
endfunc
function msac_decode_symbol_adapt16_neon, export=1
decode_update 16
b L(renorm)
endfunc
function msac_decode_hi_tok_neon, export=1
push {r4-r10,lr}
vld1.16 {d0}, [r1, :64] // cdf
add r4, r0, #RNG
vmov.i16 d31, #0x7f00 // 0x7f00
movrel_local r5, coeffs, 30-2*3
vmvn.i16 d30, #0x3f // 0xffc0
ldrh r9, [r1, #6] // count = cdf[n_symbols]
vld1.16 {d1[]}, [r4, :16] // rng
movrel_local r4, bits
vld1.16 {d29}, [r5] // EC_MIN_PROB * (n_symbols - ret)
add r5, r0, #DIF + 2
vld1.16 {q8}, [r4, :128]
mov r2, #-24
vand d20, d0, d30 // cdf & 0xffc0
ldr r10, [r0, #ALLOW_UPDATE_CDF]
vld1.16 {d2[]}, [r5, :16] // dif >> (EC_WIN_SIZE - 16)
sub sp, sp, #48
ldr r6, [r0, #CNT]
ldr r7, [r0, #DIF]
vmov d3, d2
1:
vand d23, d1, d31 // rng & 0x7f00
vqdmulh.s16 d18, d20, d23 // ((cdf >> EC_PROB_SHIFT) * (r - 128)) >> 1
add r12, sp, #14
vadd.i16 d6, d20, d29 // v = cdf + EC_MIN_PROB * (n_symbols - ret)
vadd.i16 d6, d18, d6 // v = ((cdf >> EC_PROB_SHIFT) * r) >> 1 + EC_MIN_PROB * (n_symbols - ret)
vmov.i16 d7, #0
vst1.16 {d1[0]}, [r12, :16] // store original u = s->rng
add r12, sp, #16
vcge.u16 q2, q1, q3 // c >= v
vst1.16 {q3}, [r12] // store v values to allow indexed access
vand q9, q2, q8 // One bit per halfword set in the mask
vadd.i16 d18, d18, d19 // Aggregate mask bits
vpadd.i16 d18, d18, d18
vpadd.i16 d18, d18, d18
vmov.u16 r3, d18[0]
cmp r10, #0
add r2, r2, #5
rbit r3, r3
add r8, sp, #16
clz lr, r3 // ret
beq 2f
// update_cdf
vmov.i8 d22, #0xff
mov r4, #-5
vrhadd.u16 d6, d22, d4 // i >= val ? -1 : 32768
sub r4, r4, r9, lsr #4 // -((count >> 4) + 5)
vsub.i16 d6, d6, d0 // (32768 - cdf[i]) or (-1 - cdf[i])
vdup.16 d18, r4 // -rate
sub r9, r9, r9, lsr #5 // count - (count == 32)
vsub.i16 d0, d0, d4 // cdf + (i >= val ? 1 : 0)
vshl.s16 d6, d6, d18 // ({32768,-1} - cdf[i]) >> rate
add r9, r9, #1 // count + (count < 32)
vadd.i16 d0, d0, d6 // cdf + (32768 - cdf[i]) >> rate
vst1.16 {d0}, [r1, :64]
vand d20, d0, d30 // cdf & 0xffc0
strh r9, [r1, #6]
2:
add r8, r8, lr, lsl #1
ldrh r3, [r8] // v
ldrh r4, [r8, #-2] // u
sub r4, r4, r3 // rng = u - v
clz r5, r4 // clz(rng)
eor r5, r5, #16 // d = clz(rng) ^ 16
sub r7, r7, r3, lsl #16 // dif - (v << 16)
lsl r4, r4, r5 // rng << d
subs r6, r6, r5 // cnt -= d
lsl r7, r7, r5 // (dif - (v << 16)) << d
str r4, [r0, #RNG]
vdup.16 d1, r4
bhs 5f
// refill
ldr r3, [r0, #BUF_POS] // BUF_POS
ldr r4, [r0, #BUF_END] // BUF_END
add r5, r3, #4
subs r5, r5, r4
bhi 7f
ldr r8, [r3] // next_bits
rsb r5, r6, #16
add r4, r6, #16 // shift_bits = cnt + 16
mvn r8, r8
lsr r5, r5, #3 // num_bytes_read
rev r8, r8 // next_bits = bswap(next_bits)
lsr r8, r8, r4 // next_bits >>= shift_bits
3: // refill_end
add r3, r3, r5
add r6, r6, r5, lsl #3 // cnt += num_bits_read
str r3, [r0, #BUF_POS]
4: // refill_end2
orr r7, r7, r8 // dif |= next_bits
5: // end
lsl lr, lr, #1
sub lr, lr, #5
lsr r12, r7, #16
adds r2, r2, lr // carry = tok_br < 3 || tok == 15
vdup.16 q1, r12
bcc 1b // loop if !carry
add r2, r2, #30
str r6, [r0, #CNT]
add sp, sp, #48
str r7, [r0, #DIF]
lsr r0, r2, #1
pop {r4-r10,pc}
6: // pad_with_ones
add r8, r6, #-240
lsr r8, r8, r8
b 4b
7: // refill_eob
cmp r3, r4
bhs 6b
ldr r8, [r4, #-4]
lsl r5, r5, #3
lsr r8, r8, r5
add r5, r6, #16
mvn r8, r8
sub r4, r4, r3 // num_bytes_left
rev r8, r8
lsr r8, r8, r5
rsb r5, r6, #16
lsr r5, r5, #3
cmp r5, r4
it hs
movhs r5, r4
b 3b
endfunc
function msac_decode_bool_equi_neon, export=1
push {r4-r10,lr}
ldr r5, [r0, #RNG]
ldr r6, [r0, #CNT]
sub sp, sp, #48
ldr r7, [r0, #DIF]
bic r4, r5, #0xff // r &= 0xff00
add r4, r4, #8
mov r2, #0
subs r8, r7, r4, lsl #15 // dif - vw
lsr r4, r4, #1 // v
sub r5, r5, r4 // r - v
itee lo
movlo r2, #1
movhs r4, r5 // if (ret) v = r - v;
movhs r7, r8 // if (ret) dif = dif - vw;
clz r5, r4 // clz(rng)
eor r5, r5, #16 // d = clz(rng) ^ 16
mov lr, r2
b L(renorm2)
endfunc
function msac_decode_bool_neon, export=1
push {r4-r10,lr}
ldr r5, [r0, #RNG]
ldr r6, [r0, #CNT]
sub sp, sp, #48
ldr r7, [r0, #DIF]
lsr r4, r5, #8 // r >> 8
bic r1, r1, #0x3f // f &= ~63
mul r4, r4, r1
mov r2, #0
lsr r4, r4, #7
add r4, r4, #4 // v
subs r8, r7, r4, lsl #16 // dif - vw
sub r5, r5, r4 // r - v
itee lo
movlo r2, #1
movhs r4, r5 // if (ret) v = r - v;
movhs r7, r8 // if (ret) dif = dif - vw;
clz r5, r4 // clz(rng)
eor r5, r5, #16 // d = clz(rng) ^ 16
mov lr, r2
b L(renorm2)
endfunc
function msac_decode_bool_adapt_neon, export=1
push {r4-r10,lr}
ldr r9, [r1] // cdf[0-1]
ldr r5, [r0, #RNG]
movw lr, #0xffc0
ldr r6, [r0, #CNT]
sub sp, sp, #48
ldr r7, [r0, #DIF]
lsr r4, r5, #8 // r >> 8
and r2, r9, lr // f &= ~63
mul r4, r4, r2
mov r2, #0
lsr r4, r4, #7
add r4, r4, #4 // v
subs r8, r7, r4, lsl #16 // dif - vw
sub r5, r5, r4 // r - v
ldr r10, [r0, #ALLOW_UPDATE_CDF]
itee lo
movlo r2, #1
movhs r4, r5 // if (ret) v = r - v;
movhs r7, r8 // if (ret) dif = dif - vw;
cmp r10, #0
clz r5, r4 // clz(rng)
eor r5, r5, #16 // d = clz(rng) ^ 16
mov lr, r2
beq L(renorm2)
lsr r2, r9, #16 // count = cdf[1]
uxth r9, r9 // cdf[0]
sub r3, r2, r2, lsr #5 // count - (count >= 32)
lsr r2, r2, #4 // count >> 4
add r10, r3, #1 // count + (count < 32)
add r2, r2, #4 // rate = (count >> 4) | 4
sub r9, r9, lr // cdf[0] -= bit
sub r3, r9, lr, lsl #15 // {cdf[0], cdf[0] - 32769}
asr r3, r3, r2 // {cdf[0], cdf[0] - 32769} >> rate
sub r9, r9, r3 // cdf[0]
strh r9, [r1]
strh r10, [r1, #2]
b L(renorm2)
endfunc

View file

@ -0,0 +1,303 @@
/*
* Copyright © 2021, VideoLAN and dav1d authors
* Copyright © 2021, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include "src/arm/asm.S"
#include "util.S"
// void dav1d_splat_mv_neon(refmvs_block **rr, const refmvs_block *rmv,
// int bx4, int bw4, int bh4)
function splat_mv_neon, export=1
push {r4, lr}
vld1.8 {q3}, [r1]
ldr r4, [sp, #8]
clz r3, r3
adr lr, L(splat_tbl)
sub r3, r3, #26
vext.8 q2, q3, q3, #12
ldr r3, [lr, r3, lsl #2]
add r2, r2, r2, lsl #1
vext.8 q0, q2, q3, #4
add r3, lr, r3
vext.8 q1, q2, q3, #8
lsl r2, r2, #2
vext.8 q2, q2, q3, #12
vmov q3, q0
1:
ldr r1, [r0], #4
subs r4, r4, #1
add r1, r1, r2
bx r3
.align 2
L(splat_tbl):
.word 320f - L(splat_tbl) + CONFIG_THUMB
.word 160f - L(splat_tbl) + CONFIG_THUMB
.word 80f - L(splat_tbl) + CONFIG_THUMB
.word 40f - L(splat_tbl) + CONFIG_THUMB
.word 20f - L(splat_tbl) + CONFIG_THUMB
.word 10f - L(splat_tbl) + CONFIG_THUMB
10:
vst1.8 {d0}, [r1]
vstr s2, [r1, #8]
bgt 1b
pop {r4, pc}
20:
vst1.8 {q0}, [r1]
vstr d2, [r1, #16]
bgt 1b
pop {r4, pc}
40:
vst1.8 {q0, q1}, [r1]!
vst1.8 {q2}, [r1]
bgt 1b
pop {r4, pc}
320:
vst1.8 {q0, q1}, [r1]!
vst1.8 {q2, q3}, [r1]!
vst1.8 {q1, q2}, [r1]!
vst1.8 {q0, q1}, [r1]!
vst1.8 {q2, q3}, [r1]!
vst1.8 {q1, q2}, [r1]!
160:
vst1.8 {q0, q1}, [r1]!
vst1.8 {q2, q3}, [r1]!
vst1.8 {q1, q2}, [r1]!
80:
vst1.8 {q0, q1}, [r1]!
vst1.8 {q2, q3}, [r1]!
vst1.8 {q1, q2}, [r1]
bgt 1b
pop {r4, pc}
endfunc
const mv_tbls, align=4
.byte 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
.byte 0, 1, 2, 3, 8, 0, 1, 2, 3, 8, 0, 1, 2, 3, 8, 0
.byte 4, 5, 6, 7, 9, 4, 5, 6, 7, 9, 4, 5, 6, 7, 9, 4
.byte 4, 5, 6, 7, 9, 4, 5, 6, 7, 9, 4, 5, 6, 7, 9, 4
endconst
const mask_mult, align=4
.byte 1, 2, 1, 2, 0, 0, 0, 0
endconst
// void dav1d_save_tmvs_neon(refmvs_temporal_block *rp, ptrdiff_t stride,
// refmvs_block **rr, const uint8_t *ref_sign,
// int col_end8, int row_end8,
// int col_start8, int row_start8)
function save_tmvs_neon, export=1
push {r4-r11,lr}
ldrd r4, r5, [sp, #36]
ldrd r6, r7, [sp, #44]
vmov.i8 d30, #0
vld1.8 {d31}, [r3]
adr r8, L(save_tmvs_tbl)
movrel_local lr, mask_mult
movrel_local r12, mv_tbls
vld1.8 {d29}, [lr]
vext.8 d31, d30, d31, #7 // [0, ref_sign]
mov r3, #5
mul r1, r1, r3 // stride *= 5
sub r5, r5, r7 // h = row_end8 - row_start8
lsl r7, r7, #1 // row_start8 <<= 1
1:
mov r3, #5
mov r11, #12*2
and r9, r7, #30 // (y & 15) * 2
ldr r9, [r2, r9, lsl #2] // b = rr[(y & 15) * 2]
add r9, r9, #12 // &b[... + 1]
mla r10, r4, r11, r9 // end_cand_b = &b[col_end8*2 + 1]
mla r9, r6, r11, r9 // cand_b = &b[x*2 + 1]
mla r3, r6, r3, r0 // &rp[x]
push {r2,r4,r6}
2:
ldrb r11, [r9, #10] // cand_b->bs
add lr, r9, #8
vld1.8 {d0, d1}, [r9] // cand_b->mv
add r11, r8, r11, lsl #3
vld1.16 {d2[]}, [lr] // cand_b->ref
ldrh lr, [r11] // bw8
mov r2, r8
add r9, r9, lr, lsl #1 // cand_b += bw8*2
cmp r9, r10
vmov d4, d0
bge 3f
ldrb r2, [r9, #10] // cand_b->bs
add lr, r9, #8
vld1.8 {d6, d7}, [r9] // cand_b->mv
add r2, r8, r2, lsl #3
vld1.16 {d2[1]}, [lr] // cand_b->ref
ldrh lr, [r2] // bw8
add r9, r9, lr, lsl #1 // cand_b += bw8*2
vmov d5, d6
3:
vabs.s16 q2, q2 // abs(mv[].xy)
vtbl.8 d2, {d31}, d2 // ref_sign[ref]
vshr.u16 q2, q2, #12 // abs(mv[].xy) >> 12
vmull.u8 q1, d2, d29 // ref_sign[ref] * {1, 2}
vceq.i32 q2, q2, #0 // abs(mv[].xy) <= 4096
vmovn.i32 d4, q2 // abs() condition to 16 bit
vand d2, d2, d4 // h[0-3] contains conditions for mv[0-1]
vpadd.i16 d2, d2, d2 // Combine condition for [1] and [0]
vmov.u16 r4, d2[0] // Extract case for first block
vmov.u16 r6, d2[1]
ldr r11, [r11, #4] // Fetch jump table entry
ldr r2, [r2, #4]
add r4, r12, r4, lsl #4
add r6, r12, r6, lsl #4
vld1.8 {d2, d3}, [r4] // Load permutation table base on case
vld1.8 {d4, d5}, [r6]
add r11, r8, r11 // Find jump table target
add r2, r8, r2
vtbl.8 d16, {d0, d1}, d2 // Permute cand_b to output refmvs_temporal_block
vtbl.8 d17, {d0, d1}, d3
vtbl.8 d18, {d6, d7}, d4
vtbl.8 d19, {d6, d7}, d5
vmov q0, q8
// q1 follows on q0 (q8), with another 3 full repetitions of the pattern.
vext.8 q1, q8, q8, #1
vext.8 q10, q9, q9, #1
// q2 ends with 3 complete repetitions of the pattern.
vext.8 q2, q8, q1, #4
vext.8 q11, q9, q10, #4
blx r11
bge 4f // if (cand_b >= end)
vmov q0, q9
vmov q1, q10
vmov q2, q11
cmp r9, r10
blx r2
blt 2b // if (cand_b < end)
4:
pop {r2,r4,r6}
subs r5, r5, #1 // h--
add r7, r7, #2 // y += 2
add r0, r0, r1 // rp += stride
bgt 1b
pop {r4-r11,pc}
.align 2
L(save_tmvs_tbl):
.word 16 * 12
.word 160f - L(save_tmvs_tbl) + CONFIG_THUMB
.word 16 * 12
.word 160f - L(save_tmvs_tbl) + CONFIG_THUMB
.word 8 * 12
.word 80f - L(save_tmvs_tbl) + CONFIG_THUMB
.word 8 * 12
.word 80f - L(save_tmvs_tbl) + CONFIG_THUMB
.word 8 * 12
.word 80f - L(save_tmvs_tbl) + CONFIG_THUMB
.word 8 * 12
.word 80f - L(save_tmvs_tbl) + CONFIG_THUMB
.word 4 * 12
.word 40f - L(save_tmvs_tbl) + CONFIG_THUMB
.word 4 * 12
.word 40f - L(save_tmvs_tbl) + CONFIG_THUMB
.word 4 * 12
.word 40f - L(save_tmvs_tbl) + CONFIG_THUMB
.word 4 * 12
.word 40f - L(save_tmvs_tbl) + CONFIG_THUMB
.word 2 * 12
.word 20f - L(save_tmvs_tbl) + CONFIG_THUMB
.word 2 * 12
.word 20f - L(save_tmvs_tbl) + CONFIG_THUMB
.word 2 * 12
.word 20f - L(save_tmvs_tbl) + CONFIG_THUMB
.word 2 * 12
.word 20f - L(save_tmvs_tbl) + CONFIG_THUMB
.word 2 * 12
.word 20f - L(save_tmvs_tbl) + CONFIG_THUMB
.word 1 * 12
.word 10f - L(save_tmvs_tbl) + CONFIG_THUMB
.word 1 * 12
.word 10f - L(save_tmvs_tbl) + CONFIG_THUMB
.word 1 * 12
.word 10f - L(save_tmvs_tbl) + CONFIG_THUMB
.word 1 * 12
.word 10f - L(save_tmvs_tbl) + CONFIG_THUMB
.word 1 * 12
.word 10f - L(save_tmvs_tbl) + CONFIG_THUMB
.word 1 * 12
.word 10f - L(save_tmvs_tbl) + CONFIG_THUMB
.word 1 * 12
.word 10f - L(save_tmvs_tbl) + CONFIG_THUMB
10:
add r4, r3, #4
vst1.32 {d0[0]}, [r3]
vst1.8 {d0[4]}, [r4]
add r3, r3, #5
bx lr
20:
add r4, r3, #8
vst1.8 {d0}, [r3]
vst1.16 {d1[0]}, [r4]
add r3, r3, #2*5
bx lr
40:
add r4, r3, #16
vst1.8 {q0}, [r3]
vst1.32 {d2[0]}, [r4]
add r3, r3, #4*5
bx lr
80:
add r4, r3, #(8*5-16)
// This writes 6 full entries plus 2 extra bytes
vst1.8 {q0, q1}, [r3]
// Write the last few, overlapping with the first write.
vst1.8 {q2}, [r4]
add r3, r3, #8*5
bx lr
160:
add r4, r3, #6*5
add r6, r3, #12*5
// This writes 6 full entries plus 2 extra bytes
vst1.8 {q0, q1}, [r3]
// Write another 6 full entries, slightly overlapping with the first set
vst1.8 {q0, q1}, [r4]
add r4, r3, #(16*5-16)
// Write 8 bytes (one full entry) after the first 12
vst1.8 {d0}, [r6]
// Write the last 3 entries
vst1.8 {q2}, [r4]
add r3, r3, #16*5
bx lr
endfunc

View file

@ -0,0 +1,202 @@
/******************************************************************************
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2015 Martin Storsjo
* Copyright © 2015 Janne Grunau
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*****************************************************************************/
#ifndef DAV1D_SRC_ARM_32_UTIL_S
#define DAV1D_SRC_ARM_32_UTIL_S
#include "config.h"
#include "src/arm/asm.S"
#include "src/arm/arm-arch.h"
.macro v4bx rd
#if __ARM_ARCH >= 5 || defined(__ARM_ARCH_4T__)
bx \rd
#else
mov pc, \rd
#endif
.endm
.macro v4blx rd
#if __ARM_ARCH >= 5
blx \rd
#else
mov lr, pc
v4bx \rd
#endif
.endm
.macro movrel_local rd, val, offset=0
#if (__ARM_ARCH >= 7 || defined(__ARM_ARCH_6T2__)) && !defined(PIC)
movw \rd, #:lower16:\val+\offset
movt \rd, #:upper16:\val+\offset
#else
ldr \rd, 90001f
b 90002f
90001:
.word \val + \offset - (90002f + 8 - 4 * CONFIG_THUMB)
90002:
add \rd, \rd, pc
#endif
.endm
.macro movrel rd, val, offset=0
#if defined(PIC) && defined(__APPLE__)
ldr \rd, 1f
b 2f
1:
.word 3f - (2f + 8 - 4 * CONFIG_THUMB)
2:
ldr \rd, [pc, \rd]
.if \offset < 0
sub \rd, \rd, #-(\offset)
.elseif \offset > 0
add \rd, \rd, #\offset
.endif
.non_lazy_symbol_pointer
3:
.indirect_symbol \val
.word 0
.text
#else
movrel_local \rd, \val, \offset
#endif
.endm
// This macro clobbers r7 (and r12 on windows) and stores data at the
// bottom of the stack; sp is the start of the space allocated that
// the caller can use.
.macro sub_sp_align space
#if CONFIG_THUMB
mov r7, sp
and r7, r7, #15
#else
and r7, sp, #15
#endif
sub sp, sp, r7
// Now the stack is aligned, store the amount of adjustment back
// on the stack, as we don't want to waste a register as frame
// pointer.
str r7, [sp, #-16]!
#ifdef _WIN32
.if \space > 8192
// Here, we'd need to touch two (or more) pages while decrementing
// the stack pointer.
.error "sub_sp_align doesn't support values over 8K at the moment"
.elseif \space > 4096
sub r7, sp, #4096
ldr r12, [r7]
sub r7, r7, #(\space - 4096)
mov sp, r7
.else
sub sp, sp, #\space
.endif
#else
.if \space >= 4096
sub sp, sp, #(\space)/4096*4096
.endif
.if (\space % 4096) != 0
sub sp, sp, #(\space)%4096
.endif
#endif
.endm
.macro add_sp_align space
.if \space >= 4096
add sp, sp, #(\space)/4096*4096
.endif
.if (\space % 4096) != 0
add sp, sp, #(\space)%4096
.endif
ldr r7, [sp], #16
// Add back the original stack adjustment
add sp, sp, r7
.endm
.macro transpose_8x8b q0, q1, q2, q3, r0, r1, r2, r3, r4, r5, r6, r7
vtrn.32 \q0, \q2
vtrn.32 \q1, \q3
vtrn.16 \r0, \r2
vtrn.16 \r1, \r3
vtrn.16 \r4, \r6
vtrn.16 \r5, \r7
vtrn.8 \r0, \r1
vtrn.8 \r2, \r3
vtrn.8 \r4, \r5
vtrn.8 \r6, \r7
.endm
.macro transpose_8x8h r0, r1, r2, r3, r4, r5, r6, r7, d0, d1, d2, d3, d4, d5, d6, d7
vswp \d0, \d4
vswp \d1, \d5
vswp \d2, \d6
vswp \d3, \d7
vtrn.32 \r0, \r2
vtrn.32 \r1, \r3
vtrn.32 \r4, \r6
vtrn.32 \r5, \r7
vtrn.16 \r0, \r1
vtrn.16 \r2, \r3
vtrn.16 \r4, \r5
vtrn.16 \r6, \r7
.endm
.macro transpose_4x8b q0, q1, r0, r1, r2, r3
vtrn.16 \q0, \q1
vtrn.8 \r0, \r1
vtrn.8 \r2, \r3
.endm
.macro transpose_4x4s q0, q1, q2, q3, r0, r1, r2, r3, r4, r5, r6, r7
vswp \r1, \r4 // vtrn.64 \q0, \q2
vswp \r3, \r6 // vtrn.64 \q1, \q3
vtrn.32 \q0, \q1
vtrn.32 \q2, \q3
.endm
.macro transpose_4x4h q0, q1, r0, r1, r2, r3
vtrn.32 \q0, \q1
vtrn.16 \r0, \r1
vtrn.16 \r2, \r3
.endm
.macro transpose_4x8h r0, r1, r2, r3
vtrn.32 \r0, \r2
vtrn.32 \r1, \r3
vtrn.16 \r0, \r1
vtrn.16 \r2, \r3
.endm
#endif /* DAV1D_SRC_ARM_32_UTIL_S */

View file

@ -0,0 +1,520 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2019, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include "src/arm/asm.S"
#include "util.S"
#include "cdef_tmpl.S"
.macro pad_top_bottom s1, s2, w, stride, rn, rw, ret
tst w7, #1 // CDEF_HAVE_LEFT
b.eq 2f
// CDEF_HAVE_LEFT
sub \s1, \s1, #2
sub \s2, \s2, #2
tst w7, #2 // CDEF_HAVE_RIGHT
b.eq 1f
// CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
ldr \rn\()0, [\s1]
ldr s1, [\s1, #\w]
ldr \rn\()2, [\s2]
ldr s3, [\s2, #\w]
uxtl v0.8h, v0.8b
uxtl v1.8h, v1.8b
uxtl v2.8h, v2.8b
uxtl v3.8h, v3.8b
str \rw\()0, [x0]
str d1, [x0, #2*\w]
add x0, x0, #2*\stride
str \rw\()2, [x0]
str d3, [x0, #2*\w]
.if \ret
ret
.else
add x0, x0, #2*\stride
b 3f
.endif
1:
// CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
ldr \rn\()0, [\s1]
ldr h1, [\s1, #\w]
ldr \rn\()2, [\s2]
ldr h3, [\s2, #\w]
uxtl v0.8h, v0.8b
uxtl v1.8h, v1.8b
uxtl v2.8h, v2.8b
uxtl v3.8h, v3.8b
str \rw\()0, [x0]
str s1, [x0, #2*\w]
str s31, [x0, #2*\w+4]
add x0, x0, #2*\stride
str \rw\()2, [x0]
str s3, [x0, #2*\w]
str s31, [x0, #2*\w+4]
.if \ret
ret
.else
add x0, x0, #2*\stride
b 3f
.endif
2:
// !CDEF_HAVE_LEFT
tst w7, #2 // CDEF_HAVE_RIGHT
b.eq 1f
// !CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
ldr \rn\()0, [\s1]
ldr h1, [\s1, #\w]
ldr \rn\()2, [\s2]
ldr h3, [\s2, #\w]
uxtl v0.8h, v0.8b
uxtl v1.8h, v1.8b
uxtl v2.8h, v2.8b
uxtl v3.8h, v3.8b
str s31, [x0]
stur \rw\()0, [x0, #4]
str s1, [x0, #4+2*\w]
add x0, x0, #2*\stride
str s31, [x0]
stur \rw\()2, [x0, #4]
str s3, [x0, #4+2*\w]
.if \ret
ret
.else
add x0, x0, #2*\stride
b 3f
.endif
1:
// !CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
ldr \rn\()0, [\s1]
ldr \rn\()1, [\s2]
uxtl v0.8h, v0.8b
uxtl v1.8h, v1.8b
str s31, [x0]
stur \rw\()0, [x0, #4]
str s31, [x0, #4+2*\w]
add x0, x0, #2*\stride
str s31, [x0]
stur \rw\()1, [x0, #4]
str s31, [x0, #4+2*\w]
.if \ret
ret
.else
add x0, x0, #2*\stride
.endif
3:
.endm
.macro load_n_incr dst, src, incr, w
.if \w == 4
ld1 {\dst\().s}[0], [\src], \incr
.else
ld1 {\dst\().8b}, [\src], \incr
.endif
.endm
// void dav1d_cdef_paddingX_8bpc_neon(uint16_t *tmp, const pixel *src,
// ptrdiff_t src_stride, const pixel (*left)[2],
// const pixel *const top,
// const pixel *const bottom, int h,
// enum CdefEdgeFlags edges);
.macro padding_func w, stride, rn, rw
function cdef_padding\w\()_8bpc_neon, export=1
cmp w7, #0xf // fully edged
b.eq cdef_padding\w\()_edged_8bpc_neon
movi v30.8h, #0x80, lsl #8
mov v31.16b, v30.16b
sub x0, x0, #2*(2*\stride+2)
tst w7, #4 // CDEF_HAVE_TOP
b.ne 1f
// !CDEF_HAVE_TOP
st1 {v30.8h, v31.8h}, [x0], #32
.if \w == 8
st1 {v30.8h, v31.8h}, [x0], #32
.endif
b 3f
1:
// CDEF_HAVE_TOP
add x9, x4, x2
pad_top_bottom x4, x9, \w, \stride, \rn, \rw, 0
// Middle section
3:
tst w7, #1 // CDEF_HAVE_LEFT
b.eq 2f
// CDEF_HAVE_LEFT
tst w7, #2 // CDEF_HAVE_RIGHT
b.eq 1f
// CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
0:
ld1 {v0.h}[0], [x3], #2
ldr h2, [x1, #\w]
load_n_incr v1, x1, x2, \w
subs w6, w6, #1
uxtl v0.8h, v0.8b
uxtl v1.8h, v1.8b
uxtl v2.8h, v2.8b
str s0, [x0]
stur \rw\()1, [x0, #4]
str s2, [x0, #4+2*\w]
add x0, x0, #2*\stride
b.gt 0b
b 3f
1:
// CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
ld1 {v0.h}[0], [x3], #2
load_n_incr v1, x1, x2, \w
subs w6, w6, #1
uxtl v0.8h, v0.8b
uxtl v1.8h, v1.8b
str s0, [x0]
stur \rw\()1, [x0, #4]
str s31, [x0, #4+2*\w]
add x0, x0, #2*\stride
b.gt 1b
b 3f
2:
tst w7, #2 // CDEF_HAVE_RIGHT
b.eq 1f
// !CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
0:
ldr h1, [x1, #\w]
load_n_incr v0, x1, x2, \w
subs w6, w6, #1
uxtl v0.8h, v0.8b
uxtl v1.8h, v1.8b
str s31, [x0]
stur \rw\()0, [x0, #4]
str s1, [x0, #4+2*\w]
add x0, x0, #2*\stride
b.gt 0b
b 3f
1:
// !CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
load_n_incr v0, x1, x2, \w
subs w6, w6, #1
uxtl v0.8h, v0.8b
str s31, [x0]
stur \rw\()0, [x0, #4]
str s31, [x0, #4+2*\w]
add x0, x0, #2*\stride
b.gt 1b
3:
tst w7, #8 // CDEF_HAVE_BOTTOM
b.ne 1f
// !CDEF_HAVE_BOTTOM
st1 {v30.8h, v31.8h}, [x0], #32
.if \w == 8
st1 {v30.8h, v31.8h}, [x0], #32
.endif
ret
1:
// CDEF_HAVE_BOTTOM
add x9, x5, x2
pad_top_bottom x5, x9, \w, \stride, \rn, \rw, 1
endfunc
.endm
padding_func 8, 16, d, q
padding_func 4, 8, s, d
// void cdef_paddingX_edged_8bpc_neon(uint8_t *tmp, const pixel *src,
// ptrdiff_t src_stride, const pixel (*left)[2],
// const pixel *const top,
// const pixel *const bottom, int h,
// enum CdefEdgeFlags edges);
.macro padding_func_edged w, stride, reg
function cdef_padding\w\()_edged_8bpc_neon, export=1
sub x4, x4, #2
sub x5, x5, #2
sub x0, x0, #(2*\stride+2)
.if \w == 4
ldr d0, [x4]
ldr d1, [x4, x2]
st1 {v0.8b, v1.8b}, [x0], #16
.else
add x9, x4, x2
ldr d0, [x4]
ldr s1, [x4, #8]
ldr d2, [x9]
ldr s3, [x9, #8]
str d0, [x0]
str s1, [x0, #8]
str d2, [x0, #\stride]
str s3, [x0, #\stride+8]
add x0, x0, #2*\stride
.endif
0:
ld1 {v0.h}[0], [x3], #2
ldr h2, [x1, #\w]
load_n_incr v1, x1, x2, \w
subs w6, w6, #1
str h0, [x0]
stur \reg\()1, [x0, #2]
str h2, [x0, #2+\w]
add x0, x0, #\stride
b.gt 0b
.if \w == 4
ldr d0, [x5]
ldr d1, [x5, x2]
st1 {v0.8b, v1.8b}, [x0], #16
.else
add x9, x5, x2
ldr d0, [x5]
ldr s1, [x5, #8]
ldr d2, [x9]
ldr s3, [x9, #8]
str d0, [x0]
str s1, [x0, #8]
str d2, [x0, #\stride]
str s3, [x0, #\stride+8]
.endif
ret
endfunc
.endm
padding_func_edged 8, 16, d
padding_func_edged 4, 8, s
tables
filter 8, 8
filter 4, 8
find_dir 8
.macro load_px_8 d1, d2, w
.if \w == 8
add x6, x2, w9, sxtb // x + off
sub x9, x2, w9, sxtb // x - off
ld1 {\d1\().d}[0], [x6] // p0
add x6, x6, #16 // += stride
ld1 {\d2\().d}[0], [x9] // p1
add x9, x9, #16 // += stride
ld1 {\d1\().d}[1], [x6] // p0
ld1 {\d2\().d}[1], [x9] // p0
.else
add x6, x2, w9, sxtb // x + off
sub x9, x2, w9, sxtb // x - off
ld1 {\d1\().s}[0], [x6] // p0
add x6, x6, #8 // += stride
ld1 {\d2\().s}[0], [x9] // p1
add x9, x9, #8 // += stride
ld1 {\d1\().s}[1], [x6] // p0
add x6, x6, #8 // += stride
ld1 {\d2\().s}[1], [x9] // p1
add x9, x9, #8 // += stride
ld1 {\d1\().s}[2], [x6] // p0
add x6, x6, #8 // += stride
ld1 {\d2\().s}[2], [x9] // p1
add x9, x9, #8 // += stride
ld1 {\d1\().s}[3], [x6] // p0
ld1 {\d2\().s}[3], [x9] // p1
.endif
.endm
.macro handle_pixel_8 s1, s2, thresh_vec, shift, tap, min
.if \min
umin v3.16b, v3.16b, \s1\().16b
umax v4.16b, v4.16b, \s1\().16b
umin v3.16b, v3.16b, \s2\().16b
umax v4.16b, v4.16b, \s2\().16b
.endif
uabd v16.16b, v0.16b, \s1\().16b // abs(diff)
uabd v20.16b, v0.16b, \s2\().16b // abs(diff)
ushl v17.16b, v16.16b, \shift // abs(diff) >> shift
ushl v21.16b, v20.16b, \shift // abs(diff) >> shift
uqsub v17.16b, \thresh_vec, v17.16b // clip = imax(0, threshold - (abs(diff) >> shift))
uqsub v21.16b, \thresh_vec, v21.16b // clip = imax(0, threshold - (abs(diff) >> shift))
cmhi v18.16b, v0.16b, \s1\().16b // px > p0
cmhi v22.16b, v0.16b, \s2\().16b // px > p1
umin v17.16b, v17.16b, v16.16b // imin(abs(diff), clip)
umin v21.16b, v21.16b, v20.16b // imin(abs(diff), clip)
dup v19.16b, \tap // taps[k]
neg v16.16b, v17.16b // -imin()
neg v20.16b, v21.16b // -imin()
bsl v18.16b, v16.16b, v17.16b // constrain() = apply_sign()
bsl v22.16b, v20.16b, v21.16b // constrain() = apply_sign()
mla v1.16b, v18.16b, v19.16b // sum += taps[k] * constrain()
mla v2.16b, v22.16b, v19.16b // sum += taps[k] * constrain()
.endm
// void cdef_filterX_edged_8bpc_neon(pixel *dst, ptrdiff_t dst_stride,
// const uint8_t *tmp, int pri_strength,
// int sec_strength, int dir, int damping,
// int h);
.macro filter_func_8 w, pri, sec, min, suffix
function cdef_filter\w\suffix\()_edged_8bpc_neon
.if \pri
movrel x8, pri_taps
and w9, w3, #1
add x8, x8, w9, uxtw #1
.endif
movrel x9, directions\w
add x5, x9, w5, uxtw #1
movi v30.8b, #7
dup v28.8b, w6 // damping
.if \pri
dup v25.16b, w3 // threshold
.endif
.if \sec
dup v27.16b, w4 // threshold
.endif
trn1 v24.8b, v25.8b, v27.8b
clz v24.8b, v24.8b // clz(threshold)
sub v24.8b, v30.8b, v24.8b // ulog2(threshold)
uqsub v24.8b, v28.8b, v24.8b // shift = imax(0, damping - ulog2(threshold))
neg v24.8b, v24.8b // -shift
.if \sec
dup v26.16b, v24.b[1]
.endif
.if \pri
dup v24.16b, v24.b[0]
.endif
1:
.if \w == 8
add x12, x2, #16
ld1 {v0.d}[0], [x2] // px
ld1 {v0.d}[1], [x12] // px
.else
add x12, x2, #1*8
add x13, x2, #2*8
add x14, x2, #3*8
ld1 {v0.s}[0], [x2] // px
ld1 {v0.s}[1], [x12] // px
ld1 {v0.s}[2], [x13] // px
ld1 {v0.s}[3], [x14] // px
.endif
// We need 9-bits or two 8-bit accululators to fit the sum.
// Max of |sum| > 15*2*6(pri) + 4*4*3(sec) = 228.
// Start sum at -1 instead of 0 to help handle rounding later.
movi v1.16b, #255 // sum
movi v2.16b, #0 // sum
.if \min
mov v3.16b, v0.16b // min
mov v4.16b, v0.16b // max
.endif
// Instead of loading sec_taps 2, 1 from memory, just set it
// to 2 initially and decrease for the second round.
// This is also used as loop counter.
mov w11, #2 // sec_taps[0]
2:
.if \pri
ldrb w9, [x5] // off1
load_px_8 v5, v6, \w
.endif
.if \sec
add x5, x5, #4 // +2*2
ldrb w9, [x5] // off2
load_px_8 v28, v29, \w
.endif
.if \pri
ldrb w10, [x8] // *pri_taps
handle_pixel_8 v5, v6, v25.16b, v24.16b, w10, \min
.endif
.if \sec
add x5, x5, #8 // +2*4
ldrb w9, [x5] // off3
load_px_8 v5, v6, \w
handle_pixel_8 v28, v29, v27.16b, v26.16b, w11, \min
handle_pixel_8 v5, v6, v27.16b, v26.16b, w11, \min
sub x5, x5, #11 // x5 -= 2*(2+4); x5 += 1;
.else
add x5, x5, #1 // x5 += 1
.endif
subs w11, w11, #1 // sec_tap-- (value)
.if \pri
add x8, x8, #1 // pri_taps++ (pointer)
.endif
b.ne 2b
// Perform halving adds since the value won't fit otherwise.
// To handle the offset for negative values, use both halving w/ and w/o rounding.
srhadd v5.16b, v1.16b, v2.16b // sum >> 1
shadd v6.16b, v1.16b, v2.16b // (sum - 1) >> 1
cmlt v1.16b, v5.16b, #0 // sum < 0
bsl v1.16b, v6.16b, v5.16b // (sum - (sum < 0)) >> 1
srshr v1.16b, v1.16b, #3 // (8 + sum - (sum < 0)) >> 4
usqadd v0.16b, v1.16b // px + (8 + sum ...) >> 4
.if \min
umin v0.16b, v0.16b, v4.16b
umax v0.16b, v0.16b, v3.16b // iclip(px + .., min, max)
.endif
.if \w == 8
st1 {v0.d}[0], [x0], x1
add x2, x2, #2*16 // tmp += 2*tmp_stride
subs w7, w7, #2 // h -= 2
st1 {v0.d}[1], [x0], x1
.else
st1 {v0.s}[0], [x0], x1
add x2, x2, #4*8 // tmp += 4*tmp_stride
st1 {v0.s}[1], [x0], x1
subs w7, w7, #4 // h -= 4
st1 {v0.s}[2], [x0], x1
st1 {v0.s}[3], [x0], x1
.endif
// Reset pri_taps and directions back to the original point
sub x5, x5, #2
.if \pri
sub x8, x8, #2
.endif
b.gt 1b
ret
endfunc
.endm
.macro filter_8 w
filter_func_8 \w, pri=1, sec=0, min=0, suffix=_pri
filter_func_8 \w, pri=0, sec=1, min=0, suffix=_sec
filter_func_8 \w, pri=1, sec=1, min=1, suffix=_pri_sec
.endm
filter_8 8
filter_8 4

View file

@ -0,0 +1,229 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2020, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include "src/arm/asm.S"
#include "util.S"
#include "cdef_tmpl.S"
.macro pad_top_bot_16 s1, s2, w, stride, reg, ret
tst w7, #1 // CDEF_HAVE_LEFT
b.eq 2f
// CDEF_HAVE_LEFT
sub \s1, \s1, #4
sub \s2, \s2, #4
tst w7, #2 // CDEF_HAVE_RIGHT
b.eq 1f
// CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
ldr \reg\()0, [\s1]
ldr d1, [\s1, #2*\w]
ldr \reg\()2, [\s2]
ldr d3, [\s2, #2*\w]
str \reg\()0, [x0]
str d1, [x0, #2*\w]
add x0, x0, #2*\stride
str \reg\()2, [x0]
str d3, [x0, #2*\w]
.if \ret
ret
.else
add x0, x0, #2*\stride
b 3f
.endif
1:
// CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
ldr \reg\()0, [\s1]
ldr s1, [\s1, #2*\w]
ldr \reg\()2, [\s2]
ldr s3, [\s2, #2*\w]
str \reg\()0, [x0]
str s1, [x0, #2*\w]
str s31, [x0, #2*\w+4]
add x0, x0, #2*\stride
str \reg\()2, [x0]
str s3, [x0, #2*\w]
str s31, [x0, #2*\w+4]
.if \ret
ret
.else
add x0, x0, #2*\stride
b 3f
.endif
2:
// !CDEF_HAVE_LEFT
tst w7, #2 // CDEF_HAVE_RIGHT
b.eq 1f
// !CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
ldr \reg\()0, [\s1]
ldr s1, [\s1, #2*\w]
ldr \reg\()2, [\s2]
ldr s3, [\s2, #2*\w]
str s31, [x0]
stur \reg\()0, [x0, #4]
str s1, [x0, #4+2*\w]
add x0, x0, #2*\stride
str s31, [x0]
stur \reg\()2, [x0, #4]
str s3, [x0, #4+2*\w]
.if \ret
ret
.else
add x0, x0, #2*\stride
b 3f
.endif
1:
// !CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
ldr \reg\()0, [\s1]
ldr \reg\()1, [\s2]
str s31, [x0]
stur \reg\()0, [x0, #4]
str s31, [x0, #4+2*\w]
add x0, x0, #2*\stride
str s31, [x0]
stur \reg\()1, [x0, #4]
str s31, [x0, #4+2*\w]
.if \ret
ret
.else
add x0, x0, #2*\stride
.endif
3:
.endm
.macro load_n_incr_16 dst, src, incr, w
.if \w == 4
ld1 {\dst\().4h}, [\src], \incr
.else
ld1 {\dst\().8h}, [\src], \incr
.endif
.endm
// void dav1d_cdef_paddingX_16bpc_neon(uint16_t *tmp, const pixel *src,
// ptrdiff_t src_stride, const pixel (*left)[2],
// const pixel *const top,
// const pixel *const bottom, int h,
// enum CdefEdgeFlags edges);
.macro padding_func_16 w, stride, reg
function cdef_padding\w\()_16bpc_neon, export=1
movi v30.8h, #0x80, lsl #8
mov v31.16b, v30.16b
sub x0, x0, #2*(2*\stride+2)
tst w7, #4 // CDEF_HAVE_TOP
b.ne 1f
// !CDEF_HAVE_TOP
st1 {v30.8h, v31.8h}, [x0], #32
.if \w == 8
st1 {v30.8h, v31.8h}, [x0], #32
.endif
b 3f
1:
// CDEF_HAVE_TOP
add x9, x4, x2
pad_top_bot_16 x4, x9, \w, \stride, \reg, 0
// Middle section
3:
tst w7, #1 // CDEF_HAVE_LEFT
b.eq 2f
// CDEF_HAVE_LEFT
tst w7, #2 // CDEF_HAVE_RIGHT
b.eq 1f
// CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
0:
ld1 {v0.s}[0], [x3], #4
ldr s2, [x1, #2*\w]
load_n_incr_16 v1, x1, x2, \w
subs w6, w6, #1
str s0, [x0]
stur \reg\()1, [x0, #4]
str s2, [x0, #4+2*\w]
add x0, x0, #2*\stride
b.gt 0b
b 3f
1:
// CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
ld1 {v0.s}[0], [x3], #4
load_n_incr_16 v1, x1, x2, \w
subs w6, w6, #1
str s0, [x0]
stur \reg\()1, [x0, #4]
str s31, [x0, #4+2*\w]
add x0, x0, #2*\stride
b.gt 1b
b 3f
2:
tst w7, #2 // CDEF_HAVE_RIGHT
b.eq 1f
// !CDEF_HAVE_LEFT+CDEF_HAVE_RIGHT
0:
ldr s1, [x1, #2*\w]
load_n_incr_16 v0, x1, x2, \w
subs w6, w6, #1
str s31, [x0]
stur \reg\()0, [x0, #4]
str s1, [x0, #4+2*\w]
add x0, x0, #2*\stride
b.gt 0b
b 3f
1:
// !CDEF_HAVE_LEFT+!CDEF_HAVE_RIGHT
load_n_incr_16 v0, x1, x2, \w
subs w6, w6, #1
str s31, [x0]
stur \reg\()0, [x0, #4]
str s31, [x0, #4+2*\w]
add x0, x0, #2*\stride
b.gt 1b
3:
tst w7, #8 // CDEF_HAVE_BOTTOM
b.ne 1f
// !CDEF_HAVE_BOTTOM
st1 {v30.8h, v31.8h}, [x0], #32
.if \w == 8
st1 {v30.8h, v31.8h}, [x0], #32
.endif
ret
1:
// CDEF_HAVE_BOTTOM
add x9, x5, x2
pad_top_bot_16 x5, x9, \w, \stride, \reg, 1
endfunc
.endm
padding_func_16 8, 16, q
padding_func_16 4, 8, d
tables
filter 8, 16
filter 4, 16
find_dir 16

View file

@ -0,0 +1,511 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2020, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include "src/arm/asm.S"
#include "util.S"
.macro dir_table w, stride
const directions\w
.byte -1 * \stride + 1, -2 * \stride + 2
.byte 0 * \stride + 1, -1 * \stride + 2
.byte 0 * \stride + 1, 0 * \stride + 2
.byte 0 * \stride + 1, 1 * \stride + 2
.byte 1 * \stride + 1, 2 * \stride + 2
.byte 1 * \stride + 0, 2 * \stride + 1
.byte 1 * \stride + 0, 2 * \stride + 0
.byte 1 * \stride + 0, 2 * \stride - 1
// Repeated, to avoid & 7
.byte -1 * \stride + 1, -2 * \stride + 2
.byte 0 * \stride + 1, -1 * \stride + 2
.byte 0 * \stride + 1, 0 * \stride + 2
.byte 0 * \stride + 1, 1 * \stride + 2
.byte 1 * \stride + 1, 2 * \stride + 2
.byte 1 * \stride + 0, 2 * \stride + 1
endconst
.endm
.macro tables
dir_table 8, 16
dir_table 4, 8
const pri_taps
.byte 4, 2, 3, 3
endconst
.endm
.macro load_px d1, d2, w
.if \w == 8
add x6, x2, w9, sxtb #1 // x + off
sub x9, x2, w9, sxtb #1 // x - off
ld1 {\d1\().8h}, [x6] // p0
ld1 {\d2\().8h}, [x9] // p1
.else
add x6, x2, w9, sxtb #1 // x + off
sub x9, x2, w9, sxtb #1 // x - off
ld1 {\d1\().4h}, [x6] // p0
add x6, x6, #2*8 // += stride
ld1 {\d2\().4h}, [x9] // p1
add x9, x9, #2*8 // += stride
ld1 {\d1\().d}[1], [x6] // p0
ld1 {\d2\().d}[1], [x9] // p1
.endif
.endm
.macro handle_pixel s1, s2, thresh_vec, shift, tap, min
.if \min
umin v2.8h, v2.8h, \s1\().8h
smax v3.8h, v3.8h, \s1\().8h
umin v2.8h, v2.8h, \s2\().8h
smax v3.8h, v3.8h, \s2\().8h
.endif
uabd v16.8h, v0.8h, \s1\().8h // abs(diff)
uabd v20.8h, v0.8h, \s2\().8h // abs(diff)
ushl v17.8h, v16.8h, \shift // abs(diff) >> shift
ushl v21.8h, v20.8h, \shift // abs(diff) >> shift
uqsub v17.8h, \thresh_vec, v17.8h // clip = imax(0, threshold - (abs(diff) >> shift))
uqsub v21.8h, \thresh_vec, v21.8h // clip = imax(0, threshold - (abs(diff) >> shift))
sub v18.8h, \s1\().8h, v0.8h // diff = p0 - px
sub v22.8h, \s2\().8h, v0.8h // diff = p1 - px
neg v16.8h, v17.8h // -clip
neg v20.8h, v21.8h // -clip
smin v18.8h, v18.8h, v17.8h // imin(diff, clip)
smin v22.8h, v22.8h, v21.8h // imin(diff, clip)
dup v19.8h, \tap // taps[k]
smax v18.8h, v18.8h, v16.8h // constrain() = imax(imin(diff, clip), -clip)
smax v22.8h, v22.8h, v20.8h // constrain() = imax(imin(diff, clip), -clip)
mla v1.8h, v18.8h, v19.8h // sum += taps[k] * constrain()
mla v1.8h, v22.8h, v19.8h // sum += taps[k] * constrain()
.endm
// void dav1d_cdef_filterX_Ybpc_neon(pixel *dst, ptrdiff_t dst_stride,
// const uint16_t *tmp, int pri_strength,
// int sec_strength, int dir, int damping,
// int h, size_t edges);
.macro filter_func w, bpc, pri, sec, min, suffix
function cdef_filter\w\suffix\()_\bpc\()bpc_neon
.if \bpc == 8
ldr w8, [sp] // edges
cmp w8, #0xf
b.eq cdef_filter\w\suffix\()_edged_8bpc_neon
.endif
.if \pri
.if \bpc == 16
ldr w9, [sp, #8] // bitdepth_max
clz w9, w9
sub w9, w9, #24 // -bitdepth_min_8
neg w9, w9 // bitdepth_min_8
.endif
movrel x8, pri_taps
.if \bpc == 16
lsr w9, w3, w9 // pri_strength >> bitdepth_min_8
and w9, w9, #1 // (pri_strength >> bitdepth_min_8) & 1
.else
and w9, w3, #1
.endif
add x8, x8, w9, uxtw #1
.endif
movrel x9, directions\w
add x5, x9, w5, uxtw #1
movi v30.4h, #15
dup v28.4h, w6 // damping
.if \pri
dup v25.8h, w3 // threshold
.endif
.if \sec
dup v27.8h, w4 // threshold
.endif
trn1 v24.4h, v25.4h, v27.4h
clz v24.4h, v24.4h // clz(threshold)
sub v24.4h, v30.4h, v24.4h // ulog2(threshold)
uqsub v24.4h, v28.4h, v24.4h // shift = imax(0, damping - ulog2(threshold))
neg v24.4h, v24.4h // -shift
.if \sec
dup v26.8h, v24.h[1]
.endif
.if \pri
dup v24.8h, v24.h[0]
.endif
1:
.if \w == 8
ld1 {v0.8h}, [x2] // px
.else
add x12, x2, #2*8
ld1 {v0.4h}, [x2] // px
ld1 {v0.d}[1], [x12] // px
.endif
movi v1.8h, #0 // sum
.if \min
mov v2.16b, v0.16b // min
mov v3.16b, v0.16b // max
.endif
// Instead of loading sec_taps 2, 1 from memory, just set it
// to 2 initially and decrease for the second round.
// This is also used as loop counter.
mov w11, #2 // sec_taps[0]
2:
.if \pri
ldrb w9, [x5] // off1
load_px v4, v5, \w
.endif
.if \sec
add x5, x5, #4 // +2*2
ldrb w9, [x5] // off2
load_px v6, v7, \w
.endif
.if \pri
ldrb w10, [x8] // *pri_taps
handle_pixel v4, v5, v25.8h, v24.8h, w10, \min
.endif
.if \sec
add x5, x5, #8 // +2*4
ldrb w9, [x5] // off3
load_px v4, v5, \w
handle_pixel v6, v7, v27.8h, v26.8h, w11, \min
handle_pixel v4, v5, v27.8h, v26.8h, w11, \min
sub x5, x5, #11 // x5 -= 2*(2+4); x5 += 1;
.else
add x5, x5, #1 // x5 += 1
.endif
subs w11, w11, #1 // sec_tap-- (value)
.if \pri
add x8, x8, #1 // pri_taps++ (pointer)
.endif
b.ne 2b
cmlt v4.8h, v1.8h, #0 // -(sum < 0)
add v1.8h, v1.8h, v4.8h // sum - (sum < 0)
srshr v1.8h, v1.8h, #4 // (8 + sum - (sum < 0)) >> 4
add v0.8h, v0.8h, v1.8h // px + (8 + sum ...) >> 4
.if \min
smin v0.8h, v0.8h, v3.8h
smax v0.8h, v0.8h, v2.8h // iclip(px + .., min, max)
.endif
.if \bpc == 8
xtn v0.8b, v0.8h
.endif
.if \w == 8
add x2, x2, #2*16 // tmp += tmp_stride
subs w7, w7, #1 // h--
.if \bpc == 8
st1 {v0.8b}, [x0], x1
.else
st1 {v0.8h}, [x0], x1
.endif
.else
.if \bpc == 8
st1 {v0.s}[0], [x0], x1
.else
st1 {v0.d}[0], [x0], x1
.endif
add x2, x2, #2*16 // tmp += 2*tmp_stride
subs w7, w7, #2 // h -= 2
.if \bpc == 8
st1 {v0.s}[1], [x0], x1
.else
st1 {v0.d}[1], [x0], x1
.endif
.endif
// Reset pri_taps and directions back to the original point
sub x5, x5, #2
.if \pri
sub x8, x8, #2
.endif
b.gt 1b
ret
endfunc
.endm
.macro filter w, bpc
filter_func \w, \bpc, pri=1, sec=0, min=0, suffix=_pri
filter_func \w, \bpc, pri=0, sec=1, min=0, suffix=_sec
filter_func \w, \bpc, pri=1, sec=1, min=1, suffix=_pri_sec
function cdef_filter\w\()_\bpc\()bpc_neon, export=1
cbnz w3, 1f // pri_strength
b cdef_filter\w\()_sec_\bpc\()bpc_neon // only sec
1:
cbnz w4, 1f // sec_strength
b cdef_filter\w\()_pri_\bpc\()bpc_neon // only pri
1:
b cdef_filter\w\()_pri_sec_\bpc\()bpc_neon // both pri and sec
endfunc
.endm
const div_table
.short 840, 420, 280, 210, 168, 140, 120, 105
endconst
const alt_fact
.short 420, 210, 140, 105, 105, 105, 105, 105, 140, 210, 420, 0
endconst
.macro cost_alt d1, d2, s1, s2, s3, s4
smull v22.4s, \s1\().4h, \s1\().4h // sum_alt[n]*sum_alt[n]
smull2 v23.4s, \s1\().8h, \s1\().8h
smull v24.4s, \s2\().4h, \s2\().4h
smull v25.4s, \s3\().4h, \s3\().4h // sum_alt[n]*sum_alt[n]
smull2 v26.4s, \s3\().8h, \s3\().8h
smull v27.4s, \s4\().4h, \s4\().4h
mul v22.4s, v22.4s, v29.4s // sum_alt[n]^2*fact
mla v22.4s, v23.4s, v30.4s
mla v22.4s, v24.4s, v31.4s
mul v25.4s, v25.4s, v29.4s // sum_alt[n]^2*fact
mla v25.4s, v26.4s, v30.4s
mla v25.4s, v27.4s, v31.4s
addv \d1, v22.4s // *cost_ptr
addv \d2, v25.4s // *cost_ptr
.endm
.macro find_best s1, s2, s3
.ifnb \s2
mov w5, \s2\().s[0]
.endif
cmp w4, w1 // cost[n] > best_cost
csel w0, w3, w0, gt // best_dir = n
csel w1, w4, w1, gt // best_cost = cost[n]
.ifnb \s2
add w3, w3, #1 // n++
cmp w5, w1 // cost[n] > best_cost
mov w4, \s3\().s[0]
csel w0, w3, w0, gt // best_dir = n
csel w1, w5, w1, gt // best_cost = cost[n]
add w3, w3, #1 // n++
.endif
.endm
// Steps for loading and preparing each row
.macro dir_load_step1 s1, bpc
.if \bpc == 8
ld1 {\s1\().8b}, [x0], x1
.else
ld1 {\s1\().8h}, [x0], x1
.endif
.endm
.macro dir_load_step2 s1, bpc
.if \bpc == 8
usubl \s1\().8h, \s1\().8b, v31.8b
.else
ushl \s1\().8h, \s1\().8h, v8.8h
.endif
.endm
.macro dir_load_step3 s1, bpc
// Nothing for \bpc == 8
.if \bpc != 8
sub \s1\().8h, \s1\().8h, v31.8h
.endif
.endm
// int dav1d_cdef_find_dir_Xbpc_neon(const pixel *img, const ptrdiff_t stride,
// unsigned *const var)
.macro find_dir bpc
function cdef_find_dir_\bpc\()bpc_neon, export=1
.if \bpc == 16
str d8, [sp, #-0x10]!
clz w3, w3 // clz(bitdepth_max)
sub w3, w3, #24 // -bitdepth_min_8
dup v8.8h, w3
.endif
sub sp, sp, #32 // cost
mov w3, #8
.if \bpc == 8
movi v31.16b, #128
.else
movi v31.8h, #128
.endif
movi v30.16b, #0
movi v1.8h, #0 // v0-v1 sum_diag[0]
movi v3.8h, #0 // v2-v3 sum_diag[1]
movi v5.8h, #0 // v4-v5 sum_hv[0-1]
movi v7.8h, #0 // v6-v7 sum_alt[0]
dir_load_step1 v26, \bpc // Setup first row early
movi v17.8h, #0 // v16-v17 sum_alt[1]
movi v18.8h, #0 // v18-v19 sum_alt[2]
dir_load_step2 v26, \bpc
movi v19.8h, #0
dir_load_step3 v26, \bpc
movi v21.8h, #0 // v20-v21 sum_alt[3]
.irpc i, 01234567
addv h25, v26.8h // [y]
rev64 v27.8h, v26.8h
addp v28.8h, v26.8h, v30.8h // [(x >> 1)]
add v5.8h, v5.8h, v26.8h // sum_hv[1]
ext v27.16b, v27.16b, v27.16b, #8 // [-x]
rev64 v29.4h, v28.4h // [-(x >> 1)]
ins v4.h[\i], v25.h[0] // sum_hv[0]
.if \i < 6
ext v22.16b, v30.16b, v26.16b, #(16-2*(3-(\i/2)))
ext v23.16b, v26.16b, v30.16b, #(16-2*(3-(\i/2)))
add v18.8h, v18.8h, v22.8h // sum_alt[2]
add v19.4h, v19.4h, v23.4h // sum_alt[2]
.else
add v18.8h, v18.8h, v26.8h // sum_alt[2]
.endif
.if \i == 0
mov v20.16b, v26.16b // sum_alt[3]
.elseif \i == 1
add v20.8h, v20.8h, v26.8h // sum_alt[3]
.else
ext v24.16b, v30.16b, v26.16b, #(16-2*(\i/2))
ext v25.16b, v26.16b, v30.16b, #(16-2*(\i/2))
add v20.8h, v20.8h, v24.8h // sum_alt[3]
add v21.4h, v21.4h, v25.4h // sum_alt[3]
.endif
.if \i == 0
mov v0.16b, v26.16b // sum_diag[0]
dir_load_step1 v26, \bpc
mov v2.16b, v27.16b // sum_diag[1]
dir_load_step2 v26, \bpc
mov v6.16b, v28.16b // sum_alt[0]
dir_load_step3 v26, \bpc
mov v16.16b, v29.16b // sum_alt[1]
.else
ext v22.16b, v30.16b, v26.16b, #(16-2*\i)
ext v23.16b, v26.16b, v30.16b, #(16-2*\i)
ext v24.16b, v30.16b, v27.16b, #(16-2*\i)
ext v25.16b, v27.16b, v30.16b, #(16-2*\i)
.if \i != 7 // Nothing to load for the final row
dir_load_step1 v26, \bpc // Start setting up the next row early.
.endif
add v0.8h, v0.8h, v22.8h // sum_diag[0]
add v1.8h, v1.8h, v23.8h // sum_diag[0]
add v2.8h, v2.8h, v24.8h // sum_diag[1]
add v3.8h, v3.8h, v25.8h // sum_diag[1]
.if \i != 7
dir_load_step2 v26, \bpc
.endif
ext v22.16b, v30.16b, v28.16b, #(16-2*\i)
ext v23.16b, v28.16b, v30.16b, #(16-2*\i)
ext v24.16b, v30.16b, v29.16b, #(16-2*\i)
ext v25.16b, v29.16b, v30.16b, #(16-2*\i)
.if \i != 7
dir_load_step3 v26, \bpc
.endif
add v6.8h, v6.8h, v22.8h // sum_alt[0]
add v7.4h, v7.4h, v23.4h // sum_alt[0]
add v16.8h, v16.8h, v24.8h // sum_alt[1]
add v17.4h, v17.4h, v25.4h // sum_alt[1]
.endif
.endr
movi v31.4s, #105
smull v26.4s, v4.4h, v4.4h // sum_hv[0]*sum_hv[0]
smlal2 v26.4s, v4.8h, v4.8h
smull v27.4s, v5.4h, v5.4h // sum_hv[1]*sum_hv[1]
smlal2 v27.4s, v5.8h, v5.8h
mul v26.4s, v26.4s, v31.4s // cost[2] *= 105
mul v27.4s, v27.4s, v31.4s // cost[6] *= 105
addv s4, v26.4s // cost[2]
addv s5, v27.4s // cost[6]
rev64 v1.8h, v1.8h
rev64 v3.8h, v3.8h
ext v1.16b, v1.16b, v1.16b, #10 // sum_diag[0][14-n]
ext v3.16b, v3.16b, v3.16b, #10 // sum_diag[1][14-n]
str s4, [sp, #2*4] // cost[2]
str s5, [sp, #6*4] // cost[6]
movrel x4, div_table
ld1 {v31.8h}, [x4]
smull v22.4s, v0.4h, v0.4h // sum_diag[0]*sum_diag[0]
smull2 v23.4s, v0.8h, v0.8h
smlal v22.4s, v1.4h, v1.4h
smlal2 v23.4s, v1.8h, v1.8h
smull v24.4s, v2.4h, v2.4h // sum_diag[1]*sum_diag[1]
smull2 v25.4s, v2.8h, v2.8h
smlal v24.4s, v3.4h, v3.4h
smlal2 v25.4s, v3.8h, v3.8h
uxtl v30.4s, v31.4h // div_table
uxtl2 v31.4s, v31.8h
mul v22.4s, v22.4s, v30.4s // cost[0]
mla v22.4s, v23.4s, v31.4s // cost[0]
mul v24.4s, v24.4s, v30.4s // cost[4]
mla v24.4s, v25.4s, v31.4s // cost[4]
addv s0, v22.4s // cost[0]
addv s2, v24.4s // cost[4]
movrel x5, alt_fact
ld1 {v29.4h, v30.4h, v31.4h}, [x5]// div_table[2*m+1] + 105
str s0, [sp, #0*4] // cost[0]
str s2, [sp, #4*4] // cost[4]
uxtl v29.4s, v29.4h // div_table[2*m+1] + 105
uxtl v30.4s, v30.4h
uxtl v31.4s, v31.4h
cost_alt s6, s16, v6, v7, v16, v17 // cost[1], cost[3]
cost_alt s18, s20, v18, v19, v20, v21 // cost[5], cost[7]
str s6, [sp, #1*4] // cost[1]
str s16, [sp, #3*4] // cost[3]
mov w0, #0 // best_dir
mov w1, v0.s[0] // best_cost
mov w3, #1 // n
str s18, [sp, #5*4] // cost[5]
str s20, [sp, #7*4] // cost[7]
mov w4, v6.s[0]
find_best v6, v4, v16
find_best v16, v2, v18
find_best v18, v5, v20
find_best v20
eor w3, w0, #4 // best_dir ^4
ldr w4, [sp, w3, uxtw #2]
sub w1, w1, w4 // best_cost - cost[best_dir ^ 4]
lsr w1, w1, #10
str w1, [x2] // *var
add sp, sp, #32
.if \bpc == 16
ldr d8, [sp], 0x10
.endif
ret
endfunc
.endm

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,925 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2020, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include "src/arm/asm.S"
#include "util.S"
// depending on how many pixels need to be stored, returns:
// x14 = (1 << 0) : 0 pixels
// x14 = (1 << 4) : inner 4 pixels
// x14 = (1 << 6) : inner 6 pixels
// x14 = 0 : all pixels
.macro loop_filter wd
function lpf_8_wd\wd\()_neon
uabd v0.8h, v22.8h, v23.8h // abs(p1 - p0)
uabd v1.8h, v25.8h, v24.8h // abs(q1 - q0)
uabd v2.8h, v23.8h, v24.8h // abs(p0 - q0)
uabd v3.8h, v22.8h, v25.8h // abs(p1 - q1)
.if \wd >= 6
uabd v4.8h, v21.8h, v22.8h // abs(p2 - p1)
uabd v5.8h, v26.8h, v25.8h // abs(q2 - q1)
.endif
.if \wd >= 8
uabd v6.8h, v20.8h, v21.8h // abs(p3 - p2)
uabd v7.8h, v27.8h, v26.8h // abs(q3 - q3)
.endif
.if \wd >= 6
umax v4.8h, v4.8h, v5.8h
.endif
uqadd v2.8h, v2.8h, v2.8h // abs(p0 - q0) * 2
.if \wd >= 8
umax v6.8h, v6.8h, v7.8h
.endif
ushr v3.8h, v3.8h, #1
.if \wd >= 8
umax v4.8h, v4.8h, v6.8h
.endif
.if \wd >= 6
and v4.16b, v4.16b, v14.16b
.endif
umax v0.8h, v0.8h, v1.8h // max(abs(p1 - p0), abs(q1 - q0))
uqadd v2.8h, v2.8h, v3.8h // abs(p0 - q0) * 2 + abs(p1 - q1) >> 1
.if \wd >= 6
umax v4.8h, v0.8h, v4.8h
cmhs v1.8h, v11.8h, v4.8h // max(abs(p1 - p0), abs(q1 - q0), abs(), abs(), ...) <= I
.else
cmhs v1.8h, v11.8h, v0.8h // max(abs(p1 - p0), abs(q1 - q0)) <= I
.endif
cmhs v2.8h, v10.8h, v2.8h // abs(p0 - q0) * 2 + abs(p1 - q1) >> 1 <= E
and v1.16b, v1.16b, v2.16b // fm
and v1.16b, v1.16b, v13.16b // fm && wd >= 4
.if \wd >= 6
and v14.16b, v14.16b, v1.16b // fm && wd > 4
.endif
.if \wd >= 16
and v15.16b, v15.16b, v1.16b // fm && wd == 16
.endif
mov x16, v1.d[0]
mov x17, v1.d[1]
adds x16, x16, x17
b.ne 9f // if (!fm || wd < 4) return;
mov x14, #(1 << 0)
ret
9:
.if \wd >= 6
movi v10.8h, #1
uabd v2.8h, v21.8h, v23.8h // abs(p2 - p0)
uabd v3.8h, v22.8h, v23.8h // abs(p1 - p0)
uabd v4.8h, v25.8h, v24.8h // abs(q1 - q0)
uabd v5.8h, v26.8h, v24.8h // abs(q2 - q0)
dup v9.8h, w9 // bitdepth_min_8
.if \wd >= 8
uabd v6.8h, v20.8h, v23.8h // abs(p3 - p0)
uabd v7.8h, v27.8h, v24.8h // abs(q3 - q0)
.endif
umax v2.8h, v2.8h, v3.8h
umax v4.8h, v4.8h, v5.8h
.if \wd >= 8
umax v6.8h, v6.8h, v7.8h
.endif
umax v2.8h, v2.8h, v4.8h
ushl v10.8h, v10.8h, v9.8h // F = 1 << bitdepth_min_8
.if \wd >= 8
umax v2.8h, v2.8h, v6.8h
.endif
.if \wd == 16
uabd v3.8h, v17.8h, v23.8h // abs(p6 - p0)
uabd v4.8h, v18.8h, v23.8h // abs(p5 - p0)
uabd v5.8h, v19.8h, v23.8h // abs(p4 - p0)
.endif
cmhs v2.8h, v10.8h, v2.8h // flat8in
.if \wd == 16
uabd v6.8h, v28.8h, v24.8h // abs(q4 - q0)
uabd v7.8h, v29.8h, v24.8h // abs(q5 - q0)
uabd v8.8h, v30.8h, v24.8h // abs(q6 - q0)
.endif
and v14.16b, v2.16b, v14.16b // flat8in && fm && wd > 4
bic v1.16b, v1.16b, v14.16b // fm && wd >= 4 && !flat8in
.if \wd == 16
umax v3.8h, v3.8h, v4.8h
umax v5.8h, v5.8h, v6.8h
.endif
mov x16, v1.d[0]
mov x17, v1.d[1]
.if \wd == 16
umax v7.8h, v7.8h, v8.8h
umax v3.8h, v3.8h, v5.8h
umax v3.8h, v3.8h, v7.8h
cmhs v3.8h, v10.8h, v3.8h // flat8out
.endif
adds x16, x16, x17
.if \wd == 16
and v15.16b, v15.16b, v3.16b // flat8out && fm && wd == 16
and v15.16b, v15.16b, v14.16b // flat8out && flat8in && fm && wd == 16
bic v14.16b, v14.16b, v15.16b // flat8in && fm && wd >= 4 && !flat8out
.endif
b.eq 1f // skip wd == 4 case
.endif
dup v3.8h, w8 // bitdepth_max
sub v2.8h, v22.8h, v25.8h // p1 - q1
ushr v3.8h, v3.8h, #1 // 128 << bitdepth_min_8 - 1
cmhi v0.8h, v0.8h, v12.8h // hev
not v9.16b, v3.16b // - 128 * (1 << bitdepth_min_8)
smin v2.8h, v2.8h, v3.8h // iclip_diff(p1 - q1)
smax v2.8h, v2.8h, v9.8h // iclip_diff(p1 - q1)
and v4.16b, v2.16b, v0.16b // if (hev) iclip_diff(p1 - q1)
sub v2.8h, v24.8h, v23.8h
movi v5.8h, #3
bic v0.16b, v1.16b, v0.16b // (fm && wd >= 4 && !hev)
mul v2.8h, v2.8h, v5.8h
movi v6.8h, #4
add v2.8h, v2.8h, v4.8h
smin v2.8h, v2.8h, v3.8h // f = iclip_diff()
smax v2.8h, v2.8h, v9.8h // f = iclip_diff()
sqadd v4.8h, v6.8h, v2.8h // f + 4
sqadd v5.8h, v5.8h, v2.8h // f + 3
smin v4.8h, v4.8h, v3.8h // imin(f + 4, 128 << bitdepth_min_8 - 1)
smin v5.8h, v5.8h, v3.8h // imin(f + 3, 128 << bitdepth_min_8 - 1)
sshr v4.8h, v4.8h, #3 // f1
sshr v5.8h, v5.8h, #3 // f2
movi v9.8h, #0
dup v3.8h, w8 // bitdepth_max
sqadd v2.8h, v23.8h, v5.8h // p0 + f2
sqsub v6.8h, v24.8h, v4.8h // q0 - f1
srshr v4.8h, v4.8h, #1 // (f1 + 1) >> 1
smin v2.8h, v2.8h, v3.8h // out p0 = iclip_pixel()
smin v6.8h, v6.8h, v3.8h // out q0 = iclip_pixel()
smax v2.8h, v2.8h, v9.8h // out p0 = iclip_pixel()
smax v6.8h, v6.8h, v9.8h // out q0 = iclip_pixel()
bit v23.16b, v2.16b, v1.16b // if (fm && wd >= 4)
bit v24.16b, v6.16b, v1.16b // if (fm && wd >= 4)
sqadd v2.8h, v22.8h, v4.8h // p1 + f
sqsub v6.8h, v25.8h, v4.8h // q1 - f
smin v2.8h, v2.8h, v3.8h // out p1 = iclip_pixel()
smin v6.8h, v6.8h, v3.8h // out q1 = iclip_pixel()
smax v2.8h, v2.8h, v9.8h // out p1 = iclip_pixel()
smax v6.8h, v6.8h, v9.8h // out q1 = iclip_pixel()
bit v22.16b, v2.16b, v0.16b // if (fm && wd >= 4 && !hev)
bit v25.16b, v6.16b, v0.16b // if (fm && wd >= 4 && !hev)
1:
.if \wd == 6
mov x16, v14.d[0]
mov x17, v14.d[1]
adds x16, x16, x17
b.eq 2f // skip if there's no flat8in
add v0.8h, v21.8h, v21.8h // p2 * 2
add v2.8h, v21.8h, v22.8h // p2 + p1
add v4.8h, v22.8h, v23.8h // p1 + p0
add v6.8h, v23.8h, v24.8h // p0 + q0
add v8.8h, v0.8h, v2.8h
add v10.8h, v4.8h, v6.8h
add v12.8h, v24.8h, v25.8h // q0 + q1
add v8.8h, v8.8h, v10.8h
sub v12.8h, v12.8h, v0.8h
add v10.8h, v25.8h, v26.8h // q1 + q2
urshr v0.8h, v8.8h, #3 // out p1
add v8.8h, v8.8h, v12.8h
sub v10.8h, v10.8h, v2.8h
add v12.8h, v26.8h, v26.8h // q2 + q2
urshr v1.8h, v8.8h, #3 // out p0
add v8.8h, v8.8h, v10.8h
sub v12.8h, v12.8h, v4.8h
urshr v2.8h, v8.8h, #3 // out q0
bit v22.16b, v0.16b, v14.16b // p1 if (flat8in)
add v8.8h, v8.8h, v12.8h
bit v23.16b, v1.16b, v14.16b // p0 if (flat8in)
urshr v3.8h, v8.8h, #3 // out q1
bit v24.16b, v2.16b, v14.16b // q0 if (flat8in)
bit v25.16b, v3.16b, v14.16b // q1 if (flat8in)
.elseif \wd >= 8
mov x16, v14.d[0]
mov x17, v14.d[1]
adds x16, x16, x17
.if \wd == 8
b.eq 8f // skip if there's no flat8in
.else
b.eq 2f // skip if there's no flat8in
.endif
add v0.8h, v20.8h, v21.8h // p3 + p2
add v2.8h, v22.8h, v25.8h // p1 + q1
add v4.8h, v20.8h, v22.8h // p3 + p1
add v6.8h, v23.8h, v26.8h // p0 + q2
add v8.8h, v0.8h, v0.8h // 2 * (p3 + p2)
add v9.8h, v23.8h, v24.8h // p0 + q0
add v8.8h, v8.8h, v4.8h // + p3 + p1
sub v2.8h, v2.8h, v0.8h // p1 + q1 - p3 - p2
add v8.8h, v8.8h, v9.8h // + p0 + q0
sub v6.8h, v6.8h, v4.8h // p0 + q2 - p3 - p1
urshr v10.8h, v8.8h, #3 // out p2
add v8.8h, v8.8h, v2.8h
add v0.8h, v20.8h, v23.8h // p3 + p0
add v2.8h, v24.8h, v27.8h // q0 + q3
urshr v11.8h, v8.8h, #3 // out p1
add v8.8h, v8.8h, v6.8h
sub v2.8h, v2.8h, v0.8h // q0 + q3 - p3 - p0
add v4.8h, v21.8h, v24.8h // p2 + q0
add v6.8h, v25.8h, v27.8h // q1 + q3
urshr v12.8h, v8.8h, #3 // out p0
add v8.8h, v8.8h, v2.8h
sub v6.8h, v6.8h, v4.8h // q1 + q3 - p2 - q0
add v0.8h, v22.8h, v25.8h // p1 + q1
add v2.8h, v26.8h, v27.8h // q2 + q3
urshr v13.8h, v8.8h, #3 // out q0
add v8.8h, v8.8h, v6.8h
sub v2.8h, v2.8h, v0.8h // q2 + q3 - p1 - q1
urshr v0.8h, v8.8h, #3 // out q1
add v8.8h, v8.8h, v2.8h
bit v21.16b, v10.16b, v14.16b
bit v22.16b, v11.16b, v14.16b
bit v23.16b, v12.16b, v14.16b
urshr v1.8h, v8.8h, #3 // out q2
bit v24.16b, v13.16b, v14.16b
bit v25.16b, v0.16b, v14.16b
bit v26.16b, v1.16b, v14.16b
.endif
2:
.if \wd == 16
mov x16, v15.d[0]
mov x17, v15.d[1]
adds x16, x16, x17
b.ne 1f // check if flat8out is needed
mov x16, v14.d[0]
mov x17, v14.d[1]
adds x16, x16, x17
b.eq 8f // if there was no flat8in, just write the inner 4 pixels
b 7f // if flat8in was used, write the inner 6 pixels
1:
add v2.8h, v17.8h, v17.8h // p6 + p6
add v4.8h, v17.8h, v18.8h // p6 + p5
add v6.8h, v17.8h, v19.8h // p6 + p4
add v8.8h, v17.8h, v20.8h // p6 + p3
add v12.8h, v2.8h, v4.8h
add v10.8h, v6.8h, v8.8h
add v6.8h, v17.8h, v21.8h // p6 + p2
add v12.8h, v12.8h, v10.8h
add v8.8h, v17.8h, v22.8h // p6 + p1
add v10.8h, v18.8h, v23.8h // p5 + p0
add v6.8h, v6.8h, v8.8h
add v8.8h, v19.8h, v24.8h // p4 + q0
add v12.8h, v12.8h, v6.8h
add v10.8h, v10.8h, v8.8h
add v6.8h, v20.8h, v25.8h // p3 + q1
add v12.8h, v12.8h, v10.8h
sub v6.8h, v6.8h, v2.8h
add v2.8h, v21.8h, v26.8h // p2 + q2
urshr v0.8h, v12.8h, #4 // out p5
add v12.8h, v12.8h, v6.8h // - (p6 + p6) + (p3 + q1)
sub v2.8h, v2.8h, v4.8h
add v4.8h, v22.8h, v27.8h // p1 + q3
add v6.8h, v17.8h, v19.8h // p6 + p4
urshr v1.8h, v12.8h, #4 // out p4
add v12.8h, v12.8h, v2.8h // - (p6 + p5) + (p2 + q2)
sub v4.8h, v4.8h, v6.8h
add v6.8h, v23.8h, v28.8h // p0 + q4
add v8.8h, v17.8h, v20.8h // p6 + p3
urshr v2.8h, v12.8h, #4 // out p3
add v12.8h, v12.8h, v4.8h // - (p6 + p4) + (p1 + q3)
sub v6.8h, v6.8h, v8.8h
add v8.8h, v24.8h, v29.8h // q0 + q5
add v4.8h, v17.8h, v21.8h // p6 + p2
urshr v3.8h, v12.8h, #4 // out p2
add v12.8h, v12.8h, v6.8h // - (p6 + p3) + (p0 + q4)
sub v8.8h, v8.8h, v4.8h
add v6.8h, v25.8h, v30.8h // q1 + q6
add v10.8h, v17.8h, v22.8h // p6 + p1
urshr v4.8h, v12.8h, #4 // out p1
add v12.8h, v12.8h, v8.8h // - (p6 + p2) + (q0 + q5)
sub v6.8h, v6.8h, v10.8h
add v8.8h, v26.8h, v30.8h // q2 + q6
bif v0.16b, v18.16b, v15.16b // out p5
add v10.8h, v18.8h, v23.8h // p5 + p0
urshr v5.8h, v12.8h, #4 // out p0
add v12.8h, v12.8h, v6.8h // - (p6 + p1) + (q1 + q6)
sub v8.8h, v8.8h, v10.8h
add v10.8h, v27.8h, v30.8h // q3 + q6
bif v1.16b, v19.16b, v15.16b // out p4
add v18.8h, v19.8h, v24.8h // p4 + q0
urshr v6.8h, v12.8h, #4 // out q0
add v12.8h, v12.8h, v8.8h // - (p5 + p0) + (q2 + q6)
sub v10.8h, v10.8h, v18.8h
add v8.8h, v28.8h, v30.8h // q4 + q6
bif v2.16b, v20.16b, v15.16b // out p3
add v18.8h, v20.8h, v25.8h // p3 + q1
urshr v7.8h, v12.8h, #4 // out q1
add v12.8h, v12.8h, v10.8h // - (p4 + q0) + (q3 + q6)
sub v18.8h, v8.8h, v18.8h
add v10.8h, v29.8h, v30.8h // q5 + q6
bif v3.16b, v21.16b, v15.16b // out p2
add v20.8h, v21.8h, v26.8h // p2 + q2
urshr v8.8h, v12.8h, #4 // out q2
add v12.8h, v12.8h, v18.8h // - (p3 + q1) + (q4 + q6)
sub v10.8h, v10.8h, v20.8h
add v18.8h, v30.8h, v30.8h // q6 + q6
bif v4.16b, v22.16b, v15.16b // out p1
add v20.8h, v22.8h, v27.8h // p1 + q3
urshr v9.8h, v12.8h, #4 // out q3
add v12.8h, v12.8h, v10.8h // - (p2 + q2) + (q5 + q6)
sub v18.8h, v18.8h, v20.8h
bif v5.16b, v23.16b, v15.16b // out p0
urshr v10.8h, v12.8h, #4 // out q4
add v12.8h, v12.8h, v18.8h // - (p1 + q3) + (q6 + q6)
urshr v11.8h, v12.8h, #4 // out q5
bif v6.16b, v24.16b, v15.16b // out q0
bif v7.16b, v25.16b, v15.16b // out q1
bif v8.16b, v26.16b, v15.16b // out q2
bif v9.16b, v27.16b, v15.16b // out q3
bif v10.16b, v28.16b, v15.16b // out q4
bif v11.16b, v29.16b, v15.16b // out q5
.endif
mov x14, #0
ret
.if \wd == 16
7:
// Return to a shorter epilogue, writing only the inner 6 pixels
mov x14, #(1 << 6)
ret
.endif
.if \wd >= 8
8:
// Return to a shorter epilogue, writing only the inner 4 pixels
mov x14, #(1 << 4)
ret
.endif
endfunc
.endm
loop_filter 16
loop_filter 8
loop_filter 6
loop_filter 4
.macro lpf_8_wd16
bl lpf_8_wd16_neon
cbz x14, 1f
tbnz x14, #6, 7f
tbnz x14, #4, 8f
ret x15
1:
.endm
.macro lpf_8_wd8
bl lpf_8_wd8_neon
cbz x14, 1f
tbnz x14, #4, 8f
ret x15
1:
.endm
.macro lpf_8_wd6
bl lpf_8_wd6_neon
cbz x14, 1f
ret x15
1:
.endm
.macro lpf_8_wd4
bl lpf_8_wd4_neon
cbz x14, 1f
ret x15
1:
.endm
function lpf_v_4_8_neon
mov x15, x30
sub x16, x0, x1, lsl #1
ld1 {v22.8h}, [x16], x1 // p1
ld1 {v24.8h}, [x0], x1 // q0
ld1 {v23.8h}, [x16], x1 // p0
ld1 {v25.8h}, [x0], x1 // q1
sub x0, x0, x1, lsl #1
lpf_8_wd4
sub x16, x0, x1, lsl #1
st1 {v22.8h}, [x16], x1 // p1
st1 {v24.8h}, [x0], x1 // q0
st1 {v23.8h}, [x16], x1 // p0
st1 {v25.8h}, [x0], x1 // q1
sub x0, x0, x1, lsl #1
ret x15
endfunc
function lpf_h_4_8_neon
mov x15, x30
sub x16, x0, #4
add x0, x16, x1, lsl #2
ld1 {v22.d}[0], [x16], x1
ld1 {v22.d}[1], [x0], x1
ld1 {v23.d}[0], [x16], x1
ld1 {v23.d}[1], [x0], x1
ld1 {v24.d}[0], [x16], x1
ld1 {v24.d}[1], [x0], x1
ld1 {v25.d}[0], [x16], x1
ld1 {v25.d}[1], [x0], x1
add x0, x0, #4
transpose_4x8h v22, v23, v24, v25, v26, v27, v28, v29
lpf_8_wd4
sub x16, x0, x1, lsl #3
sub x16, x16, #4
transpose_4x8h v22, v23, v24, v25, v26, v27, v28, v29
add x0, x16, x1, lsl #2
st1 {v22.d}[0], [x16], x1
st1 {v22.d}[1], [x0], x1
st1 {v23.d}[0], [x16], x1
st1 {v23.d}[1], [x0], x1
st1 {v24.d}[0], [x16], x1
st1 {v24.d}[1], [x0], x1
st1 {v25.d}[0], [x16], x1
st1 {v25.d}[1], [x0], x1
add x0, x0, #4
ret x15
endfunc
function lpf_v_6_8_neon
mov x15, x30
sub x16, x0, x1, lsl #1
sub x16, x16, x1
ld1 {v21.8h}, [x16], x1 // p2
ld1 {v24.8h}, [x0], x1 // q0
ld1 {v22.8h}, [x16], x1 // p1
ld1 {v25.8h}, [x0], x1 // q1
ld1 {v23.8h}, [x16], x1 // p0
ld1 {v26.8h}, [x0], x1 // q2
sub x0, x0, x1, lsl #1
sub x0, x0, x1
lpf_8_wd6
sub x16, x0, x1, lsl #1
st1 {v22.8h}, [x16], x1 // p1
st1 {v24.8h}, [x0], x1 // q0
st1 {v23.8h}, [x16], x1 // p0
st1 {v25.8h}, [x0], x1 // q1
sub x0, x0, x1, lsl #1
ret x15
endfunc
function lpf_h_6_8_neon
mov x15, x30
sub x16, x0, #8
add x0, x16, x1, lsl #2
ld1 {v20.8h}, [x16], x1
ld1 {v24.8h}, [x0], x1
ld1 {v21.8h}, [x16], x1
ld1 {v25.8h}, [x0], x1
ld1 {v22.8h}, [x16], x1
ld1 {v26.8h}, [x0], x1
ld1 {v23.8h}, [x16], x1
ld1 {v27.8h}, [x0], x1
add x0, x0, #8
transpose_8x8h v20, v21, v22, v23, v24, v25, v26, v27, v28, v29
lpf_8_wd6
sub x16, x0, x1, lsl #3
sub x16, x16, #4
transpose_4x8h v22, v23, v24, v25, v26, v27, v28, v29
add x0, x16, x1, lsl #2
st1 {v22.d}[0], [x16], x1
st1 {v22.d}[1], [x0], x1
st1 {v23.d}[0], [x16], x1
st1 {v23.d}[1], [x0], x1
st1 {v24.d}[0], [x16], x1
st1 {v24.d}[1], [x0], x1
st1 {v25.d}[0], [x16], x1
st1 {v25.d}[1], [x0], x1
add x0, x0, #4
ret x15
endfunc
function lpf_v_8_8_neon
mov x15, x30
sub x16, x0, x1, lsl #2
ld1 {v20.8h}, [x16], x1 // p3
ld1 {v24.8h}, [x0], x1 // q0
ld1 {v21.8h}, [x16], x1 // p2
ld1 {v25.8h}, [x0], x1 // q1
ld1 {v22.8h}, [x16], x1 // p1
ld1 {v26.8h}, [x0], x1 // q2
ld1 {v23.8h}, [x16], x1 // p0
ld1 {v27.8h}, [x0], x1 // q3
sub x0, x0, x1, lsl #2
lpf_8_wd8
sub x16, x0, x1, lsl #1
sub x16, x16, x1
st1 {v21.8h}, [x16], x1 // p2
st1 {v24.8h}, [x0], x1 // q0
st1 {v22.8h}, [x16], x1 // p1
st1 {v25.8h}, [x0], x1 // q1
st1 {v23.8h}, [x16], x1 // p0
st1 {v26.8h}, [x0], x1 // q2
sub x0, x0, x1, lsl #1
sub x0, x0, x1
ret x15
8:
sub x16, x0, x1, lsl #1
st1 {v22.8h}, [x16], x1 // p1
st1 {v24.8h}, [x0], x1 // q0
st1 {v23.8h}, [x16], x1 // p0
st1 {v25.8h}, [x0], x1 // q1
sub x0, x0, x1, lsl #1
ret x15
endfunc
function lpf_h_8_8_neon
mov x15, x30
sub x16, x0, #8
add x0, x16, x1, lsl #2
ld1 {v20.8h}, [x16], x1
ld1 {v24.8h}, [x0], x1
ld1 {v21.8h}, [x16], x1
ld1 {v25.8h}, [x0], x1
ld1 {v22.8h}, [x16], x1
ld1 {v26.8h}, [x0], x1
ld1 {v23.8h}, [x16], x1
ld1 {v27.8h}, [x0], x1
add x0, x0, #8
transpose_8x8h v20, v21, v22, v23, v24, v25, v26, v27, v28, v29
lpf_8_wd8
sub x16, x0, x1, lsl #3
sub x16, x16, #8
transpose_8x8h v20, v21, v22, v23, v24, v25, v26, v27, v28, v29
add x0, x16, x1, lsl #2
st1 {v20.8h}, [x16], x1
st1 {v24.8h}, [x0], x1
st1 {v21.8h}, [x16], x1
st1 {v25.8h}, [x0], x1
st1 {v22.8h}, [x16], x1
st1 {v26.8h}, [x0], x1
st1 {v23.8h}, [x16], x1
st1 {v27.8h}, [x0], x1
add x0, x0, #8
ret x15
8:
sub x16, x0, x1, lsl #3
sub x16, x16, #4
transpose_4x8h v22, v23, v24, v25, v26, v27, v28, v29
add x0, x16, x1, lsl #2
st1 {v22.d}[0], [x16], x1
st1 {v22.d}[1], [x0], x1
st1 {v23.d}[0], [x16], x1
st1 {v23.d}[1], [x0], x1
st1 {v24.d}[0], [x16], x1
st1 {v24.d}[1], [x0], x1
st1 {v25.d}[0], [x16], x1
st1 {v25.d}[1], [x0], x1
add x0, x0, #4
ret x15
endfunc
function lpf_v_16_8_neon
mov x15, x30
sub x16, x0, x1, lsl #3
add x16, x16, x1
ld1 {v17.8h}, [x16], x1 // p6
ld1 {v24.8h}, [x0], x1 // q0
ld1 {v18.8h}, [x16], x1 // p5
ld1 {v25.8h}, [x0], x1 // q1
ld1 {v19.8h}, [x16], x1 // p4
ld1 {v26.8h}, [x0], x1 // q2
ld1 {v20.8h}, [x16], x1 // p3
ld1 {v27.8h}, [x0], x1 // q3
ld1 {v21.8h}, [x16], x1 // p2
ld1 {v28.8h}, [x0], x1 // q4
ld1 {v22.8h}, [x16], x1 // p1
ld1 {v29.8h}, [x0], x1 // q5
ld1 {v23.8h}, [x16], x1 // p0
ld1 {v30.8h}, [x0], x1 // q6
sub x0, x0, x1, lsl #3
add x0, x0, x1
lpf_8_wd16
sub x16, x0, x1, lsl #2
sub x16, x16, x1, lsl #1
st1 {v0.8h}, [x16], x1 // p5
st1 {v6.8h}, [x0], x1 // q0
st1 {v1.8h}, [x16], x1 // p4
st1 {v7.8h}, [x0], x1 // q1
st1 {v2.8h}, [x16], x1 // p3
st1 {v8.8h}, [x0], x1 // q2
st1 {v3.8h}, [x16], x1 // p2
st1 {v9.8h}, [x0], x1 // q3
st1 {v4.8h}, [x16], x1 // p1
st1 {v10.8h}, [x0], x1 // q4
st1 {v5.8h}, [x16], x1 // p0
st1 {v11.8h}, [x0], x1 // q5
sub x0, x0, x1, lsl #2
sub x0, x0, x1, lsl #1
ret x15
7:
sub x16, x0, x1
sub x16, x16, x1, lsl #1
st1 {v21.8h}, [x16], x1 // p2
st1 {v24.8h}, [x0], x1 // q0
st1 {v22.8h}, [x16], x1 // p1
st1 {v25.8h}, [x0], x1 // q1
st1 {v23.8h}, [x16], x1 // p0
st1 {v26.8h}, [x0], x1 // q2
sub x0, x0, x1, lsl #1
sub x0, x0, x1
ret x15
8:
sub x16, x0, x1, lsl #1
st1 {v22.8h}, [x16], x1 // p1
st1 {v24.8h}, [x0], x1 // q0
st1 {v23.8h}, [x16], x1 // p0
st1 {v25.8h}, [x0], x1 // q1
sub x0, x0, x1, lsl #1
ret x15
endfunc
function lpf_h_16_8_neon
mov x15, x30
sub x16, x0, #16
ld1 {v16.8h}, [x16], x1
ld1 {v24.8h}, [x0], x1
ld1 {v17.8h}, [x16], x1
ld1 {v25.8h}, [x0], x1
ld1 {v18.8h}, [x16], x1
ld1 {v26.8h}, [x0], x1
ld1 {v19.8h}, [x16], x1
ld1 {v27.8h}, [x0], x1
ld1 {v20.8h}, [x16], x1
ld1 {v28.8h}, [x0], x1
ld1 {v21.8h}, [x16], x1
ld1 {v29.8h}, [x0], x1
ld1 {v22.8h}, [x16], x1
ld1 {v30.8h}, [x0], x1
ld1 {v23.8h}, [x16], x1
ld1 {v31.8h}, [x0], x1
transpose_8x8h v16, v17, v18, v19, v20, v21, v22, v23, v0, v1
transpose_8x8h v24, v25, v26, v27, v28, v29, v30, v31, v0, v1
lpf_8_wd16
sub x0, x0, x1, lsl #3
sub x16, x0, #16
transpose_8x8h v16, v17, v0, v1, v2, v3, v4, v5, v18, v19
transpose_8x8h v6, v7, v8, v9, v10, v11, v30, v31, v18, v19
st1 {v16.8h}, [x16], x1
st1 {v6.8h}, [x0], x1
st1 {v17.8h}, [x16], x1
st1 {v7.8h}, [x0], x1
st1 {v0.8h}, [x16], x1
st1 {v8.8h}, [x0], x1
st1 {v1.8h}, [x16], x1
st1 {v9.8h}, [x0], x1
st1 {v2.8h}, [x16], x1
st1 {v10.8h}, [x0], x1
st1 {v3.8h}, [x16], x1
st1 {v11.8h}, [x0], x1
st1 {v4.8h}, [x16], x1
st1 {v30.8h}, [x0], x1
st1 {v5.8h}, [x16], x1
st1 {v31.8h}, [x0], x1
ret x15
7:
sub x16, x0, x1, lsl #3
sub x16, x16, #8
transpose_8x8h v20, v21, v22, v23, v24, v25, v26, v27, v28, v29
add x0, x16, x1, lsl #2
st1 {v20.8h}, [x16], x1
st1 {v24.8h}, [x0], x1
st1 {v21.8h}, [x16], x1
st1 {v25.8h}, [x0], x1
st1 {v22.8h}, [x16], x1
st1 {v26.8h}, [x0], x1
st1 {v23.8h}, [x16], x1
st1 {v27.8h}, [x0], x1
add x0, x0, #8
ret x15
8:
sub x16, x0, x1, lsl #3
sub x16, x16, #4
transpose_4x8h v22, v23, v24, v25, v26, v27, v28, v29
add x0, x16, x1, lsl #2
st1 {v22.d}[0], [x16], x1
st1 {v22.d}[1], [x0], x1
st1 {v23.d}[0], [x16], x1
st1 {v23.d}[1], [x0], x1
st1 {v24.d}[0], [x16], x1
st1 {v24.d}[1], [x0], x1
st1 {v25.d}[0], [x16], x1
st1 {v25.d}[1], [x0], x1
add x0, x0, #4
ret x15
endfunc
// void dav1d_lpf_v_sb_y_16bpc_neon(pixel *dst, const ptrdiff_t stride,
// const uint32_t *const vmask,
// const uint8_t (*l)[4], ptrdiff_t b4_stride,
// const Av1FilterLUT *lut, const int w,
// const int bitdepth_max)
.macro lpf_func dir, type
function lpf_\dir\()_sb_\type\()_16bpc_neon, export=1
mov x11, x30
mov w8, w7 // bitdepth_max
clz w9, w8
mov w10, #24
sub w9, w10, w9 // bitdepth_min_8
stp d8, d9, [sp, #-0x40]!
stp d10, d11, [sp, #0x10]
stp d12, d13, [sp, #0x20]
stp d14, d15, [sp, #0x30]
ldp w6, w7, [x2] // vmask[0], vmask[1]
.ifc \type, y
ldr w2, [x2, #8] // vmask[2]
.endif
add x5, x5, #128 // Move to sharp part of lut
.ifc \type, y
orr w7, w7, w2 // vmask[1] |= vmask[2]
.endif
.ifc \dir, v
sub x4, x3, x4, lsl #2
.else
sub x3, x3, #4
lsl x4, x4, #2
.endif
orr w6, w6, w7 // vmask[0] |= vmask[1]
1:
tst w6, #0x03
.ifc \dir, v
ld1 {v0.8b}, [x4], #8
ld1 {v1.8b}, [x3], #8
.else
ld2 {v0.s,v1.s}[0], [x3], x4
ld2 {v0.s,v1.s}[1], [x3], x4
.endif
b.eq 7f // if (!(vm & bits)) continue;
ld1r {v5.8b}, [x5] // sharp[0]
add x5, x5, #8
movi v2.2s, #0xff
dup v13.2s, w6 // vmask[0]
dup v31.8h, w9 // bitdepth_min_8
and v0.8b, v0.8b, v2.8b // Keep only lowest byte in each 32 bit word
and v1.8b, v1.8b, v2.8b
cmtst v3.8b, v1.8b, v2.8b // Check for nonzero values in l[0][0]
movi v4.8b, #1
ld1r {v6.8b}, [x5] // sharp[1]
sub x5, x5, #8
bif v1.8b, v0.8b, v3.8b // if (!l[0][0]) L = l[offset][0]
cmtst v2.2s, v1.2s, v2.2s // L != 0
mul v1.2s, v1.2s, v4.2s // L
.ifc \type, y
dup v15.2s, w2 // vmask[2]
.endif
dup v14.2s, w7 // vmask[1]
mov x16, v2.d[0]
cmp x16, #0
b.eq 7f // if (!L) continue;
neg v5.8b, v5.8b // -sharp[0]
movrel x16, word_12
ushr v12.8b, v1.8b, #4 // H
ld1 {v16.2s}, [x16]
sshl v3.8b, v1.8b, v5.8b // L >> sharp[0]
.ifc \type, y
cmtst v15.2s, v15.2s, v16.2s // if (vmask[2] & bits)
.endif
movi v7.8b, #2
umin v3.8b, v3.8b, v6.8b // imin(L >> sharp[0], sharp[1])
add v0.8b, v1.8b, v7.8b // L + 2
umax v11.8b, v3.8b, v4.8b // imax(imin(), 1) = limit = I
add v0.8b, v0.8b, v0.8b // 2*(L + 2)
cmtst v14.2s, v14.2s, v16.2s // if (vmask[1] & bits)
uxtl v12.8h, v12.8b
add v10.8b, v0.8b, v11.8b // 2*(L + 2) + limit = E
cmtst v13.2s, v13.2s, v16.2s // if (vmask[0] & bits)
uxtl v11.8h, v11.8b
uxtl v10.8h, v10.8b
and v13.8b, v13.8b, v2.8b // vmask[0] &= L != 0
sxtl v14.8h, v14.8b
sxtl v13.8h, v13.8b
.ifc \type, y
sxtl v15.8h, v15.8b
.endif
ushl v12.8h, v12.8h, v31.8h
ushl v11.8h, v11.8h, v31.8h
ushl v10.8h, v10.8h, v31.8h
.ifc \type, y
tst w2, #0x03
b.eq 2f
// wd16
bl lpf_\dir\()_16_8_neon
b 8f
2:
.endif
tst w7, #0x03
b.eq 3f
.ifc \type, y
// wd8
bl lpf_\dir\()_8_8_neon
.else
// wd6
bl lpf_\dir\()_6_8_neon
.endif
b 8f
3:
// wd4
bl lpf_\dir\()_4_8_neon
.ifc \dir, h
b 8f
7:
// For dir h, the functions above increment x0.
// If the whole function is skipped, increment it here instead.
add x0, x0, x1, lsl #3
.else
7:
.endif
8:
lsr w6, w6, #2 // vmask[0] >>= 2
lsr w7, w7, #2 // vmask[1] >>= 2
.ifc \type, y
lsr w2, w2, #2 // vmask[2] >>= 2
.endif
.ifc \dir, v
add x0, x0, #16
.else
// For dir h, x0 is returned incremented
.endif
cbnz w6, 1b
ldp d14, d15, [sp, #0x30]
ldp d12, d13, [sp, #0x20]
ldp d10, d11, [sp, #0x10]
ldp d8, d9, [sp], 0x40
ret x11
endfunc
.endm
lpf_func v, y
lpf_func h, y
lpf_func v, uv
lpf_func h, uv
const word_12
.word 1, 2
endconst

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,334 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2018, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include "src/arm/asm.S"
#include "util.S"
// Series of LUTs for efficiently computing sgr's 1 - x/(x+1) table.
// In the comments, let RefTable denote the original, reference table.
const x_by_x_tables
// RangeMins
//
// Min(RefTable[i*8:i*8+8])
// First two values are zeroed.
//
// Lookup using RangeMins[(x >> 3)]
.byte 0, 0, 11, 8, 6, 5, 5, 4, 4, 3, 3, 3, 2, 2, 2, 2
.byte 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
// DiffMasks
//
// This contains a bit pattern, indicating at which index positions the value of RefTable changes. For each range
// in the RangeMins table (covering 8 RefTable entries), we have one byte; each bit indicates whether the value of
// RefTable changes at that particular index.
// Using popcount, we can integrate the diff bit field. By shifting away bits in a byte, we can refine the range of
// the integral. Finally, adding the integral to RangeMins[(x>>3)] reconstructs RefTable (for x > 15).
//
// Lookup using DiffMasks[(x >> 3)]
.byte 0x00, 0x00, 0xD4, 0x44
.byte 0x42, 0x04, 0x00, 0x00
.byte 0x00, 0x80, 0x00, 0x00
.byte 0x04, 0x00, 0x00, 0x00
.byte 0x00, 0x00, 0x00, 0x00
.byte 0x00, 0x40, 0x00, 0x00
.byte 0x00, 0x00, 0x00, 0x00
.byte 0x00, 0x00, 0x00, 0x02
// Binary form:
// 0b00000000, 0b00000000, 0b11010100, 0b01000100
// 0b01000010, 0b00000100, 0b00000000, 0b00000000
// 0b00000000, 0b10000000, 0b00000000, 0b00000000
// 0b00000100, 0b00000000, 0b00000000, 0b00000000
// 0b00000000, 0b00000000, 0b00000000, 0b00000000
// 0b00000000, 0b01000000, 0b00000000, 0b00000000
// 0b00000000, 0b00000000, 0b00000000, 0b00000000
// 0b00000000, 0b00000000, 0b00000000, 0b00000010
// RefLo
//
// RefTable[0:16]
// i.e. First 16 elements of the original table.
// Add to the sum obtained in the rest of the other lut logic to include the first 16 bytes of RefTable.
//
// Lookup using RangeMins[x] (tbl will replace x > 15 with 0)
.byte 255, 128, 85, 64, 51, 43, 37, 32, 28, 26, 23, 21, 20, 18, 17, 16
// Pseudo assembly
//
// hi_bits = x >> 3
// tbl ref, {RefLo}, x
// tbl diffs, {DiffMasks[0:16], DiffMasks[16:32]}, hi_bits
// tbl min, {RangeMins[0:16], RangeMins[16:32]}, hi_bits
// lo_bits = x & 0x7
// diffs = diffs << lo_bits
// ref = ref + min
// integral = popcnt(diffs)
// ref = ref + integral
// return ref
endconst
// void dav1d_sgr_box3_vert_neon(int32_t **sumsq, int16_t **sum,
// int32_t *AA, int16_t *BB,
// const int w, const int s,
// const int bitdepth_max);
function sgr_box3_vert_neon, export=1
stp d8, d9, [sp, #-0x40]!
stp d10, d11, [sp, #0x10]
stp d12, d13, [sp, #0x20]
stp d14, d15, [sp, #0x30]
add w4, w4, #2
clz w9, w6 // bitdepth_max
dup v28.4s, w5 // strength
ldp x5, x6, [x0]
ldr x0, [x0, #16]
ldp x7, x8, [x1]
ldr x1, [x1, #16]
movi v31.4s, #9 // n
sub w9, w9, #24 // -bitdepth_min_8
movrel x12, x_by_x_tables
mov w13, #455 // one_by_x
ld1 {v24.16b, v25.16b, v26.16b, v27.16b}, [x12] // RangeMins, DiffMasks
movi v22.16b, #0x7
ldr q23, [x12, #64] //RefLo
dup v6.8h, w9 // -bitdepth_min_8
saddl v7.4s, v6.4h, v6.4h // -2*bitdepth_min_8
dup v30.4s, w13 // one_by_x
ld1 {v8.4s, v9.4s, v10.4s, v11.4s}, [x5], #64
ld1 {v12.4s, v13.4s, v14.4s, v15.4s}, [x6], #64
ld1 {v16.4s, v17.4s, v18.4s, v19.4s}, [x0], #64
ld1 {v20.8h, v21.8h}, [x8], #32
ld1 {v0.8h, v1.8h}, [x7], #32
1:
ld1 {v2.8h, v3.8h}, [x1], #32
add v8.4s, v8.4s, v12.4s
add v9.4s, v9.4s, v13.4s
add v10.4s, v10.4s, v14.4s
add v11.4s, v11.4s, v15.4s
add v0.8h, v0.8h, v20.8h
add v1.8h, v1.8h, v21.8h
add v16.4s, v16.4s, v8.4s
add v17.4s, v17.4s, v9.4s
add v18.4s, v18.4s, v10.4s
add v19.4s, v19.4s, v11.4s
add v4.8h, v2.8h, v0.8h
add v5.8h, v3.8h, v1.8h
srshl v16.4s, v16.4s, v7.4s
srshl v17.4s, v17.4s, v7.4s
srshl v18.4s, v18.4s, v7.4s
srshl v19.4s, v19.4s, v7.4s
srshl v9.8h, v4.8h, v6.8h
srshl v13.8h, v5.8h, v6.8h
mul v16.4s, v16.4s, v31.4s // a * n
mul v17.4s, v17.4s, v31.4s // a * n
mul v18.4s, v18.4s, v31.4s // a * n
mul v19.4s, v19.4s, v31.4s // a * n
umull v8.4s, v9.4h, v9.4h // b * b
umull2 v9.4s, v9.8h, v9.8h // b * b
umull v12.4s, v13.4h, v13.4h // b * b
umull2 v13.4s, v13.8h, v13.8h // b * b
uqsub v16.4s, v16.4s, v8.4s // imax(a * n - b * b, 0)
uqsub v17.4s, v17.4s, v9.4s // imax(a * n - b * b, 0)
uqsub v18.4s, v18.4s, v12.4s // imax(a * n - b * b, 0)
uqsub v19.4s, v19.4s, v13.4s // imax(a * n - b * b, 0)
mul v16.4s, v16.4s, v28.4s // p * s
mul v17.4s, v17.4s, v28.4s // p * s
mul v18.4s, v18.4s, v28.4s // p * s
mul v19.4s, v19.4s, v28.4s // p * s
uqshrn v16.4h, v16.4s, #16
uqshrn2 v16.8h, v17.4s, #16
uqshrn v18.4h, v18.4s, #16
uqshrn2 v18.8h, v19.4s, #16
uqrshrn v1.8b, v16.8h, #4 // imin(z, 255)
uqrshrn2 v1.16b, v18.8h, #4 // imin(z, 255)
ld1 {v16.4s, v17.4s}, [x0], #32
subs w4, w4, #16
ushr v0.16b, v1.16b, #3
ld1 {v8.4s, v9.4s}, [x5], #32
tbl v2.16b, {v26.16b, v27.16b}, v0.16b // RangeMins
tbl v0.16b, {v24.16b, v25.16b}, v0.16b // DiffMasks
tbl v3.16b, {v23.16b}, v1.16b // RefLo
and v1.16b, v1.16b, v22.16b
ld1 {v12.4s, v13.4s}, [x6], #32
ushl v1.16b, v2.16b, v1.16b
ld1 {v20.8h, v21.8h}, [x8], #32
add v3.16b, v3.16b, v0.16b
cnt v1.16b, v1.16b
ld1 {v18.4s, v19.4s}, [x0], #32
add v3.16b, v3.16b, v1.16b
ld1 {v10.4s, v11.4s}, [x5], #32
uxtl v0.8h, v3.8b // x
uxtl2 v1.8h, v3.16b // x
ld1 {v14.4s, v15.4s}, [x6], #32
umull v2.4s, v0.4h, v4.4h // x * BB[i]
umull2 v3.4s, v0.8h, v4.8h // x * BB[i]
umull v4.4s, v1.4h, v5.4h // x * BB[i]
umull2 v5.4s, v1.8h, v5.8h // x * BB[i]
mul v2.4s, v2.4s, v30.4s // x * BB[i] * sgr_one_by_x
mul v3.4s, v3.4s, v30.4s // x * BB[i] * sgr_one_by_x
mul v4.4s, v4.4s, v30.4s // x * BB[i] * sgr_one_by_x
mul v5.4s, v5.4s, v30.4s // x * BB[i] * sgr_one_by_x
st1 {v0.8h, v1.8h}, [x3], #32
ld1 {v0.8h, v1.8h}, [x7], #32
srshr v2.4s, v2.4s, #12 // AA[i]
srshr v3.4s, v3.4s, #12 // AA[i]
srshr v4.4s, v4.4s, #12 // AA[i]
srshr v5.4s, v5.4s, #12 // AA[i]
st1 {v2.4s, v3.4s, v4.4s, v5.4s}, [x2], #64
b.gt 1b
ldp d14, d15, [sp, #0x30]
ldp d12, d13, [sp, #0x20]
ldp d10, d11, [sp, #0x10]
ldp d8, d9, [sp], 0x40
ret
endfunc
// void dav1d_sgr_box5_vert_neon(int32_t **sumsq, int16_t **sum,
// int32_t *AA, int16_t *BB,
// const int w, const int s,
// const int bitdepth_max);
function sgr_box5_vert_neon, export=1
stp d8, d9, [sp, #-0x30]!
stp d10, d11, [sp, #0x10]
stp d12, d13, [sp, #0x20]
add w4, w4, #2
clz w15, w6 // bitdepth_max
dup v28.4s, w5 // strength
ldp x5, x6, [x0]
ldp x7, x8, [x0, #16]
ldr x0, [x0, #32]
ldp x9, x10, [x1]
ldp x11, x12, [x1, #16]
ldr x1, [x1, #32]
movi v31.4s, #25 // n
sub w15, w15, #24 // -bitdepth_min_8
movrel x13, x_by_x_tables
movi v30.4s, #164
ld1 {v24.16b, v25.16b, v26.16b, v27.16b}, [x13] // RangeMins, DiffMasks
dup v6.8h, w15 // -bitdepth_min_8
movi v19.8b, #0x7
ldr q18, [x13, #64] // RefLo
saddl v7.4s, v6.4h, v6.4h // -2*bitdepth_min_8
ld1 {v8.4s, v9.4s}, [x5], #32
ld1 {v10.4s, v11.4s}, [x6], #32
ld1 {v12.4s, v13.4s}, [x7], #32
ld1 {v16.4s, v17.4s}, [x8], #32
ld1 {v20.8h}, [x9], #16
ld1 {v21.8h}, [x10], #16
ld1 {v22.8h}, [x11], #16
ld1 {v23.8h}, [x12], #16
ld1 {v0.4s, v1.4s}, [x0], #32
ld1 {v2.8h}, [x1], #16
1:
add v8.4s, v8.4s, v10.4s
add v9.4s, v9.4s, v11.4s
add v12.4s, v12.4s, v16.4s
add v13.4s, v13.4s, v17.4s
add v20.8h, v20.8h, v21.8h
add v22.8h, v22.8h, v23.8h
add v0.4s, v0.4s, v8.4s
add v1.4s, v1.4s, v9.4s
add v2.8h, v2.8h, v20.8h
add v0.4s, v0.4s, v12.4s
add v1.4s, v1.4s, v13.4s
add v2.8h, v2.8h, v22.8h
subs w4, w4, #8
srshl v0.4s, v0.4s, v7.4s
srshl v1.4s, v1.4s, v7.4s
srshl v4.8h, v2.8h, v6.8h
mul v0.4s, v0.4s, v31.4s // a * n
mul v1.4s, v1.4s, v31.4s // a * n
umull v3.4s, v4.4h, v4.4h // b * b
umull2 v4.4s, v4.8h, v4.8h // b * b
uqsub v0.4s, v0.4s, v3.4s // imax(a * n - b * b, 0)
uqsub v1.4s, v1.4s, v4.4s // imax(a * n - b * b, 0)
mul v0.4s, v0.4s, v28.4s // p * s
mul v1.4s, v1.4s, v28.4s // p * s
ld1 {v8.4s, v9.4s}, [x5], #32
uqshrn v0.4h, v0.4s, #16
uqshrn2 v0.8h, v1.4s, #16
ld1 {v10.4s, v11.4s}, [x6], #32
uqrshrn v0.8b, v0.8h, #4 // imin(z, 255)
ld1 {v12.4s, v13.4s}, [x7], #32
ushr v1.8b, v0.8b, #3
ld1 {v16.4s, v17.4s}, [x8], #32
tbl v5.8b, {v26.16b, v27.16b}, v1.8b // RangeMins
tbl v1.8b, {v24.16b, v25.16b}, v1.8b // DiffMasks
tbl v4.8b, {v18.16b}, v0.8b // RefLo
and v0.8b, v0.8b, v19.8b
ld1 {v20.8h}, [x9], #16
ushl v5.8b, v5.8b, v0.8b
add v4.8b, v4.8b, v1.8b
ld1 {v21.8h}, [x10], #16
cnt v5.8b, v5.8b
ld1 {v22.8h}, [x11], #16
add v5.8b, v4.8b, v5.8b
ld1 {v23.8h}, [x12], #16
uxtl v5.8h, v5.8b // x
ld1 {v0.4s, v1.4s}, [x0], #32
umull v3.4s, v5.4h, v2.4h // x * BB[i]
umull2 v4.4s, v5.8h, v2.8h // x * BB[i]
mul v3.4s, v3.4s, v30.4s // x * BB[i] * sgr_one_by_x
mul v4.4s, v4.4s, v30.4s // x * BB[i] * sgr_one_by_x
srshr v3.4s, v3.4s, #12 // AA[i]
srshr v4.4s, v4.4s, #12 // AA[i]
ld1 {v2.8h}, [x1], #16
st1 {v3.4s, v4.4s}, [x2], #32
st1 {v5.8h}, [x3], #16
b.gt 1b
ldp d12, d13, [sp, #0x20]
ldp d10, d11, [sp, #0x10]
ldp d8, d9, [sp], 0x30
ret
endfunc

View file

@ -0,0 +1,704 @@
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2018, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include "src/arm/asm.S"
#define FILTER_OUT_STRIDE 384
.macro sgr_funcs bpc
// void dav1d_sgr_finish_filter1_2rows_Xbpc_neon(int16_t *tmp,
// const pixel *src,
// const ptrdiff_t src_stride,
// const int32_t **a,
// const int16_t **b,
// const int w, const int h);
function sgr_finish_filter1_2rows_\bpc\()bpc_neon, export=1
stp d8, d9, [sp, #-0x40]!
stp d10, d11, [sp, #0x10]
stp d12, d13, [sp, #0x20]
stp d14, d15, [sp, #0x30]
ldp x7, x8, [x3]
ldp x9, x3, [x3, #16]
ldp x10, x11, [x4]
ldp x12, x4, [x4, #16]
mov x13, #FILTER_OUT_STRIDE
cmp w6, #1
add x2, x1, x2 // src + stride
csel x2, x1, x2, le // if (h <= 1) x2 = x1
add x13, x0, x13, lsl #1
movi v30.8h, #3
movi v31.4s, #3
1:
ld1 {v0.8h, v1.8h}, [x10], #32
ld1 {v2.8h, v3.8h}, [x11], #32
ld1 {v4.8h, v5.8h}, [x12], #32
ld1 {v6.8h, v7.8h}, [x4], #32
ld1 {v16.4s, v17.4s, v18.4s}, [x7], #48
ld1 {v19.4s, v20.4s, v21.4s}, [x8], #48
ld1 {v22.4s, v23.4s, v24.4s}, [x9], #48
ld1 {v25.4s, v26.4s, v27.4s}, [x3], #48
2:
ext v8.16b, v0.16b, v1.16b, #2 // [0][1]
ext v9.16b, v2.16b, v3.16b, #2 // [1][1]
ext v10.16b, v4.16b, v5.16b, #2 // [2][1]
ext v11.16b, v0.16b, v1.16b, #4 // [0][2]
ext v12.16b, v2.16b, v3.16b, #4 // [1][2]
ext v13.16b, v4.16b, v5.16b, #4 // [2][2]
add v14.8h, v2.8h, v8.8h // [1][0] + [0][1]
add v15.8h, v9.8h, v10.8h // [1][1] + [2][1]
add v28.8h, v0.8h, v11.8h // [0][0] + [0][2]
add v14.8h, v14.8h, v12.8h // () + [1][2]
add v29.8h, v4.8h, v13.8h // [2][0] + [2][2]
ext v8.16b, v6.16b, v7.16b, #2 // [3][1]
ext v11.16b, v6.16b, v7.16b, #4 // [3][2]
add v14.8h, v14.8h, v15.8h // mid
add v15.8h, v28.8h, v29.8h // corners
add v28.8h, v4.8h, v9.8h // [2][0] + [1][1]
add v29.8h, v10.8h, v8.8h // [2][1] + [3][1]
add v2.8h, v2.8h, v12.8h // [1][0] + [1][2]
add v28.8h, v28.8h, v13.8h // () + [2][2]
add v4.8h, v6.8h, v11.8h // [3][0] + [3][2]
add v0.8h, v28.8h, v29.8h // mid
add v2.8h, v2.8h, v4.8h // corners
shl v4.8h, v14.8h, #2
mla v4.8h, v15.8h, v30.8h // * 3 -> a
shl v0.8h, v0.8h, #2
mla v0.8h, v2.8h, v30.8h // * 3 -> a
ext v8.16b, v16.16b, v17.16b, #4 // [0][1]
ext v9.16b, v17.16b, v18.16b, #4
ext v10.16b, v16.16b, v17.16b, #8 // [0][2]
ext v11.16b, v17.16b, v18.16b, #8
ext v12.16b, v19.16b, v20.16b, #4 // [1][1]
ext v13.16b, v20.16b, v21.16b, #4
add v8.4s, v8.4s, v19.4s // [0][1] + [1][0]
add v9.4s, v9.4s, v20.4s
add v16.4s, v16.4s, v10.4s // [0][0] + [0][2]
add v17.4s, v17.4s, v11.4s
ext v14.16b, v19.16b, v20.16b, #8 // [1][2]
ext v15.16b, v20.16b, v21.16b, #8
add v16.4s, v16.4s, v22.4s // () + [2][0]
add v17.4s, v17.4s, v23.4s
add v28.4s, v12.4s, v14.4s // [1][1] + [1][2]
add v29.4s, v13.4s, v15.4s
ext v10.16b, v22.16b, v23.16b, #4 // [2][1]
ext v11.16b, v23.16b, v24.16b, #4
add v8.4s, v8.4s, v28.4s // mid (incomplete)
add v9.4s, v9.4s, v29.4s
add v19.4s, v19.4s, v14.4s // [1][0] + [1][2]
add v20.4s, v20.4s, v15.4s
add v14.4s, v22.4s, v12.4s // [2][0] + [1][1]
add v15.4s, v23.4s, v13.4s
ext v12.16b, v22.16b, v23.16b, #8 // [2][2]
ext v13.16b, v23.16b, v24.16b, #8
ext v28.16b, v25.16b, v26.16b, #4 // [3][1]
ext v29.16b, v26.16b, v27.16b, #4
add v8.4s, v8.4s, v10.4s // () + [2][1] = mid
add v9.4s, v9.4s, v11.4s
add v14.4s, v14.4s, v10.4s // () + [2][1]
add v15.4s, v15.4s, v11.4s
ext v10.16b, v25.16b, v26.16b, #8 // [3][2]
ext v11.16b, v26.16b, v27.16b, #8
add v16.4s, v16.4s, v12.4s // () + [2][2] = corner
add v17.4s, v17.4s, v13.4s
add v12.4s, v12.4s, v28.4s // [2][2] + [3][1]
add v13.4s, v13.4s, v29.4s
add v25.4s, v25.4s, v10.4s // [3][0] + [3][2]
add v26.4s, v26.4s, v11.4s
add v14.4s, v14.4s, v12.4s // mid
add v15.4s, v15.4s, v13.4s
add v19.4s, v19.4s, v25.4s // corner
add v20.4s, v20.4s, v26.4s
.if \bpc == 8
ld1 {v25.8b}, [x1], #8 // src
ld1 {v26.8b}, [x2], #8
.else
ld1 {v25.8h}, [x1], #16 // src
ld1 {v26.8h}, [x2], #16
.endif
shl v8.4s, v8.4s, #2
shl v9.4s, v9.4s, #2
mla v8.4s, v16.4s, v31.4s // * 3 -> b
mla v9.4s, v17.4s, v31.4s
.if \bpc == 8
uxtl v25.8h, v25.8b // src
uxtl v26.8h, v26.8b
.endif
shl v14.4s, v14.4s, #2
shl v15.4s, v15.4s, #2
mla v14.4s, v19.4s, v31.4s // * 3 -> b
mla v15.4s, v20.4s, v31.4s
umlsl v8.4s, v4.4h, v25.4h // b - a * src
umlsl2 v9.4s, v4.8h, v25.8h
umlsl v14.4s, v0.4h, v26.4h // b - a * src
umlsl2 v15.4s, v0.8h, v26.8h
mov v0.16b, v1.16b
rshrn v8.4h, v8.4s, #9
rshrn2 v8.8h, v9.4s, #9
mov v2.16b, v3.16b
rshrn v14.4h, v14.4s, #9
rshrn2 v14.8h, v15.4s, #9
subs w5, w5, #8
mov v4.16b, v5.16b
st1 {v8.8h}, [x0], #16
mov v6.16b, v7.16b
st1 {v14.8h}, [x13], #16
b.le 3f
mov v16.16b, v18.16b
mov v19.16b, v21.16b
mov v22.16b, v24.16b
mov v25.16b, v27.16b
ld1 {v1.8h}, [x10], #16
ld1 {v3.8h}, [x11], #16
ld1 {v5.8h}, [x12], #16
ld1 {v7.8h}, [x4], #16
ld1 {v17.4s, v18.4s}, [x7], #32
ld1 {v20.4s, v21.4s}, [x8], #32
ld1 {v23.4s, v24.4s}, [x9], #32
ld1 {v26.4s, v27.4s}, [x3], #32
b 2b
3:
ldp d14, d15, [sp, #0x30]
ldp d12, d13, [sp, #0x20]
ldp d10, d11, [sp, #0x10]
ldp d8, d9, [sp], 0x40
ret
endfunc
// void dav1d_sgr_finish_weighted1_Xbpc_neon(pixel *dst,
// const int32_t **a, const int16_t **b,
// const int w, const int w1,
// const int bitdepth_max);
function sgr_finish_weighted1_\bpc\()bpc_neon, export=1
ldp x7, x8, [x1]
ldr x1, [x1, #16]
ldp x9, x10, [x2]
ldr x2, [x2, #16]
dup v31.8h, w4
dup v30.8h, w5
movi v6.8h, #3
movi v7.4s, #3
1:
ld1 {v0.8h, v1.8h}, [x9], #32
ld1 {v2.8h, v3.8h}, [x10], #32
ld1 {v4.8h, v5.8h}, [x2], #32
ld1 {v16.4s, v17.4s, v18.4s}, [x7], #48
ld1 {v19.4s, v20.4s, v21.4s}, [x8], #48
ld1 {v22.4s, v23.4s, v24.4s}, [x1], #48
2:
ext v25.16b, v0.16b, v1.16b, #2 // -stride
ext v26.16b, v2.16b, v3.16b, #2 // 0
ext v27.16b, v4.16b, v5.16b, #2 // +stride
ext v28.16b, v0.16b, v1.16b, #4 // +1-stride
ext v29.16b, v2.16b, v3.16b, #4 // +1
add v2.8h, v2.8h, v25.8h // -1, -stride
ext v25.16b, v4.16b, v5.16b, #4 // +1+stride
add v26.8h, v26.8h, v27.8h // 0, +stride
add v0.8h, v0.8h, v28.8h // -1-stride, +1-stride
add v2.8h, v2.8h, v26.8h
add v4.8h, v4.8h, v25.8h // -1+stride, +1+stride
add v2.8h, v2.8h, v29.8h // +1
add v0.8h, v0.8h, v4.8h
ext v25.16b, v16.16b, v17.16b, #4 // -stride
ext v26.16b, v17.16b, v18.16b, #4
shl v2.8h, v2.8h, #2
ext v27.16b, v16.16b, v17.16b, #8 // +1-stride
ext v28.16b, v17.16b, v18.16b, #8
ext v29.16b, v19.16b, v20.16b, #4 // 0
ext v4.16b, v20.16b, v21.16b, #4
mla v2.8h, v0.8h, v6.8h // * 3 -> a
add v25.4s, v25.4s, v19.4s // -stride, -1
add v26.4s, v26.4s, v20.4s
add v16.4s, v16.4s, v27.4s // -1-stride, +1-stride
add v17.4s, v17.4s, v28.4s
ext v27.16b, v19.16b, v20.16b, #8 // +1
ext v28.16b, v20.16b, v21.16b, #8
add v16.4s, v16.4s, v22.4s // -1+stride
add v17.4s, v17.4s, v23.4s
add v29.4s, v29.4s, v27.4s // 0, +1
add v4.4s, v4.4s, v28.4s
add v25.4s, v25.4s, v29.4s
add v26.4s, v26.4s, v4.4s
ext v27.16b, v22.16b, v23.16b, #4 // +stride
ext v28.16b, v23.16b, v24.16b, #4
ext v29.16b, v22.16b, v23.16b, #8 // +1+stride
ext v4.16b, v23.16b, v24.16b, #8
.if \bpc == 8
ld1 {v19.8b}, [x0] // src
.else
ld1 {v19.8h}, [x0] // src
.endif
add v25.4s, v25.4s, v27.4s // +stride
add v26.4s, v26.4s, v28.4s
add v16.4s, v16.4s, v29.4s // +1+stride
add v17.4s, v17.4s, v4.4s
shl v25.4s, v25.4s, #2
shl v26.4s, v26.4s, #2
mla v25.4s, v16.4s, v7.4s // * 3 -> b
mla v26.4s, v17.4s, v7.4s
.if \bpc == 8
uxtl v19.8h, v19.8b // src
.endif
mov v0.16b, v1.16b
umlsl v25.4s, v2.4h, v19.4h // b - a * src
umlsl2 v26.4s, v2.8h, v19.8h
mov v2.16b, v3.16b
rshrn v25.4h, v25.4s, #9
rshrn2 v25.8h, v26.4s, #9
subs w3, w3, #8
// weighted1
mov v4.16b, v5.16b
ld1 {v1.8h}, [x9], #16
ld1 {v3.8h}, [x10], #16
smull v26.4s, v25.4h, v31.4h // v = t1 * w1
smull2 v27.4s, v25.8h, v31.8h
ld1 {v5.8h}, [x2], #16
rshrn v26.4h, v26.4s, #11
rshrn2 v26.8h, v27.4s, #11
usqadd v19.8h, v26.8h
.if \bpc == 8
mov v16.16b, v18.16b
sqxtun v26.8b, v19.8h
mov v19.16b, v21.16b
mov v22.16b, v24.16b
st1 {v26.8b}, [x0], #8
.else
mov v16.16b, v18.16b
umin v26.8h, v19.8h, v30.8h
mov v19.16b, v21.16b
mov v22.16b, v24.16b
st1 {v26.8h}, [x0], #16
.endif
b.le 3f
ld1 {v17.4s, v18.4s}, [x7], #32
ld1 {v20.4s, v21.4s}, [x8], #32
ld1 {v23.4s, v24.4s}, [x1], #32
b 2b
3:
ret
endfunc
// void dav1d_sgr_finish_filter2_2rows_Xbpc_neon(int16_t *tmp,
// const pixel *src,
// const ptrdiff_t stride,
// const int32_t **a,
// const int16_t **b,
// const int w, const int h);
function sgr_finish_filter2_2rows_\bpc\()bpc_neon, export=1
stp d8, d9, [sp, #-0x40]!
stp d10, d11, [sp, #0x10]
stp d12, d13, [sp, #0x20]
stp d14, d15, [sp, #0x30]
ldp x3, x7, [x3]
ldp x4, x8, [x4]
mov x10, #FILTER_OUT_STRIDE
cmp w6, #1
add x2, x1, x2 // src + stride
csel x2, x1, x2, le // if (h <= 1) x2 = x1
add x10, x0, x10, lsl #1
movi v4.8h, #5
movi v5.4s, #5
movi v6.8h, #6
movi v7.4s, #6
1:
ld1 {v0.8h, v1.8h}, [x4], #32
ld1 {v2.8h, v3.8h}, [x8], #32
ld1 {v16.4s, v17.4s, v18.4s}, [x3], #48
ld1 {v19.4s, v20.4s, v21.4s}, [x7], #48
2:
ext v24.16b, v0.16b, v1.16b, #4 // +1-stride
ext v25.16b, v2.16b, v3.16b, #4 // +1+stride
ext v22.16b, v0.16b, v1.16b, #2 // -stride
ext v23.16b, v2.16b, v3.16b, #2 // +stride
add v0.8h, v0.8h, v24.8h // -1-stride, +1-stride
add v25.8h, v2.8h, v25.8h // -1+stride, +1+stride
add v2.8h, v22.8h, v23.8h // -stride, +stride
add v0.8h, v0.8h, v25.8h
mul v8.8h, v25.8h, v4.8h // * 5
mla v8.8h, v23.8h, v6.8h // * 6
ext v22.16b, v16.16b, v17.16b, #4 // -stride
ext v23.16b, v17.16b, v18.16b, #4
ext v24.16b, v19.16b, v20.16b, #4 // +stride
ext v25.16b, v20.16b, v21.16b, #4
ext v26.16b, v16.16b, v17.16b, #8 // +1-stride
ext v27.16b, v17.16b, v18.16b, #8
ext v28.16b, v19.16b, v20.16b, #8 // +1+stride
ext v29.16b, v20.16b, v21.16b, #8
mul v0.8h, v0.8h, v4.8h // * 5
mla v0.8h, v2.8h, v6.8h // * 6
.if \bpc == 8
ld1 {v31.8b}, [x1], #8
ld1 {v30.8b}, [x2], #8
.else
ld1 {v31.8h}, [x1], #16
ld1 {v30.8h}, [x2], #16
.endif
add v16.4s, v16.4s, v26.4s // -1-stride, +1-stride
add v17.4s, v17.4s, v27.4s
add v19.4s, v19.4s, v28.4s // -1+stride, +1+stride
add v20.4s, v20.4s, v29.4s
add v16.4s, v16.4s, v19.4s
add v17.4s, v17.4s, v20.4s
mul v9.4s, v19.4s, v5.4s // * 5
mla v9.4s, v24.4s, v7.4s // * 6
mul v10.4s, v20.4s, v5.4s // * 5
mla v10.4s, v25.4s, v7.4s // * 6
add v22.4s, v22.4s, v24.4s // -stride, +stride
add v23.4s, v23.4s, v25.4s
// This is, surprisingly, faster than other variants where the
// mul+mla pairs are further apart, on Cortex A53.
mul v16.4s, v16.4s, v5.4s // * 5
mla v16.4s, v22.4s, v7.4s // * 6
mul v17.4s, v17.4s, v5.4s // * 5
mla v17.4s, v23.4s, v7.4s // * 6
.if \bpc == 8
uxtl v31.8h, v31.8b
uxtl v30.8h, v30.8b
.endif
umlsl v16.4s, v0.4h, v31.4h // b - a * src
umlsl2 v17.4s, v0.8h, v31.8h
umlsl v9.4s, v8.4h, v30.4h // b - a * src
umlsl2 v10.4s, v8.8h, v30.8h
mov v0.16b, v1.16b
rshrn v16.4h, v16.4s, #9
rshrn2 v16.8h, v17.4s, #9
rshrn v9.4h, v9.4s, #8
rshrn2 v9.8h, v10.4s, #8
subs w5, w5, #8
mov v2.16b, v3.16b
st1 {v16.8h}, [x0], #16
st1 {v9.8h}, [x10], #16
b.le 9f
mov v16.16b, v18.16b
mov v19.16b, v21.16b
ld1 {v1.8h}, [x4], #16
ld1 {v3.8h}, [x8], #16
ld1 {v17.4s, v18.4s}, [x3], #32
ld1 {v20.4s, v21.4s}, [x7], #32
b 2b
9:
ldp d14, d15, [sp, #0x30]
ldp d12, d13, [sp, #0x20]
ldp d10, d11, [sp, #0x10]
ldp d8, d9, [sp], 0x40
ret
endfunc
// void dav1d_sgr_finish_weighted2_Xbpc_neon(pixel *dst, const ptrdiff_t stride,
// const int32_t **a,
// const int16_t **b,
// const int w, const int h,
// const int w1,
// const int bitdepth_max);
function sgr_finish_weighted2_\bpc\()bpc_neon, export=1
stp d8, d9, [sp, #-0x30]!
str d10, [sp, #0x10]
stp d14, d15, [sp, #0x20]
dup v14.8h, w6
dup v15.8h, w7
ldp x2, x7, [x2]
ldp x3, x8, [x3]
cmp w5, #1
add x1, x0, x1 // src + stride
// if (h <= 1), set the pointer to the second row to any dummy buffer
// we can clobber (x2 in this case)
csel x1, x2, x1, le
movi v4.8h, #5
movi v5.4s, #5
movi v6.8h, #6
movi v7.4s, #6
1:
ld1 {v0.8h, v1.8h}, [x3], #32
ld1 {v2.8h, v3.8h}, [x8], #32
ld1 {v16.4s, v17.4s, v18.4s}, [x2], #48
ld1 {v19.4s, v20.4s, v21.4s}, [x7], #48
2:
ext v24.16b, v0.16b, v1.16b, #4 // +1-stride
ext v25.16b, v2.16b, v3.16b, #4 // +1+stride
ext v22.16b, v0.16b, v1.16b, #2 // -stride
ext v23.16b, v2.16b, v3.16b, #2 // +stride
add v0.8h, v0.8h, v24.8h // -1-stride, +1-stride
add v25.8h, v2.8h, v25.8h // -1+stride, +1+stride
add v2.8h, v22.8h, v23.8h // -stride, +stride
add v0.8h, v0.8h, v25.8h
mul v8.8h, v25.8h, v4.8h // * 5
mla v8.8h, v23.8h, v6.8h // * 6
ext v22.16b, v16.16b, v17.16b, #4 // -stride
ext v23.16b, v17.16b, v18.16b, #4
ext v24.16b, v19.16b, v20.16b, #4 // +stride
ext v25.16b, v20.16b, v21.16b, #4
ext v26.16b, v16.16b, v17.16b, #8 // +1-stride
ext v27.16b, v17.16b, v18.16b, #8
ext v28.16b, v19.16b, v20.16b, #8 // +1+stride
ext v29.16b, v20.16b, v21.16b, #8
mul v0.8h, v0.8h, v4.8h // * 5
mla v0.8h, v2.8h, v6.8h // * 6
.if \bpc == 8
ld1 {v31.8b}, [x0]
ld1 {v30.8b}, [x1]
.else
ld1 {v31.8h}, [x0]
ld1 {v30.8h}, [x1]
.endif
add v16.4s, v16.4s, v26.4s // -1-stride, +1-stride
add v17.4s, v17.4s, v27.4s
add v19.4s, v19.4s, v28.4s // -1+stride, +1+stride
add v20.4s, v20.4s, v29.4s
add v16.4s, v16.4s, v19.4s
add v17.4s, v17.4s, v20.4s
mul v9.4s, v19.4s, v5.4s // * 5
mla v9.4s, v24.4s, v7.4s // * 6
mul v10.4s, v20.4s, v5.4s // * 5
mla v10.4s, v25.4s, v7.4s // * 6
add v22.4s, v22.4s, v24.4s // -stride, +stride
add v23.4s, v23.4s, v25.4s
// This is, surprisingly, faster than other variants where the
// mul+mla pairs are further apart, on Cortex A53.
mul v16.4s, v16.4s, v5.4s // * 5
mla v16.4s, v22.4s, v7.4s // * 6
mul v17.4s, v17.4s, v5.4s // * 5
mla v17.4s, v23.4s, v7.4s // * 6
.if \bpc == 8
uxtl v31.8h, v31.8b
uxtl v30.8h, v30.8b
.endif
umlsl v16.4s, v0.4h, v31.4h // b - a * src
umlsl2 v17.4s, v0.8h, v31.8h
umlsl v9.4s, v8.4h, v30.4h // b - a * src
umlsl2 v10.4s, v8.8h, v30.8h
mov v0.16b, v1.16b
rshrn v16.4h, v16.4s, #9
rshrn2 v16.8h, v17.4s, #9
rshrn v9.4h, v9.4s, #8
rshrn2 v9.8h, v10.4s, #8
subs w4, w4, #8
// weighted1
mov v2.16b, v3.16b
ld1 {v1.8h}, [x3], #16
ld1 {v3.8h}, [x8], #16
smull v22.4s, v16.4h, v14.4h // v
smull2 v23.4s, v16.8h, v14.8h
mov v16.16b, v18.16b
smull v24.4s, v9.4h, v14.4h
smull2 v25.4s, v9.8h, v14.8h
mov v19.16b, v21.16b
rshrn v22.4h, v22.4s, #11
rshrn2 v22.8h, v23.4s, #11
rshrn v23.4h, v24.4s, #11
rshrn2 v23.8h, v25.4s, #11
usqadd v31.8h, v22.8h
usqadd v30.8h, v23.8h
.if \bpc == 8
sqxtun v22.8b, v31.8h
sqxtun v23.8b, v30.8h
st1 {v22.8b}, [x0], #8
st1 {v23.8b}, [x1], #8
.else
umin v22.8h, v31.8h, v15.8h
umin v23.8h, v30.8h, v15.8h
st1 {v22.8h}, [x0], #16
st1 {v23.8h}, [x1], #16
.endif
b.le 3f
ld1 {v17.4s, v18.4s}, [x2], #32
ld1 {v20.4s, v21.4s}, [x7], #32
b 2b
3:
ldp d14, d15, [sp, #0x20]
ldr d10, [sp, #0x10]
ldp d8, d9, [sp], 0x30
ret
endfunc
// void dav1d_sgr_weighted2_Xbpc_neon(pixel *dst, const ptrdiff_t stride,
// const int16_t *t1, const int16_t *t2,
// const int w, const int h,
// const int16_t wt[2], const int bitdepth_max);
function sgr_weighted2_\bpc\()bpc_neon, export=1
cmp w5, #2
add x10, x0, x1
add x12, x2, #2*FILTER_OUT_STRIDE
add x13, x3, #2*FILTER_OUT_STRIDE
ld2r {v30.8h, v31.8h}, [x6] // wt[0], wt[1]
.if \bpc == 16
dup v29.8h, w7
.endif
mov x8, #4*FILTER_OUT_STRIDE
lsl x1, x1, #1
add w9, w4, #7
bic x9, x9, #7 // Aligned width
.if \bpc == 8
sub x1, x1, x9
.else
sub x1, x1, x9, lsl #1
.endif
sub x8, x8, x9, lsl #1
mov w9, w4
b.lt 2f
1:
.if \bpc == 8
ld1 {v0.8b}, [x0]
ld1 {v16.8b}, [x10]
.else
ld1 {v0.8h}, [x0]
ld1 {v16.8h}, [x10]
.endif
ld1 {v1.8h}, [x2], #16
ld1 {v17.8h}, [x12], #16
ld1 {v2.8h}, [x3], #16
ld1 {v18.8h}, [x13], #16
subs w4, w4, #8
.if \bpc == 8
uxtl v0.8h, v0.8b
uxtl v16.8h, v16.8b
.endif
smull v3.4s, v1.4h, v30.4h // wt[0] * t1
smlal v3.4s, v2.4h, v31.4h // wt[1] * t2
smull2 v4.4s, v1.8h, v30.8h // wt[0] * t1
smlal2 v4.4s, v2.8h, v31.8h // wt[1] * t2
smull v19.4s, v17.4h, v30.4h // wt[0] * t1
smlal v19.4s, v18.4h, v31.4h // wt[1] * t2
smull2 v20.4s, v17.8h, v30.8h // wt[0] * t1
smlal2 v20.4s, v18.8h, v31.8h // wt[1] * t2
rshrn v3.4h, v3.4s, #11
rshrn2 v3.8h, v4.4s, #11
rshrn v19.4h, v19.4s, #11
rshrn2 v19.8h, v20.4s, #11
usqadd v0.8h, v3.8h
usqadd v16.8h, v19.8h
.if \bpc == 8
sqxtun v3.8b, v0.8h
sqxtun v19.8b, v16.8h
st1 {v3.8b}, [x0], #8
st1 {v19.8b}, [x10], #8
.else
umin v3.8h, v0.8h, v29.8h
umin v19.8h, v16.8h, v29.8h
st1 {v3.8h}, [x0], #16
st1 {v19.8h}, [x10], #16
.endif
b.gt 1b
subs w5, w5, #2
cmp w5, #1
b.lt 0f
mov w4, w9
add x0, x0, x1
add x10, x10, x1
add x2, x2, x8
add x12, x12, x8
add x3, x3, x8
add x13, x13, x8
b.eq 2f
b 1b
2:
.if \bpc == 8
ld1 {v0.8b}, [x0]
.else
ld1 {v0.8h}, [x0]
.endif
ld1 {v1.8h}, [x2], #16
ld1 {v2.8h}, [x3], #16
subs w4, w4, #8
.if \bpc == 8
uxtl v0.8h, v0.8b
.endif
smull v3.4s, v1.4h, v30.4h // wt[0] * t1
smlal v3.4s, v2.4h, v31.4h // wt[1] * t2
smull2 v4.4s, v1.8h, v30.8h // wt[0] * t1
smlal2 v4.4s, v2.8h, v31.8h // wt[1] * t2
rshrn v3.4h, v3.4s, #11
rshrn2 v3.8h, v4.4s, #11
usqadd v0.8h, v3.8h
.if \bpc == 8
sqxtun v3.8b, v0.8h
st1 {v3.8b}, [x0], #8
.else
umin v3.8h, v0.8h, v29.8h
st1 {v3.8h}, [x0], #16
.endif
b.gt 2b
0:
ret
endfunc
.endm

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,595 @@
/*
* Copyright © 2019, VideoLAN and dav1d authors
* Copyright © 2019, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include "src/arm/asm.S"
#include "util.S"
#define BUF_POS 0
#define BUF_END 8
#define DIF 16
#define RNG 24
#define CNT 28
#define ALLOW_UPDATE_CDF 32
#define COEFFS_BASE_OFFSET 30
#define MASKS8_OFFSET (64-COEFFS_BASE_OFFSET)
const coeffs
.short 60, 56, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0
.short 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
// masks8
.short -0x202, -0x202, -0x202, -0x202, -0x202, -0x202, -0x202, 0xF0E
endconst
.macro ld1_n d0, d1, src, sz, n
.if \n <= 8
ld1 {\d0\sz}, [\src]
.else
ld1 {\d0\sz, \d1\sz}, [\src]
.endif
.endm
.macro st1_n s0, s1, dst, sz, n
.if \n <= 8
st1 {\s0\sz}, [\dst]
.else
st1 {\s0\sz, \s1\sz}, [\dst]
.endif
.endm
.macro ushr_n d0, d1, s0, s1, shift, sz, n
ushr \d0\sz, \s0\sz, \shift
.if \n == 16
ushr \d1\sz, \s1\sz, \shift
.endif
.endm
.macro add_n d0, d1, s0, s1, s2, s3, sz, n
add \d0\sz, \s0\sz, \s2\sz
.if \n == 16
add \d1\sz, \s1\sz, \s3\sz
.endif
.endm
.macro sub_n d0, d1, s0, s1, s2, s3, sz, n
sub \d0\sz, \s0\sz, \s2\sz
.if \n == 16
sub \d1\sz, \s1\sz, \s3\sz
.endif
.endm
.macro and_n d0, d1, s0, s1, s2, s3, sz, n
and \d0\sz, \s0\sz, \s2\sz
.if \n == 16
and \d1\sz, \s1\sz, \s3\sz
.endif
.endm
.macro cmhs_n d0, d1, s0, s1, s2, s3, sz, n
cmhs \d0\sz, \s0\sz, \s2\sz
.if \n == 16
cmhs \d1\sz, \s1\sz, \s3\sz
.endif
.endm
.macro sshl_n d0, d1, s0, s1, s2, s3, sz, n
sshl \d0\sz, \s0\sz, \s2\sz
.if \n == 16
sshl \d1\sz, \s1\sz, \s3\sz
.endif
.endm
.macro sqdmulh_n d0, d1, s0, s1, s2, s3, sz, n
sqdmulh \d0\sz, \s0\sz, \s2\sz
.if \n == 16
sqdmulh \d1\sz, \s1\sz, \s3\sz
.endif
.endm
.macro str_n idx0, idx1, dstreg, dstoff, n
str \idx0, [\dstreg, \dstoff]
.if \n == 16
str \idx1, [\dstreg, \dstoff + 16]
.endif
.endm
// unsigned dav1d_msac_decode_symbol_adapt4_neon(MsacContext *s, uint16_t *cdf,
// size_t n_symbols);
function msac_decode_symbol_adapt4_neon, export=1
.macro decode_update sz, szb, n
.if \n == 16
sub sp, sp, #48
.endif
add x8, x0, #RNG
ld1_n v0, v1, x1, \sz, \n // cdf
ld1r {v29\sz}, [x8] // rng
movrel x9, coeffs, COEFFS_BASE_OFFSET
movi v31\sz, #0x7f, lsl #8 // 0x7f00
sub x10, x9, x2, lsl #1
mvni v30\sz, #0x3f // 0xffc0
and v7\szb, v29\szb, v31\szb // rng & 0x7f00
.if \n == 16
str h29, [sp, #14] // store original u = s->rng
.endif
and_n v2, v3, v0, v1, v30, v30, \szb, \n // cdf & 0xffc0
ld1_n v4, v5, x10, \sz, \n // EC_MIN_PROB * (n_symbols - ret)
sqdmulh_n v6, v7, v2, v3, v7, v7, \sz, \n // ((cdf >> EC_PROB_SHIFT) * (r - 128)) >> 1
ldr d28, [x0, #DIF]
add_n v4, v5, v2, v3, v4, v5, \sz, \n // v = cdf + EC_MIN_PROB * (n_symbols - ret)
add_n v4, v5, v6, v7, v4, v5, \sz, \n // v = ((cdf >> EC_PROB_SHIFT) * r) >> 1 + EC_MIN_PROB * (n_symbols - ret)
dup v30\sz, v28.h[3] // dif >> (EC_WIN_SIZE - 16)
.if \n == 8
ldur q31, [x9, #MASKS8_OFFSET]
.elseif \n == 16
str_n q4, q5, sp, #16, \n // store v values to allow indexed access
.endif
// After the condition starts being true it continues, such that the vector looks like:
// 0, 0, 0 ... -1, -1
cmhs_n v2, v3, v30, v30, v4, v5, \sz, \n // c >= v
.if \n == 4
ext v29\szb, v29\szb, v4\szb, #6 // u
umov x15, v2.d[0]
ldr w4, [x0, #ALLOW_UPDATE_CDF]
rev x15, x15
sub v29\sz, v29\sz, v4\sz // rng = u-v
// rev + clz = count trailing zeros
clz x15, x15 // 16*ret
.elseif \n == 8
// The final short of the compare is always set.
// Using addv, subtract -0x202*ret from this value to create a lookup table for a short.
// For n == 8:
// -0x202 + -0x202 + ... + 0xF0E
// (0x202*7) | (1 << 8)
// ^-------offset for second byte of the short
and v31\szb, v31\szb, v2\szb
ext v29\szb, v29\szb, v4\szb, #14 // u
addv h31, v31\sz // ((2*ret + 1) << 8) | (2*ret)
ldr w4, [x0, #ALLOW_UPDATE_CDF]
sub v30\sz, v30\sz, v4\sz // (dif >> 48) - v
smov w15, v31.b[0] // 2*ret
sub v29\sz, v29\sz, v4\sz // rng = u-v
.elseif \n == 16
add v6\sz, v2\sz, v3\sz
addv h31, v6\sz // -n + ret
ldr w4, [x0, #ALLOW_UPDATE_CDF]
smov w15, v31.h[0]
.endif
cbz w4, 0f
// update_cdf
ldrh w3, [x1, x2, lsl #1] // count = cdf[n_symbols]
.if \n == 16
// 16 case has a lower bound that guarantees n_symbols > 2
mov w4, #-5
.elseif \n == 8
mvn w14, w2
mov w4, #-4
cmn w14, #3 // set C if n_symbols <= 2
.else
// if n_symbols < 4 (or < 6 even) then
// (1 + n_symbols) >> 2 == n_symbols > 2
add w14, w2, #17 // (1 + n_symbols) + (4 << 2)
.endif
sub_n v16, v17, v0, v1, v2, v3, \sz, \n // cdf + (i >= val ? 1 : 0)
orr v2\sz, #0x80, lsl #8
.if \n == 16
orr v3\sz, #0x80, lsl #8
.endif
.if \n == 16
sub w4, w4, w3, lsr #4 // -((count >> 4) + 5)
.elseif \n == 8
lsr w14, w3, #4 // count >> 4
sbc w4, w4, w14 // -((count >> 4) + (n_symbols > 2) + 4)
.else
neg w4, w14, lsr #2 // -((n_symbols > 2) + 4)
sub w4, w4, w3, lsr #4 // -((count >> 4) + (n_symbols > 2) + 4)
.endif
sub_n v2, v3, v2, v3, v0, v1, \sz, \n // (32768 - cdf[i]) or (-1 - cdf[i])
dup v6\sz, w4 // -rate
sub w3, w3, w3, lsr #5 // count - (count == 32)
sshl_n v2, v3, v2, v3, v6, v6, \sz, \n // ({32768,-1} - cdf[i]) >> rate
add w3, w3, #1 // count + (count < 32)
add_n v0, v1, v16, v17, v2, v3, \sz, \n // cdf + (32768 - cdf[i]) >> rate
st1_n v0, v1, x1, \sz, \n
strh w3, [x1, x2, lsl #1]
0:
// renorm
.if \n == 4
ldr w6, [x0, #CNT]
ldr x7, [x0, #DIF]
mov x4, v29.d[0] // rng (packed)
mov x3, v4.d[0] // v (packed)
// Shift 'v'/'rng' for ret into the 16 least sig bits. There is
// garbage in the remaining bits, but we can work around this.
lsr x4, x4, x15 // rng
lsr x3, x3, x15 // v
lsl w5, w4, #16 // rng << 16
sub x7, x7, x3, lsl #48 // dif - (v << 48)
clz w5, w5 // d = clz(rng << 16)
lsl w4, w4, w5 // rng << d
subs w6, w6, w5 // cnt -= d
lsl x7, x7, x5 // (dif - (v << 48)) << d
strh w4, [x0, #RNG]
b.lo 1f
str w6, [x0, #CNT]
str x7, [x0, #DIF]
lsr w0, w15, #4
ret
1:
lsr w15, w15, #4
b L(refill)
.elseif \n == 8
ldr w6, [x0, #CNT]
tbl v30.8b, {v30.16b}, v31.8b
tbl v29.8b, {v29.16b}, v31.8b
ins v28.h[3], v30.h[0] // dif - (v << 48)
clz v0.4h, v29.4h // d = clz(rng)
umov w5, v0.h[0]
ushl v29.4h, v29.4h, v0.4h // rng << d
// The vec for clz(rng) is filled with garbage after the first short,
// but ushl/sshl conveniently uses only the first byte for the shift
// amount.
ushl d28, d28, d0 // (dif - (v << 48)) << d
subs w6, w6, w5 // cnt -= d
str h29, [x0, #RNG]
b.lo 1f
str w6, [x0, #CNT]
str d28, [x0, #DIF]
lsr w0, w15, #1 // ret
ret
1:
lsr w15, w15, #1 // ret
mov x7, v28.d[0]
b L(refill)
.elseif \n == 16
add x8, sp, w15, sxtw #1
ldrh w3, [x8, #48] // v
ldurh w4, [x8, #46] // u
ldr w6, [x0, #CNT]
ldr x7, [x0, #DIF]
sub w4, w4, w3 // rng = u - v
clz w5, w4 // clz(rng)
eor w5, w5, #16 // d = clz(rng) ^ 16
sub x7, x7, x3, lsl #48 // dif - (v << 48)
lsl w4, w4, w5 // rng << d
subs w6, w6, w5 // cnt -= d
lsl x7, x7, x5 // (dif - (v << 48)) << d
str w4, [x0, #RNG]
add sp, sp, #48
b.lo 1f
str w6, [x0, #CNT]
str x7, [x0, #DIF]
add w0, w15, #\n // ret
ret
1:
add w15, w15, #\n // ret
b L(refill)
.endif
.endm
decode_update .4h, .8b, 4
L(refill):
// refill
ldp x3, x4, [x0] // BUF_POS, BUF_END
add x5, x3, #8
subs x5, x5, x4
b.hi 6f
ldr x8, [x3] // next_bits
add w4, w6, #-48 // shift_bits = cnt + 16 (- 64)
mvn x8, x8
neg w5, w4
rev x8, x8 // next_bits = bswap(next_bits)
lsr w5, w5, #3 // num_bytes_read
lsr x8, x8, x4 // next_bits >>= (shift_bits & 63)
2: // refill_end
add x3, x3, x5
add w6, w6, w5, lsl #3 // cnt += num_bits_read
str x3, [x0, #BUF_POS]
3: // refill_end2
orr x7, x7, x8 // dif |= next_bits
4: // end
str w6, [x0, #CNT]
str x7, [x0, #DIF]
mov w0, w15
ret
5: // pad_with_ones
add w8, w6, #-16
ror x8, x8, x8
b 3b
6: // refill_eob
cmp x3, x4
b.hs 5b
ldr x8, [x4, #-8]
lsl w5, w5, #3
lsr x8, x8, x5
add w5, w6, #-48
mvn x8, x8
sub w4, w4, w3 // num_bytes_left
rev x8, x8
lsr x8, x8, x5
neg w5, w5
lsr w5, w5, #3
cmp w5, w4
csel w5, w5, w4, lo // num_bytes_read
b 2b
endfunc
function msac_decode_symbol_adapt8_neon, export=1
decode_update .8h, .16b, 8
endfunc
function msac_decode_symbol_adapt16_neon, export=1
decode_update .8h, .16b, 16
endfunc
function msac_decode_hi_tok_neon, export=1
ld1 {v0.4h}, [x1] // cdf
add x16, x0, #RNG
movi v31.4h, #0x7f, lsl #8 // 0x7f00
movrel x17, coeffs, COEFFS_BASE_OFFSET-2*3
mvni v30.4h, #0x3f // 0xffc0
ldrh w9, [x1, #6] // count = cdf[n_symbols]
ld1r {v3.4h}, [x16] // rng
ld1 {v29.4h}, [x17] // EC_MIN_PROB * (n_symbols - ret)
add x17, x0, #DIF + 6
mov w13, #-24*8
and v17.8b, v0.8b, v30.8b // cdf & 0xffc0
ldr w10, [x0, #ALLOW_UPDATE_CDF]
ld1r {v1.8h}, [x17] // dif >> (EC_WIN_SIZE - 16)
ldr w6, [x0, #CNT]
ldr x7, [x0, #DIF]
1:
and v7.8b, v3.8b, v31.8b // rng & 0x7f00
sqdmulh v6.4h, v17.4h, v7.4h // ((cdf >> EC_PROB_SHIFT) * (r - 128)) >> 1
add v4.4h, v17.4h, v29.4h // v = cdf + EC_MIN_PROB * (n_symbols - ret)
add v4.4h, v6.4h, v4.4h // v = ((cdf >> EC_PROB_SHIFT) * r) >> 1 + EC_MIN_PROB * (n_symbols - ret)
cmhs v2.4h, v1.4h, v4.4h // c >= v
add w13, w13, #5*8
ext v18.8b, v3.8b, v4.8b, #6 // u
umov x15, v2.d[0]
rev x15, x15
sub v18.4h, v18.4h, v4.4h // rng = u-v
// rev + clz = count trailing zeros
clz x15, x15 // 16*ret
cbz w10, 2f
// update_cdf
sub v5.4h, v0.4h, v2.4h // cdf[i] + (i >= val ? 1 : 0)
mov w4, #-5
orr v2.4h, #0x80, lsl #8 // i >= val ? -1 : 32768
sub w4, w4, w9, lsr #4 // -((count >> 4) + 5)
sub v2.4h, v2.4h, v0.4h // (32768 - cdf[i]) or (-1 - cdf[i])
dup v6.4h, w4 // -rate
sub w9, w9, w9, lsr #5 // count - (count == 32)
sshl v2.4h, v2.4h, v6.4h // ({32768,-1} - cdf[i]) >> rate
add w9, w9, #1 // count + (count < 32)
add v0.4h, v5.4h, v2.4h // cdf[i] + (32768 - cdf[i]) >> rate
st1 {v0.4h}, [x1]
and v17.8b, v0.8b, v30.8b // cdf & 0xffc0
strh w9, [x1, #6]
2:
mov x4, v18.d[0] // rng (packed)
mov x3, v4.d[0] // v (packed)
// Shift 'v'/'rng' for ret into the 16 least sig bits. There is
// garbage in the remaining bits, but we can work around this.
lsr x4, x4, x15 // rng
lsr x3, x3, x15 // v
lsl w5, w4, #16 // rng << 16
sub x7, x7, x3, lsl #48 // dif - (v << 48)
clz w5, w5 // d = clz(rng << 16)
lsl w4, w4, w5 // rng << d
subs w6, w6, w5 // cnt -= d
lsl x7, x7, x5 // (dif - (v << 48)) << d
strh w4, [x0, #RNG]
dup v3.4h, w4
b.hs 5f
// refill
ldp x3, x4, [x0] // BUF_POS, BUF_END
add x5, x3, #8
subs x5, x5, x4
b.hi 7f
ldr x8, [x3] // next_bits
add w4, w6, #-48 // shift_bits = cnt + 16 (- 64)
mvn x8, x8
neg w5, w4
rev x8, x8 // next_bits = bswap(next_bits)
lsr w5, w5, #3 // num_bytes_read
lsr x8, x8, x4 // next_bits >>= (shift_bits & 63)
3: // refill_end
add x3, x3, x5
add w6, w6, w5, lsl #3 // cnt += num_bits_read
str x3, [x0, #BUF_POS]
4: // refill_end2
orr x7, x7, x8 // dif |= next_bits
5: // end
sub w15, w15, #5*8
lsr x12, x7, #48
adds w13, w13, w15 // carry = tok_br < 3 || tok == 15
dup v1.8h, w12
b.cc 1b // loop if !carry
add w13, w13, #30*8
str w6, [x0, #CNT]
str x7, [x0, #DIF]
lsr w0, w13, #4
ret
6: // pad_with_ones
add w8, w6, #-16
ror x8, x8, x8
b 4b
7: // refill_eob
cmp x3, x4
b.hs 6b
ldr x8, [x4, #-8]
lsl w5, w5, #3
lsr x8, x8, x5
add w5, w6, #-48
mvn x8, x8
sub w4, w4, w3 // num_bytes_left
rev x8, x8
lsr x8, x8, x5
neg w5, w5
lsr w5, w5, #3
cmp w5, w4
csel w5, w5, w4, lo // num_bytes_read
b 3b
endfunc
function msac_decode_bool_equi_neon, export=1
ldp w5, w6, [x0, #RNG] // + CNT
ldr x7, [x0, #DIF]
bic w4, w5, #0xff // r &= 0xff00
add w4, w4, #8
subs x8, x7, x4, lsl #47 // dif - vw
lsr w4, w4, #1 // v
sub w5, w5, w4 // r - v
cset w15, lo
csel w4, w5, w4, hs // if (ret) v = r - v;
csel x7, x8, x7, hs // if (ret) dif = dif - vw;
clz w5, w4 // clz(rng)
eor w5, w5, #16 // d = clz(rng) ^ 16
lsl w4, w4, w5 // rng << d
subs w6, w6, w5 // cnt -= d
lsl x7, x7, x5 // (dif - (v << 48)) << d
str w4, [x0, #RNG]
b.lo L(refill)
str w6, [x0, #CNT]
str x7, [x0, #DIF]
mov w0, w15
ret
endfunc
function msac_decode_bool_neon, export=1
ldp w5, w6, [x0, #RNG] // + CNT
ldr x7, [x0, #DIF]
lsr w4, w5, #8 // r >> 8
bic w1, w1, #0x3f // f &= ~63
mul w4, w4, w1
lsr w4, w4, #7
add w4, w4, #4 // v
subs x8, x7, x4, lsl #48 // dif - vw
sub w5, w5, w4 // r - v
cset w15, lo
csel w4, w5, w4, hs // if (ret) v = r - v;
csel x7, x8, x7, hs // if (ret) dif = dif - vw;
clz w5, w4 // clz(rng)
eor w5, w5, #16 // d = clz(rng) ^ 16
lsl w4, w4, w5 // rng << d
subs w6, w6, w5 // cnt -= d
lsl x7, x7, x5 // (dif - (v << 48)) << d
str w4, [x0, #RNG]
b.lo L(refill)
str w6, [x0, #CNT]
str x7, [x0, #DIF]
mov w0, w15
ret
endfunc
function msac_decode_bool_adapt_neon, export=1
ldr w9, [x1] // cdf[0-1]
ldp w5, w6, [x0, #RNG] // + CNT
ldr x7, [x0, #DIF]
lsr w4, w5, #8 // r >> 8
and w2, w9, #0xffc0 // f &= ~63
mul w4, w4, w2
lsr w4, w4, #7
add w4, w4, #4 // v
subs x8, x7, x4, lsl #48 // dif - vw
sub w5, w5, w4 // r - v
cset w15, lo
csel w4, w5, w4, hs // if (ret) v = r - v;
csel x7, x8, x7, hs // if (ret) dif = dif - vw;
ldr w10, [x0, #ALLOW_UPDATE_CDF]
clz w5, w4 // clz(rng)
eor w5, w5, #16 // d = clz(rng) ^ 16
cbz w10, 1f
lsr w2, w9, #16 // count = cdf[1]
and w9, w9, #0xffff // cdf[0]
sub w3, w2, w2, lsr #5 // count - (count >= 32)
lsr w2, w2, #4 // count >> 4
add w10, w3, #1 // count + (count < 32)
add w2, w2, #4 // rate = (count >> 4) | 4
sub w9, w9, w15 // cdf[0] -= bit
sub w11, w9, w15, lsl #15 // {cdf[0], cdf[0] - 32769}
asr w11, w11, w2 // {cdf[0], cdf[0] - 32769} >> rate
sub w9, w9, w11 // cdf[0]
strh w9, [x1]
strh w10, [x1, #2]
1:
lsl w4, w4, w5 // rng << d
subs w6, w6, w5 // cnt -= d
lsl x7, x7, x5 // (dif - (v << 48)) << d
str w4, [x0, #RNG]
b.lo L(refill)
str w6, [x0, #CNT]
str x7, [x0, #DIF]
mov w0, w15
ret
endfunc

View file

@ -0,0 +1,546 @@
/*
* Copyright © 2021, VideoLAN and dav1d authors
* Copyright © 2021, Martin Storsjo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
#include "src/arm/asm-offsets.h"
#include "src/arm/asm.S"
#include "util.S"
#define INVALID_MV 0x80008000
// void dav1d_splat_mv_neon(refmvs_block **rr, const refmvs_block *rmv,
// int bx4, int bw4, int bh4)
function splat_mv_neon, export=1
ld1 {v3.16b}, [x1]
clz w3, w3
movrel x5, splat_tbl
sub w3, w3, #26
ext v2.16b, v3.16b, v3.16b, #12
ldrsw x3, [x5, w3, uxtw #2]
add w2, w2, w2, lsl #1
ext v0.16b, v2.16b, v3.16b, #4
add x3, x5, x3
ext v1.16b, v2.16b, v3.16b, #8
lsl w2, w2, #2
ext v2.16b, v2.16b, v3.16b, #12
1:
ldr x1, [x0], #8
subs w4, w4, #1
add x1, x1, x2
br x3
10:
AARCH64_VALID_JUMP_TARGET
st1 {v0.8b}, [x1]
str s2, [x1, #8]
b.gt 1b
ret
20:
AARCH64_VALID_JUMP_TARGET
st1 {v0.16b}, [x1]
str d1, [x1, #16]
b.gt 1b
ret
320:
AARCH64_VALID_JUMP_TARGET
st1 {v0.16b, v1.16b, v2.16b}, [x1], #48
st1 {v0.16b, v1.16b, v2.16b}, [x1], #48
st1 {v0.16b, v1.16b, v2.16b}, [x1], #48
st1 {v0.16b, v1.16b, v2.16b}, [x1], #48
160:
AARCH64_VALID_JUMP_TARGET
st1 {v0.16b, v1.16b, v2.16b}, [x1], #48
st1 {v0.16b, v1.16b, v2.16b}, [x1], #48
80:
AARCH64_VALID_JUMP_TARGET
st1 {v0.16b, v1.16b, v2.16b}, [x1], #48
40:
AARCH64_VALID_JUMP_TARGET
st1 {v0.16b, v1.16b, v2.16b}, [x1]
b.gt 1b
ret
endfunc
jumptable splat_tbl
.word 320b - splat_tbl
.word 160b - splat_tbl
.word 80b - splat_tbl
.word 40b - splat_tbl
.word 20b - splat_tbl
.word 10b - splat_tbl
endjumptable
const mv_tbls, align=4
.byte 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
.byte 0, 1, 2, 3, 8, 0, 1, 2, 3, 8, 0, 1, 2, 3, 8, 0
.byte 4, 5, 6, 7, 9, 4, 5, 6, 7, 9, 4, 5, 6, 7, 9, 4
.byte 4, 5, 6, 7, 9, 4, 5, 6, 7, 9, 4, 5, 6, 7, 9, 4
endconst
const mask_mult, align=4
.byte 1, 2, 1, 2, 0, 0, 0, 0
endconst
// void dav1d_save_tmvs_neon(refmvs_temporal_block *rp, ptrdiff_t stride,
// refmvs_block **rr, const uint8_t *ref_sign,
// int col_end8, int row_end8,
// int col_start8, int row_start8)
function save_tmvs_neon, export=1
AARCH64_SIGN_LINK_REGISTER
stp x29, x30, [sp, #-16]!
mov x29, sp
movi v30.8b, #0
ld1 {v31.8b}, [x3]
movrel x8, save_tmvs_tbl
movrel x16, mask_mult
movrel x13, mv_tbls
ld1 {v29.8b}, [x16]
ext v31.8b, v30.8b, v31.8b, #7 // [0, ref_sign]
mov w15, #5
mov w14, #12*2
sxtw x4, w4
sxtw x6, w6
mul w1, w1, w15 // stride *= 5
sub w5, w5, w7 // h = row_end8 - row_start8
lsl w7, w7, #1 // row_start8 <<= 1
1:
mov w15, #5
and w9, w7, #30 // (y & 15) * 2
ldr x9, [x2, w9, uxtw #3] // b = rr[(y & 15) * 2]
add x9, x9, #12 // &b[... + 1]
madd x10, x4, x14, x9 // end_cand_b = &b[col_end8*2 + 1]
madd x9, x6, x14, x9 // cand_b = &b[x*2 + 1]
madd x3, x6, x15, x0 // &rp[x]
2:
ldrb w11, [x9, #10] // cand_b->bs
ld1 {v0.16b}, [x9] // cand_b->mv
add x11, x8, w11, uxtw #3
ldr h1, [x9, #8] // cand_b->ref
ldr w12, [x11] // bw8
mov x15, x8
add x9, x9, w12, uxtw #1 // cand_b += bw8*2
cmp x9, x10
mov v2.8b, v0.8b
b.ge 3f
ldrb w15, [x9, #10] // cand_b->bs
add x16, x9, #8
ld1 {v4.16b}, [x9] // cand_b->mv
add x15, x8, w15, uxtw #3
ld1 {v1.h}[1], [x16] // cand_b->ref
ldr w12, [x15] // bw8
add x9, x9, w12, uxtw #1 // cand_b += bw8*2
trn1 v2.2d, v0.2d, v4.2d
3:
abs v2.8h, v2.8h // abs(mv[].xy)
tbl v1.8b, {v31.16b}, v1.8b // ref_sign[ref]
ushr v2.8h, v2.8h, #12 // abs(mv[].xy) >> 12
umull v1.8h, v1.8b, v29.8b // ref_sign[ref] * {1, 2}
cmeq v2.4s, v2.4s, #0 // abs(mv[].xy) <= 4096
xtn v2.4h, v2.4s // abs() condition to 16 bit
and v1.8b, v1.8b, v2.8b // h[0-3] contains conditions for mv[0-1]
addp v1.4h, v1.4h, v1.4h // Combine condition for [1] and [0]
umov w16, v1.h[0] // Extract case for first block
umov w17, v1.h[1]
ldrsw x11, [x11, #4] // Fetch jump table entry
ldrsw x15, [x15, #4]
ldr q1, [x13, w16, uxtw #4] // Load permutation table base on case
ldr q5, [x13, w17, uxtw #4]
add x11, x8, x11 // Find jump table target
add x15, x8, x15
tbl v0.16b, {v0.16b}, v1.16b // Permute cand_b to output refmvs_temporal_block
tbl v4.16b, {v4.16b}, v5.16b
// v1 follows on v0, with another 3 full repetitions of the pattern.
ext v1.16b, v0.16b, v0.16b, #1
ext v5.16b, v4.16b, v4.16b, #1
// v2 ends with 3 complete repetitions of the pattern.
ext v2.16b, v0.16b, v1.16b, #4
ext v6.16b, v4.16b, v5.16b, #4
blr x11
b.ge 4f // if (cand_b >= end)
mov v0.16b, v4.16b
mov v1.16b, v5.16b
mov v2.16b, v6.16b
cmp x9, x10
blr x15
b.lt 2b // if (cand_b < end)
4:
subs w5, w5, #1 // h--
add w7, w7, #2 // y += 2
add x0, x0, x1 // rp += stride
b.gt 1b
ldp x29, x30, [sp], #16
AARCH64_VALIDATE_LINK_REGISTER
ret
10:
AARCH64_VALID_CALL_TARGET
add x16, x3, #4
st1 {v0.s}[0], [x3]
st1 {v0.b}[4], [x16]
add x3, x3, #5
ret
20:
AARCH64_VALID_CALL_TARGET
add x16, x3, #8
st1 {v0.d}[0], [x3]
st1 {v0.h}[4], [x16]
add x3, x3, #2*5
ret
40:
AARCH64_VALID_CALL_TARGET
st1 {v0.16b}, [x3]
str s1, [x3, #16]
add x3, x3, #4*5
ret
80:
AARCH64_VALID_CALL_TARGET
// This writes 6 full entries plus 2 extra bytes
st1 {v0.16b, v1.16b}, [x3]
// Write the last few, overlapping with the first write.
stur q2, [x3, #(8*5-16)]
add x3, x3, #8*5
ret
160:
AARCH64_VALID_CALL_TARGET
add x16, x3, #6*5
add x17, x3, #12*5
// This writes 6 full entries plus 2 extra bytes
st1 {v0.16b, v1.16b}, [x3]
// Write another 6 full entries, slightly overlapping with the first set
st1 {v0.16b, v1.16b}, [x16]
// Write 8 bytes (one full entry) after the first 12
st1 {v0.8b}, [x17]
// Write the last 3 entries
str q2, [x3, #(16*5-16)]
add x3, x3, #16*5
ret
endfunc
jumptable save_tmvs_tbl
.word 16 * 12
.word 160b - save_tmvs_tbl
.word 16 * 12
.word 160b - save_tmvs_tbl
.word 8 * 12
.word 80b - save_tmvs_tbl
.word 8 * 12
.word 80b - save_tmvs_tbl
.word 8 * 12
.word 80b - save_tmvs_tbl
.word 8 * 12
.word 80b - save_tmvs_tbl
.word 4 * 12
.word 40b - save_tmvs_tbl
.word 4 * 12
.word 40b - save_tmvs_tbl
.word 4 * 12
.word 40b - save_tmvs_tbl
.word 4 * 12
.word 40b - save_tmvs_tbl
.word 2 * 12
.word 20b - save_tmvs_tbl
.word 2 * 12
.word 20b - save_tmvs_tbl
.word 2 * 12
.word 20b - save_tmvs_tbl
.word 2 * 12
.word 20b - save_tmvs_tbl
.word 2 * 12
.word 20b - save_tmvs_tbl
.word 1 * 12
.word 10b - save_tmvs_tbl
.word 1 * 12
.word 10b - save_tmvs_tbl
.word 1 * 12
.word 10b - save_tmvs_tbl
.word 1 * 12
.word 10b - save_tmvs_tbl
.word 1 * 12
.word 10b - save_tmvs_tbl
.word 1 * 12
.word 10b - save_tmvs_tbl
.word 1 * 12
.word 10b - save_tmvs_tbl
endjumptable
// void dav1d_load_tmvs_neon(const refmvs_frame *const rf, int tile_row_idx,
// const int col_start8, const int col_end8,
// const int row_start8, int row_end8)
function load_tmvs_neon, export=1
rf .req x0
tile_row_idx .req w1
col_start8 .req w2
col_end8 .req w3
row_start8 .req w4
row_end8 .req w5
col_start8i .req w6
col_end8i .req w7
rp_proj .req x8
stride5 .req x9
wstride5 .req w9
stp x28, x27, [sp, #-96]!
stp x26, x25, [sp, #16]
stp x24, x23, [sp, #32]
stp x22, x21, [sp, #48]
stp x20, x19, [sp, #64]
stp x29, x30, [sp, #80]
ldr w15, [rf, #RMVSF_N_TILE_THREADS]
ldp w16, w17, [rf, #RMVSF_IW8] // include rf->ih8 too
sub col_start8i, col_start8, #8 // col_start8 - 8
add col_end8i, col_end8, #8 // col_end8 + 8
ldr wstride5, [rf, #RMVSF_RP_STRIDE]
ldr rp_proj, [rf, #RMVSF_RP_PROJ]
cmp w15, #1
csel tile_row_idx, wzr, tile_row_idx, eq // if (rf->n_tile_threads == 1) tile_row_idx = 0
bic col_start8i, col_start8i, col_start8i, asr #31 // imax(col_start8 - 8, 0)
cmp col_end8i, w16
csel col_end8i, col_end8i, w16, lt // imin(col_end8 + 8, rf->iw8)
lsl tile_row_idx, tile_row_idx, #4 // 16 * tile_row_idx
cmp row_end8, w17
csel row_end8, row_end8, w17, lt // imin(row_end8, rf->ih8)
add wstride5, wstride5, wstride5, lsl #2 // stride * sizeof(refmvs_temporal_block)
and w15, row_start8, #15 // row_start8 & 15
add w10, col_start8, col_start8, lsl #2 // col_start8 * sizeof(refmvs_temporal_block)
smaddl rp_proj, tile_row_idx, wstride5, rp_proj // &rf->rp_proj[16 * stride * tile_row_idx]
smaddl x10, w15, wstride5, x10 // ((row_start8 & 15) * stride + col_start8) * sizeof(refmvs_temporal_block)
mov w15, #INVALID_MV
sub w11, col_end8, col_start8 // xfill loop count
add x10, x10, rp_proj // &rf->rp_proj[16 * stride * tile_row_idx + (row_start8 & 15) * stride + col_start8]
add x15, x15, x15, lsl #40 // first 64b of 4 [INVALID_MV, 0]... patterns
mov w17, #(INVALID_MV >> 8) // last 32b of 4 patterns
sub w12, row_end8, row_start8 // yfill loop count
ror x16, x15, #48 // second 64b of 4 patterns
ldr w19, [rf, #RMVSF_N_MFMVS]
5: // yfill loop
and w13, w11, #-4 // xfill 4x count by patterns
mov x14, x10 // fill_ptr = row_ptr
add x10, x10, stride5 // row_ptr += stride
sub w12, w12, #1 // y--
cbz w13, 3f
4: // xfill loop 4x
sub w13, w13, #4 // xfill 4x count -= 4
stp x15, x16, [x14]
str w17, [x14, #16]
add x14, x14, #20 // fill_ptr += 4 * sizeof(refmvs_temporal_block)
cbnz w13, 4b
3: // up to 3 residuals
tbz w11, #1, 1f
str x15, [x14]
strh w16, [x14, #8]
add x14, x14, #10 // fill_ptr += 2 * sizeof(refmvs_temporal_block)
1: // up to 1 residual
tbz w11, #0, 2f
str w15, [x14]
2:
cbnz w12, 5b // yfill loop
cbz w19, 11f // if (!rf->n_mfmvs) skip nloop
add x29, rf, #RMVSF_MFMV_REF2CUR
mov w10, #0 // n = 0
movi v3.2s, #255 // 0x3FFF >> 6, for MV clamp
movrel x1, div_mult_tbl
10: // nloop
ldrsb w16, [x29, x10] // ref2cur = rf->mfmv_ref2cur[n]
cmp w16, #-32
b.eq 9f // if (ref2cur == INVALID_REF2CUR) continue
add x17, x10, #(RMVSF_MFMV_REF - RMVSF_MFMV_REF2CUR) // n - (&rf->mfmv_ref - &rf->mfmv_ref2cur)
mov x20, #4
ldrb w17, [x29, x17] // ref = rf->mfmv_ref[n]
ldr x13, [x29, #(RMVSF_RP_REF - RMVSF_MFMV_REF2CUR)]
sub x21, x10, x10, lsl #3 // -(n * 7)
smaddl x20, row_start8, wstride5, x20 // row_start8 * stride * sizeof(refmvs_temporal_block) + 4
mov w12, row_start8 // y = row_start8
add x28, x29, #(RMVSF_MFMV_REF2REF - RMVSF_MFMV_REF2CUR - 1) // &rf->mfmv_ref2ref - 1
ldr x13, [x13, x17, lsl #3] // rf->rp_ref[ref]
sub x28, x28, x21 // rf->mfmv_ref2ref[n] - 1
sub w17, w17, #4 // ref_sign = ref - 4
add x13, x13, x20 // r = &rf->rp_ref[ref][row_start8 * stride].ref
dup v0.2s, w17 // ref_sign
5: // yloop
and w14, w12, #-8 // y_sb_align = y & ~7
mov w11, col_start8i // x = col_start8i
add w15, w14, #8 // y_sb_align + 8
cmp w14, row_start8
csel w14, w14, row_start8, gt // imax(y_sb_align, row_start8)
cmp w15, row_end8
csel w15, w15, row_end8, lt // imin(y_sb_align + 8, row_end8)
4: // xloop
add x23, x13, x11, lsl #2 // partial &r[x] address
ldrb w22, [x23, x11] // b_ref = rb->ref
cbz w22, 6f // if (!b_ref) continue
ldrb w24, [x28, x22] // ref2ref = rf->mfmv_ref2ref[n][b_ref - 1]
cbz w24, 6f // if (!ref2ref) continue
ldrh w20, [x1, x24, lsl #1] // div_mult[ref2ref]
add x23, x23, x11 // &r[x]
mul w20, w20, w16 // frac = ref2cur * div_mult[ref2ref]
ldur s1, [x23, #-4] // mv{y, x} = rb->mv
fmov s2, w20 // frac
sxtl v1.4s, v1.4h
mul v1.2s, v1.2s, v2.s[0] // offset{y, x} = frac * mv{y, x}
ssra v1.2s, v1.2s, #31 // offset{y, x} + (offset{y, x} >> 31)
ldur w25, [x23, #-4] // b_mv = rb->mv
srshr v1.2s, v1.2s, #14 // (offset{y, x} + (offset{y, x} >> 31) + 8192) >> 14
abs v2.2s, v1.2s // abs(offset{y, x})
eor v1.8b, v1.8b, v0.8b // offset{y, x} ^ ref_sign
sshr v2.2s, v2.2s, #6 // abs(offset{y, x}) >> 6
cmlt v1.2s, v1.2s, #0 // sign(offset{y, x} ^ ref_sign): -1 or 0
umin v2.2s, v2.2s, v3.2s // iclip(abs(offset{y, x}) >> 6, 0, 0x3FFF >> 6)
neg v4.2s, v2.2s
bsl v1.8b, v4.8b, v2.8b // apply_sign(iclip(abs(offset{y, x}) >> 6, 0, 0x3FFF >> 6))
fmov x20, d1 // offset{y, x}
add w21, w12, w20 // pos_y = y + offset.y
cmp w21, w14 // pos_y >= y_proj_start
b.lt 1f
cmp w21, w15 // pos_y < y_proj_end
b.ge 1f
add x26, x11, x20, asr #32 // pos_x = x + offset.x
and w27, w21, #15 // pos_y & 15
add x21, x26, x26, lsl #2 // pos_x * sizeof(refmvs_temporal_block)
umaddl x27, w27, wstride5, rp_proj // &rp_proj[(pos_y & 15) * stride]
add x27, x27, x21 // &rp_proj[(pos_y & 15) * stride + pos_x]
3: // copy loop
and w20, w11, #-8 // x_sb_align = x & ~7
sub w21, w20, #8 // x_sb_align - 8
cmp w21, col_start8
csel w21, w21, col_start8, gt // imax(x_sb_align - 8, col_start8)
cmp w26, w21 // pos_x >= imax(x_sb_align - 8, col_start8)
b.lt 2f
add w20, w20, #16 // x_sb_align + 16
cmp w20, col_end8
csel w20, w20, col_end8, lt // imin(x_sb_align + 16, col_end8)
cmp w26, w20 // pos_x < imin(x_sb_align + 16, col_end8)
b.ge 2f
str w25, [x27] // rp_proj[pos + pos_x].mv = rb->mv (b_mv)
strb w24, [x27, #4] // rp_proj[pos + pos_x].ref = ref2ref
2: // search part of copy loop
add w11, w11, #1 // x++
cmp w11, col_end8i // if (++x >= col_end8i) break xloop
b.ge 8f
ldrb w20, [x23, #5]! // rb++; rb->ref
cmp w20, w22 // if (rb->ref != b_ref) break
b.ne 7f
ldur w21, [x23, #-4] // rb->mv.n
cmp w21, w25 // if (rb->mv.n != b_mv.n) break
b.ne 7f
add w26, w26, #1 // pos_x++
add x27, x27, #5 // advance &rp_proj[(pos_y & 15) * stride + pos_x]
b 3b // copy loop
1: // search loop
add w11, w11, #1 // x++
cmp w11, col_end8i // if (++x >= col_end8i) break xloop
b.ge 8f
ldrb w20, [x23, #5]! // rb++; rb->ref
cmp w20, w22 // if (rb->ref != b_ref) break
b.ne 7f
ldur w21, [x23, #-4] // rb->mv.n
cmp w21, w25 // if (rb->mv.n == b_mv.n) continue
b.eq 1b // search loop
7:
cmp w11, col_end8i // x < col_end8i
b.lt 4b // xloop
6: // continue case of xloop
add w11, w11, #1 // x++
cmp w11, col_end8i // x < col_end8i
b.lt 4b // xloop
8:
add w12, w12, #1 // y++
add x13, x13, stride5 // r += stride
cmp w12, row_end8 // y < row_end8
b.lt 5b // yloop
9:
add w10, w10, #1
cmp w10, w19 // n < rf->n_mfmvs
b.lt 10b // nloop
11:
ldp x29, x30, [sp, #80]
ldp x20, x19, [sp, #64]
ldp x22, x21, [sp, #48]
ldp x24, x23, [sp, #32]
ldp x26, x25, [sp, #16]
ldp x28, x27, [sp], #96
ret
.unreq rf
.unreq tile_row_idx
.unreq col_start8
.unreq col_end8
.unreq row_start8
.unreq row_end8
.unreq col_start8i
.unreq col_end8i
.unreq rp_proj
.unreq stride5
.unreq wstride5
endfunc
const div_mult_tbl
.hword 0, 16384, 8192, 5461, 4096, 3276, 2730, 2340
.hword 2048, 1820, 1638, 1489, 1365, 1260, 1170, 1092
.hword 1024, 963, 910, 862, 819, 780, 744, 712
.hword 682, 655, 630, 606, 585, 564, 546, 528
endconst

Some files were not shown because too many files have changed in this diff Show more