Add complete test infrastructure for WebGL GAL visual regression testing: - scripts/test-gal-regression.sh: Master script that builds both backends, runs tests, and performs two-level comparison (native vs baseline, webgl vs native) - scripts/build-gal-webgl-test.sh: WASM build using Makefile with em++ - tests/gal-regression/wasm/: WebGL test harness (stub WEBGL_GAL) - tests/e2e/gal-webgl.spec.ts: Playwright test for screenshot capture Fix Homebrew Emscripten environment in scripts/common/env.sh: - Set EMSDK_PYTHON for Python 3.10+ (em++ reads this, not $PYTHON) - Add bundled LLVM to PATH (Emscripten needs its clang with WASM backend) Verified: Native vs Baseline passes (28/28), WebGL generates blank screenshots as expected (WEBGL_GAL implementation is Phase 2). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
8.1 KiB
WebGL GAL Port - Master Plan
Goal
Port KiCad's GAL (Graphics Abstraction Layer) from OpenGL to WebGL to enable full KiCad functionality in the browser. Use the existing 28-scenario test suite to verify visual parity between native OpenGL and WebGL implementations.
Current State
- GAL Test Harness: 28 scenarios covering 100% of GAL API (~70 methods)
- Native Test: C++ binary using real OPENGL_GAL, outputs PNGs to
tests/gal-regression/baseline/ - KiCad WASM: Already runs in browser but crashes on OpenGL compatibility issues
- OpenGL GAL: ~9,500 lines of C++/GLSL using mix of legacy GL and modern VBOs
Key Decisions
- Approach: Copy and modify existing OpenGL GAL code
- Scope: Full feature parity (all 28 scenarios)
- Location: Develop in
tests/gal-regression/first, move to KiCad later
Architecture
Two-backend test architecture:
┌─────────────────────────────────────────────────────────────┐
│ SAME 28 SCENARIO FILES │
│ (scenarios/*.cpp - pure GAL API calls) │
└─────────────────────────────────────────────────────────────┘
│
┌───────────────┴───────────────┐
▼ ▼
┌─────────────────────────────┐ ┌─────────────────────────┐
│ NATIVE TEST HARNESS │ │ WEBGL TEST HARNESS │
│ (gal_native_test.cpp) │ │ (gal_webgl_test.cpp) │
│ │ │ │
│ Uses: OPENGL_GAL │ │ Uses: WEBGL_GAL │
│ Runs: macOS native │ │ Runs: Browser/WASM │
└─────────────────────────────┘ └─────────────────────────┘
│ │
▼ ▼
┌─────────────────────────────┐ ┌─────────────────────────┐
│ output/native/gal-*.png │ │ output/webgl/gal-*.png │
└─────────────────────────────┘ └─────────────────────────┘
Master Test Script: scripts/test-gal-regression.sh
This is the only script we run. Single command to build, test, and compare everything:
#!/bin/bash
# Single script to build, run, and compare both backends
# 1. BUILD BOTH
scripts/build-gal-native-test.sh
scripts/build-gal-webgl-test.sh
# 2. RUN BOTH TESTS
./tests/gal-regression/native/build/gal_native_test --output tests/gal-regression/output/native/
npx playwright test gal-webgl.spec.ts # outputs to tests/gal-regression/output/webgl/
# 3. COMPARE (two-level)
compare_screenshots output/native/ baseline/ # Catch native regressions
compare_screenshots output/webgl/ output/native/ # Verify WebGL matches native
# 4. REPORT
# Exit 0 if all match, exit 1 if any differ
Two-level comparison:
- native vs baseline → Catches if native code regressed
- webgl vs native → Verifies WebGL implementation matches
Output structure:
tests/gal-regression/
├── baseline/ # Committed reference screenshots
├── output/
│ ├── native/ # Fresh native run
│ └── webgl/ # WebGL run via Playwright
Phases
Phase 1: Master Test Script & WebGL Harness Infrastructure
Create the unified test script and WASM-based test harness.
Deliverables:
scripts/test-gal-regression.sh- Master build/test/compare scripttests/gal-regression/wasm/directory structuretests/gal-regression/wasm/Makefile- Emscripten build (use Makefile, not CMake)tests/gal-regression/wasm/gal_webgl_test.cpp- WASM entry pointtests/gal-regression/wasm/gal_webgl_test.html- Test page with canvasscripts/build-gal-webgl-test.sh- WASM build script (uses Makefile)tests/e2e/gal-webgl.spec.ts- Playwright spec for screenshots
Build Approach:
- Use a Makefile with direct
em++calls (liketests/apps/Makefile.wasm) - Avoid
emcmake cmakewhich requires Python 3.10+ (system has 3.9.6) - Follow the same pattern as
build-wasm-test.sh
Verification: Master script builds both, runs native successfully, WebGL loads empty page.
Phase 2: WEBGL_GAL Implementation
Copy and modify OpenGL GAL to create pure WebGL implementation.
Approach: Start with kicad/common/gal/opengl/opengl_gal.cpp, then:
- Replace legacy immediate mode (
glBegin/glEnd) with VBO-based rendering - Replace GL matrix stack with glm matrices (already used internally)
- Adapt shaders for WebGL 2.0 / GLSL ES 3.0
- Handle WebGL-specific limitations
Key Files:
tests/gal-regression/wasm/webgl_gal.h- Class declarationtests/gal-regression/wasm/webgl_gal.cpp- Main implementationtests/gal-regression/wasm/webgl_shaders.cpp- Shader sources- Adapt vertex_manager, gpu_manager as needed
Verification: Scenario 0 (basic-lines) renders, master script compares successfully.
Phase 3: Complete API Coverage
Implement all GAL methods to pass all 28 scenarios.
Method Groups (incremental):
- Basic drawing: DrawLine, DrawSegment, DrawCircle, DrawArc
- Shapes: DrawRectangle, DrawPolygon, DrawPolyline
- Advanced: DrawBezier, DrawBezierArc, DrawArcSegment, DrawSegmentChain
- State: Colors, transforms, depth testing, render targets
- Groups: BeginGroup, EndGroup, DrawGroup, ChangeGroupColor/Depth
- Text: DrawGlyph, DrawGlyphs, BitmapText
- Special: DrawGrid, DrawCursor, DrawBitmap
Verification: Run master script after each group - all implemented scenarios match.
Phase 4: Integration with KiCad
Move WEBGL_GAL into KiCad source and enable for browser builds.
Deliverables:
- Move
webgl_gal.*tokicad/common/gal/webgl/ - CMake integration for Emscripten builds
- Runtime GAL selection based on platform
- KiCad WASM builds successfully with WEBGL_GAL
Verification: KiCad loads in browser, opens PCB, renders correctly.
File Structure
tests/gal-regression/
├── baseline/ # Committed reference (from native)
├── output/
│ ├── native/ # Fresh native run
│ └── webgl/ # WebGL run via Playwright
├── native/ # Native C++ harness (existing)
│ ├── gal_native_test.cpp
│ └── ...
├── wasm/ # WASM harness (new)
│ ├── Makefile # Use Makefile, not CMake (avoids Python issues)
│ ├── gal_webgl_test.cpp
│ ├── gal_webgl_test.html
│ ├── webgl_gal.h
│ ├── webgl_gal.cpp
│ └── webgl_shaders.cpp
└── scenarios/ # Shared scenarios (existing)
scripts/
├── build-gal-native-test.sh # existing
├── build-gal-webgl-test.sh # new
└── test-gal-regression.sh # new - MASTER SCRIPT
Critical Files to Modify/Create
New files:
scripts/test-gal-regression.sh- Master test scriptscripts/build-gal-webgl-test.sh- WASM buildtests/gal-regression/wasm/*- All WASM harness filestests/e2e/gal-webgl.spec.ts- Playwright test
Reference files (copy from):
kicad/common/gal/opengl/opengl_gal.cpp(3098 lines)kicad/common/gal/opengl/opengl_gal.h(614 lines)kicad/common/gal/opengl/shader.cpp(298 lines)kicad/common/gal/opengl/vertex_manager.cpp(318 lines)kicad/common/gal/opengl/gpu_manager.cpp(340 lines)