docs(gal): Update README and refresh WebGL baselines
README updates: - Document WebGL GAL integration in kicad/common/gal/webgl/ - Add Test Scripts section with all 4 GAL scripts - Add WebGL Integration section explaining the architecture - Update Directory Structure to include wasm/ and baseline-webgl/ - Add Comparison Thresholds section Baseline updates: - Refresh 20 WebGL baseline images after KiCad integration - Minor anti-aliasing differences from previous baselines Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
|
@ -1,13 +1,51 @@
|
||||||
# GAL Regression Test Harness
|
# GAL Regression Test Suite
|
||||||
|
|
||||||
Native test harness for KiCad's OPENGL_GAL (Graphics Abstraction Layer) to enable visual regression testing of the WebGL port.
|
Visual regression testing for KiCad's Graphics Abstraction Layer (GAL), covering both native OpenGL and WebGL implementations.
|
||||||
|
|
||||||
## Purpose
|
## Overview
|
||||||
|
|
||||||
This test suite exercises KiCad's actual OPENGL_GAL implementation to:
|
This test suite validates KiCad's GAL rendering by:
|
||||||
- Generate baseline screenshots for visual regression testing
|
- Running 28 test scenarios that exercise all 70 GAL API methods
|
||||||
- Verify GAL API coverage (70/70 methods tested)
|
- Comparing native OpenGL output against committed baselines
|
||||||
- Provide reference implementations for the WebGL port
|
- Comparing WebGL WASM output against native (for parity verification)
|
||||||
|
- Detecting rendering regressions during development
|
||||||
|
|
||||||
|
## WebGL GAL Integration
|
||||||
|
|
||||||
|
The WebGL GAL implementation lives in **`kicad/common/gal/webgl/`** (~27,800 lines) and is a full port of KiCad's OPENGL_GAL to WebGL 2.0 / OpenGL ES 3.0.
|
||||||
|
|
||||||
|
Key changes from native OpenGL:
|
||||||
|
- GLSL ES 3.0 shaders (`attribute`→`in`, `varying`→`out`, `texture2D()`→`texture()`)
|
||||||
|
- VAOs required (WebGL 2.0 requirement)
|
||||||
|
- No legacy GL (`glBegin/glEnd` replaced with VBOs)
|
||||||
|
- GLU tesselator replaced with earcut.hpp
|
||||||
|
|
||||||
|
The WASM test harness in `wasm/` links against KiCad's WebGL GAL to verify the implementation matches native rendering.
|
||||||
|
|
||||||
|
## Test Scripts
|
||||||
|
|
||||||
|
| Script | Purpose |
|
||||||
|
|--------|---------|
|
||||||
|
| `scripts/build-gal-native-test.sh` | Build native OpenGL test harness (macOS) |
|
||||||
|
| `scripts/build-gal-webgl-test.sh` | Build WebGL WASM test harness |
|
||||||
|
| `scripts/test-gal-regression.sh` | **Master script**: builds both, runs tests, compares native vs baseline AND webgl vs native |
|
||||||
|
| `scripts/test-gal-webgl.sh` | WebGL regression monitor: compares webgl vs baseline-webgl |
|
||||||
|
|
||||||
|
### Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run full regression suite (recommended)
|
||||||
|
./scripts/test-gal-regression.sh
|
||||||
|
|
||||||
|
# Run WebGL-only tests (faster, for WebGL development)
|
||||||
|
./scripts/test-gal-webgl.sh
|
||||||
|
|
||||||
|
# Build native test only
|
||||||
|
./scripts/build-gal-native-test.sh
|
||||||
|
|
||||||
|
# Build WebGL test only
|
||||||
|
./scripts/build-gal-webgl-test.sh
|
||||||
|
```
|
||||||
|
|
||||||
## Test Scenarios
|
## Test Scenarios
|
||||||
|
|
||||||
|
|
@ -44,66 +82,112 @@ This test suite exercises KiCad's actual OPENGL_GAL implementation to:
|
||||||
| 26 | bitmap | DrawBitmap (see limitation below) |
|
| 26 | bitmap | DrawBitmap (see limitation below) |
|
||||||
| 27 | transform-api | Transform() API documentation |
|
| 27 | transform-api | Transform() API documentation |
|
||||||
|
|
||||||
## Building
|
## Building & Running
|
||||||
|
|
||||||
|
### Native Test Harness
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Build
|
||||||
./scripts/build-gal-native-test.sh
|
./scripts/build-gal-native-test.sh
|
||||||
```
|
|
||||||
|
|
||||||
## Running
|
# Run all scenarios
|
||||||
|
|
||||||
```bash
|
|
||||||
# Run all scenarios and save to baseline folder
|
|
||||||
./tests/gal-regression/native/build/gal_native_test \
|
./tests/gal-regression/native/build/gal_native_test \
|
||||||
--output ./tests/gal-regression/baseline
|
--output ./tests/gal-regression/output/native
|
||||||
|
|
||||||
# Run specific scenario (by number)
|
# Run specific scenario (by number)
|
||||||
./tests/gal-regression/native/build/gal_native_test \
|
./tests/gal-regression/native/build/gal_native_test \
|
||||||
--output ./tests/gal-regression/baseline 5
|
--output ./tests/gal-regression/output/native 5
|
||||||
|
|
||||||
# Show window (non-headless)
|
# Show window (non-headless)
|
||||||
./tests/gal-regression/native/build/gal_native_test --show
|
./tests/gal-regression/native/build/gal_native_test --show
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### WebGL Test Harness
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build
|
||||||
|
./scripts/build-gal-webgl-test.sh
|
||||||
|
|
||||||
|
# Run via Playwright (headless)
|
||||||
|
cd tests && npx playwright test gal-webgl.spec.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
## Baselines
|
||||||
|
|
||||||
|
Two sets of baseline screenshots:
|
||||||
|
|
||||||
|
| Folder | Purpose |
|
||||||
|
|--------|---------|
|
||||||
|
| `baseline/` | Native OpenGL reference (28 PNGs) |
|
||||||
|
| `baseline-webgl/` | WebGL reference (29 PNGs) |
|
||||||
|
|
||||||
|
### Updating Baselines
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Update native baseline (after verifying output looks correct)
|
||||||
|
cp tests/gal-regression/output/native/*.png tests/gal-regression/baseline/
|
||||||
|
|
||||||
|
# Update WebGL baseline
|
||||||
|
cp tests/gal-regression/output/webgl/*.png tests/gal-regression/baseline-webgl/
|
||||||
|
```
|
||||||
|
|
||||||
## Known Limitations
|
## Known Limitations
|
||||||
|
|
||||||
### DrawBitmap (Scenario 26)
|
### DrawBitmap (Scenario 26)
|
||||||
|
|
||||||
The DrawBitmap test shows empty panels because OPENGL_GAL::DrawBitmap uses legacy OpenGL immediate mode (`glBegin`/`glVertex3f`/`glEnd`) which is incompatible with the shader-based rendering pipeline used by the test harness.
|
The DrawBitmap test shows empty panels because OPENGL_GAL::DrawBitmap uses legacy OpenGL immediate mode (`glBegin`/`glVertex3f`/`glEnd`) which is incompatible with the shader-based rendering pipeline used by the test harness.
|
||||||
|
|
||||||
In KiCad's production code, DrawBitmap works because:
|
In KiCad's production code, DrawBitmap works because the VIEW rendering system orchestrates buffer flushes between render targets.
|
||||||
1. The VIEW rendering system orchestrates buffer flushes between render targets
|
|
||||||
2. GPU_MANAGER::DrawAll() deactivates the shader after flushing vertices
|
|
||||||
3. The fixed-function pipeline can then render the textured quad
|
|
||||||
|
|
||||||
In our isolated test harness, the shader remains active throughout rendering, causing the legacy GL calls to fail silently.
|
|
||||||
|
|
||||||
This is acceptable because:
|
This is acceptable because:
|
||||||
- DrawBitmap is primarily used for reference images in schematics
|
- DrawBitmap is primarily used for reference images in schematics
|
||||||
- The WebGL port will need its own bitmap rendering implementation anyway
|
- The WebGL port has its own bitmap rendering implementation
|
||||||
- All other 69 GAL methods are fully tested
|
- All other 69 GAL methods are fully tested
|
||||||
|
|
||||||
### Transform() API (Scenario 27) - EXCLUDED FROM COMPARISON
|
### Transform() API (Scenario 27) - EXCLUDED FROM COMPARISON
|
||||||
|
|
||||||
The Transform() method is **dead code in KiCad** - never called anywhere in the codebase. KiCad uses Rotate(), Translate(), Scale() instead.
|
The Transform() method is **dead code in KiCad** - never called anywhere in the codebase. KiCad uses Rotate(), Translate(), Scale() instead. The scenario is kept for documentation but excluded from comparisons.
|
||||||
|
|
||||||
In native OPENGL_GAL, Transform() calls `glMultMatrixd()` which modifies GL_MODELVIEW, but VERTEX_MANAGER uses its own independent `m_transform` - so glMultMatrixd has no visible effect on rendered output. The scenario is kept for documentation but excluded from WebGL vs Native comparisons since both implementations are effectively broken (by design).
|
|
||||||
|
|
||||||
## Directory Structure
|
## Directory Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
tests/gal-regression/
|
tests/gal-regression/
|
||||||
├── README.md # This file
|
├── README.md # This file
|
||||||
├── baseline/ # Reference PNG screenshots
|
├── baseline/ # Native OpenGL reference (28 PNGs)
|
||||||
|
├── baseline-webgl/ # WebGL reference (29 PNGs)
|
||||||
|
├── output/
|
||||||
|
│ ├── native/ # Fresh native test output
|
||||||
|
│ └── webgl/ # Fresh WebGL test output
|
||||||
├── native/
|
├── native/
|
||||||
│ ├── CMakeLists.txt
|
│ ├── CMakeLists.txt
|
||||||
│ ├── gal_native_test.cpp # Main test driver
|
│ ├── gal_native_test.cpp # Main test driver
|
||||||
│ ├── gal_test_accessor.cpp # Private member accessors
|
│ ├── gal_test_accessor.cpp # Private member accessors
|
||||||
│ ├── kicad_stubs.cpp # KiCad symbol stubs
|
│ ├── kicad_stubs.cpp # KiCad symbol stubs
|
||||||
│ ├── bitmap_base_stub.h # Bitmap test patterns
|
│ ├── bitmap_base_stub.h # Bitmap test patterns
|
||||||
│ ├── kifont_stub.h # Glyph factory helpers
|
│ ├── kifont_stub.h # Glyph factory helpers
|
||||||
│ └── generated/ # Shader source files
|
│ └── generated/ # Shader source files
|
||||||
|
├── wasm/
|
||||||
|
│ ├── Makefile # WebGL WASM build
|
||||||
|
│ ├── gal_webgl_test.cpp # WASM entry point
|
||||||
|
│ ├── gal_webgl_test.html # Test page with canvas
|
||||||
|
│ ├── wasm_stubs.cpp # WASM-specific stubs
|
||||||
|
│ └── generated/ # ES 3.0 shader sources
|
||||||
└── scenarios/
|
└── scenarios/
|
||||||
├── gal_test_scenarios.cpp # Scenario registry
|
├── gal_test_scenarios.cpp # Scenario registry
|
||||||
└── scenario_*.cpp # Individual test scenarios
|
└── scenario_*.cpp # Individual test scenarios (shared by native & wasm)
|
||||||
|
|
||||||
|
kicad/common/gal/webgl/ # WebGL GAL implementation (in KiCad repo)
|
||||||
|
├── webgl_gal.cpp # Main implementation
|
||||||
|
├── webgl_gal.h # Class declaration
|
||||||
|
├── gpu_manager.cpp # VBO/VAO management
|
||||||
|
├── vertex_manager.cpp # Vertex accumulation
|
||||||
|
├── shader.cpp # GLSL ES 3.0 compilation
|
||||||
|
├── glu_tess_impl.cpp # GLU tesselator (earcut.hpp)
|
||||||
|
└── ... # ~20 files total
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Comparison Thresholds
|
||||||
|
|
||||||
|
- **Native vs Baseline**: 0% difference (exact match expected)
|
||||||
|
- **WebGL vs Native**: ~7/28 exact matches typical (minor anti-aliasing differences acceptable)
|
||||||
|
- **WebGL vs Baseline-WebGL**: 1% threshold (catches actual regressions)
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 486 KiB After Width: | Height: | Size: 491 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |