perf(sync): scope frame-loop barriers to swapchain image + real per-pass stages (#115) #137

Merged
catbot merged 1 commit from claude/issue-115 into master 2026-06-17 21:45:13 +02:00
Member

Summary

The frame loop's inter-pass barrier (Window.cpp:881-888) and acquire/present barriers (:818, :893) set both stage masks to ALL_COMMANDS, and the inter-pass dependency used a queue-wide VkMemoryBarrier. That fully serialised against every pipeline stage and forced a full cache flush/invalidate every frame, when all the next pass needs is the swapchain image the previous one wrote.

This is the single co-dependent deliverable for both barrier families (merged from former #117): they share one fix (derive the real per-pass stage union) and one correctness constraint (RT passes).

Changes

  • Inter-pass (Window.cpp): replaced the global VkMemoryBarrier with an image memory barrier scoped to the swapchain image's single colour subresource (BuildSwapchainInterPassBarrier) — only that image's caches round-trip, exactly as the intra-pass UI barrier at UI.cpp:264 already does. The stage masks come from each pass's own stage.
  • Per-pass stage derivation: new RenderPass::SwapchainStage() virtual, overridden by UIRenderer -> COMPUTE_SHADER and RTPass -> RAY_TRACING_SHADER. The acquire dst / present src masks use SwapchainStageUnion(passes) — the real union of the frame's passes (an all-compute frame narrows to COMPUTE_SHADER only; any RT pass folds in RAY_TRACING_SHADER).
  • Correctness constraint: a hardcoded COMPUTE->COMPUTE mask would under-synchronise an RT pass and corrupt the image. The base default and empty-passes fallback are the conservative COMPUTE_SHADER | RAY_TRACING_SHADER | TRANSFER union, so a polymorphic or un-overridden pass can only be over-, never under-, synchronised.

Tests

  • SwapchainBarrierScope (new, pure CPU — no GPU): pins that the compute and RT stages are distinct (the under-sync trap), that each pass type reports its real stage through the base pointer, that SwapchainStageUnion narrows an all-compute frame to COMPUTE_SHADER only and unions a mixed frame, and that the inter-pass barrier is scoped to the single swapchain subresource.
  • FrameLoopSync (existing, real GPU + compositor): drives the real frame loop with the validation layer enabled and asserts zero validation errors — the regression guard for the narrowed acquire/present masks.

Full suite: 21 passed (native). DOM/wasm target also builds clean.

Resolves #115

🤖 Generated with Claude Code

## Summary The frame loop's **inter-pass** barrier (`Window.cpp:881-888`) and **acquire/present** barriers (`:818`, `:893`) set both stage masks to `ALL_COMMANDS`, and the inter-pass dependency used a queue-wide `VkMemoryBarrier`. That fully serialised against every pipeline stage and forced a full cache flush/invalidate every frame, when all the next pass needs is the swapchain image the previous one wrote. This is the single co-dependent deliverable for both barrier families (merged from former #117): they share one fix (derive the real per-pass stage union) and one correctness constraint (RT passes). ## Changes - **Inter-pass** (`Window.cpp`): replaced the global `VkMemoryBarrier` with an image memory barrier scoped to the swapchain image's single colour subresource (`BuildSwapchainInterPassBarrier`) — only that image's caches round-trip, exactly as the intra-pass UI barrier at `UI.cpp:264` already does. The stage masks come from each pass's own stage. - **Per-pass stage derivation**: new `RenderPass::SwapchainStage()` virtual, overridden by `UIRenderer` -> `COMPUTE_SHADER` and `RTPass` -> `RAY_TRACING_SHADER`. The acquire `dst` / present `src` masks use `SwapchainStageUnion(passes)` — the *real* union of the frame's passes (an all-compute frame narrows to `COMPUTE_SHADER` only; any RT pass folds in `RAY_TRACING_SHADER`). - **Correctness constraint**: a hardcoded `COMPUTE`->`COMPUTE` mask would under-synchronise an RT pass and corrupt the image. The base default and empty-passes fallback are the conservative `COMPUTE_SHADER | RAY_TRACING_SHADER | TRANSFER` union, so a polymorphic or un-overridden pass can only be over-, never under-, synchronised. ## Tests - **`SwapchainBarrierScope`** (new, pure CPU — no GPU): pins that the compute and RT stages are distinct (the under-sync trap), that each pass type reports its real stage through the base pointer, that `SwapchainStageUnion` narrows an all-compute frame to `COMPUTE_SHADER` only and unions a mixed frame, and that the inter-pass barrier is scoped to the single swapchain subresource. - **`FrameLoopSync`** (existing, real GPU + compositor): drives the real frame loop with the validation layer enabled and asserts zero validation errors — the regression guard for the narrowed acquire/present masks. Full suite: **21 passed** (native). DOM/wasm target also builds clean. Resolves #115 🤖 Generated with [Claude Code](https://claude.com/claude-code)
The inter-pass and acquire/present barriers in the frame loop set both
stage masks to ALL_COMMANDS, and the inter-pass dependency used a
queue-wide VkMemoryBarrier — fully serialising against every pipeline
stage and flushing all caches every frame, when all the next pass needs
is the swapchain image the previous one wrote.

Replace the inter-pass global VkMemoryBarrier with an image memory
barrier scoped to the swapchain image's single colour subresource (as
the intra-pass UI barrier already does), and derive the barrier stage
masks per pass: RenderPass::SwapchainStage() is overridden by UIRenderer
(COMPUTE_SHADER) and RTPass (RAY_TRACING_SHADER), so a compute->compute
edge only serialises COMPUTE while an RT pass pulls in RAY_TRACING — the
acquire/present frame-edge masks use the real union of the frame's
passes (SwapchainStageUnion). The base default and the empty-passes
fallback are the conservative COMPUTE | RAY_TRACING | TRANSFER union, so
a polymorphic or un-overridden pass can only be over- not
under-synchronised.

Adds SwapchainBarrierScope (pure CPU) pinning the per-pass derivation,
the union narrowing, and the inter-pass barrier scope; FrameLoopSync
already drives the real GPU frame loop with validation enabled.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
catbot merged commit 82fd6916d9 into master 2026-06-17 21:45:13 +02:00
catbot deleted branch claude/issue-115 2026-06-17 21:45:14 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Catcrafts/Crafter.Graphics!137
No description provided.