mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-04 23:12:02 +00:00
b72956d0c0
## Problem After the WebGL2 renderer migration, a small number of users (~a dozen of 100k DAU) report ~5fps. Root cause: they run WebGL **without GPU acceleration** (hardware acceleration disabled, blocklisted driver, or a locked-down machine), so they get a SwiftShader/software context. Software-rendered WebGL is hopeless for a real-time game — ~1fps locally. We are not supporting a canvas2d fallback. Instead: demand a GPU-accelerated context, and if we can't get one, **gate** the user with actionable instructions rather than letting the game crawl. ## What this does - **`initGL()`** ([initGL.ts](../blob/webgl-software-render-gate/src/client/render/gl/initGL.ts)) — demands `failIfMajorPerformanceCaveat: true` **and** inspects the unmasked renderer string. The flag alone isn't enough: when hardware acceleration is turned off in browser *settings* (vs. a blocklisted driver), Chrome still hands back a SwiftShader context, so we'd otherwise run at 1fps. Classifies the outcome as `ok` / `software` / `unsupported`. - **`GPURenderer`** throws `GLUnavailableError` on a non-accelerated context; the game-start `catch` shows the gate and removes the orphaned canvas. - **`<webgl-gate>`** Lit component renders a full-screen blocking gate with per-browser steps (Chrome / Edge / Firefox / Safari) for enabling hardware acceleration / WebGL. - **`gl_init` analytics event** fires every session (`status` + `renderer` for non-ok) via the existing Google Tag, so we can size the real affected % within a day. ## Notes / decisions - The gate copy is **intentionally inlined (not translated)** — it's a rarely-seen, browser-specific troubleshooting screen; 28 Crowdin keys would be poor cost/benefit, and a non-English user still has to navigate English browser menus. - `showGLGate` lazy-loads the component (`import()`), so the `render/gl` module that `Renderer.ts` imports doesn't statically pull a UI component into its graph. ## Update: fingerprint-capped contexts (#4357) A third failure class, integrated after the initial PR: `privacy.resistFingerprinting` (default-on in LibreWolf and Mullvad Browser, opt-in in Firefox) caps `MAX_TEXTURE_SIZE` at 2048 on an otherwise hardware-accelerated context. The renderer unconditionally allocates a 4096-wide palette texture, so the oversized `texImage2D` calls fail silently and the whole map renders **black** (#4357). - `initGL` now reads `MAX_TEXTURE_SIZE` after the software check and classifies the context as **`limited`** when it's below `getPaletteSize()` (4096 — the hard floor every game needs). - Unlike `software`/`unsupported`, **`limited` is a warning, not a hard block**: `initGL` still returns the context, the game starts normally, and the gate is shown with a "Continue anyway" button. `GPURenderer` exposes the capped renderer/size via `glLimited` (surfaced through `MapRenderer`), which `ClientGameRunner` uses to show the warning and log analytics. - The gate shows fingerprinting-specific instructions for `limited` (add the site to `privacy.resistFingerprinting.exemptedDomains` in `about:config`) instead of the hardware-acceleration steps. - `gl_init` reports `max_texture_size` alongside the renderer for this status, so we can size the RFP-affected population too. Fixes #4357 ## Test plan - [x] Unit tests for `initGL`'s `ok` / `software` / `unsupported` branching, incl. the "returns a context but renderer is software" case (`tests/client/initGL.test.ts`). - [x] lint / prettier / tsc clean. - [x] **Verified in real browsers (macOS).** All three gate states reproduced: - `software`: Chrome with `--use-gl=angle --use-angle=swiftshader` (confirmed "Software only" at `chrome://gpu`), and Chrome with hardware acceleration toggled off in settings — both show the hard gate instead of a 1fps game. - `unsupported`: Firefox with `webgl.disabled=true` shows the unsupported gate. - `limited`: Firefox with `privacy.resistFingerprinting=true` (MAX_TEXTURE_SIZE capped to 2048, same as LibreWolf's default) shows the dismissible warning; "Continue anyway" starts the game, and exempting the site via `privacy.resistFingerprinting.exemptedDomains` removes the warning. ## Acceptance criteria - Accelerated users: unchanged. - Software / no-accel users: see the enable-acceleration gate, not a 1fps game. - No-WebGL2 users: see the unsupported gate. - `gl_init` fires every session with status (+ renderer for non-ok). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>