Problem
`tests/webgl_save_restore.spec.js` has three tests that fail when WebGL2 is actually available in the test environment:
- "should preserve transform across save/restore"
- "should handle nested save/restore correctly"
- "should handle deep nesting (20 levels)"
All three fail at the same assertion shape: after a `save()` → mutate → `restore()` sequence, `renderer.currentTransform.val[0]` reads as `0` instead of the expected `1` (the identity-matrix top-left).
These were silently masked because the tests guard with:
```js
if (!isWebGL) {
return;
}
```
The `failIfMajorPerformanceCaveat: true` option in the test setup means chromium headless without GPU flags falls back to Canvas, the guard returns early, and the failure never reports.
Why this is being filed now
While landing #1480 (mesh-depth single-clear refactor), I temporarily added chromium swiftshader launch flags to `vitest.config.ts` so the new WebGL2 pixel-level tests would run in CI. That surfaced these three failures. The flags were reverted to keep #1480's scope tight; this issue tracks the underlying bug.
Repro
Add to `vitest.config.ts`:
```ts
provider: playwright({
launchOptions: {
args: [
"--use-gl=angle",
"--use-angle=swiftshader",
"--enable-unsafe-swiftshader",
"--ignore-gpu-blocklist",
],
},
}),
```
Then `pnpm vitest run tests/webgl_save_restore.spec.js` produces:
```
3 failed | 10 passed (13)
- should preserve transform across save/restore
AssertionError: expected +0 to be close to 1
- should handle nested save/restore correctly
AssertionError: expected +0 to be close to 1
- should handle deep nesting (20 levels)
AssertionError: expected +0 to be close to 1
```
Reproduces on a clean checkout of master (no #1480 changes) — pre-existing bug.
Suspected area
The test predates the RenderState refactor (commit af34dd3 "Refactor renderer state into RenderState with zero-allocation save/restore"). One of:
- The pre-allocated index-based stack indexes the wrong slot for transform state
- `save()` captures by reference instead of cloning — mutations to currentTransform between save/restore leak into the saved value
- `restore()` writes the post-mutation matrix back instead of the saved one
Color save/restore tests pass; only transform fails. So the bug is specific to how the transform matrix is captured / restored, not the broader save/restore stack mechanics.
Acceptance
Related
Problem
`tests/webgl_save_restore.spec.js` has three tests that fail when WebGL2 is actually available in the test environment:
All three fail at the same assertion shape: after a `save()` → mutate → `restore()` sequence, `renderer.currentTransform.val[0]` reads as `0` instead of the expected `1` (the identity-matrix top-left).
These were silently masked because the tests guard with:
```js
if (!isWebGL) {
return;
}
```
The `failIfMajorPerformanceCaveat: true` option in the test setup means chromium headless without GPU flags falls back to Canvas, the guard returns early, and the failure never reports.
Why this is being filed now
While landing #1480 (mesh-depth single-clear refactor), I temporarily added chromium swiftshader launch flags to `vitest.config.ts` so the new WebGL2 pixel-level tests would run in CI. That surfaced these three failures. The flags were reverted to keep #1480's scope tight; this issue tracks the underlying bug.
Repro
Add to `vitest.config.ts`:
```ts
provider: playwright({
launchOptions: {
args: [
"--use-gl=angle",
"--use-angle=swiftshader",
"--enable-unsafe-swiftshader",
"--ignore-gpu-blocklist",
],
},
}),
```
Then `pnpm vitest run tests/webgl_save_restore.spec.js` produces:
```
3 failed | 10 passed (13)
AssertionError: expected +0 to be close to 1
AssertionError: expected +0 to be close to 1
AssertionError: expected +0 to be close to 1
```
Reproduces on a clean checkout of master (no #1480 changes) — pre-existing bug.
Suspected area
The test predates the RenderState refactor (commit af34dd3 "Refactor renderer state into RenderState with zero-allocation save/restore"). One of:
Color save/restore tests pass; only transform fails. So the bug is specific to how the transform matrix is captured / restored, not the broader save/restore stack mechanics.
Acceptance
Related