Skip to content

Render follow-ups drain (re-applied on 0.19): UiTransform paint + degraded effect groups#75

Merged
intendednull merged 2 commits into
mainfrom
followups-render-v2
Jun 19, 2026
Merged

Render follow-ups drain (re-applied on 0.19): UiTransform paint + degraded effect groups#75
intendednull merged 2 commits into
mainfrom
followups-render-v2

Conversation

@intendednull

Copy link
Copy Markdown
Owner

Render track of the follow-ups-drain campaign (docs/plans/2026-06-18-followups-drain.md), re-applied on Bevy 0.19-rc. The original render PR (#71) was built on 0.18 and went stale when the BSN/0.19 migration (#72) rewrote the render pipeline; #71 is closed. A read-only investigation confirmed both gaps still exist on 0.19 and that the design ports verbatim/near-verbatim (the migration left PackedInstance at 52B/13-floats and the WGSL shader structure untouched).

Slices

  1. 86c995c UiTransform affine paint (rotate + scale) — render now consumes the full 2D affine from GlobalTransform (pillar-5: never a ResolvedTransform re-read, so render == picking) instead of dropping all but translation. The affine basis is appended after the existing 13 floats so every field offset is unchanged (alpha stays float 7, named COLOR_FLOAT_OFFSET/ALPHA_FLOAT_OFFSET); identity affine → existing pixels byte-identical (4 instance-hex snapshots re-blessed). Quad + shadow WGSL transform the corner about box-local origin. Residuals kept open: transform-origin (layout-side), skew/general-Matrix (bridge TRS decompose), perspective/Preserve3d/backface (C-tier).

  2. c1d1fe8 degraded effect groups forward-composite flat — a budget-degraded group used to vanish; it now folds group.opacity per-instance and draws flat (effect-compositor.md §2.3), for root-degraded groups (nested deferred → debug_assert + new follow-up). Per-tier dirty gates prevent compounding alpha drift; glyph alpha uses GLYPH_ALPHA_FLOAT_OFFSET=11 (not quad's 7). R2 builds on R1's PackedInstance layout.

Verification

cargo fmt --all --check, cargo clippy --workspace --all-targets -D warnings, RUSTDOCFLAGS=-D warnings cargo doc --workspace --no-deps, and cargo test --workspace (185 ok / 0 failed) all green on 0.19. The GPU reftests (render_transform_paint_gpu, render_degraded_group_gpu) pass on the local RX 6700 XT — including degraded_glyph_fold_idempotent_under_quad_dirty_only_frame, whose assertion was corrected (white-ink R+G stability, not the mutated blue background) before it broke CI on 0.18. The pinned-lavapipe GPU CI lane exercises them here.

🤖 Generated with Claude Code

intendednull and others added 2 commits June 19, 2026 04:31
…n 0.19]

Re-applies the UiTransform-affine-paint follow-up on the Bevy 0.19-rc render
pipeline. It was implemented on 0.18 (stale PR #71, closed) but the BSN/0.19
migration rewrote the render plumbing; a fresh investigation confirmed the gap
still exists on 0.19 and the design ports verbatim (the migration left
PackedInstance at 52B/13-floats and the WGSL shader structure untouched).

Render now consumes the full 2D affine GlobalTransform composed by the bridge,
instead of dropping all but translation -- so a rotated/scaled UI element paints
correctly. extracted_node_for reads global_transform.affine().matrix3 xy columns
(pillar-5: GlobalTransform, never a ResolvedTransform re-read, so render ==
picking). ExtractedNode.affine flows through PackedInstance, the bucket raw
record (now 17 floats), packed_to_raw, the prepare RawBufferVec, the quad vertex
layout (array_stride 52->68, attrs at locations 8/9), and both quad + shadow
WGSL (corner = rect_pos + mat2x2(affine) * box-local corner).

Constraint (R2 depends on it): the affine basis is APPENDED after the existing
13 floats so every field offset is unchanged -- color stays float 4, alpha
float 7, named COLOR_FLOAT_OFFSET / ALPHA_FLOAT_OFFSET consts. Identity affine =
[1,0,0,1] -> existing pixels byte-identical; 4 instance-hex snapshots re-blessed
with the trailing identity floats. The 0.19-only immediate_size pipeline field
is orthogonal and untouched.

Scope = transform-paint only. Residuals kept open: transform-origin (layout 6e
does not bake ui.origin -> rotated elements pivot top-left); skew / general
TransformMatrix::Matrix (bounded by the bridge's TRS-only decompose);
perspective / Preserve3d / BackfaceVisibility (C-tier). clip-and-transform.md
B.5 + follow-ups.md narrowed to transform-paint LANDED.

Cross-crate: buiy_verify ExtractedNode/PackedInstance sites + snapshot tests
updated. Verified on 0.19: clippy --workspace -D warnings clean; render + lib +
buiy_verify suites green; GPU rotate/scale reftest passes on the RX 6700 XT
(was only compile-checked in the slice; run here to close the loop). R1 lands
before R2 (hard PackedInstance-offset dependency).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DHcf8nQ9PTT3m5E7u3Q6XV
…ed on 0.19]

Re-applies the degraded-effect-groups follow-up on Bevy 0.19-rc (0.18 impl was
on the closed stale PR #71). Builds on R1 (86c995c): the [f32;17] PackedInstance
layout + ALPHA_FLOAT_OFFSET now exist. Gap confirmed still present on 0.19
(node.rs still skipped degraded groups; compositor had no fold); ports
near-verbatim since the 0.19 ViewNode->buiy_pass migration left the skip site's
logic identical (the node edit is comment-only).

A budget-degraded effect group (no pooled target) used to vanish; it now folds
group.opacity per-instance (re-tint-in-place) and merges its ranges into the
flat draw, for ROOT-degraded groups (parent==None). prepare_effect_groups grew
RtPoolBudget/RenderQueue/ResMut buffers/ExtractedGlyphs/ExtractedTextQuads
params (all present on 0.19) and reconstructs the same quad_dirty/glyph_dirty
signals prepare.rs uses.

Per-tier dirty gates (the load-bearing correctness point): the alpha-FOLD gates
on the buffer-repack signal (quad fold on quad_dirty, glyph fold on glyph_dirty),
the range-MERGE gates on the partition-rebuild signal (quad_dirty || glyph_dirty)
- distinct so a retained-already-folded glyph buffer does not re-fold (drift to
black) yet its range still re-merges on a quad-dirty-only frame (does not vanish).
Glyph alpha uses GLYPH_ALPHA_FLOAT_OFFSET=11 (color[3]), not quad's 7.

Scoped to ROOT-degraded; a nested degraded child needs a different draw path
(composite into the parent's off-screen target) - debug_assert-guarded +
release-skip + filed as a new follow-up section. The GPU glyph-idempotency test
asserts WHITE-INK red+green stability (NOT the blue background the fixture
mutates - the assertion bug that false-failed CI on 0.18, fixed here).

Verified on 0.19: clippy --workspace -D warnings clean; render_compositor 35 +
render_effect_groups 16 headless; all 4 GPU tests pass on the RX 6700 XT
(degraded_glyph_fold_idempotent + range_remerges + no-compound + nested-no-
corrupt). effect-compositor.md 2.3 As-landed + follow-ups.md LANDED + nested
follow-up. Final render-track slice.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DHcf8nQ9PTT3m5E7u3Q6XV
@intendednull intendednull merged commit 6cf2d8d into main Jun 19, 2026
7 checks passed
intendednull added a commit that referenced this pull request Jun 19, 2026
Final doc pass. All 13 actionable slices landed (layout #69, text #74, render
#75 re-applied on Bevy 0.19-rc); each slice already flipped its own follow-up
entry to LANDED via the per-slice commits. This pass reconciles the remainder:

- Flip the superseded "anchor target IS sticky/table/multicol" entry to LANDED
  (closed by Phase 7 Task 9 / the PostTaffyPositionOverrides shared correction
  buffer = Option 1 of its own sketch; tested in layout_sticky.rs).
- Document position_try_max_depth as Deferred-not-built with a re-open trigger
  (speculative: gated on unmeasured profiling -> a cap is an unused knob).
- Add re-open triggers to the multi-reference-reftest-aggregation and
  golden-prune deferred entries (tested-but-unused / nothing-to-prune-yet).
- Flip the campaign plan to landed (doc + README catalog [active] -> [landed]).

node-draw-model was already LANDED; the build-item entries were verified LANDED
(spot-checked all 13). Blocked items (cross-window anchor, per-window top layer,
sticky em/rem/V* insets, clear_warned_once, R11 BoxShadow draw-skip, multi-range
selection, nested degraded composite) remain correctly documented as gated on
their unbuilt subsystems / renderer features.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DHcf8nQ9PTT3m5E7u3Q6XV
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.

1 participant