feat(3d): gl1 shim M0-M2 — FFP-on-WebGL2 substrate + lighting; 12 scenarios truly green

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>
This commit is contained in:
Istvan Matejcsok 2026-07-03 11:37:51 +02:00
commit 071eef5454
14 changed files with 2496 additions and 6 deletions

View file

@ -48,6 +48,7 @@ KICAD_INCLUDES = -I../native \
-I$(KICAD_ROOT)/thirdparty/nlohmann_json \
-I$(KICAD_ROOT)/thirdparty \
-I$(PROJECT_ROOT)/wasm/stubs \
-I$(PROJECT_ROOT)/wasm/gl1/include \
-I$(SYSROOT)/include
ifdef DEBUG
@ -74,11 +75,11 @@ BASE_LDFLAGS = $(DEPS_EH_FLAGS) \
-sEXPORT_NAME='create3DTest' \
-sENVIRONMENT=web,worker
# Pure WebGL 2.0 context; the FFP calls are stubbed C no-ops (no
# Pure WebGL 2.0 context; the FFP surface is implemented by wasm/gl1 (no
# LEGACY_GL_EMULATION), same as the production kicad_editor build.
EM_GL_FLAGS = -sMAX_WEBGL_VERSION=2
LDFLAGS = $(DEBUG_LDFLAGS) $(BASE_LDFLAGS) $(EM_GL_FLAGS) $(WX_LDFLAGS)
LDFLAGS = $(DEBUG_LDFLAGS) $(BASE_LDFLAGS) $(EM_GL_FLAGS) $(WX_LDFLAGS) $(GL1_WRAP_LDFLAGS)
MAIN_SRCS = 3d_webgl_test.cpp
@ -157,11 +158,18 @@ KICAD_3D_SRCS = \
$(KICAD_ROOT)/thirdparty/clipper2/Clipper2Lib/src/clipper.offset.cpp \
$(KICAD_ROOT)/thirdparty/clipper2/Clipper2Lib/src/clipper.rectclip.cpp
# THE RED STATE: legacy fixed-function GL as no-ops.
FFP_STUB_SRCS = $(PROJECT_ROOT)/wasm/stubs/gl_ffp_stub.c
# The GL1->WebGL2 emulation layer (wasm/gl1): implements the FFP surface the
# renderer needs and --wrap-intercepts the Emscripten-owned names it must
# observe. sources.txt / wrapped_symbols.txt are shared with the production
# link site (scripts/kicad/build-kicad-target.sh).
GL1_DIR = $(PROJECT_ROOT)/wasm/gl1
GL1_SRCS := $(addprefix $(GL1_DIR)/src/,$(shell cat $(GL1_DIR)/sources.txt))
SRCS = $(MAIN_SRCS) $(SCENARIO_SRCS) $(TESTIMPL_SRCS) $(KICAD_3D_SRCS)
OBJS = $(SRCS:.cpp=.o) $(FFP_STUB_SRCS:.c=.o)
comma := ,
GL1_WRAP_LDFLAGS := $(foreach sym,$(shell cat $(GL1_DIR)/wrapped_symbols.txt),-Wl$(comma)--wrap=$(sym))
SRCS = $(MAIN_SRCS) $(SCENARIO_SRCS) $(TESTIMPL_SRCS) $(KICAD_3D_SRCS) $(GL1_SRCS)
OBJS = $(SRCS:.cpp=.o)
DEPS = $(SRCS:.cpp=.d)
TARGET = $(OUTPUT_DIR)/3d_webgl_test.js
@ -188,6 +196,7 @@ clean:
rm -f $(OUTPUT_DIR)/3d_webgl_test.wasm
rm -f $(OUTPUT_DIR)/3d_webgl_test.html
rm -f ../scenarios/*.o ../scenarios/*.d ../native/*.o ../native/*.d
rm -f $(GL1_DIR)/src/*.o $(GL1_DIR)/src/*.d
.PHONY: all clean