Skip to content

feat(webgl): add initial ANGLE WebGL2 context - #21

Draft
Alx8g wants to merge 14 commits into
mystralengine:mainfrom
Alx8g:feat/angle-webgl2
Draft

Alx8g wants to merge 14 commits into
mystralengine:mainfrom
Alx8g:feat/angle-webgl2

Conversation

@Alx8g

@Alx8g Alx8g commented Aug 28, 2026

Copy link
Copy Markdown

Closes the first implementation milestone from #20.

What this adds

  • optional MYSTRAL_USE_WEBGL desktop build flag for Windows, Linux, and macOS
  • external MYSTRAL_ANGLE_ROOT package support with platform runtime validation
  • dynamically loaded ANGLE EGL/GLES runtime
  • explicit ANGLE backend selection: D3D11 on Windows, Vulkan on Linux, and Metal on macOS
  • Win32, X11, Wayland, Metal, and offscreen EGL surface support
  • OpenGL ES 3 context with ANGLE WebGL compatibility and robust initialization
  • main and generated canvas getContext("webgl2") integration
  • uncapped automatic presentation after animation-frame callbacks
  • pbuffer fallback for headless and additional contexts
  • context destruction before the SDL native window is destroyed
  • generic js::Engine WebGL bindings covering all 71 methods and 120 constants observed in the unchanged Three.js workload
  • shaders, buffers, textures, framebuffers, uniforms, render targets, instancing, draw, completion, parameters and pixel readback
  • document.createElementNS() and WebGL context class compatibility needed by Three.js
  • persistent native callback lifetime for contexts created inside animation frames
  • deferred no-libuv HTTP completion matching the async implementation contract
  • AudioParam class, scheduling methods, and prototype compatibility
  • FileReader, DOM class identities, style methods, collections, comments, and document fragments
  • pinned Lexbor v3 HTML5 parser and DOM core
  • native template.innerHTML parsing with attributes, text, comments, traversal, mutation, and deep cloning
  • examples/webgl2-triangle.js and examples/html-template.js end-to-end validation

ANGLE runtime libraries are copied beside the mystral executable at build time but are not committed to this repository. Reproducible Linux and macOS packages are proposed in library-builder PR #1.

Windows validation

Built the complete Release runtime with V8 13.1, Dawn, Skia, SDL3, static curl/zlib and ANGLE using Visual Studio 2022.

Hardware:

  • AMD Radeon RX 580
  • ANGLE D3D11
  • OpenGL ES 3.0

Windowed result:

[WebGL] Native window: 00000000001D0E4C
[WebGL] Renderer: ANGLE (AMD, Radeon RX 580 Series (...) Direct3D11 vs_5_0 ps_5_0, D3D11)
[WebGL] Version: OpenGL ES 3.0.0 (...)
[WebGL] Surface: window
Center pixel: 38,166,255,255
WEBGL2_TRIANGLE_RESULT=pass

The triangle was also captured visibly in the SDL window. A separate --no-sdl run selected the offscreen surface and passed the same shader, draw and pixel validation.

Linux validation

Built the complete runtime with V8, Dawn, Skia, SDL3 and the packaged ANGLE Vulkan libraries. The full CLI ran under SDL/X11 with Dawn and ANGLE sharing the same window:

ANGLE renderer: ANGLE (... llvmpipe ...)
WebGL version: WebGL 2.0 Mystral ANGLE
Center pixel: 38,166,255,255
WEBGL2_TRIANGLE_RESULT=pass
WEBGL2_PRESENTED_FRAMES=270

Separate package, native context, JavaScript binding, and X11 presentation tests all rendered and read back the expected pixels. Headless and X11 tests also passed under AddressSanitizer and UndefinedBehaviorSanitizer without reported errors.

macOS validation

The library-builder matrix builds and render-tests ANGLE Metal packages on Apple Silicon and Intel macOS. Each test creates an EGL/OpenGL ES 3 pbuffer, draws a triangle, and validates its center pixel. Packaged dylibs use executable-relative @rpath install names and are ad-hoc signed after relocation.

The Mystral integration preserves SDL/Dawn's original CAMetalLayer and gives ANGLE a separate child layer. The full Mystral application has not yet been run on macOS hardware.

Unchanged Three.js validation inside Mystral V8

Three.js r181 was loaded unchanged through Mystral's CommonJS loader and rendered through the new native bindings:

THREE_WEBGL2_RESULT=pass revision=181 calls=1
THREE_WEBGL2_COVERAGE_RESULT=pass revision=181 calls=3 triangles=962 pixels=78613

The coverage scene exercised MeshStandardMaterial, typed-array texture uploads, shadow maps, a WebGLRenderTarget, and InstancedMesh. It completed with no GL error.

An unchanged older browser-game runtime previously progressed through its embedded Three.js WebGLRenderer construction with the same ANGLE backend.

Current browser-game payload validation

The current 8.66 MB two-argument browser payload is now invoked through Mystral V8 with page bootstrap scripts and the exact Howler bundle. It initializes native AudioContext, creates three independent Three.js/ANGLE renderers, mounts its Svelte templates through Lexbor, and completes synchronous execution without a JS or native fault:

BROWSER_PAYLOAD_LOADER=type:function,arity:2
BROWSER_PAYLOAD_EXECUTION=completed

A Windows CDB investigation also found and fixed a synchronous no-libuv HTTP stub violating the async callback contract, which had caused a V8 persistent-handle double release.

Current limits

This is a draft because it is the graphics foundation, not full browser WebGL compatibility yet:

  • workload-driven API subset, not the full WebGL 2 IDL
  • the first WebGL context owns the native window; multi-canvas compositing is not implemented
  • complete page-level DOM ownership, CSS layout, and UI painting are not implemented
  • no WebGL conformance suite integration yet
  • resource deletion and context-loss lifecycle are incomplete
  • context attributes such as multisample antialiasing need complete framebuffer negotiation
  • full Mystral window presentation still requires validation on macOS hardware

Next milestones

  1. persistent page-level DOM ownership and selector integration
  2. CSS cascade/layout and Skia UI painting
  3. browser-compatible WebGL resource deletion, context loss and remaining IDL
  4. networking/storage completion and WebGL CTS coverage

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant