Visual Regression and Baseline Policy¶
This document is the single source of truth for visual-regression signals, baseline storage, update rules, and the minimum validation expected for each kind of change. WhatsCanvas uses two complementary image signals:
- exact pixel hashes for deterministic local gates
- fuzzy PPM comparison for driver-sensitive scenes
Exact Hash Gate¶
Exact hashes are fast and strict. They are best for local fixed-time, non-MSAA runs where the GPU and driver are stable.
Common environment:
WHATSCANVAS_EXIT_AFTER_FIRST_FRAME=1
WHATSCANVAS_FIXED_TIME_SECONDS=1.25
WHATSCANVAS_DISABLE_MSAA=1
WHATSCANVAS_PRINT_PIXEL_HASH=1
Fuzzy PPM Comparison¶
Use scripts/compare_ppm_fuzzy.py when exact hashes are too sensitive but the rendered image should still remain visually close to a baseline.
python scripts/compare_ppm_fuzzy.py baseline.ppm candidate.ppm \
--max-channel-delta 3 \
--max-mean-delta 0.75 \
--max-changed-percent 5.0
The script prints machine-readable metrics:
FUZZY_PPM_COMPARE_MAX_CHANNEL_DELTAFUZZY_PPM_COMPARE_MEAN_DELTAFUZZY_PPM_COMPARE_CHANGED_PERCENTFUZZY_PPM_COMPARE_RESULT
The script currently supports binary P6 PPM files with maxval=255, matching Canvas::savePixelsPPM.
Baseline Categories¶
| Category | Primary Gate | Baseline Type | Notes |
|---|---|---|---|
| Core API behavior | ctest -L unit |
Assertions | Geometry, state, text utilities, resource lifecycle, and backend contracts. |
| Public API reference | scripts/api_reference_check.* |
Generated-doc freshness | Fails when doc/public/reference/API_REFERENCE.md is stale relative to include/wsc/. |
| Version consistency | scripts/version_consistency_check.* |
Metadata consistency | Keeps project versions, public macros, docs, and package naming aligned. |
| Package consumer | scripts/package_consumer_smoke.* |
External CMake build | Verifies that a separate project can consume the installed package. |
| Deterministic smoke | scripts/smoke_test.* |
Exact hash / first-frame checks | Use fixed time and disabled MSAA where possible. |
| Text rendering | scripts/text_pixel_regression.* |
Fuzzy PPM | Covers font-regression and text-showcase by default. |
| Effects and scenes | scripts/validation_scene_smoke.* plus captures |
Exact hash or fuzzy PPM | Covers gradients, shadows, blend modes, strokes, and other driver-sensitive effects. |
| Cross-backend filters | *FilterPixelParityTests |
In-memory fuzzy premultiplied RGBA | Records error metrics, worst channel/location, and hashes against Software. |
| OpenGLES build health | scripts/opengles_build_smoke.* |
Build plus Mesa EGL parity | Protects GL-family portability and GLES filter execution. |
Official Baseline Storage¶
- Keep committed baselines under
tests/baselines/. - Never store authoritative baselines in generated build directories.
- Keep text baselines under
tests/baselines/text/. - Give review captures stable names containing the scene and, when needed, the platform and configuration.
Updating Text Baselines¶
Windows:
macOS / Linux:
Accept a baseline update only when the rendering change is intentional, the affected scenes are named in the commit or pull request, thresholds were not loosened to hide unrelated changes, and the update is reproducible locally.
Capturing A Validation Scene¶
WHATSCANVAS_VALIDATION_SCENE=gradient-effect \
WHATSCANVAS_EXIT_AFTER_FIRST_FRAME=1 \
WHATSCANVAS_FIXED_TIME_SECONDS=1.25 \
WHATSCANVAS_DISABLE_MSAA=1 \
WHATSCANVAS_CAPTURE_PPM=build/gradient-effect.ppm \
./build/WhatsCanvasDemo
On Windows PowerShell:
$env:WHATSCANVAS_VALIDATION_SCENE = "gradient-effect"
$env:WHATSCANVAS_EXIT_AFTER_FIRST_FRAME = "1"
$env:WHATSCANVAS_FIXED_TIME_SECONDS = "1.25"
$env:WHATSCANVAS_DISABLE_MSAA = "1"
$env:WHATSCANVAS_CAPTURE_PPM = "build\\gradient-effect.ppm"
build\\Debug\\WhatsCanvasDemo.exe
Threshold Rules¶
- Use exact hashes for stable non-MSAA smoke gates.
- Use fuzzy comparison for shadows, gradients, text, and other driver-sensitive scenes.
- Tighten thresholds when a scene becomes more deterministic.
- Loosen thresholds only with an explanation and image review.
- Prefer a targeted scene over broadly relaxing an existing one.
- Cover pure state and geometry behavior with unit tests where possible.
- Review fuzzy threshold changes like code changes because loose thresholds can hide real regressions.
Required Checks by Change Type¶
| Change Type | Minimum Checks |
|---|---|
| Public API or packaging | ctest -L unit; package configure/build if touched |
| Install/package CMake | scripts/package_consumer_smoke.* |
| Version or release workflow | scripts/version_consistency_check.* |
| Public headers | Regenerate doc/public/reference/API_REFERENCE.md, then run scripts/api_reference_check.* |
| Text/font stack | ctest -L text, scripts/text_pixel_regression.* |
| GL shader/render path | Smoke test, relevant validation scene, fuzzy comparison when captured |
| Image-filter backend | Matching *FilterPixelParityTests; benchmark smoke for performance wiring |
| OpenGLES portability | scripts/opengles_build_smoke.* and GLES parity under Mesa EGL |
| Documentation only | Link/keyword review and no private project context |
Detailed execution records and platform matrices live under internal/validation/;
they are project evidence, not normative user documentation.