subagent transcript
session 18e25685 · workflow wf_23df5b1c
delegated task
Review the vendored Coin GL glue port for wasm. Read /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/3rdParty/coin/src/glue/gl.cpp (search for __EMSC
▸ Magik
Review the vendored Coin GL glue port for wasm. Read /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/3rdParty/coin/src/glue/gl.cpp (search for __EMSCRIPTEN__ blocks: cc_glglue_getprocaddress, glglue_set_glVersion version-string parse, cc_glglue_glActiveTexture null guard), /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/3rdParty/coin/src/glue/gl_egl.cpp (eglBindAPI), and /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Gui/Quarter/QuarterWidget.cpp (fcWasmSyncGLContext call in actualRedraw). Assess correctness of the getprocaddress routing (emscripten_GetProcAddress + fcWasmResolveGL), the GLES version parse, whether Coin will actually resolve+call the right functions, and any signature/indirect-call hazards. Report findings + whether the glue is sufficient for rendering.
Fable
thinking
I'll start by examining the files to understand what we're working with.
Fable
⚙ Bash {"command": "grep -n \"__EMSCRIPTEN__\\|fcWasmResolveGL\\|emscripten_GetProcAddress\\|cc_glglue_getprocaddress\\|glActiveTexture\\|glglue_set_glVersion\" /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/3rdParty/coin/src/glue/gl.cpp", "desc…
Fable
⚙ Bash {"command": "grep -n \"__EMSCRIPTEN__\\|eglBindAPI\\|BindAPI\" /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/3rdParty/coin/src/glue/gl_egl.cpp", "description": "Find EMSCRIPTEN blocks in gl_egl.cpp"}
Fable
⚙ Bash {"command": "grep -n \"fcWasmSyncGLContext\\|actualRedraw\\|__EMSCRIPTEN__\" /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Gui/Quarter/QuarterWidget.cpp", "description": "Find fcWasmSyncGLContext in QuarterWidget.cpp"}
Fable
⚙ Read {"file_path": "/home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/3rdParty/coin/src/glue/gl.cpp", "offset": 605, "limit": 80}
Fable
⚙ Read {"file_path": "/home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/3rdParty/coin/src/glue/gl.cpp", "offset": 705, "limit": 80}
Fable
thinking
I'm tracing through the version string parsing logic for WebGL. The string "OpenGL ES 3.0 (WebGL 2.0 ...)" gets processed by advancing past non-digit characters until hitting '3', then looking for the decimal point to extract the version number.
Now I need to check the null guard for glActiveTexture and how it's initialized.
Fable
⚙ Read {"file_path": "/home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/3rdParty/coin/src/glue/gl.cpp", "offset": 1040, "limit": 95}
Fable
⚙ Read {"file_path": "/home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/3rdParty/coin/src/glue/gl.cpp", "offset": 2985, "limit": 20}
Fable
thinking
I need to locate fcWasmResolveGL and check the WasmGLFixedFunc.cpp file along with the sync context to understand how they work together.
Fable
Now let me look at the wasm-side implementations: fcWasmResolveGL, fcWasmSyncGLContext, and the fixed-func emulation.
Fable
⚙ Bash {"command": "grep -rn \"fcWasmResolveGL\\|fcWasmSyncGLContext\\|emscripten_GetProcAddress\\|FC_WASM_EGL_API\\|eglBindAPI\" /home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Gui/ 2>/dev/null | head -50", "description": "Find wasm GL glue impl…
Fable
⚙ Read {"file_path": "/home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/3rdParty/coin/src/glue/gl_egl.cpp", "offset": 95, "limit": 30}
Fable
⚙ Read {"file_path": "/home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Gui/WasmGLFixedFunc.cpp"}
Fable
thinking
Looking at the function routing in gl.cpp, I see that `cc_glglue_getprocaddress` first tries `emscripten_GetProcAddress`, then falls back to `fcWasmResolveGL` if that doesn't work. The function signature matches what Emscripten expects, so the initial call should work correctly.
Now I'm checking for potential signature mismatches in the indirect function calls. When Coin resolves a function pointer like `glActiveTexture` through Emscripten, it gets back a real function with signature `void(GLenum)`, which matches Coin's typedef `COIN_PFNGLACTIVETEXTUREPROC`. For the multitexture functions like `glMultiTexCoord2f`, both the standard signature and our implementation use `void(GLenum, GLfloat, …
Fable
⚙ Read {"file_path": "/home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Gui/Quarter/QuarterWidget.cpp", "offset": 880, "limit": 40}
Fable
⚙ Read {"file_path": "/home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Gui/Quarter/QuarterWidget.cpp", "offset": 995, "limit": 40}
Fable
thinking
I'm checking whether the version parsing correctly identifies WebGL2 as desktop GL 3.0 and whether the glue layer properly routes to the right functions without trapping. The real question for review is whether the glue implementation is sufficient for rendering. I'm also spotting a potential correctness issue with the `emscripten_GetProcAddress` declaration—the actual Emscripten signature differs from what's declared.
There's a build-configuration dependency here: `emscripten_GetProcAddress` only works if compiled with `-sGL_ENABLE_GET_PROC_ADDRESS=1`, otherwise it may not even link. That's a risk worth flagging. The `glActiveTexture` path resolves correctly to Emscripten's real implementa …
Fable
⚙ Bash {"command": "grep -rn \"GL_ENABLE_GET_PROC_ADDRESS\\|emscripten_GetProcAddress\\|LEGACY_GL\\|FULL_ES2\\|FULL_ES3\\|MAX_WEBGL_VERSION\\|MIN_WEBGL_VERSION\\|WasmGLFixedFunc\" /home/magik6k/lcad-wasm/freecad-port/ 2>/dev/null | grep -iv \"\\.m…
Fable
⚙ Bash {"command": "grep -rn \"GL_ENABLE_GET_PROC_ADDRESS\\|MAX_WEBGL_VERSION\\|MIN_WEBGL_VERSION\\|FULL_ES3\\|sGL\\|-lGL\\|WasmGLFixedFunc\\|EXPORTED\" /home/magik6k/lcad-wasm/freecad-port/ 2>/dev/null | grep -v \"3rdParty\\|/research/\\|\\.md:\"…
Fable
thinking
The build flags look good — with GL_ENABLE_GET_PROC_ADDRESS and FULL_ES3 enabled, emscripten should provide GLES3 functions and emscripten_GetProcAddress should work. Now I need to verify what happens when emscripten_GetProcAddress is called with those flags.
Since FULL_ES3 provides GLES3 rather than GLES1 fixed-function, legacy names like glVertexPointer will return 0 from emscripten_GetProcAddress and fall through to fcWasmResolveGL, while modern functions like glActiveTexture are available. The critical issue is that our WasmGLFixedFunc.cpp defines strong symbols for glEnable, glDisable, glDrawArrays, and glDrawElements — so when Qt calls these functions, they'll use our implementations …
Fable
⚙ Read {"file_path": "/home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/3rdParty/coin/src/glue/gl_egl.cpp", "offset": 220, "limit": 110}
Fable
thinking
I'm spotting a use-before-init bug where `surface_attrib` references uninitialized `ctx` at lines 293-299, but `ctx` doesn't get initialized until line 301. There's also an inconsistency in the offscreen rendering path—it's using EGL_OPENGL_BIT instead of the ES variant, which doesn't align with the ES API binding, though this code path might not actually be exercised in practice.
The EGL stubs in WasmGLFixedFunc.cpp return 0, so offscreen rendering won't work on wasm anyway. This is a pre-existing issue but tangential to the main focus. The core findings are solid: the getprocaddress routing is correct (emscripten first for real GLES3/WebGL2 functions, then our resolver for legacy multitex …
Fable
I have enough to complete the assessment. Let me verify one detail about the version-gated multitexture path and the offscreen ctx ordering.
Fable
⚙ Read {"file_path": "/home/magik6k/lcad-wasm/freecad-port/FreeCAD/src/Main/CMakeLists.txt", "offset": 135, "limit": 20}
Fable
thinking
All the build flags check out, so I'm ready to share what I found.
Fable
I have completed my review. The build flags confirm the routing preconditions (`-sGL_ENABLE_GET_PROC_ADDRESS=1`, `-sFULL_ES3=1`, `-sMAX_WEBGL_VERSION=2`, `-lEGL`). Let me report.
Fable
⚙ StructuredOutput {"findings": [{"severity": "info", "category": "assessment-summary", "summary": "The wasm GL glue is correct in its three focus areas and is plausibly sufficient for the FreeCAD viewport geometry subset, with known gaps (no textures, no off…