#462

fix(vgpu): guard stale surface readback

DraftAli-Karakiwants to merge intofrom

Problem

Canvas surface readback can silently return zero-filled data when surface.color is read after the browser has presented the rendered texture. At that point GPUCanvasContext.getCurrentTexture() refers to a fresh, unrendered presentation texture rather than the one submitted by the completed frame. This is the behavior reported in #387.

Expected and actual behavior

Expected: readback succeeds only for the current canvas texture that was actually submitted by a completed frame, and stale or not-yet-submitted surface reads fail clearly.

Actual: surface.color.read() wraps whichever texture getCurrentTexture() returns at access time, so deferred reads can silently copy from a new zero-filled texture.

Reproduction / use case

Render to a canvas surface, allow presentation to advance, then call surface.color.read(...). The canvas shows the rendered output while readback can contain zeros. The regression test models the presentation advance by rotating the mocked current-texture identity.

Related work and proposal

Related to #387; this is the same silent-failure family as the separate compute report in #416.

This proposal:

  • records the exact canvas texture attached to each frame;
  • promotes it to readable state only after successful queue submission;
  • rejects reads during an active frame, before submission, after cancellation, or after presentation advances;
  • reports VGPU-SURFACE-READ-UNAVAILABLE with an offscreen-target workaround;
  • documents the current-presentation-frame constraint and regenerates reference docs.

The texture-identity check follows the WebGPU canvas current-texture lifecycle described by the W3C specification: https://www.w3.org/TR/webgpu/#canvas-context-getcurrenttexture

Validation

  • packages/vgpu-api/tests/surface-mock.test.ts: 14 passed
  • full vgpu-api suite excluding the repository's known Windows child-command suites: 736 passed, 79 skipped
  • pnpm run typecheck: passed
  • pnpm run check:skill-drift: passed
  • git diff --check: passed
  • GitHub CI: all substantive test, Windows, Docker GPU, docs, and security jobs passed
  • pnpm test:fast: 1,092 passed, but the Windows checkout still has unrelated path, child-process, and WGSL fixture-resolution failures
  • docs snippet verification is blocked locally because its direct spawnSync("pnpm") lookup returns ENOENT on this Windows host

PR type

contribution

Activity

6
vercel[bot]1mo ago

@Ali-Karaki is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

Ali-Karaki1mo ago

@matiasngf This draft addresses #387 by guarding stale canvas-surface readback across the frame lifecycle. It remains a draft contribution proposal, and all substantive GitHub CI jobs are green. Could you review it when convenient?

This pull request is a draft

Merging is unavailable until it is marked ready for review.