fix(ci): 3D specs — 180s viewer-open wait for llvmpipe; skip deadlock spec on CI

Follow-up to the headed-llvmpipe switch. That run (28652367347) stopped CRASHING —
every failure became a plain timeout, confirming llvmpipe gives a stable WebGL context
(no more CONTEXT_LOST / "Target crashed") but software raytracing is just slow:

- The first board raytrace takes ~60s on llvmpipe, right at openThreeDViewer's 60s
  wait → raise it to 180s (shared helper + the models spec's inline copy). Real GPU
  returns in ~2s, so it is only CI headroom.
- The deadlock spec asserts the wasm main thread stays responsive within ~15s DURING a
  raytrace — a premise only true on a fast (real) GPU. Under slow software rendering a
  legitimately-slow raytrace is indistinguishable from a deadlock, so skip it on CI
  (test.skip on process.env.CI). The Worker-boot deadlock MECHANISM stays covered on CI
  by the standalone coroutine-pthread-ondemand / raytrace-threads wx harnesses; the spec
  still runs locally on a real GPU.
- Gate the headed + llvmpipe launch flags on CI so chromium-ci-3d behaves like a normal
  bundled-Chromium project locally.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Istvan Matejcsok 2026-07-03 15:35:17 +02:00
commit d60bc1575b
4 changed files with 33 additions and 15 deletions

View file

@ -35,6 +35,14 @@ import { countGlCanvases, loadBoard, logThreeDDiag, openThreeDViewer } from './u
* (preserveDrawingBuffer=true), since a CDP screenshot of a WebGL canvas is blank on swiftshader.
*/
test.describe('3D viewer camera-move deadlock', () => {
// CI-skip: this test asserts the wasm main thread stays responsive within ~15s DURING a
// raytrace. That premise only holds on a real GPU (fast render); on CI's software WebGL
// (Mesa llvmpipe, GPU-less VM) a legitimately-slow raytrace is indistinguishable from a
// deadlock, so the test can't run meaningfully there. The pthread-Worker-boot deadlock
// MECHANISM it guards is already covered on CI by the standalone wx harnesses
// (coroutine-pthread-ondemand, raytrace-threads). Runs locally on a real GPU.
test.skip(!!process.env.CI, 'raytracer liveness assertions require a real GPU; deadlock '
+ 'mechanism is covered on CI by the standalone coroutine-pthread-ondemand/raytrace-threads harnesses');
// One 187 MB wasm runtime is already heavy; keep this serial and generous.
test.describe.configure({ mode: 'serial' });
test.setTimeout(240000);

View file

@ -151,14 +151,16 @@ async function openThreeDViewer(page: Page, glBefore: number): Promise<number> {
await page.keyboard.press('Alt+3');
}
// 180s (not 60s): the first board raytrace on CI's Mesa llvmpipe software WebGL takes ~60s
// (real GPU ~2s). See threed-viewer.ts openThreeDViewer for the rationale.
await page.waitForFunction(() => {
return !!document.querySelector('#window-container [id^="window-"]')
|| document.querySelectorAll('canvas[id^="glcanvas-"]').length > 0;
}, null, { timeout: 60000 });
}, null, { timeout: 180000 });
await page.waitForFunction((before: number) =>
document.querySelectorAll('canvas[id^="glcanvas-"]').length > before,
glBefore, { timeout: 60000 });
glBefore, { timeout: 180000 });
const glAfter = await countGlCanvases(page);
console.log(`[TEST] glcanvas count after opening 3D viewer: ${glAfter}`);

View file

@ -111,15 +111,18 @@ export async function openThreeDViewer(page: Page, glBefore: number): Promise<nu
await page.keyboard.press('Alt+3');
}
// 180s (not 60s): opening the viewer kicks the FIRST full board raytrace, which on CI's
// software WebGL (Mesa llvmpipe, GPU-less VM) takes ~60s — right at the old limit. Real GPU
// returns in ~2s, so the larger cap is only a CI headroom.
await page.waitForFunction(() => {
// A new top-level window div beyond the main pcbnew frame.
return !!document.querySelector('#window-container [id^="window-"]')
|| document.querySelectorAll('canvas[id^="glcanvas-"]').length > 0;
}, null, { timeout: 60000 });
}, null, { timeout: 180000 });
await page.waitForFunction((before: number) =>
document.querySelectorAll('canvas[id^="glcanvas-"]').length > before,
glBefore, { timeout: 60000 });
glBefore, { timeout: 180000 });
const glAfter = await countGlCanvases(page);
console.log(`[TEST] glcanvas count after opening 3D viewer: ${glAfter}`);

View file

@ -267,17 +267,22 @@ export default defineConfig({
use: {
...devices["Desktop Chrome"],
viewport: { width: 1280, height: 720 },
// Headed only matters on CI (real GPU locally); harmless headed locally too.
headless: !process.env.CI,
launchOptions: {
args: [
"--use-gl=angle",
"--use-angle=gl",
"--disable-gpu-watchdog",
"--disable-gpu-process-crash-limit",
"--enable-unsafe-swiftshader",
],
},
// The headed + Mesa-llvmpipe stack is a CI-only need (the GPU-less VM). Locally this
// project should behave like any other bundled-Chromium project, so gate it on CI.
...(process.env.CI
? {
headless: false,
launchOptions: {
args: [
"--use-gl=angle",
"--use-angle=gl",
"--disable-gpu-watchdog",
"--disable-gpu-process-crash-limit",
"--enable-unsafe-swiftshader",
],
},
}
: { launchOptions: { args: ["--enable-unsafe-swiftshader"] } }),
},
},
{