docs: ✏️ cleanup and organize docs
This commit is contained in:
parent
8db6cfadc3
commit
8e413f89ec
29 changed files with 85 additions and 3340 deletions
154
docs/features/archive/ipc-api/ipc-api.md
Normal file
154
docs/features/archive/ipc-api/ipc-api.md
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
# KiCad IPC API - WASM Fork Changes
|
||||
|
||||
> **ARCHIVED — open cleanup TODO, not yet actioned.** Describes `#ifdef KICAD_IPC_API` guards added to ~18 KiCad source files that could be reverted to reduce fork diff. Archiving this doc does **not** perform the revert — that remains a separate task.
|
||||
|
||||
## Overview
|
||||
|
||||
We added `#ifdef KICAD_IPC_API` guards to 18 KiCad source files. These guards wrap:
|
||||
- `#include` statements for protobuf/API headers
|
||||
- `Serialize()` and `Deserialize()` methods
|
||||
|
||||
**Key insight:** Since our build uses `KICAD_IPC_API=ON` (line 251 of `scripts/kicad/build-pcbnew.sh`), these guards don't actually disable any code - everything compiles. The guards can be safely reverted to reduce fork divergence.
|
||||
|
||||
## Modified Files
|
||||
|
||||
| File | What We Guarded |
|
||||
|------|-----------------|
|
||||
| `common/eda_shape.cpp` | `#include` for API headers, `Serialize()`, `Deserialize()` |
|
||||
| `common/eda_text.cpp` | `#include` for API headers, `Serialize()`, `Deserialize()` |
|
||||
| `common/netclass.cpp` | `#include` for API headers, `Serialize()`, `Deserialize()` |
|
||||
| `include/api/api_utils.h` | Entire namespace content (utility functions) |
|
||||
| `pcbnew/api/api_pcb_utils.h` | Entire file content |
|
||||
| `pcbnew/board_connected_item.cpp` | `#include` for API headers, `Serialize()`, `Deserialize()` |
|
||||
| `pcbnew/board_stackup_manager/board_stackup.cpp` | `#include` for API headers, `Serialize()`, `Deserialize()` |
|
||||
| `pcbnew/footprint.cpp` | `#include` for API headers, `Serialize()`, `Deserialize()` |
|
||||
| `pcbnew/pad.cpp` | `#include` for API headers, `Serialize()`, `Deserialize()` |
|
||||
| `pcbnew/padstack.cpp` | `#include` for API headers, `Serialize()`, `Deserialize()` |
|
||||
| `pcbnew/pcb_dimension.cpp` | `#include` for API headers, `Serialize()`, `Deserialize()` |
|
||||
| `pcbnew/pcb_field.cpp` | `#include` for API headers, `Serialize()`, `Deserialize()` |
|
||||
| `pcbnew/pcb_group.cpp` | `#include` for API headers, `Serialize()`, `Deserialize()` |
|
||||
| `pcbnew/pcb_shape.cpp` | `#include` for API headers, `Serialize()`, `Deserialize()` |
|
||||
| `pcbnew/pcb_text.cpp` | `#include` for API headers, `Serialize()`, `Deserialize()` |
|
||||
| `pcbnew/pcb_textbox.cpp` | `#include` for API headers, `Serialize()`, `Deserialize()` |
|
||||
| `pcbnew/pcb_track.cpp` | `#include` for API headers, `Serialize()`, `Deserialize()` |
|
||||
| `pcbnew/zone.cpp` | `#include` for API headers, `Serialize()`, `Deserialize()` |
|
||||
|
||||
## Example of Our Changes
|
||||
|
||||
**Before (upstream):**
|
||||
```cpp
|
||||
#include <api/api_enums.h>
|
||||
#include <api/api_utils.h>
|
||||
#include <api/board/board_types.pb.h>
|
||||
|
||||
void PAD::Serialize( google::protobuf::Any &aContainer ) const
|
||||
{
|
||||
// ... serialization code
|
||||
}
|
||||
```
|
||||
|
||||
**After (our fork):**
|
||||
```cpp
|
||||
#ifdef KICAD_IPC_API
|
||||
#include <api/api_enums.h>
|
||||
#include <api/api_utils.h>
|
||||
#include <api/board/board_types.pb.h>
|
||||
#endif
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
void PAD::Serialize( google::protobuf::Any &aContainer ) const
|
||||
{
|
||||
// ... serialization code
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
## Why We Added These Guards
|
||||
|
||||
Originally added to allow building with `KICAD_IPC_API=OFF`, which would:
|
||||
- Skip protobuf dependency
|
||||
- Exclude serialization methods that depend on protobuf types
|
||||
|
||||
However, our current build has `KICAD_IPC_API=ON`, making these guards unnecessary.
|
||||
|
||||
## How to Revert
|
||||
|
||||
To revert these files to upstream (base commit `4bfed3f174`):
|
||||
|
||||
```bash
|
||||
cd kicad
|
||||
git checkout 4bfed3f174 -- \
|
||||
common/eda_shape.cpp \
|
||||
common/eda_text.cpp \
|
||||
common/netclass.cpp \
|
||||
include/api/api_utils.h \
|
||||
pcbnew/api/api_pcb_utils.h \
|
||||
pcbnew/board_connected_item.cpp \
|
||||
pcbnew/board_stackup_manager/board_stackup.cpp \
|
||||
pcbnew/footprint.cpp \
|
||||
pcbnew/pad.cpp \
|
||||
pcbnew/padstack.cpp \
|
||||
pcbnew/pcb_dimension.cpp \
|
||||
pcbnew/pcb_field.cpp \
|
||||
pcbnew/pcb_group.cpp \
|
||||
pcbnew/pcb_shape.cpp \
|
||||
pcbnew/pcb_text.cpp \
|
||||
pcbnew/pcb_textbox.cpp \
|
||||
pcbnew/pcb_track.cpp \
|
||||
pcbnew/zone.cpp
|
||||
```
|
||||
|
||||
Then rebuild:
|
||||
```bash
|
||||
./docker/build.sh --clean-kicad
|
||||
```
|
||||
|
||||
## Note: toolbars_pcb_editor.cpp
|
||||
|
||||
This file has `#ifdef KICAD_SCRIPTING` guards (not IPC API guards):
|
||||
|
||||
```cpp
|
||||
#ifdef KICAD_SCRIPTING
|
||||
#include "../scripting/python_scripting.h"
|
||||
#endif
|
||||
...
|
||||
#ifdef KICAD_SCRIPTING
|
||||
bool scriptingAvailable = SCRIPTING::IsWxAvailable();
|
||||
#else
|
||||
bool scriptingAvailable = false;
|
||||
#endif
|
||||
```
|
||||
|
||||
**Cannot be fully reverted** because:
|
||||
- `KICAD_SCRIPTING=OFF` for WASM builds (CMakeLists.txt lines 135-138)
|
||||
- Without guards, build fails (python_scripting.h not built, SCRIPTING class doesn't exist)
|
||||
|
||||
This is a separate concern from the IPC API and is documented here for completeness.
|
||||
|
||||
## Impact of Reversion
|
||||
|
||||
- **Fork diff reduction:** 18 fewer modified files
|
||||
- **Build behavior:** No change (KICAD_IPC_API=ON, code compiles identically)
|
||||
- **Functionality:** No change (serialization methods still available)
|
||||
|
||||
## Related: IPC API Architecture
|
||||
|
||||
KiCad's IPC API uses:
|
||||
- **Protobuf messages** for request/response serialization
|
||||
- **NNG sockets** for transport (stubbed in WASM - see `wasm/stubs/nng_stub.c`)
|
||||
- **API_HANDLER_PCB** class for handling requests (instantiated in PCB_EDIT_FRAME)
|
||||
|
||||
Our stub at `wasm/stubs/api_plugin_stub.cpp` provides no-op implementations for:
|
||||
- `KICAD_API_SERVER::Start()`, `Stop()`, `Running()`
|
||||
- `KICAD_API_SERVER::RegisterHandler()`, `DeregisterHandler()`
|
||||
|
||||
## Future: JavaScript Bridge
|
||||
|
||||
To expose the IPC API to JavaScript (optional enhancement):
|
||||
|
||||
1. Modify `api_plugin_stub.cpp` to store registered handlers
|
||||
2. Create Embind bindings in `wasm/bindings/api_bridge.cpp`
|
||||
3. Expose `KiCadApi_HandleRequest(protobufData)` function
|
||||
4. Use `protobuf.js` on JS side for message creation/parsing
|
||||
|
||||
This would enable JS automation without modifying any KiCad source files.
|
||||
264
docs/features/archive/webgl/0001-opengl-gal-webgl-strategy.md
Normal file
264
docs/features/archive/webgl/0001-opengl-gal-webgl-strategy.md
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
# OpenGL, GAL, and WebGL Strategy for KiCad WASM
|
||||
|
||||
> **ARCHIVED / HISTORICAL** — the WebGL-GAL backend described here was implemented (see `kicad/common/gal/webgl/`, ~22.5k lines). Live test docs: [`tests/gal-regression/README.md`](../../../../tests/gal-regression/README.md). Kept for design rationale.
|
||||
|
||||
## Summary
|
||||
|
||||
This document analyzes KiCad's graphics architecture and evaluates strategies for WebGL rendering in the WASM build.
|
||||
|
||||
## Current Implementation: Emscripten LEGACY_GL_EMULATION
|
||||
|
||||
We currently use Emscripten's legacy OpenGL emulation:
|
||||
|
||||
```bash
|
||||
-sLEGACY_GL_EMULATION -sMAX_WEBGL_VERSION=2
|
||||
```
|
||||
|
||||
**How it works:**
|
||||
|
||||
```
|
||||
KiCad/wxWidgets C++ (glBegin, glVertex, glColor, etc.)
|
||||
│
|
||||
▼
|
||||
gl_immediate_shim.js (our fix for color-per-vertex bug)
|
||||
│
|
||||
▼
|
||||
Emscripten GLImmediate (translates legacy GL → shaders + VBOs)
|
||||
│
|
||||
▼
|
||||
WebGL 2.0 (ES 3.0 compatible, shader-based)
|
||||
```
|
||||
|
||||
**Key components:**
|
||||
|
||||
| Component | File | Purpose |
|
||||
|-----------|------|---------|
|
||||
| wxGLCanvas | `wxwidgets/src/wasm/glcanvas.cpp` | Creates WebGL contexts on dedicated HTML5 canvases |
|
||||
| GL Shim | `wasm/shims/gl_immediate_shim.js` | Fixes color-per-vertex bug in GLImmediate |
|
||||
| GLU Tesselator | `wasm/stubs/glu_wasm_impl.cpp` | Polygon triangulation using earcut (GLU not available in WebGL) |
|
||||
| GLEW Stub | `wasm/cmake/FindGLEW.cmake` | Stubs out GLEW (not needed with Emscripten) |
|
||||
| kiglew.h | `kicad/include/gal/opengl/kiglew.h` | Maps double→float, stubs unsupported functions |
|
||||
|
||||
---
|
||||
|
||||
## GLU Status
|
||||
|
||||
**KiCad uses GLU** for polygon tesselation (`gluTess*` functions for zones, complex shapes).
|
||||
|
||||
**We already solved this** with `/wasm/stubs/glu_wasm_impl.cpp` which implements the GLU tesselator API using KiCad's earcut algorithm. This works with both LEGACY_GL_EMULATION and would work with pure ES3.
|
||||
|
||||
GLU is NOT a blocker.
|
||||
|
||||
---
|
||||
|
||||
## Where KiCad Uses Legacy OpenGL
|
||||
|
||||
Two separate systems use legacy OpenGL:
|
||||
|
||||
### 1. OPENGL_GAL (2D Rendering)
|
||||
|
||||
Used for schematic and PCB editors.
|
||||
|
||||
**Files:**
|
||||
- `kicad/common/gal/opengl/opengl_gal.cpp` - Main implementation
|
||||
- `kicad/common/gal/opengl/gpu_manager.cpp` - VBO management
|
||||
- `kicad/common/gal/opengl/opengl_compositor.cpp` - Framebuffer compositing
|
||||
- `kicad/common/gal/opengl/antialiasing.cpp` - AA effects
|
||||
|
||||
**Legacy GL usage in opengl_gal.cpp:**
|
||||
- Lines 1557-1605: Bitmap rendering with `glBegin(GL_QUADS)`
|
||||
- Lines 2690-2755: Cursor drawing with `glBegin(GL_LINES)`
|
||||
- Lines 566-629, 1558-1602, 2704-2751: Matrix stack operations (`glPushMatrix`, `glPopMatrix`, `glMatrixMode`)
|
||||
|
||||
### 2. 3D Viewer (3D Rendering)
|
||||
|
||||
Separate from GAL, used for 3D board visualization.
|
||||
|
||||
**Files using legacy GL:**
|
||||
- `kicad/3d-viewer/3d_rendering/opengl/render_3d_opengl.cpp`
|
||||
- `kicad/3d-viewer/3d_rendering/opengl/opengl_utils.cpp`
|
||||
- `kicad/3d-viewer/3d_rendering/opengl/layer_triangles.cpp`
|
||||
- `kicad/3d-viewer/3d_rendering/opengl/3d_spheres_gizmo.cpp`
|
||||
- `kicad/3d-viewer/3d_rendering/opengl/3d_model.cpp`
|
||||
- `kicad/3d-viewer/3d_model_viewer/eda_3d_model_viewer.cpp`
|
||||
- `kicad/3d-viewer/3d_canvas/eda_3d_canvas_pivot.cpp`
|
||||
|
||||
---
|
||||
|
||||
## If We Cover GAL, Is That Enough?
|
||||
|
||||
**For 2D editing (schematic + PCB): YES**
|
||||
|
||||
The entire 2D rendering pipeline goes through GAL. A working GAL backend enables full schematic and PCB editing.
|
||||
|
||||
**For 3D viewer: NO**
|
||||
|
||||
The 3D viewer is a separate rendering system. It could be disabled/stubbed initially and added later.
|
||||
|
||||
---
|
||||
|
||||
## The GAL API
|
||||
|
||||
GAL (Graphics Abstraction Layer) is a clean 2D drawing interface defined in `kicad/include/gal/graphics_abstraction_layer.h`.
|
||||
|
||||
**NO raw OpenGL is exposed.** The API consists of ~40 virtual methods:
|
||||
|
||||
```cpp
|
||||
// Drawing primitives
|
||||
virtual void DrawLine(const VECTOR2D& start, const VECTOR2D& end);
|
||||
virtual void DrawSegment(const VECTOR2D& start, const VECTOR2D& end, double width);
|
||||
virtual void DrawPolyline(const std::vector<VECTOR2D>& points);
|
||||
virtual void DrawCircle(const VECTOR2D& center, double radius);
|
||||
virtual void DrawArc(const VECTOR2D& center, double radius, const EDA_ANGLE& start, const EDA_ANGLE& angle);
|
||||
virtual void DrawRectangle(const VECTOR2D& start, const VECTOR2D& end);
|
||||
virtual void DrawPolygon(const SHAPE_POLY_SET& polySet);
|
||||
virtual void DrawBitmap(const BITMAP_BASE& bitmap, double alpha);
|
||||
virtual void DrawGlyph(const KIFONT::GLYPH& glyph);
|
||||
|
||||
// Attributes
|
||||
virtual void SetFillColor(const COLOR4D& color);
|
||||
virtual void SetStrokeColor(const COLOR4D& color);
|
||||
virtual void SetLineWidth(float width);
|
||||
virtual void SetIsFill(bool enabled);
|
||||
virtual void SetIsStroke(bool enabled);
|
||||
virtual void SetLayerDepth(double depth);
|
||||
|
||||
// Transforms (matrix stack)
|
||||
virtual void Save();
|
||||
virtual void Restore();
|
||||
virtual void Transform(const MATRIX3x3D& matrix);
|
||||
virtual void Rotate(double angle);
|
||||
virtual void Translate(const VECTOR2D& translation);
|
||||
virtual void Scale(const VECTOR2D& scale);
|
||||
|
||||
// Rendering control
|
||||
virtual void BeginDrawing();
|
||||
virtual void EndDrawing();
|
||||
virtual void SetTarget(RENDER_TARGET target);
|
||||
virtual void ClearTarget(RENDER_TARGET target);
|
||||
virtual void ClearScreen();
|
||||
|
||||
// Grid and cursor
|
||||
virtual void DrawGrid();
|
||||
virtual void DrawCursor(const VECTOR2D& position);
|
||||
```
|
||||
|
||||
**Existing GAL implementations:**
|
||||
|
||||
| Class | File | Purpose |
|
||||
|-------|------|---------|
|
||||
| `OPENGL_GAL` | `kicad/include/gal/opengl/opengl_gal.h` | OpenGL rendering (uses legacy GL internally) |
|
||||
| `CAIRO_GAL` | `kicad/include/gal/cairo/cairo_gal.h` | Cairo software rendering |
|
||||
| `CALLBACK_GAL` | `kicad/include/callback_gal.h` | Hit testing, no actual rendering |
|
||||
|
||||
---
|
||||
|
||||
## What Breaks with FULL_ES3 (No Legacy Emulation)
|
||||
|
||||
If we removed `LEGACY_GL_EMULATION`:
|
||||
|
||||
| Feature | Used In | Status in FULL_ES3 |
|
||||
|---------|---------|-------------------|
|
||||
| `gluTess*` (tesselation) | Polygon rendering | **Our stub works** |
|
||||
| `glBegin/glEnd` | Bitmap quads, cursor | Not available |
|
||||
| `glVertex/glColor` | Immediate mode drawing | Not available |
|
||||
| `glPushMatrix/glPopMatrix` | Transformations | Not available |
|
||||
| `glMatrixMode` | Matrix switching | Not available |
|
||||
| `GL_QUADS` | Bitmap rendering | Not available (only triangles) |
|
||||
| `glEnableClientState` | Legacy vertex arrays | Not available |
|
||||
|
||||
---
|
||||
|
||||
## Strategy Options
|
||||
|
||||
### Option 1: Keep LEGACY_GL_EMULATION (Current)
|
||||
|
||||
**Pros:**
|
||||
- Works now
|
||||
- Minimal code changes to KiCad
|
||||
- All immediate mode functions available
|
||||
|
||||
**Cons:**
|
||||
- ~200KB binary overhead from GLImmediate
|
||||
- Runtime overhead from emulation
|
||||
- Color-per-vertex bug requires our shim
|
||||
- Some edge cases may not work
|
||||
|
||||
**Build flags:**
|
||||
```bash
|
||||
-sLEGACY_GL_EMULATION -sMAX_WEBGL_VERSION=2
|
||||
```
|
||||
|
||||
### Option 2: Create WEBGL_GAL (New Backend)
|
||||
|
||||
Create a new GAL implementation that uses pure WebGL 2.0 (ES 3.0) without legacy emulation.
|
||||
|
||||
**Pros:**
|
||||
- No emulation overhead
|
||||
- Smaller binary
|
||||
- Cleaner, more maintainable
|
||||
- Better performance
|
||||
|
||||
**Cons:**
|
||||
- Development effort (~2-3 weeks)
|
||||
- Need to maintain separate backend
|
||||
|
||||
**Estimated scope:**
|
||||
```
|
||||
New class: WEBGL_GAL : public GAL
|
||||
|
||||
Files needed:
|
||||
├── webgl_gal.h (~300 lines)
|
||||
├── webgl_gal.cpp (~2500 lines)
|
||||
├── webgl_shaders.cpp (~500 lines)
|
||||
└── webgl_compositor.cpp (~500 lines)
|
||||
|
||||
Total: ~3500-4000 lines
|
||||
```
|
||||
|
||||
**Why it's feasible:**
|
||||
- GAL API is clean - no raw GL leaks through
|
||||
- CAIRO_GAL proves it works (~2500 lines)
|
||||
- All drawing is 2D with simple primitives
|
||||
- KiCad's shaders already exist and work in WebGL
|
||||
|
||||
### Option 3: Cairo-only (Software Rendering)
|
||||
|
||||
Use CAIRO_GAL exclusively, render to HTML5 2D canvas.
|
||||
|
||||
**Pros:**
|
||||
- Already exists
|
||||
- No WebGL needed
|
||||
- Works everywhere
|
||||
|
||||
**Cons:**
|
||||
- Slow (CPU-only)
|
||||
- May struggle with complex boards
|
||||
- No hardware acceleration
|
||||
|
||||
---
|
||||
|
||||
## Recommendation
|
||||
|
||||
**Short-term:** Keep LEGACY_GL_EMULATION - it works and allows rapid development.
|
||||
|
||||
**Medium-term:** Create WEBGL_GAL - cleaner architecture, better performance, removes emulation hacks.
|
||||
|
||||
**For 3D viewer:** Disable initially, add later as separate effort.
|
||||
|
||||
---
|
||||
|
||||
## Key Files Reference
|
||||
|
||||
| Purpose | File |
|
||||
|---------|------|
|
||||
| Build flags | `scripts/common/env.sh` |
|
||||
| wxGLCanvas WASM | `wxwidgets/src/wasm/glcanvas.cpp` |
|
||||
| GL immediate shim | `wasm/shims/gl_immediate_shim.js` |
|
||||
| GLU tesselator | `wasm/stubs/glu_wasm_impl.cpp` |
|
||||
| KiCad GL compat | `kicad/include/gal/opengl/kiglew.h` |
|
||||
| KiCad shaders | `kicad/common/gal/shaders/kicad_*.glsl` |
|
||||
| GAL base class | `kicad/include/gal/graphics_abstraction_layer.h` |
|
||||
| OPENGL_GAL | `kicad/include/gal/opengl/opengl_gal.h` |
|
||||
| CAIRO_GAL | `kicad/include/gal/cairo/cairo_gal.h` |
|
||||
| GL documentation | `tests/GL_README.md` |
|
||||
289
docs/features/archive/webgl/0002-gal-native-test-architecture.md
Normal file
289
docs/features/archive/webgl/0002-gal-native-test-architecture.md
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
# GAL Native Test Harness Architecture
|
||||
|
||||
> **ARCHIVED / HISTORICAL** — the WebGL-GAL backend described here was implemented (see `kicad/common/gal/webgl/`). Live test docs: [`tests/gal-regression/README.md`](../../../../tests/gal-regression/README.md). Kept for design rationale.
|
||||
|
||||
## Overview
|
||||
|
||||
The GAL native test harness is a standalone macOS application that compiles KiCad's actual `OPENGL_GAL` rendering engine against system wxWidgets. It generates baseline PNG screenshots for visual regression testing of WebGL rendering in the WASM build.
|
||||
|
||||
**Purpose**: Compare native OpenGL rendering (ground truth) against WebGL rendering in the browser to detect visual regressions.
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ GAL Native Test │
|
||||
├─────────────────────────────────────────────────────────────────────┤
|
||||
│ gal_native_test.cpp (wxApp + wxFrame) │
|
||||
│ └─ Creates OPENGL_GAL on wxGLCanvas │
|
||||
│ └─ Runs 11 test scenarios │
|
||||
│ └─ Captures FBO → PNG for each │
|
||||
├─────────────────────────────────────────────────────────────────────┤
|
||||
│ kicad_stubs.cpp │ gal_test_accessor.cpp │
|
||||
│ • PGM_BASE singleton │ • Template accessor for │
|
||||
│ • ADVANCED_CFG │ private OPENGL_GAL members │
|
||||
│ • KIFONT stubs │ • FBO reading │
|
||||
│ • Observable stubs │ │
|
||||
├─────────────────────────────────────────────────────────────────────┤
|
||||
│ KiCad OPENGL_GAL (from submodule) │
|
||||
│ kicad/common/gal/opengl/*.cpp (18 source files) │
|
||||
├─────────────────────────────────────────────────────────────────────┤
|
||||
│ System Dependencies │
|
||||
│ wxWidgets (via homebrew) │ GLEW │ OpenGL │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## GAL Code Source
|
||||
|
||||
The test harness compiles **KiCad's actual OPENGL_GAL** from the kicad submodule:
|
||||
|
||||
### Source Files (`/kicad/common/gal/opengl/`)
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `opengl_gal.cpp` | Main GAL implementation - drawing primitives |
|
||||
| `opengl_compositor.cpp` | FBO management, layer compositing |
|
||||
| `antialiasing.cpp` | SMAA antialiasing implementation |
|
||||
| `vertex_manager.cpp` | Vertex buffer accumulation |
|
||||
| `vertex_item.cpp` | Individual vertex items |
|
||||
| `vertex_container.cpp` | Vertex storage base class |
|
||||
| `cached_container.cpp` | Cached geometry container |
|
||||
| `cached_container_gpu.cpp` | GPU-resident cached geometry |
|
||||
| `cached_container_ram.cpp` | RAM-backed cached geometry |
|
||||
| `noncached_container.cpp` | Per-frame geometry |
|
||||
| `gpu_manager.cpp` | GPU buffer management |
|
||||
| `shader.cpp` | GLSL shader compilation/linking |
|
||||
| `utils.cpp` | OpenGL utility functions |
|
||||
| `gl_resources.cpp` | OpenGL resource management |
|
||||
| `hidpi_gl_canvas.cpp` | HiDPI-aware GL canvas |
|
||||
| `graphics_abstraction_layer.cpp` | GAL base class |
|
||||
| `color4d.cpp` | Color handling |
|
||||
| `gal_display_options.cpp` | Display options |
|
||||
|
||||
### Build Configuration (`CMakeLists.txt`)
|
||||
|
||||
```cmake
|
||||
# Links against system wxWidgets
|
||||
find_program(WX_CONFIG_EXECUTABLE wx-config
|
||||
HINTS /opt/homebrew/bin /usr/local/bin)
|
||||
|
||||
# Includes KiCad headers from submodule
|
||||
target_include_directories(gal_native_test PRIVATE
|
||||
${KICAD_SOURCE}/include
|
||||
${KICAD_SOURCE}/include/gal
|
||||
${KICAD_SOURCE}/include/gal/opengl
|
||||
${KICAD_SOURCE}/libs/kimath/include
|
||||
${KICAD_SOURCE}/libs/core/include
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Generated Files
|
||||
|
||||
### Location
|
||||
|
||||
`/tests/gal-regression/native/generated/`
|
||||
|
||||
### Purpose
|
||||
|
||||
GLSL shaders must be embedded as strings at runtime. `generate_shaders.py` converts shader source files to C++ hex arrays.
|
||||
|
||||
### Generator Script
|
||||
|
||||
`generate_shaders.py` reads from `/kicad/common/gal/shaders/` and creates:
|
||||
|
||||
| Shader | Generated Files | Purpose |
|
||||
|--------|-----------------|---------|
|
||||
| `kicad.frag` | `glsl_kicad_frag.cpp/h` | Fragment shader (coloring) |
|
||||
| `kicad.vert` | `glsl_kicad_vert.cpp/h` | Vertex shader (transforms) |
|
||||
| `smaa_base.glsl` | `glsl_smaa_base.cpp/h` | SMAA common structures |
|
||||
| `smaa_pass_1_*.glsl` | 3 file pairs | SMAA edge detection |
|
||||
| `smaa_pass_2_*.glsl` | 2 file pairs | SMAA blending weights |
|
||||
| `smaa_pass_3_*.glsl` | 2 file pairs | SMAA neighborhood blending |
|
||||
|
||||
### Generated Code Structure
|
||||
|
||||
```cpp
|
||||
// generated/glsl_kicad_frag.cpp
|
||||
namespace KIGFX {
|
||||
namespace BUILTIN_SHADERS {
|
||||
static unsigned char glsl_kicad_frag_bytes[] = { 0x2f, 0x2a, ... };
|
||||
std::string glsl_kicad_frag = std::string(
|
||||
reinterpret_cast<char const*>(glsl_kicad_frag_bytes), 4233);
|
||||
}}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Test Harness Components
|
||||
|
||||
### `gal_native_test.cpp`
|
||||
|
||||
Main test driver with wxApp/wxFrame:
|
||||
|
||||
1. Creates `OPENGL_GAL` on a wxGLCanvas
|
||||
2. Configures coordinate system for 1:1 world-to-screen mapping
|
||||
3. Iterates through test scenarios
|
||||
4. Captures FBO contents as PNG screenshots
|
||||
|
||||
Key configuration:
|
||||
```cpp
|
||||
// Critical: Set 1:1 world-to-screen mapping
|
||||
// GAL default is for PCB nanometers (3.937e-8), which would
|
||||
// compress pixel coordinates (0-800) to ~0.003 screen pixels
|
||||
m_gal->SetWorldUnitLength(1.0 / ADVANCED_CFG::GetCfg().m_ScreenDPI);
|
||||
```
|
||||
|
||||
### `kicad_stubs.cpp`
|
||||
|
||||
Minimal implementations for KiCad symbols not included in GAL:
|
||||
|
||||
- `PGM_BASE` singleton with `GL_CONTEXT_MANAGER`
|
||||
- `ADVANCED_CFG` with `m_ScreenDPI = 91`
|
||||
- `KIFONT` stubs (returns nullptr for fonts)
|
||||
- `OBSERVABLE_BASE` observer pattern stubs
|
||||
- UI dialog stubs (`DisplayError`, etc.)
|
||||
|
||||
### `gal_test_accessor.cpp`
|
||||
|
||||
Uses C++ template technique to access private members:
|
||||
|
||||
```cpp
|
||||
// Access private OPENGL_GAL members without modifying headers
|
||||
template<typename T, T> struct steal_impl;
|
||||
template<typename T, T ptr>
|
||||
struct steal_impl {
|
||||
friend T get(steal_impl*) { return ptr; }
|
||||
};
|
||||
```
|
||||
|
||||
Provides:
|
||||
- `GetCompositorMainBufferTexture()` - For screenshot reading
|
||||
- `GetCompositorMainFBO()` - FBO ID access
|
||||
- `ReadCompositorFBOPixels()` - Direct pixel readback
|
||||
|
||||
### `gal_test_scenarios.cpp`
|
||||
|
||||
11 rendering test scenarios using the GAL API.
|
||||
|
||||
---
|
||||
|
||||
## Test Coverage Analysis
|
||||
|
||||
### Current Scenarios
|
||||
|
||||
| # | Name | GAL Features Tested |
|
||||
|---|------|-------------------|
|
||||
| 0 | basic-lines | `DrawLine`, `SetStrokeColor`, `SetLineWidth` |
|
||||
| 1 | line-widths | `DrawLine` with varying widths (0.5 to 12.0) |
|
||||
| 2 | circles | `DrawCircle` (filled and stroked) |
|
||||
| 3 | arcs | `DrawArc` |
|
||||
| 4 | rectangles | `DrawRectangle` (filled and stroked) |
|
||||
| 5 | polygons | `DrawPolygon`, `DrawPolyline` |
|
||||
| 6 | alpha-blending | `SetFillColor` with alpha transparency |
|
||||
| 7 | transforms | `Save`, `Restore`, `Rotate`, `Translate`, `Scale` |
|
||||
| 8 | grid-cursor | `DrawGrid`, `DrawCursor` |
|
||||
| 9 | segments | `DrawSegment` |
|
||||
| 10 | complex-scene | `SetLayerDepth` (z-ordering) |
|
||||
|
||||
### Coverage: ~19% of GAL API (14 of 73 methods)
|
||||
|
||||
### Missing Coverage (Priority Order)
|
||||
|
||||
**High Priority** (Critical for KiCad functionality):
|
||||
1. `DrawBitmap()` - Image/icon rendering
|
||||
2. `DrawCurve()` - Bezier curves
|
||||
3. `DrawGlyph()` / `BitmapText()` - Text rendering
|
||||
4. `DrawSegmentChain()` - Complex paths
|
||||
5. `DrawArcSegment()` - Filled arc segments
|
||||
|
||||
**Medium Priority** (Performance-critical features):
|
||||
6. Group methods: `BeginGroup()`, `EndGroup()`, `DrawGroup()`, `ClearCache()`
|
||||
7. Render targets: `SetTarget()`, offscreen rendering
|
||||
8. `SetNegativeDrawMode()` - Gerber-style rendering
|
||||
|
||||
**Low Priority** (Already implicit or not relevant to WASM):
|
||||
9. `EnableDepthTest()` - Implicit in complex-scene
|
||||
10. Context locking - Single-threaded in WASM
|
||||
|
||||
---
|
||||
|
||||
## Code Quality Assessment
|
||||
|
||||
### Strengths
|
||||
|
||||
1. **Clean separation** - Stubs, accessor, scenarios in separate files
|
||||
2. **Minimal stubs** - Only implements what's needed
|
||||
3. **Safe accessor** - Template technique avoids `#define private public`
|
||||
4. **Standard shader embedding** - Common practice for GL applications
|
||||
|
||||
### Architecture Decisions
|
||||
|
||||
| Decision | Rationale |
|
||||
|----------|-----------|
|
||||
| Compile actual KiCad GAL | Ground truth for comparison |
|
||||
| System wxWidgets | Native OpenGL context |
|
||||
| FBO reading | Clean screenshots without window capture |
|
||||
| Hex shader embedding | Runtime shader loading like KiCad |
|
||||
|
||||
---
|
||||
|
||||
## Running the Test
|
||||
|
||||
### Build
|
||||
|
||||
```bash
|
||||
./scripts/build-gal-native-test.sh
|
||||
```
|
||||
|
||||
### Execute
|
||||
|
||||
```bash
|
||||
./tests/gal-regression/native/build/gal_native_test --output ./baselines
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--output <dir>` | Output directory for PNG files |
|
||||
| `--width <w>` | Canvas width (default: 800) |
|
||||
| `--height <h>` | Canvas height (default: 600) |
|
||||
| `--show` | Show window instead of headless |
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
### Immediate: Expand Test Coverage
|
||||
|
||||
1. Add `DrawBitmap` scenario with simple test image
|
||||
2. Add `DrawCurve` (Bezier) scenario
|
||||
3. Add text rendering scenario (requires KIFONT implementation)
|
||||
4. Add `DrawSegmentChain` scenario
|
||||
5. Add `DrawArcSegment` scenario
|
||||
|
||||
### Future: WebGL Comparison
|
||||
|
||||
1. Run same scenarios in WASM build
|
||||
2. Compare native vs WebGL screenshots
|
||||
3. Automate regression detection
|
||||
|
||||
---
|
||||
|
||||
## File Reference
|
||||
|
||||
| File | Location |
|
||||
|------|----------|
|
||||
| Test driver | `tests/gal-regression/native/gal_native_test.cpp` |
|
||||
| Stubs | `tests/gal-regression/native/kicad_stubs.cpp` |
|
||||
| Private accessor | `tests/gal-regression/native/gal_test_accessor.cpp` |
|
||||
| Test scenarios | `tests/gal-regression/scenarios/gal_test_scenarios.cpp` |
|
||||
| CMake config | `tests/gal-regression/native/CMakeLists.txt` |
|
||||
| Shader generator | `tests/gal-regression/native/generate_shaders.py` |
|
||||
| Build script | `scripts/build-gal-native-test.sh` |
|
||||
|
|
@ -0,0 +1,235 @@
|
|||
# WebGL GAL Port - Implementation Complete
|
||||
|
||||
> **ARCHIVED / HISTORICAL** — the WebGL-GAL backend described here was implemented (see `kicad/common/gal/webgl/`). Live test docs: [`tests/gal-regression/README.md`](../../../../tests/gal-regression/README.md). Kept for design rationale.
|
||||
|
||||
## Status: ALL PHASES COMPLETE ✅
|
||||
|
||||
**Branch:** `webgl` (21+ commits)
|
||||
|
||||
## 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.
|
||||
|
||||
## Final State
|
||||
- **WebGL GAL**: Fully integrated into `kicad/common/gal/webgl/` (~27,800 lines)
|
||||
- **GAL Test Suite**: 28 scenarios passing, visual parity with native OpenGL
|
||||
- **KiCad WASM**: Builds and runs successfully with WebGL GAL
|
||||
- **3D Viewer**: Disabled with stubs for WASM builds (`KICAD_BUILD_3D_VIEWER_WASM=OFF`)
|
||||
|
||||
## Key Decisions
|
||||
- **Approach**: Copy and modify existing OpenGL GAL code
|
||||
- **Scope**: Full feature parity (all 28 scenarios)
|
||||
- **Location**: Developed in `tests/gal-regression/wasm/` first, moved to KiCad for integration
|
||||
|
||||
## 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:
|
||||
|
||||
```bash
|
||||
#!/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:**
|
||||
1. **native vs baseline** → Catches if native code regressed
|
||||
2. **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 - ALL COMPLETE ✅
|
||||
|
||||
### Phase 1: Native Test Harness ✅
|
||||
Created unified test infrastructure with 28 scenarios covering 100% of GAL API.
|
||||
|
||||
**Commits:** 490f531 → 051fb87
|
||||
|
||||
**Deliverables:**
|
||||
- [x] `scripts/test-gal-regression.sh` - Master build/test/compare script
|
||||
- [x] `scripts/build-gal-native-test.sh` - Native build script
|
||||
- [x] `tests/gal-regression/native/` - Native C++ test harness using OPENGL_GAL
|
||||
- [x] `tests/gal-regression/scenarios/` - 28 shared test scenarios
|
||||
- [x] `tests/gal-regression/baseline/` - Native OpenGL reference screenshots
|
||||
|
||||
### Phase 2: WebGL GAL Implementation ✅
|
||||
Full port of OPENGL_GAL to WebGL 2.0 / OpenGL ES 3.0.
|
||||
|
||||
**Commits:** a4f444f → 74faa7e
|
||||
|
||||
**Key Changes:**
|
||||
- Replaced legacy `glBegin/glEnd` with VBO-based rendering
|
||||
- Replaced GL matrix stack with glm matrices
|
||||
- Converted GLSL shaders to ES 3.0 (`attribute`→`in`, `varying`→`out`, etc.)
|
||||
- Added VAO support (required for WebGL 2.0)
|
||||
- Replaced GLU tesselator with earcut.hpp
|
||||
|
||||
**Deliverables:**
|
||||
- [x] `tests/gal-regression/wasm/webgl/` - Initial WebGL GAL implementation
|
||||
- [x] `scripts/build-gal-webgl-test.sh` - WASM build script
|
||||
- [x] `tests/e2e/gal-webgl.spec.ts` - Playwright spec for screenshots
|
||||
|
||||
### Phase 3: Complete API Coverage ✅
|
||||
All GAL methods implemented with visual parity.
|
||||
|
||||
**Method Groups (all complete):**
|
||||
- [x] Basic drawing: DrawLine, DrawSegment, DrawCircle, DrawArc
|
||||
- [x] Shapes: DrawRectangle, DrawPolygon, DrawPolyline
|
||||
- [x] Advanced: DrawBezier, DrawBezierArc, DrawArcSegment, DrawSegmentChain
|
||||
- [x] State: Colors, transforms, depth testing, render targets
|
||||
- [x] Groups: BeginGroup, EndGroup, DrawGroup, ChangeGroupColor/Depth
|
||||
- [x] Text: DrawGlyph, DrawGlyphs, BitmapText
|
||||
- [x] Special: DrawGrid, DrawCursor, DrawBitmap
|
||||
|
||||
### Phase 4: KiCad Integration ✅
|
||||
WebGL GAL moved to KiCad source tree with CMake integration.
|
||||
|
||||
**Commit:** 37d973f (KiCad submodule: 1b5bb125d2)
|
||||
|
||||
**Deliverables:**
|
||||
- [x] Move `webgl_gal.*` to `kicad/common/gal/webgl/`
|
||||
- [x] CMake integration for Emscripten builds
|
||||
- [x] 3D viewer disabled with stubs (`KICAD_BUILD_3D_VIEWER_WASM=OFF`)
|
||||
- [x] KiCad WASM builds and e2e tests pass
|
||||
|
||||
---
|
||||
|
||||
## Technical Lessons Learned
|
||||
|
||||
### 1. GLSL ES 3.0 Shader Conversion
|
||||
Desktop OpenGL shaders needed conversion for WebGL 2.0:
|
||||
```glsl
|
||||
attribute → in
|
||||
varying → out (vertex shader) / in (fragment shader)
|
||||
texture2D() → texture()
|
||||
gl_FragColor → explicit out variable
|
||||
```
|
||||
Automated in `generate_shaders.py`.
|
||||
|
||||
### 2. VAO Required for WebGL 2.0
|
||||
WebGL 2.0 requires Vertex Array Objects (VAOs):
|
||||
```cpp
|
||||
glGenVertexArrays(1, &m_vao);
|
||||
glBindVertexArray(m_vao);
|
||||
```
|
||||
|
||||
### 3. Legacy GL Elimination
|
||||
All legacy OpenGL calls replaced:
|
||||
- `glBegin/glEnd` → VBO-based rendering
|
||||
- `glPushMatrix/glPopMatrix` → glm matrix stack
|
||||
- `GL_QUADS` → `GL_TRIANGLES` (quads not supported in WebGL)
|
||||
- `glEnableClientState` → modern vertex attributes
|
||||
|
||||
### 4. GLU Tesselator Replacement
|
||||
GLU not available in WebGL. Implemented using earcut.hpp:
|
||||
- File: `kicad/common/gal/webgl/glu_tess_impl.cpp`
|
||||
- Provides `gluNewTess`, `gluTessBeginPolygon`, etc.
|
||||
|
||||
### 5. Coordinate System & Retina Scaling
|
||||
- White background required for screenshot comparison (alpha compositing)
|
||||
- Retina 2x scaling requires proper `devicePixelRatio` handling
|
||||
- World-to-screen mapping: `SetWorldUnitLength(1.0 / DPI)`
|
||||
|
||||
### 6. Alpha Blending
|
||||
Proper blend functions required for correct transparency:
|
||||
```cpp
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
```
|
||||
|
||||
### 7. 3D Viewer Stubbing Strategy
|
||||
When disabling 3D viewer (`KICAD_BUILD_3D_VIEWER_WASM=OFF`):
|
||||
- Guard includes/code with `#ifndef __EMSCRIPTEN__`
|
||||
- Stub classes need wxWidgets event table macros (`BEGIN_EVENT_TABLE`)
|
||||
- Complex classes (PANEL_PREVIEW_3D_MODEL) require all event handler stubs
|
||||
|
||||
## File Structure (Final)
|
||||
|
||||
```
|
||||
kicad/common/gal/webgl/ # WebGL GAL in KiCad source tree
|
||||
├── webgl_gal.cpp # Main implementation (3184 lines)
|
||||
├── webgl_gal.h # Class declaration (618 lines)
|
||||
├── webgl_compositor.cpp # FBO compositing
|
||||
├── webgl_antialiasing.cpp # SMAA implementation
|
||||
├── gpu_manager.cpp # VBO/VAO management
|
||||
├── vertex_manager.cpp # Vertex accumulation
|
||||
├── shader.cpp # GLSL compilation
|
||||
├── glu_tess_impl.cpp # GLU tesselator (earcut)
|
||||
├── earcut.hpp # Polygon triangulation
|
||||
└── ... (20+ files total)
|
||||
|
||||
tests/gal-regression/
|
||||
├── baseline/ # Native OpenGL reference (28 PNGs)
|
||||
├── baseline-webgl/ # WebGL reference (29 PNGs)
|
||||
├── native/ # Native test harness
|
||||
├── wasm/ # WebGL test harness (uses KiCad GAL)
|
||||
└── scenarios/ # Shared 28 test scenarios
|
||||
|
||||
wasm/stubs/
|
||||
├── 3d_canvas_stub.cpp # ~500 lines of 3D stubs
|
||||
├── 3d_viewer_stub.cpp # EDA_3D_VIEWER_FRAME stub
|
||||
└── 3d_scenegraph_stub.cpp # VRML export stubs
|
||||
|
||||
scripts/
|
||||
├── build-gal-native-test.sh # Native build script
|
||||
├── build-gal-webgl-test.sh # WASM build script
|
||||
└── test-gal-regression.sh # Master test script
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Verification Commands
|
||||
|
||||
```bash
|
||||
# Build KiCad WASM
|
||||
docker/build.sh
|
||||
|
||||
# Run GAL regression tests
|
||||
scripts/test-gal-regression.sh
|
||||
|
||||
# Run KiCad e2e tests
|
||||
cd tests && npm run test:kicad
|
||||
```
|
||||
Loading…
Reference in a new issue