LookingGlass/gl-check
Quantum e0c1394c33 [client] add gl-check script to check GL function calls
This prevents us from exceeding the minimum GL/EGL versions that we are
targetting or forced to use indirection for due to lack of guarantee in
the ABI.
2021-10-01 10:12:40 +10:00

153 lines
3.3 KiB
Bash
Executable File

#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" &> /dev/null && pwd)"
WAYLAND_SHELL="${WAYLAND_SHELL:-xdg-shell}"
CLANG_QUERY="${CLANG_QUERY:-clang-query}"
BUILD_DIR="${BUILD_DIR:-$SCRIPT_DIR/client/build}"
case "$WAYLAND_SHELL" in
xdg-shell) shell_ignore=shell_libdecor.c ;;
libdecor) shell_ignore=shell_xdg.c ;;
*)
echo "Unknown Wayland shell: $WAYLAND_SHELL"
exit 1
esac
if ! command -v "$CLANG_QUERY" &> /dev/null; then
echo "clang-query is not installed"
exit 1
fi
if [ ! -f "$BUILD_DIR/compile_commands.json" ]; then
echo "compile_commands.json not found in $BUILD_DIR"
echo 'Run cmake with -DCMAKE_EXPORT_COMPILE_COMMANDS=ON to enable'
exit 1
fi
tempdir="$(mktemp -d)"
cleanup() {
rm -rf "$tempdir"
}
trap cleanup EXIT
sed '/EGL_VERSION_1_5/,$d' /usr/include/EGL/egl.h > "$tempdir/egl1.4.h"
getCalls() {
query="$1"
dir="$2"
command=(find "$dir" -name '*.c')
if [ $# -gt 2 ]; then
command+=(-not)
shift 2
for exclude in "$@"; do
command+=(-name "$exclude")
done
fi
cat > "$tempdir/query" <<EOF
set output print
set bind-root false
m callExpr(callee(functionDecl(matchesName("::$query")).bind("func")))
EOF
"${command[@]}" -exec "$CLANG_QUERY" -p "$BUILD_DIR/compile_commands.json" -f "$tempdir/query" {} + | \
grep -Po "(?<= )\b$query(?=\()" | sort -u
}
checkCalls() {
name="$1"
file="$2"
standard="$3"
while read -r func; do
if ! grep -q "$func" "$file"; then
echo "Found $func in $name, which is not in $standard"
fails=$((fails+1))
fi
done
}
getGLCalls() {
getCalls 'gl[A-WYZ]\w*' "$@"
}
getEGLCalls() {
getCalls 'egl[A-Z]\w*' "$@"
}
getGLXCalls() {
getCalls 'glX\w+' "$@"
}
checkGLESCalls() {
name="$1"
shift
checkCalls "$name" /usr/include/GLES3/gl3.h 'OpenGL ES 3.0' < <(getGLCalls "$@")
}
checkEGLCalls() {
name="$1"
shift
checkCalls "$name" "$tempdir/egl1.4.h" 'EGL 1.4' < <(getEGLCalls "$@")
}
checkGLCalls() {
name="$1"
shift
checkCalls "$name" /usr/include/GL/gl.h 'OpenGL 1.3' < <(getGLCalls "$@")
}
checkGLXCalls() {
name="$1"
shift
checkCalls "$name" /usr/include/GL/glx.h 'GLX 1.3' < <(getGLXCalls "$@")
}
forbidCalls() {
name="$1"
while read -r func; do
echo "Found $func in $name, which is forbidden"
fails=$((fails+1))
done
}
forbidEGLCalls() {
name="$1"
shift
forbidCalls "$name" < <(getEGLCalls "$@")
}
forbidGLXCalls() {
name="$1"
shift
forbidCalls "$name" < <(getGLXCalls "$@")
}
forbidGLCalls() {
name="$1"
shift
forbidCalls "$name" < <(getGLCalls "$@")
}
fails=0
checkGLESCalls 'EGL backend' client/renderers/EGL
checkEGLCalls 'EGL backend' client/renderers/EGL
forbidGLXCalls 'EGL backend' client/renderers/EGL
checkGLCalls 'OpenGL backend' client/renderers/OpenGL
forbidGLXCalls 'OpenGL backend' client/renderers/OpenGL
checkGLXCalls 'X11 display server' client/displayservers/X11
forbidGLCalls 'X11 display server' client/displayservers/X11
checkEGLCalls 'Wayland display server' client/displayservers/Wayland "$shell_ignore"
forbidGLCalls 'Wayland display server' client/displayservers/Wayland "$shell_ignore"
forbidGLXCalls 'Wayland display server' client/displayservers/Wayland "$shell_ignore"
if [ "$fails" -eq 0 ]; then
echo 'All GL function calls look fine.'
else
echo 'Use indirection for the listed GL function calls.'
exit 1
fi