wasm/gl1: the GL1.x fixed-function emulation layer replacing the gl_ffp_stub.c no-ops in the 3d-regression harness link. This batch: - symbol split: 52 FFP-only entry points implemented; 10 Emscripten-owned names intercepted via wasm-ld --wrap (sources.txt/wrapped_symbols.txt are the shared manifests for both link sites; production hookup lands in M7) - matrix stacks (MODELVIEW/PROJECTION, glGetFloatv readback), immediate mode with all 8 GL1 primitive conversions, GL1-default state mirror - full GL 1.5 Gouraud lighting uber-shader (eye-space light capture at glLightfv time, color-material, two-side, COMBINE evaluator + alpha test wired but inert until M3/M5) - draw routing: FFP traffic identified by GL_VERTEX_ARRAY client state; blit/2D-GAL draws pass through untouched - display lists: correct glGenLists/glIsList existing-empty semantics; recorder itself is M3 (recorded commands drop with a one-time warning) Parity: 20/47 under the 0.02 floor, of which 12 verified genuinely rendering (bg-gradient x2, bounding-box, half-open-cylinder, segment x2, material x3, light x3 — eyeballed against baselines); the other 8 are small-geometry scenarios whose missing GLU/display-list content sits under the floor (become real in M3/M4). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3.7 KiB
wasm/gl1 — GL 1.x fixed-function pipeline on WebGL2
Emulation layer that lets KiCad's 3D viewer renderer (RENDER_3D_OPENGL,
pure GL 1.x fixed-function, compiled unmodified) render in the browser.
Supersedes the no-op link stubs of wasm/stubs/gl_ffp_stub.c (git history
has the old file): same public surface, real implementations.
TDD harness: tests/3d-regression/ — 47 native-golden scenarios; parity via
npm run 3d:check:parity (see that README).
How the symbols resolve
In the WASM build, gl* are plain C functions split between two providers:
- Emscripten's WebGL library (
-sMAX_WEBGL_VERSION=2) owns every modern/WebGL2 name (glClear,glDrawArrays,glTexImage2D, buffers, shaders, stencil...). - This shim owns the FFP-only names WebGL2 lacks (
glBegin, display lists, matrix stack,glLight*/glMaterial*, client-array pointers,glTexEnv*,glAlphaFunc, GLU quadrics) — seesrc/gl1_entry_ffp.cpp.
The emulator must also observe a few Emscripten-owned calls (FFP glEnable
caps, draws over client arrays, matrix readback, state recorded inside
display lists). Those are intercepted with wasm-ld --wrap: every name in
wrapped_symbols.txt gets a -Wl,--wrap=<sym> flag at both link sites, the
interceptors live in src/gl1_entry_wrapped.cpp, and __real_* forwards to
the WebGL library. No kicad/wxwidgets sources are touched.
Link sites (both read sources.txt + wrapped_symbols.txt):
tests/3d-regression/wasm/Makefile(the TDD harness)scripts/kicad/build-kicad-target.sh(GL3D_LINK_FLAGS, productionkicad_editor)
Draw routing
A glDrawArrays/glDrawElements call is FFP traffic iff GL_VERTEX_ARRAY
client state is enabled: only GL1 code calls glEnableClientState, while the
raytracer blit (eda_3d_canvas_wasm.cpp) and the 2D WebGL GAL drive their own
GLSL programs and never touch client state — their draws pass through
untouched.
Invariants that are easy to break (learned from the native goldens)
- Display lists snapshot client arrays at record time. The renderer sets
gl*Pointer, recordsglDrawArraysinsideglNewList, thendelete[]s the arrays right afterglEndList(layer_triangles.cpp) — a recorder that stores pointers reads freed memory. Copy eagerly at record. - Lights live in eye space, captured at
glLightfvtime.init_lights()runs under an identity modelview → the directional lights are anchored to the camera. Re-deriving light directions at draw time breaks every lit scenario. - Do not "fix" mismatched normal counts.
generate_middle_trianglesrejecting countersink walls (normals ≠ vertices) is upstream KiCad behavior the goldens document; tolerating it would diverge from native. - Lighting is per-vertex (Gouraud) to match fixed-function output; per-fragment lighting visibly mismatches speculars on coarse meshes.
Layout
sources.txt / wrapped_symbols.txt single source of truth for both link sites
include/gl1_shim.h internal API + the state mirror
src/gl1_entry_ffp.cpp the 52 FFP-only public entry points
src/gl1_entry_wrapped.cpp __wrap_* interceptors (mechanism-aware TU)
src/gl1_state.cpp state singleton, capability routing
src/gl1_matrix.cpp MODELVIEW/PROJECTION stacks (+readback)
src/gl1_immediate.cpp glBegin/glEnd + primitive conversion
src/gl1_dlist.cpp display-list recorder/replayer
src/gl1_draw.cpp draw execution (stream VBO, attrib setup)
src/gl1_shaders.cpp the FFP uber-program (ES 3.00) + uniforms
src/gl1_glu.cpp GLU quadrics (SGI tessellation) + gluPerspective