Skip to content

Fix nested canvas clipping and clipped clears - #1872

Open
bkaradzic-microsoft wants to merge 4 commits into
BabylonJS:masterfrom
bkaradzic-microsoft:pr/canvas-clip-clear
Open

bkaradzic-microsoft wants to merge 4 commits into
BabylonJS:masterfrom
bkaradzic-microsoft:pr/canvas-clip-clear

Conversation

@bkaradzic-microsoft

@bkaradzic-microsoft bkaradzic-microsoft commented Sep 11, 2026

Copy link
Copy Markdown
Member

Summary

  • Intersect rectangular Canvas clips with the active NanoVG scissor so nested, disjoint, translated, signed-rectangle, and restored clips retain parent bounds.
  • Implement clearRect with opaque destination-out coverage, independent of globalAlpha and filters, while restoring the prior drawing state.
  • Initialize empty NanoVG filter stacks and add GPU-readback regressions with existing render-test skip handling.
  • Fix the OpenPBR validation scene's asynchronous mesh-loading race: return the scene only after mesh import and material setup finish, using the existing per-test source replacement support. The reference image, render count, and tolerance are unchanged.
  • Fix the inherited Vulkan CI gate to require both sampler-boundary tests to run and pass without assuming a fixed total suite size.

Base

Rebased onto master at 4af724a6. Includes signed-rectangle normalization before scissor intersection. This includes the already-merged Canvas work from #1855 and does not depend on the open branding PR #1844.

Validation

  • Windows x64 / D3D11 / QuickJS, RelWithDebInfo: all 6 selected native cases passed, including all 94 JavaScript cases.
  • A delayed mesh import reproduced every pixel of the blank CI screenshot on both the PR and its upstream base (41.223% mismatch). With the scene-loading fix, both delayed and ordinary runs pass at 0.733%, below the unchanged 2.5% limit.
  • The actual snippet's transformed scene creation waits for the import, finishes all 16 material assignments, and propagates import failures.
  • The Vulkan gate accepts the actual 34-case CI report and rejects missing, skipped, failed, unexecuted, or incomplete required boundary tests.

Signed-rectangle update

  • Normalize negative width/height before intersecting with the parent clip; preserve the existing transform and antialiasing adjustment.
  • Cover both signed axes, their combination, and rotated nested clips using byte-identical GPU comparisons with equivalent positive rectangles.
  • Windows x64 / D3D11 / Chakra / RelWithDebInfo: all 6 selected native cases pass, including 68 JavaScript cases; 27 optional codec cases are pending because those plugins are disabled in this build. The new regression fails against the previous PR head on the first negative-width case and passes with the fix.
  • No Babylon.js changes, dependency updates, reference changes, or validation-gate adjustments in this update.

Copilot AI lite review requested due to automatic review settings September 11, 2026 00:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

This PR fixes correctness issues in the Canvas2D NanoVG-backed implementation, specifically around nested clipping behavior and clearRect behavior under clipping/alpha/filters, and adds GPU readback regression tests to prevent regressions.

Changes:

  • Intersect Canvas rectangle clipping with the active NanoVG scissor to preserve parent clip bounds for nested clips.
  • Implement clearRect via DESTINATION_OUT coverage while forcing globalAlpha=1 and clearing filters, restoring prior state afterward.
  • Add GPU readback regression tests for nested clips and clipped clears, with skip handling wired from the native test runner.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
Polyfills/Canvas/Source/nanovg/nanovg_filterstack.h Initializes filter stack count to avoid undefined state when creating “empty” stacks.
Polyfills/Canvas/Source/Context.cpp Updates clip handling to use scissor intersection and adjusts clearRect compositing to clear only clipped regions independent of alpha/filters.
Apps/UnitTests/Source/Tests.JavaScript.cpp Exposes a global flag to skip GPU canvas tests when render/external texture tests are disabled.
Apps/UnitTests/JavaScript/src/tests.javaScript.all.ts Adds GPU readback regression tests for nested clips and clipped clearRect.
Apps/UnitTests/JavaScript/dist/tests.javaScript.all.js Bundled output updated to include the new JS test cases.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread Polyfills/Canvas/Source/Context.cpp
Comment thread Polyfills/Canvas/Source/Context.cpp Outdated
Comment thread Apps/UnitTests/JavaScript/src/tests.javaScript.all.ts

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Copilot reviewed 4 out of 5 changed files in this pull request and generated 1 comment.

Comment thread Apps/UnitTests/JavaScript/src/tests.javaScript.all.ts
@bkaradzic-microsoft

bkaradzic-microsoft commented Sep 11, 2026

Copy link
Copy Markdown
Member Author

The Windows/Hermes failure occurred after a successful build: snippet requests returned HTTP 403 on that runner, so all 314 Playground cases failed during scene loading (three failed fetch attempts per case), before rendering.

The same commit passed all 314 cases in the Windows D3D11 and V8 jobs, and the failed snippet URLs now return HTTP 200 from a separate probe. No code or test changes are warranted by this evidence. The failed-only retry (attempt 2, job 103128300425) has now passed both Validation Tests and Unit Tests. All 34 checks are green on the same commit; no code or test changes were needed.

bkaradzic-microsoft and others added 4 commits September 18, 2026 07:27
Intersect rectangular clips with the existing NanoVG scissor so nested
clips preserve parent bounds and save/restore state. Clear clipped regions
with destination-out coverage while ignoring global alpha and filters.
Initialize empty filter stacks and add GPU-readback regressions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 60c2ec68-6de1-445d-9fc9-b699db737eae
Zero-initialize the filter element array because NanoVG copies the full
filter stack into state and draw calls. Clarify the existing asymmetric
anti-alias clip extension without changing its bounds.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 60c2ec68-6de1-445d-9fc9-b699db737eae
The snippet returns its scene before ImportMeshAsync and onMeshLoad
finish, so readiness can capture an empty scene. Preserve the import
promise and return the scene only after its completion, using the
existing per-test source replacement support.

A delayed import reproduced every pixel of the blank CI image on both
the PR and its upstream base. The scene now passes with the same delay,
without changing the reference image, render count, or tolerance.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 48fa7ec8-0cf6-48a0-b836-10b7ace38c1a
Normalize negative rectangle extents before NanoVG scissor intersection,
preserving parent bounds, transforms, and the existing AA adjustment.

Add GPU readback coverage for both signed axes and rotated nested clips,
comparing all pixels with equivalent positive rectangles. The regression
fails against the previous PR head and passes with the normalization.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 60c2ec68-6de1-445d-9fc9-b699db737eae
@bkaradzic-microsoft
bkaradzic-microsoft enabled auto-merge (squash) September 18, 2026 15:48
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.

3 participants