#!/usr/bin/env bash
# Verify the GL4ES GLVND vendor with unmodified ALT GLX applications.
set -Eeuo pipefail

MODE=automatic
RUNTIME_ROOT=/
DISPLAY_NAME=${DISPLAY:-:1}
XAUTHORITY_FILE=${XAUTHORITY:-$HOME/.Xauthority}
DURATION=15
LIFECYCLE_ITERATIONS=10
OUTPUT=

usage() {
    cat <<'EOF'
Usage: mcom03-gl4es-glvnd-probe [options]

Options:
  --automatic         Test normal Xorg/GLVND selection (default).
  --forced            Force mcom03gl4es for an isolated pre-install test.
  --runtime-root DIR  Extracted runtime root used with --forced.
  --display NAME      X display (default: $DISPLAY or :1).
  --xauthority FILE   Xauthority file (default: $XAUTHORITY or ~/.Xauthority).
  --duration SEC      glxgears duration (default: 15).
  --lifecycle-iterations N  Context lifecycle cycles (default: 10).
  --output DIR        Result directory.
  -h, --help          Show this help.

The tested binaries are ALT's unmodified glxinfo, glxgears, and glmark2.
EOF
}

while [ "$#" -gt 0 ]; do
    case "$1" in
        --automatic) MODE=automatic ;;
        --forced) MODE=forced ;;
        --runtime-root) shift; [ "$#" -gt 0 ] || exit 64; RUNTIME_ROOT=$1 ;;
        --display) shift; [ "$#" -gt 0 ] || exit 64; DISPLAY_NAME=$1 ;;
        --xauthority) shift; [ "$#" -gt 0 ] || exit 64; XAUTHORITY_FILE=$1 ;;
        --duration) shift; [ "$#" -gt 0 ] || exit 64; DURATION=$1 ;;
        --lifecycle-iterations) shift; [ "$#" -gt 0 ] || exit 64; LIFECYCLE_ITERATIONS=$1 ;;
        --output) shift; [ "$#" -gt 0 ] || exit 64; OUTPUT=$1 ;;
        -h|--help) usage; exit 0 ;;
        *) echo "Unknown option: $1" >&2; usage >&2; exit 64 ;;
    esac
    shift
done

case "$DURATION" in
    ''|*[!0-9]*|0) echo "--duration must be a positive integer." >&2; exit 64 ;;
esac
case "$LIFECYCLE_ITERATIONS" in
    ''|*[!0-9]*|0) echo "--lifecycle-iterations must be a positive integer." >&2; exit 64 ;;
esac
RUNTIME_ROOT=$(readlink -m "$RUNTIME_ROOT")
if [ -z "$OUTPUT" ]; then
    OUTPUT=/tmp/mcom03-gl4es-glvnd-$(date -u +%Y%m%dT%H%M%SZ)
fi
mkdir -p "$OUTPUT"

for command in xdpyinfo glxinfo glxgears glmark2 timeout; do
    command -v "$command" >/dev/null 2>&1 || {
        echo "Required ALT command is absent: $command" >&2
        exit 1
    }
done
LIFECYCLE=$RUNTIME_ROOT/usr/local/libexec/mcom03-gl4es-glvnd-lifecycle
[ -x "$LIFECYCLE" ] || {
    echo "GLX lifecycle probe is absent: $LIFECYCLE" >&2
    exit 1
}
[ -r "$XAUTHORITY_FILE" ] || {
    echo "Xauthority file is not readable: $XAUTHORITY_FILE" >&2
    exit 1
}

ENVIRONMENT=(
    env -u LIBGL_EGL -u LIBGL_GLES -u LIBGL_ES -u LIBGL_GL
    -u LIBGL_FB -u LIBGL_PLATFORM -u LIBGL_DRIVERS_PATH
    -u LD_LIBRARY_PATH -u LD_PRELOAD -u __GLX_VENDOR_LIBRARY_NAME
    -u __EGL_VENDOR_LIBRARY_FILENAMES -u GBM_BACKEND -u EGL_PLATFORM
    -u MESA_LOADER_DRIVER_OVERRIDE
    -u MCOM03_GL4ES_GLX_DEBUG
    "DISPLAY=$DISPLAY_NAME"
    "XAUTHORITY=$XAUTHORITY_FILE"
)
if [ "$MODE" = forced ]; then
    VENDOR_DIR=$RUNTIME_ROOT/usr/lib64
    [ -e "$VENDOR_DIR/libGLX_mcom03gl4es.so.0" ] || {
        echo "Forced runtime has no GLX vendor: $VENDOR_DIR" >&2
        exit 1
    }
    ENVIRONMENT+=(
        "LD_LIBRARY_PATH=$VENDOR_DIR"
        "__GLX_VENDOR_LIBRARY_NAME=mcom03gl4es"
        "MCOM03_GL4ES_GLX_DEBUG=1"
    )
else
    :
fi

run_graphics() {
    "${ENVIRONMENT[@]}" "$@"
}

irq_count() {
    awk '/pvrsrvkm/ {
        total = 0
        for (i = 2; i <= NF; i++) {
            if ($i ~ /^[0-9]+$/) total += $i
        }
        print total
        found = 1
    }
    END { if (!found) print 0 }' /proc/interrupts
}

run_graphics xdpyinfo >/dev/null
{
    echo "mode=$MODE"
    echo "runtime_root=$RUNTIME_ROOT"
    echo "display=$DISPLAY_NAME"
    echo "xauthority=$XAUTHORITY_FILE"
    uname -a
    rpm -q libglvnd libGL libGLX mesa 2>/dev/null || true
} >"$OUTPUT/environment.txt"

set +e
run_graphics glxinfo -B >"$OUTPUT/glxinfo-B.txt" 2>&1
GLXINFO_STATUS=$?
run_graphics "$LIFECYCLE" "$LIFECYCLE_ITERATIONS" \
    >"$OUTPUT/lifecycle.txt" 2>&1
LIFECYCLE_STATUS=$?
set -e

IRQ_BEFORE=$(irq_count)
set +e
run_graphics timeout "$DURATION" glxgears -info \
    >"$OUTPUT/glxgears.txt" 2>&1
GLXGEARS_STATUS=$?
set -e
IRQ_AFTER_GEARS=$(irq_count)

set +e
"${ENVIRONMENT[@]}" glmark2 --size 800x600 --benchmark build:duration=10 \
    >"$OUTPUT/glmark2.txt" 2>&1 &
GLMARK_PID=$!
set -e
sleep 2
if kill -0 "$GLMARK_PID" 2>/dev/null; then
    cat "/proc/$GLMARK_PID/maps" >"$OUTPUT/glmark2-maps.txt"
else
    echo "glmark2 exited before maps were captured" \
        >"$OUTPUT/glmark2-maps.txt"
fi
set +e
wait "$GLMARK_PID"
GLMARK_STATUS=$?
set -e
IRQ_AFTER=$(irq_count)

GLXINFO_GL4ES=no
GLXINFO_PVR=no
MAPS_VENDOR=no
MAPS_CORE=no
MAPS_PVR=no
LLVMPipe=no
grep -q 'GL4ES wrapper' "$OUTPUT/glxinfo-B.txt" && GLXINFO_GL4ES=yes
grep -q 'Hardware vendor is Imagination Technologies' \
    "$OUTPUT/glxinfo-B.txt" && GLXINFO_PVR=yes
grep -q 'libGLX_mcom03gl4es.so' "$OUTPUT/glmark2-maps.txt" && MAPS_VENDOR=yes
grep -q 'libGL4ES_mcom03.so' "$OUTPUT/glmark2-maps.txt" && MAPS_CORE=yes
grep -Eq 'lib(EGL|GLESv2)_mcom03pvr.so' \
    "$OUTPUT/glmark2-maps.txt" && MAPS_PVR=yes
if grep -Eqi 'llvmpipe|swrast|softpipe' \
        "$OUTPUT/glxinfo-B.txt" "$OUTPUT/glmark2.txt" \
        "$OUTPUT/glmark2-maps.txt"; then
    LLVMPipe=yes
fi

GLMARK_SCORE=$(awk '/glmark2 Score:/ { value=$NF } END { print value }' \
    "$OUTPUT/glmark2.txt")
GLXGEARS_FPS=$(awk '/frames in .* seconds/ { value=$(NF-1) } END { print value }' \
    "$OUTPUT/glxgears.txt")
IRQ_DELTA=$((IRQ_AFTER - IRQ_BEFORE))
VERDICT=FAIL
if [ "$GLXINFO_STATUS" -eq 0 ] \
        && { [ "$GLXGEARS_STATUS" -eq 0 ] || [ "$GLXGEARS_STATUS" -eq 124 ]; } \
        && [ "$GLMARK_STATUS" -eq 0 ] \
        && [ "$LIFECYCLE_STATUS" -eq 0 ] \
        && [ "$GLXINFO_GL4ES" = yes ] \
        && [ "$GLXINFO_PVR" = yes ] \
        && [ "$MAPS_VENDOR" = yes ] \
        && [ "$MAPS_CORE" = yes ] \
        && [ "$MAPS_PVR" = yes ] \
        && [ "$LLVMPipe" = no ] \
        && [ "$IRQ_DELTA" -gt 0 ]; then
    VERDICT=PASS
fi

cat >"$OUTPUT/verification.txt" <<EOF
verdict=$VERDICT
mode=$MODE
glxinfo_status=$GLXINFO_STATUS
glxinfo_gl4es=$GLXINFO_GL4ES
glxinfo_pvr=$GLXINFO_PVR
lifecycle_status=$LIFECYCLE_STATUS
lifecycle_iterations=$LIFECYCLE_ITERATIONS
glxgears_status=$GLXGEARS_STATUS
glxgears_fps_last=${GLXGEARS_FPS:-not-reported}
glmark2_status=$GLMARK_STATUS
glmark2_score=${GLMARK_SCORE:-not-reported}
maps_glx_vendor=$MAPS_VENDOR
maps_gl4es_core=$MAPS_CORE
maps_pvr_provider=$MAPS_PVR
software_renderer_seen=$LLVMPipe
pvr_irq_before=$IRQ_BEFORE
pvr_irq_after_gears=$IRQ_AFTER_GEARS
pvr_irq_after=$IRQ_AFTER
pvr_irq_delta=$IRQ_DELTA
EOF

cat "$OUTPUT/verification.txt"
echo "Logs: $OUTPUT"
[ "$VERDICT" = PASS ]
