AlmaLinux changes: Enable vc4 and v3d for Raspberry Pi graphics in AlmaLinux (Resolves: https://github.com/AlmaLinux/raspberry-pi/issues/32)

Add LLVM 21 support for gallivm (riscv64)
This commit is contained in:
Koichiro Iwao 2026-03-12 02:35:57 +00:00 committed by root
commit 2faec6499e
6 changed files with 1371 additions and 0 deletions

1
.fmf/version Normal file
View File

@ -0,0 +1 @@
1

View File

@ -4,3 +4,4 @@ product_versions:
decision_context: osci_compose_gate
rules:
- !PassingTestCaseRule {test_case_name: desktop-qe.desktop-ci.tier1-gating.functional}
- !PassingTestCaseRule {test_case_name: osci.brew-build.tier0.functional}

108
plan.fmf Normal file
View File

@ -0,0 +1,108 @@
/plan-graphics-sanity-test:
summary: Graphics stack smoke test plan
discover:
how: fmf
provision:
how: local
prepare:
how: shell
script: |
set -x # Enable verbose logging
echo "========================================"
echo "Installing desktop environment and graphics dependencies"
echo "Architecture: $(uname -m)"
echo "OS: $(cat /etc/redhat-release)"
echo "========================================"
# Install full GNOME desktop environment (minimal)
echo "Step 1: Installing GNOME desktop environment..."
dnf groupinstall -y "Server with GUI" || \
dnf groupinstall -y "GNOME Desktop" || \
dnf install -y @gnome-desktop
# Install Wayland session specifically
echo "Step 2: Installing Wayland session components..."
dnf install -y \
gnome-session-wayland-session \
gnome-shell \
mutter \
xorg-x11-server-Xwayland
# Install graphics stack dependencies
echo "Step 3: Installing graphics stack dependencies..."
dnf install -y \
mesa-dri-drivers \
mesa-libGL \
mesa-libEGL \
mesa-libGLES \
mesa-vulkan-drivers \
gtk3 \
gtk4 \
xwayland-run \
mesa-demos \
python3-gobject \
glx-utils
# Install optional packages
echo "Step 4: Installing optional packages..."
dnf install -y gtk3-devel gtk4-devel xterm glxgears || true
# Verify key components
echo "Step 5: Verifying installation..."
echo " mutter: $(which mutter || echo 'NOT FOUND')"
echo " xwfb-run: $(which xwfb-run || echo 'NOT FOUND')"
echo " glxinfo: $(which glxinfo || echo 'NOT FOUND')"
echo " Software renderer: $(ls /usr/lib64/dri/swrast_dri.so 2>/dev/null || echo 'NOT FOUND')"
echo "========================================"
echo "Installation complete"
echo "========================================"
execute:
how: tmt
/tests:
/infrastructure-test:
summary: Graphics infrastructure test (Phases 1-3)
description: |
Validates graphics stack infrastructure:
- Phase 1: System info and prerequisites
- Phase 2: Library initialization (Mesa, GTK)
- Phase 3: Headless compositor and GL context
This test verifies that the graphics stack is properly set up
before running actual rendering tests.
test: SKIP_INSTALL=1 ./tests/graphics-smoke-test-tmt.sh --phase=1-3
tty: true
order: 10
duration: 4m
contact:
- Peter Kopec <pekopec@redhat.com>
component:
- mesa
- gtk3
- mutter
- xwayland
/rendering-test:
summary: Graphics rendering verification (Phase 4)
description: |
Validates actual graphics rendering with visual verification:
- GTK3/GTK4 application startup
- GTK4 rendering test with default renderer
- GTK4 rendering test with NGL renderer
- Visual verification via PNG color analysis
- glxgears FPS test
Detects the s390x Mesa 25.2.7-3 black screen bug where
GTK4 apps show black windows with default renderer but
work correctly with GSK_RENDERER=ngl.
test: SKIP_INSTALL=1 ./tests/graphics-smoke-test-tmt.sh --phase=4
tty: true
order: 20
duration: 8m
contact:
- Peter Kopec <pekopec@redhat.com>
component:
- mesa
- gtk4
- mutter

321
tests/README.md Normal file
View File

@ -0,0 +1,321 @@
# Universal Mesa Graphics Smoke Test
Multi-architecture headless graphics stack testing for Mesa, GTK3/GTK4, and the GNOME compositor.
## Overview
This test suite validates the graphics stack functionality across **4 CPU architectures**:
- **x86_64** (Intel/AMD)
- **aarch64** (ARM 64-bit)
- **ppc64le** (PowerPC Little-Endian)
- **s390x** (IBM Z System)
The tests run entirely **headless** (no physical display required) using `xwfb-run` (Xwayland framebuffer) for testing on bare metal, VMs, or CI infrastructure.
## What It Tests
### Phase 1: System Information & Prerequisites
- Architecture and kernel information
- CPU, memory, and hardware details
- Required package installation verification:
- `mesa-dri-drivers`
- `gtk3`, `gtk4`
- `mutter` (Wayland compositor)
- `xwayland-run` (headless testing framework)
- Mesa GL/EGL/Vulkan drivers
### Phase 2: Graphics Library Initialization
- Mesa GL library loading (`libGL.so.1`)
- GTK3/GTK4 Python bindings import test
- Software renderer availability check (llvmpipe/swrast)
### Phase 3: Headless Graphics Stack
- Wayland compositor startup (`xwfb-run`)
- X11/Xwayland compatibility layer
- OpenGL context creation
- Renderer detection (`glxinfo`)
- Reports vendor, renderer, and GL version
### Phase 4: Application Rendering Tests
- **GTK3 Demo**: Application startup and rendering
- `gtk3-demo --list` (enumerate demos)
- `gtk3-demo --run=textscroll --autoquit` (actual demo execution)
- **GTK4 Demo**: Application startup and rendering
- `gtk4-demo --list` (enumerate demos)
- `gtk4-demo --run=textscroll --autoquit` (actual demo execution)
- **GTK4 Visual Verification** (detects rendering bugs):
- Renders colored shapes (red, green, blue rectangles + yellow circle)
- Saves PNG screenshot
- Analyzes color diversity to detect black screen bug
- Tests **both** default renderer and NGL renderer
- **glxgears**: OpenGL performance test
- Runs for 25 seconds
- Verifies FPS output and GL rendering
## Known Issues Detected
### s390x Mesa 25.2.7-3 Black Screen Bug
**Symptom**: GTK4 applications display black windows with the default renderer.
**Detection**: The visual verification test counts unique colors in the rendered PNG. A properly rendered image has 50+ unique color values; a black screen has <10.
**Workaround**: Setting `GSK_RENDERER=ngl` forces the NGL (new GL) renderer and fixes the issue.
This test suite automatically detects this failure and tests the NGL workaround.
## Architecture
```
universal_sanity_test/
├── main.fmf # TMT test definition (Testing Farm)
├── graphics-smoke-test-rhts.sh # Main test script with RHTS reporting
├── gtk4_render_test.py # GTK4 visual verification app
└── README.md # This file
```
### Test Framework: TMT (Test Management Tool)
The `main.fmf` file defines:
- **Plan**: `plan-graphics-sanity-test`
- Provisioning: `local` (runs on current system)
- Preparation: Installs GNOME desktop and graphics dependencies
- Execution: TMT test runner
- **Test 1**: `infrastructure-test` (Phases 1-3)
- Duration: 4 minutes
- Order: 10 (runs first)
- Tags: `CI-Tier-1`, `graphics`, `infrastructure`, `multiarch`
- **Test 2**: `rendering-test` (Phase 4)
- Duration: 8 minutes
- Order: 20 (runs second)
- Tags: `CI-Tier-1`, `graphics`, `rendering`, `visual-verification`, `multiarch`
### RHTS Reporting
All test results are reported via `tmt-report-result` for integration with:
- Testing Farm
- RHEL Testing Infrastructure
- CI/CD pipelines
Each test reports one of:
- **PASS**: Test succeeded
- **FAIL**: Critical test failed
- **WARN**: Optional test failed (doesn't affect overall result)
- **SKIP**: Test was skipped (dependency not available)
## Usage
### Run All Tests (Recommended)
```bash
./graphics-smoke-test-rhts.sh
```
### Run Only Infrastructure Tests (Phases 1-3)
```bash
./graphics-smoke-test-rhts.sh --phase=1-3
```
### Run Only Rendering Tests (Phase 4)
```bash
./graphics-smoke-test-rhts.sh --phase=4
```
### Run with TMT (Testing Farm)
```bash
tmt run --all
```
### Run Specific TMT Test
```bash
# Infrastructure only
tmt run test --name /tests/infrastructure-test
# Rendering only
tmt run test --name /tests/rendering-test
```
## Requirements
### System Requirements
- RHEL 9+, Fedora 35+, or CentOS Stream 9+
- Supported architectures: x86_64, aarch64, ppc64le, s390x
- No physical display required (fully headless)
### Required Packages
The test automatically installs these if missing:
- `mesa-dri-drivers` - Mesa DRI drivers (required)
- `mesa-libGL`, `mesa-libEGL`, `mesa-libGLES` - Mesa GL libraries
- `mesa-vulkan-drivers` - Mesa Vulkan support
- `gtk3`, `gtk4` - GTK widget toolkit
- `xwayland-run` - Headless X server wrapper
- `mutter` - GNOME Wayland compositor
- `gnome-session-wayland-session` - Wayland session components
- `mesa-demos` - GL utilities (glxinfo, glxgears)
- `python3-gobject` - Python GTK bindings
### Optional Packages
- `gtk3-devel`, `gtk4-devel` - Development tools
- `glx-utils` - GLX utilities
- `xterm` - Terminal emulator
## Output
### Logs Directory
All logs are saved to: `/tmp/graphics-test-logs/`
Key files:
- `00-master-test.log` - Complete test output
- `prereq_system-check.log` - System information and prerequisites
- `app_gtk4-render-test-default.log` - GTK4 default renderer test
- `gtk4_render_test_default.png` - Visual verification screenshot
- `gtk4_render_test_ngl.png` - NGL renderer screenshot
### Test Results Summary
The script outputs:
- Individual test results (PASS/FAIL/WARN/SKIP)
- OpenGL renderer information
- List of generated logs and screenshots
- Overall result: PASS or FAIL
### RHTS Artifacts
The following artifacts are submitted to Testing Farm:
- Master log file
- All PNG screenshots (visual evidence)
- Failed test logs (for debugging)
## Customization
### Environment Variables
```bash
# Set custom log directory
LOGDIR=/var/log/graphics-test ./graphics-smoke-test-rhts.sh
# Disable verbose logging
VERBOSE=0 ./graphics-smoke-test-rhts.sh
# Force specific GTK renderer
GSK_RENDERER=ngl ./graphics-smoke-test-rhts.sh --phase=4
```
### Manual GTK4 Render Test
```bash
# Test with default renderer
xwfb-run -w 2 -- python3 gtk4_render_test.py output.png
# Test with NGL renderer
xwfb-run -w 2 -- python3 gtk4_render_test.py output_ngl.png --renderer=ngl
# Test with other renderers
xwfb-run -w 2 -- python3 gtk4_render_test.py output_cairo.png --renderer=cairo
xwfb-run -w 2 -- python3 gtk4_render_test.py output_vulkan.png --renderer=vulkan
```
## Exit Codes
- `0` - All critical tests passed
- `1` - One or more critical tests failed
## Integration Examples
### CI/CD Pipeline (.gitlab-ci.yml)
```yaml
graphics-test:
stage: test
script:
- cd universal_sanity_test
- ./graphics-smoke-test-rhts.sh
artifacts:
when: always
paths:
- /tmp/graphics-test-logs/
expire_in: 7 days
tags:
- multiarch
```
### Testing Farm
```yaml
plans:
- name: graphics-smoke-test
discover:
how: fmf
execute:
how: tmt
```
## Troubleshooting
### Tests Fail to Start
**Problem**: Missing dependencies
**Solution**: The script auto-installs packages, but you can pre-install:
```bash
dnf install -y mesa-dri-drivers gtk4 mutter xwayland-run
```
### Black Screen Detected (s390x)
**Problem**: GTK4 apps show black windows
**Solution**: This is a known Mesa bug on s390x. Use NGL renderer:
```bash
GSK_RENDERER=ngl gtk4-app
```
### glxgears Timeout
**Problem**: `glxgears` test times out or shows no FPS
**Solution**: Check renderer:
```bash
xwfb-run -w 2 -- glxinfo | grep -i renderer
```
Ensure software renderer (llvmpipe/swrast) is available.
### xwfb-run Not Found
**Problem**: `xwayland-run` package not installed
**Solution**:
```bash
dnf install -y xwayland-run
```
## Development & Contributions
### Test Structure
Each test uses the `run_test()` wrapper:
```bash
run_test "test-name" \
"command to execute" \
"yes|no (critical)"
```
### Adding New Tests
1. Add test to appropriate phase function in `graphics-smoke-test-rhts.sh`
2. Use `run_test()` for automatic RHTS reporting
3. Update this README with test description
### Color Coding
- Blue: Section headers
- Green: Pass
- Yellow: Warning (non-critical failure)
- Red: Fail (critical failure)
## License
Testing infrastructure for Mesa and GNOME graphics stack.
## Contact
- **Maintainer**: Peter Kopec pekopec@redhat.com
- **Components Tested**: mesa, gtk3, gtk4, mutter, xwayland
- **Tags**: CI-Tier-1, graphics, multiarch, infrastructure, rendering
## See Also
- [TMT Documentation](https://tmt.readthedocs.io/)
- [Mesa Project](https://www.mesa3d.org/)
- [GTK Documentation](https://www.gtk.org/)
- [GNOME Mutter](https://gitlab.gnome.org/GNOME/mutter)

794
tests/graphics-smoke-test-tmt.sh Executable file
View File

@ -0,0 +1,794 @@
#!/bin/bash
#
# Cross-Architecture Graphics Smoke Test with TMT Reporting
# Works on: x86_64, aarch64, ppc64le, s390x
# OS: RHEL 9+, Fedora 35+
#
# Designed for Testing Farm / TMT environment
# Reports each test result using tmt-report-result
#
#set -e
set -x # Enable verbose mode - show all commands
# =============================================================================
# Configuration
# =============================================================================
TEST_TIMEOUT=30
LOGDIR=${LOGDIR:-/tmp/graphics-test-logs}
OVERALL_RESULT="PASS"
VERBOSE=${VERBOSE:-1} # Verbose logging enabled by default
# Create log directory
mkdir -p "$LOGDIR"
# Log everything to a master log file
exec > >(tee -a "$LOGDIR/00-master-test.log") 2>&1
# Color output (disabled if not a terminal)
if [ -t 1 ]; then
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
else
RED=''
GREEN=''
YELLOW=''
BLUE=''
NC=''
fi
# =============================================================================
# Helper Functions
# =============================================================================
# TMT reporting helper
tmt_report() {
local test_name="$1"
local result="$2" # PASS/FAIL/WARN/SKIP
local logfile="$3"
echo -e "${BLUE}[TMT]${NC} Reporting: $test_name = $result"
if command -v tmt-report-result >/dev/null 2>&1; then
tmt-report-result -o "$logfile" "$test_name" "$result"
else
# Fallback when not in TMT environment
echo "TMT_REPORT: $test_name $result $logfile"
fi
# Track overall failure (SKIP doesn't affect overall result)
if [ "$result" == "FAIL" ]; then
OVERALL_RESULT="FAIL"
fi
}
# TMT log submission helper (for screenshots, images, etc.)
tmt_submit() {
local file="$1"
local description="${2:-$(basename $file)}"
if [ ! -f "$file" ]; then
echo -e "${YELLOW}[TMT]${NC} Skip submit: $file (not found)"
return 1
fi
echo -e "${BLUE}[TMT]${NC} Submitting: $description"
if command -v tmt-file-submit >/dev/null 2>&1; then
tmt-file-submit -l "$file"
else
# Fallback when not in TMT environment
echo "TMT_SUBMIT: $file ($description)"
fi
}
# Test execution wrapper
run_test() {
local test_name="$1"
local test_cmd="$2"
local critical="${3:-yes}" # yes/no
local logfile="$LOGDIR/${test_name//\//_}" # Replace / with _
logfile="${logfile//[: ]/_}.log" # Replace : and space with _
echo "========================================"
echo "Running: $test_name"
echo "Command: $test_cmd"
echo "Log: $logfile"
echo -n "Result: "
if eval "$test_cmd" >"$logfile" 2>&1; then
echo -e "${GREEN}PASS${NC}"
# Show last few lines of output if verbose
if [ "$VERBOSE" == "1" ] && [ -s "$logfile" ]; then
echo " Last output lines:"
tail -5 "$logfile" | sed 's/^/ /'
fi
tmt_report "$test_name" "PASS" "$logfile"
return 0
else
local exit_code=$?
echo $exit_code >> "$logfile"
if [ "$critical" == "yes" ]; then
echo -e "${RED}FAIL${NC} (exit code: $exit_code)"
# Always show failure details
echo " Error details:"
tail -20 "$logfile" | sed 's/^/ /'
tmt_report "$test_name" "FAIL" "$logfile"
return 1
else
echo -e "${YELLOW}WARN${NC} (optional, exit code: $exit_code)"
# Show warning details if verbose
if [ "$VERBOSE" == "1" ] && [ -s "$logfile" ]; then
echo " Warning details:"
tail -10 "$logfile" | sed 's/^/ /'
fi
tmt_report "$test_name" "WARN" "$logfile"
return 0
fi
fi
}
# =============================================================================
# Dependency Installation
# =============================================================================
install_dependencies() {
local logfile="$LOGDIR/00-install-dependencies.log"
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE} Installing Dependencies${NC}"
echo -e "${BLUE}========================================${NC}"
# Required packages
local required_packages=(
mesa-dri-drivers
mesa-libGL
mesa-libEGL
gtk3
gtk4
xwayland-run
mutter
mesa-demos
python3-gobject
)
# Optional packages
local optional_packages=(
gtk3-devel
gtk4-devel
gtk4-devel-tools
xterm
)
echo "Installing required packages..." | tee "$logfile"
if command -v dnf &>/dev/null; then
# Install required packages
if dnf install -y "${required_packages[@]}" >>"$logfile" 2>&1; then
echo -e "${GREEN}${NC} Required packages installed"
tmt_report "install-dependencies" "PASS" "$logfile"
else
echo -e "${RED}${NC} Failed to install required packages"
tmt_report "install-dependencies" "FAIL" "$logfile"
echo "Check log: $logfile"
exit 1
fi
# Install optional packages (non-fatal)
echo "Installing optional packages..." | tee -a "$logfile"
for pkg in "${optional_packages[@]}"; do
dnf install -y "$pkg" >>"$logfile" 2>&1 || echo " Skipped: $pkg"
done
tmt_submit "$logfile" "Optional extra dependencies"
else
echo -e "${RED}${NC} dnf package manager not found"
tmt_report "install-dependencies" "FAIL" "$logfile"
exit 1
fi
echo
}
# =============================================================================
# Phase Functions
# =============================================================================
run_phases_1_to_3() {
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE} Phases 1-3: Infrastructure Tests${NC}"
echo -e "${BLUE}========================================${NC}"
echo "Architecture: $(uname -m)"
echo "Kernel: $(uname -r)"
echo "OS: $(cat /etc/redhat-release 2>/dev/null || cat /etc/os-release | grep PRETTY_NAME | cut -d'"' -f2)"
echo "Log directory: $LOGDIR"
echo "Date: $(date)"
echo -e "${BLUE}========================================${NC}"
echo
# Environment debugging
echo -e "${BLUE}Environment Check:${NC}"
echo "Display: ${DISPLAY:-not set}"
echo "Wayland: ${WAYLAND_DISPLAY:-not set}"
echo "XDG Runtime: ${XDG_RUNTIME_DIR:-not set}"
echo "Session type: ${XDG_SESSION_TYPE:-not set}"
echo
# Check what's already available
echo -e "${BLUE}Pre-flight Check:${NC}"
echo " mutter: $(which mutter 2>/dev/null || echo 'NOT FOUND')"
echo " xwfb-run: $(which xwfb-run 2>/dev/null || echo 'NOT FOUND')"
echo " glxinfo: $(which glxinfo 2>/dev/null || echo 'NOT FOUND')"
echo " gtk3-demo: $(which gtk3-demo 2>/dev/null || echo 'NOT FOUND')"
echo
# Check DRI drivers
echo " DRI drivers:"
if [ -d /usr/lib64/dri ]; then
ls /usr/lib64/dri/*_dri.so 2>/dev/null | head -5 | sed 's/^/ /' || echo " NONE FOUND"
else
echo " /usr/lib64/dri NOT FOUND"
fi
echo
# Install dependencies first
install_dependencies
# =========================================================================
# PHASE 1: System Info & Prerequisites Check
# =========================================================================
echo -e "${BLUE}Phase 1: System Information & Prerequisites${NC}"
echo "========================================"
echo "Running: prereq/system-check"
local prereq_log="$LOGDIR/prereq_system-check.log"
echo "Log: $prereq_log"
echo -n "Result: "
# All checks go into one log file (use subshell so exit doesn't kill parent)
(
echo "========================================="
echo "SYSTEM INFORMATION & PREREQUISITES CHECK"
echo "========================================="
echo "Date: $(date)"
echo
# Hardware & System Info
echo "--- Architecture & Kernel ---"
uname -a
echo "Architecture: $(uname -m)"
echo
echo "--- CPU Information ---"
if [ -f /proc/cpuinfo ]; then
head -30 /proc/cpuinfo
fi
echo
echo "--- Memory Information ---"
free -h
echo
echo "--- PCI Devices ---"
if command -v lspci >/dev/null 2>&1; then
lspci -v
echo
echo "VGA Devices:"
lspci | grep -i vga || echo "No VGA devices found"
else
echo "lspci not available (expected on s390x)"
fi
echo
echo "--- Hardware Details ---"
if command -v lshw >/dev/null 2>&1; then
lshw -short 2>&1 || echo "lshw failed"
else
echo "lshw not available"
fi
echo
echo "========================================="
echo "PREREQUISITE CHECKS"
echo "========================================="
echo
# Check critical packages
prereq_failed=0
echo "--- Mesa DRI Drivers ---"
if rpm -q mesa-dri-drivers; then
echo "✓ PASS"
else
echo "✗ FAIL - mesa-dri-drivers not installed"
prereq_failed=1
fi
echo
echo "--- GTK3 ---"
if rpm -q gtk3; then
echo "✓ PASS"
else
echo "✗ WARN - gtk3 not installed (optional)"
fi
echo
echo "--- GTK4 ---"
if rpm -q gtk4; then
echo "✓ PASS"
else
echo "✗ FAIL - gtk4 not installed"
prereq_failed=1
fi
echo
echo "--- xwfb-run (headless testing) ---"
if which xwfb-run; then
echo "✓ PASS"
else
echo "✗ FAIL - xwfb-run not found"
prereq_failed=1
fi
echo
echo "--- Wayland Compositor ---"
if rpm -q mutter >/dev/null 2>&1; then
rpm -q mutter
echo "✓ PASS - mutter (GNOME) found"
elif rpm -q kwin >/dev/null 2>&1; then
rpm -q kwin
echo "✓ PASS - kwin (KDE) found"
elif rpm -q weston >/dev/null 2>&1; then
rpm -q weston
echo "✓ PASS - weston found"
else
echo "✗ FAIL - No compositor found (mutter/kwin/weston)"
prereq_failed=1
fi
echo
echo "--- Mesa/GL/EGL Packages ---"
rpm -qa | grep -E 'mesa|libGL|libEGL' | sort || echo "No Mesa packages found"
echo
echo "--- DRI Drivers ---"
if [ -d /usr/lib64/dri ]; then
ls -lh /usr/lib64/dri/ | grep '_dri.so$' || echo "No DRI drivers found"
else
echo "/usr/lib64/dri directory not found"
fi
echo
echo "========================================="
if [ $prereq_failed -eq 0 ]; then
echo "RESULT: All prerequisites satisfied"
exit 0
else
echo "RESULT: Missing critical prerequisites"
exit 1
fi
) > "$prereq_log" 2>&1
if [ $? -eq 0 ]; then
echo -e "${GREEN}PASS${NC}"
tmt_report "prereq/system-check" "PASS" "$prereq_log"
else
echo -e "${RED}FAIL${NC}"
echo " Missing prerequisites - check log for details"
tail -20 "$prereq_log" | sed 's/^/ /'
tmt_report "prereq/system-check" "FAIL" "$prereq_log"
OVERALL_RESULT="FAIL"
fi
# Submit the comprehensive log
tmt_submit "$prereq_log" "system-check-full.log"
echo
# =========================================================================
# PHASE 2: Library Initialization Tests
# =========================================================================
echo -e "${BLUE}Phase 2: Graphics Library Initialization${NC}"
run_test "libinit/mesa-gl" \
"timeout 5 bash -c 'LD_PRELOAD=/usr/lib64/libGL.so.1 /bin/true 2>&1'"
run_test "libinit/gtk3" \
"timeout 5 python3 -c 'import gi; gi.require_version(\"Gtk\", \"3.0\"); from gi.repository import Gtk' 2>&1"
run_test "libinit/gtk4" \
"timeout 5 python3 -c 'import gi; gi.require_version(\"Gtk\", \"4.0\"); from gi.repository import Gtk' 2>&1" \
"no"
# Check software rendering
ls -l /usr/lib64/ > /tmp/mesa_drivers.txt
if [ -f /usr/lib64/dri/swrast_dri.so ] || [ -f /usr/lib64/dri/kms_swrast_dri.so ]; then
echo -e " Software renderer: ${GREEN}available${NC} (llvmpipe/swrast)"
tmt_report "libinit/swrast-available" "PASS" "/tmp/mesa_drivers.txt"
else
echo -e " Software renderer: ${YELLOW}not found${NC}"
tmt_report "libinit/swrast-available" "WARN" "/tmp/mesa_drivers.txt"
fi
echo
# =========================================================================
# PHASE 3: Headless Graphics Stack Tests
# =========================================================================
echo -e "${BLUE}Phase 3: Headless Graphics Stack Tests${NC}"
run_test "headless/compositor-start" \
"timeout $TEST_TIMEOUT xwfb-run -w 2 -- true"
run_test "headless/ptyxis-help" \
"timeout $TEST_TIMEOUT xwfb-run -w 2 -- ptyxis --help"
# Get and report renderer info
local renderer_log="$LOGDIR/headless-renderer-info.log"
if timeout $TEST_TIMEOUT xwfb-run -w 2 -- glxinfo >"$renderer_log" 2>&1; then
RENDERER=$(grep "OpenGL renderer" "$renderer_log" | cut -d: -f2 | xargs)
VENDOR=$(grep "OpenGL vendor" "$renderer_log" | cut -d: -f2 | xargs)
VERSION=$(grep "OpenGL version" "$renderer_log" | cut -d: -f2 | xargs)
echo -e " OpenGL vendor: ${GREEN}${VENDOR}${NC}"
echo -e " OpenGL renderer: ${GREEN}${RENDERER}${NC}"
echo -e " OpenGL version: ${GREEN}${VERSION}${NC}"
tmt_report "headless/renderer-info" "PASS" "$renderer_log"
else
tmt_report "headless/renderer-info" "FAIL" "$renderer_log"
fi
echo
}
run_phase_4() {
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE} Phase 4: Application Rendering Tests${NC}"
echo -e "${BLUE}========================================${NC}"
echo "Architecture: $(uname -m)"
echo "Log directory: $LOGDIR"
echo -e "${BLUE}========================================${NC}"
echo
# =========================================================================
# PHASE 4: Application Startup Tests
# =========================================================================
echo -e "${BLUE}Phase 4: Application Startup Tests${NC}"
# Check GTK renderer being used
echo "GTK Renderer Detection:"
echo " GTK_RENDERER env: ${GTK_RENDERER:-not set (will use default)}"
echo " GSK_RENDERER env: ${GSK_RENDERER:-not set}"
echo " GTK_DEBUG env: ${GTK_DEBUG:-not set}"
echo " Expected: GTK4 uses 'ngl' (new GL) or 'gl' renderer"
# Test GTK3 app (may not be installed on RHEL 10)
if which gtk3-demo >/dev/null 2>&1; then
run_test "app/gtk3-demo-list" \
"timeout $TEST_TIMEOUT xwfb-run -w 2 -- gtk3-demo --list"
#test some actual demo
run_test "app/gtk3-demo-textscroll" \
"timeout $TEST_TIMEOUT xwfb-run -w 2 -- gtk3-demo --run=textscroll --autoquit"
else
echo "========================================"
echo "Running: app/gtk3-demo"
echo "Command: gtk3-demo --list"
echo -n "Result: "
echo -e "${YELLOW}SKIP${NC} (gtk3-demo not installed)"
tmt_report "app/gtk3-demo" "SKIP" "/dev/null"
fi
# Test GTK4
run_test "app/gtk4-demo-list" \
"timeout $TEST_TIMEOUT xwfb-run -w 2 -- gtk4-demo --list"
#Test some actual demo
run_test "app/gtk4-demo-textscroll" \
"timeout $TEST_TIMEOUT xwfb-run -w 2 -- gtk4-demo --run=textscroll --autoquit"
# Test GTK4 rendering with actual visual verification
local gtk4_test_script="$(dirname "$0")/gtk4_render_test.py"
if [ ! -f "$gtk4_test_script" ]; then
gtk4_test_script="./gtk4_render_test.py"
fi
if [ -f "$gtk4_test_script" ] && python3 -c "import gi; gi.require_version('Gtk', '4.0')" 2>/dev/null; then
# =====================================================================
# Test 1: GTK4 with default renderer
# =====================================================================
echo "========================================"
echo "Running: app/gtk4-render-test-default (visual verification)"
local gtk4_render_log="$LOGDIR/app_gtk4-render-test-default.log"
local gtk4_render_png="$LOGDIR/gtk4_render_test_default.png"
echo "Log: $gtk4_render_log"
echo "Output: $gtk4_render_png"
echo -n "Result: "
# Test with default renderer
if timeout $TEST_TIMEOUT xwfb-run -w 2 -- python3 "$gtk4_test_script" "$gtk4_render_png" >"$gtk4_render_log" 2>&1; then
# Check if PNG has good color diversity
if [ -f "$gtk4_render_png" ]; then
local colors=$(python3 -c "
import sys
with open('$gtk4_render_png', 'rb') as f:
data = f.read()
samples = set()
for i in range(100, min(len(data)-4, 2000), 10):
samples.add(data[i:i+4])
print(len(samples))
" 2>/dev/null || echo 0)
if [ "$colors" -gt 50 ]; then
echo -e "${GREEN}PASS${NC} (${colors} unique colors - rendering OK)"
tmt_report "app/gtk4-render-test-default" "PASS" "$gtk4_render_log"
tmt_submit "$gtk4_render_png" "gtk4-render-test-default.png"
else
echo -e "${RED}FAIL${NC} (only ${colors} unique colors - black screen detected)"
tmt_report "app/gtk4-render-test-default" "FAIL" "$gtk4_render_log"
tmt_submit "$gtk4_render_png" "gtk4-render-FAILED-default.png"
fi
else
echo -e "${RED}FAIL${NC} (no PNG generated)"
tmt_report "app/gtk4-render-test-default" "FAIL" "$gtk4_render_log"
fi
else
echo -e "${RED}FAIL${NC} (app crashed or timed out)"
tmt_report "app/gtk4-render-test-default" "FAIL" "$gtk4_render_log"
fi
# =====================================================================
# Test 2: GTK4 with NGL renderer (optional/informational test)
# =====================================================================
echo "========================================"
echo "Running: app/gtk4-render-test-ngl (visual verification with GSK_RENDERER=ngl)"
echo "Note: NGL renderer test is OPTIONAL - verifies if workaround is available"
local gtk4_ngl_log="$LOGDIR/app_gtk4-render-test-ngl.log"
local gtk4_ngl_png="$LOGDIR/gtk4_render_test_ngl.png"
echo "Log: $gtk4_ngl_log"
echo "Output: $gtk4_ngl_png"
echo -n "Result: "
# Test with NGL renderer (non-critical - NGL may not be fully supported yet)
if timeout $TEST_TIMEOUT xwfb-run -w 2 -- python3 "$gtk4_test_script" "$gtk4_ngl_png" --renderer=ngl >"$gtk4_ngl_log" 2>&1; then
# Check if PNG has good color diversity
if [ -f "$gtk4_ngl_png" ]; then
local ngl_colors=$(python3 -c "
import sys
with open('$gtk4_ngl_png', 'rb') as f:
data = f.read()
samples = set()
for i in range(100, min(len(data)-4, 2000), 10):
samples.add(data[i:i+4])
print(len(samples))
" 2>/dev/null || echo 0)
if [ "$ngl_colors" -gt 50 ]; then
echo -e "${GREEN}PASS${NC} (${ngl_colors} unique colors - NGL renderer works!)"
tmt_report "app/gtk4-render-test-ngl" "PASS" "$gtk4_ngl_log"
tmt_submit "$gtk4_ngl_png" "gtk4-render-test-ngl.png"
else
echo -e "${YELLOW}WARN${NC} (only ${ngl_colors} unique colors - NGL renderer also has issues)"
tmt_report "app/gtk4-render-test-ngl" "WARN" "$gtk4_ngl_log"
tmt_submit "$gtk4_ngl_png" "gtk4-render-ngl-warn.png"
fi
else
echo -e "${YELLOW}WARN${NC} (no PNG generated - NGL renderer failed)"
tmt_report "app/gtk4-render-test-ngl" "WARN" "$gtk4_ngl_log"
fi
else
echo -e "${YELLOW}WARN${NC} (app crashed or timed out - NGL renderer not supported/broken)"
tmt_report "app/gtk4-render-test-ngl" "WARN" "$gtk4_ngl_log"
fi
else
echo "========================================"
echo "Running: app/gtk4-render-test"
echo -n "Result: "
echo -e "${YELLOW}SKIP${NC} (gtk4_render_test.py or GTK4 not available)"
tmt_report "app/gtk4-render-test-default" "SKIP" "/dev/null"
tmt_report "app/gtk4-render-test-ngl" "SKIP" "/dev/null"
fi
if which xterm >/dev/null 2>&1; then
run_test "app/xterm" \
"timeout $TEST_TIMEOUT xwfb-run -w 2 -- xterm -e true" \
"no"
fi
if which glxgears >/dev/null 2>&1; then
# glxgears runs forever, so we test differently:
# Run for 5 seconds, check if it produces FPS output
echo "========================================"
echo "Running: app/glxgears"
echo "Command: xwfb-run -w 2 -- glxgears -info & sleep 25 ; killall glxgears"
local gears_log="$LOGDIR/app_glxgears.log"
echo "Log: $gears_log"
echo -n "Result: "
# Run glxgears for 5 seconds with kill timeout
xwfb-run -w 2 -- glxgears -info >"$gears_log" 2>&1 &
sleep 25
killall glxgears
local exit_code=$?
# Wait a moment for cleanup
sleep 1
# Check if we got FPS output (means it rendered successfully)
if grep -q "frames in.*seconds.*FPS" "$gears_log"; then
echo -e "${GREEN}PASS${NC} (rendered frames successfully)"
if [ "$VERBOSE" == "1" ]; then
echo " GL Renderer:"
grep "GL_RENDERER" "$gears_log" | sed 's/^/ /'
echo " Performance:"
grep "frames in.*seconds.*FPS" "$gears_log" | head -3 | sed 's/^/ /'
fi
tmt_report "app/glxgears" "PASS" "$gears_log"
else
echo -e "${YELLOW}WARN${NC} (no FPS output, exit code: $exit_code)"
if [ "$VERBOSE" == "1" ]; then
echo " Log output:"
tail -10 "$gears_log" | sed 's/^/ /'
fi
tmt_report "app/glxgears" "WARN" "$gears_log"
fi
# Cleanup any remaining processes
killall -9 glxgears mutter dbus-run-session 2>/dev/null || true
fi
echo
}
# =============================================================================
# Main Test Execution
# =============================================================================
main() {
# Parse command-line arguments
local RUN_PHASES="all" # Default: run all phases
while [[ $# -gt 0 ]]; do
case $1 in
--phase=*)
RUN_PHASES="${1#*=}"
shift
;;
--help)
echo "Usage: $0 [--phase=1-3|4|all]"
echo " --phase=1-3 Run only infrastructure tests (Phases 1-3)"
echo " --phase=4 Run only application rendering tests (Phase 4)"
echo " --phase=all Run all phases (default)"
exit 0
;;
*)
echo "Unknown option: $1"
echo "Use --help for usage information"
exit 1
;;
esac
done
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE} Graphics Stack Smoke Test${NC}"
echo -e "${BLUE}========================================${NC}"
echo "Run mode: $RUN_PHASES"
echo "Architecture: $(uname -m)"
echo
# Run requested phases
case "$RUN_PHASES" in
"1-3")
run_phases_1_to_3
;;
"4")
run_phase_4
;;
"all")
run_phases_1_to_3
run_phase_4
;;
*)
echo "ERROR: Invalid phase specification: $RUN_PHASES"
echo "Valid options: 1-3, 4, all"
exit 1
;;
esac
# =========================================================================
# Results Summary
# =========================================================================
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE} Test Results Summary${NC}"
echo -e "${BLUE}========================================${NC}"
# Show all logs
echo "Generated logs:"
ls -lh "$LOGDIR" | tail -n +2 | awk '{printf " %s %s\n", $9, $5}'
echo
if [ "$OVERALL_RESULT" == "PASS" ]; then
echo -e "${GREEN}✓ ALL CRITICAL TESTS PASSED${NC}"
echo -e "${BLUE}========================================${NC}"
echo "Graphics stack is functional on $(uname -m)"
echo "Logs saved to: $LOGDIR"
echo "Master log: $LOGDIR/00-master-test.log"
# Submit master log and any screenshots
echo
echo "Submitting artifacts to TMT..."
tmt_submit "$LOGDIR/00-master-test.log" "master-test.log"
# Submit any PNG screenshots as visual evidence
for png in "$LOGDIR"/*.png; do
if [ -f "$png" ]; then
tmt_submit "$png" "$(basename $png)"
fi
done
# Final overall report
tmt_report "graphics-smoke-test" "PASS" "$LOGDIR/00-master-test.log"
exit 0
else
echo -e "${RED}✗ ONE OR MORE CRITICAL TESTS FAILED${NC}"
echo -e "${BLUE}========================================${NC}"
echo "Graphics stack validation failed"
echo "Logs saved to: $LOGDIR"
echo "Master log: $LOGDIR/00-master-test.log"
echo
# Show detailed failure information
echo -e "${RED}Failed Tests:${NC}"
if ls "$LOGDIR"/*.log >/dev/null 2>&1; then
for logfile in "$LOGDIR"/*.log; do
testname=$(basename "$logfile" .log)
# Check if it's a failed test (non-zero exit or error keywords)
if grep -qi "error\|fail\|cannot\|unable" "$logfile" 2>/dev/null; then
echo -e " ${RED}${NC} $testname"
echo " Log: $logfile"
echo " Last 10 lines:"
tail -10 "$logfile" | sed 's/^/ /'
echo
fi
done
fi
# Submit master log and all artifacts for debugging
echo
echo "Submitting artifacts to TMT..."
tmt_submit "$LOGDIR/00-master-test.log" "master-test.log"
# Submit all PNG screenshots as evidence of failure
for png in "$LOGDIR"/*.png; do
if [ -f "$png" ]; then
tmt_submit "$png" "$(basename $png)"
fi
done
# Submit failed test logs
for log in "$LOGDIR"/*.log; do
if [ -f "$log" ] && grep -qi "error\|fail" "$log" 2>/dev/null; then
tmt_submit "$log" "$(basename $log)"
fi
done
# Final overall report
tmt_report "graphics-smoke-test" "FAIL" "$LOGDIR/00-master-test.log"
exit 1
fi
}
# =============================================================================
# Script Entry Point
# =============================================================================
# Pass all command-line arguments to main
main "$@"

146
tests/gtk4_render_test.py Executable file
View File

@ -0,0 +1,146 @@
#!/usr/bin/env python3
"""
GTK4 Rendering Test - Verifies actual rendering by drawing and saving
Tests the s390x Mesa bug where GTK apps show black screens
"""
import sys
import os
# Parse renderer argument BEFORE importing GTK
# GSK_RENDERER must be set before GTK initializes
renderer = None
output_file = None
for i, arg in enumerate(sys.argv[1:], 1):
if arg.startswith('--renderer='):
renderer = arg.split('=', 1)[1]
elif not arg.startswith('--'):
output_file = arg
if renderer:
os.environ['GSK_RENDERER'] = renderer
print(f"Setting GSK_RENDERER={renderer} before GTK import")
#Set debug to print rear renderer of app
os.environ['GSK_DEBUG'] = "renderer"
# Now import GTK (after setting environment)
import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, GLib
import cairo
class RenderTestApp(Gtk.Application):
def __init__(self, output_file):
super().__init__(application_id='org.test.gtk4render')
self.output_file = output_file
self.rendered = False
self.drawing_area = None
def do_activate(self):
window = Gtk.ApplicationWindow(application=self)
window.set_title("GTK4 Rendering Test")
window.set_default_size(400, 300)
self.drawing_area = Gtk.DrawingArea()
self.drawing_area.set_draw_func(self.draw_callback)
window.set_child(self.drawing_area)
window.present()
# Wait for rendering, then save and quit
GLib.timeout_add(2000, self.save_and_quit)
def draw_callback(self, area, cr, width, height):
"""Draw colorful pattern to prove rendering works"""
# Red rectangle
cr.set_source_rgb(1.0, 0.0, 0.0)
cr.rectangle(10, 10, 100, 100)
cr.fill()
# Green rectangle
cr.set_source_rgb(0.0, 1.0, 0.0)
cr.rectangle(130, 10, 100, 100)
cr.fill()
# Blue rectangle
cr.set_source_rgb(0.0, 0.0, 1.0)
cr.rectangle(250, 10, 100, 100)
cr.fill()
# Yellow circle
cr.set_source_rgb(1.0, 1.0, 0.0)
cr.arc(200, 200, 50, 0, 2 * 3.14159)
cr.fill()
print(f"Draw callback called - rendering {width}x{height} surface")
self.rendered = True
def save_and_quit(self):
"""Save the rendered surface to PNG and exit"""
if not self.rendered:
print("WARNING: Draw function not called yet")
print("RESULT: WARN - Rendering may not have occurred")
self.quit()
return False
try:
# Get the window and widget dimensions
width = self.drawing_area.get_width()
height = self.drawing_area.get_height()
print(f"Creating Cairo surface {width}x{height}")
# Create a Cairo image surface
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
cr = cairo.Context(surface)
# Re-render to this surface
self.draw_callback(None, cr, width, height)
# Save to PNG
surface.write_to_png(self.output_file)
# Check file was created and has reasonable size
if os.path.exists(self.output_file):
file_size = os.path.getsize(self.output_file)
print(f"SUCCESS: Saved rendering to {self.output_file} ({file_size} bytes)")
if file_size > 1000:
print("RESULT: PASS - Rendering verified")
else:
print(f"RESULT: FAIL - PNG file too small ({file_size} bytes)")
else:
print(f"RESULT: FAIL - Failed to create {self.output_file}")
except Exception as e:
print(f"ERROR: {e}")
import traceback
traceback.print_exc()
print("RESULT: FAIL - Exception during rendering")
self.quit()
return False
def main():
global output_file
if not output_file:
print(f"Usage: {sys.argv[0]} <output.png> [--renderer=ngl|gl|cairo|vulkan]")
print(f" --renderer: GSK renderer to use (default: auto-detect)")
sys.exit(1)
print(f"GTK4 Rendering Test - will save to {output_file}")
print(f"GSK_RENDERER: {os.environ.get('GSK_RENDERER', 'not set (auto-detect)')}")
print(f"GTK_RENDERER: {os.environ.get('GTK_RENDERER', 'not set')}")
app = RenderTestApp(output_file)
exit_status = app.run(None)
sys.exit(exit_status)
if __name__ == '__main__':
main()