Expand description
Render-world half of layer compositing — a custom pass over stock
bevy_ui_render, public API only (no fork). Mechanism per frame:
extract_ui_layers(ExtractSchedule, afterextract_ui_camera_view): per promoted layer, spawn a synthetic view whoseclip_from_viewis an orthographic projection over the layer’s capture rect — the same physical screen space stock UI vertices live in — and register an emptyTransparentUiphase for it. Stock extraction / queue never know it exists.redistribute_ui_layers(PhaseSort, before the stock sort): move the already-queued phase items whosemain_entitylies in a promoted subtree, verbatim, from the camera’s UI phase into their layer’s synthetic phase — stockprepare_uinodes(and sibling prepares) iterate all phases, so the moved items are batched by stock code against the synthetic view’sViewUniformOffset. Then inject one composite-quad item per layer at the position of its first stolen item.ui_layer_capture_pass(Core2d/Core3d, beforeui_pass): render each synthetic phase into the layer’s offscreen texture (cleared transparent). Straight-alpha blending onto transparent black accumulates premultiplied color, so…- …a layer with a
filterchain then replays its staged filter run (same graph node, right after that layer’s capture): fullscreen passes capture → ping-pong textures (LayerFilterMeta::runs, staged byprepare_layer_filters), all of them or none — an uncompiled pass pipeline aborts the whole run andFilterSlot::output_validstays false, so the layer restages and retries next frame. And… - …a layer with the
TRANSFORM3Dpromotion reason replays its staged mip-downsample chain last in the iteration (mips) — its sampled texture (capture, or filter output) carries a full mip chain, rebuilt only when level 0 was rewritten. Finally… - …the composite quad (
DrawLayerComposite, drawn inside the stockui_passat the subtree’s stacking position) samples the capture — or, for a filtered layer, the final filter pass’s output — with premultiplied blending (One/OneMinusSrcAlpha) and multiplies rgb and alpha by the group alpha. 3D-transformed quads sample trilinear + anisotropic over the mip chain (minification shimmer) and feather ~1px of coverage at their silhouette (composite.wgsl’s edge AA — diagonal edges rasterize without MSAA).
Re-verify on Bevy upgrades (spike checklist): TransparentUi field set,
SortedRenderPhase::{items, transient_items} visibility, prepare_uinodes
iterating all phases, ViewSortedRenderPhases::prepare_for_new_frame
draining transients, straight ALPHA_BLENDING in UiPipeline, the
Queue → PhaseSort → PrepareBindGroups schedule shape, naga_oil NOT
re-exporting an import’s entry points (the split-stage filter pipelines
rely on pass shaders having no vertex entry of their own), naga’s namer
renaming digit-suffixed identifiers (the pad_a/pad_b constraint in
composable WGSL modules), and wgpu accepting per-stage shader modules in
RenderPipelineDescriptor (filter vertex stage = prelude module, fragment
stage = pass module).
Re-exports§
pub use store::*;
Modules§
- backdrop
- Render-world half of
backdropFilter: the snapshot blit, the backdrop filter run, and the backdrop composite quad. - clip
- Render-world half of clip-independent layer capture: the extract-window clip swap, and the composite quad’s rect clamp.
- mips
- Mip-chain generation for 3D-transformed layers’ capture textures.
- store
- The persistent capture-texture store — the resource that makes layer
capture caching possible. Split from
render.rs(which stays the pass / composite half): slot structs, allocation, and the per-frameprepare_layer_texturesmaintenance. Everything is re-exported throughsuperso consumers keep theirrender::…paths. - transform3d
- Render-world plumbing for the composite quad’s per-layer uniforms: the 3D
model matrix and the screen-space clip rect (
transform3dsupport).
Structs§
- Draw
Layer Quad - Extracted
Chain - A layer’s filter chain, extracted from
ResolvedFilterChain. Only the render-side fields cross:wire_index/layout/outset_px/scaleare main-world concerns (animation metadata, capture sizing) and stay there. - Extracted
Filter Pass - One filter pass of an extracted chain: the pass shader plus its packed uniform params.
- Extracted
Layer - One promoted layer, as seen by the render world this frame.
- Extracted
UiLayers - Per-frame extraction output.
layersis index-aligned withLayerAtlases::texturesandLayerCompositeMeta::atlas_bind_groups. - Filter
Uniforms - The Rust mirror of the prelude’s
FilterUniforms(layer/filter_prelude.wgsl) — one entry per staged filter pass inLayerFilterMeta::uniforms. The explicitpadfields reproduce the WGSL uniform-address-space layout byte for byte (160 bytes total; asserted byfilter_uniforms_match_the_documented_wgsl_layout). The digit-freepad_a/pad_bnames are load-bearing on the WGSL side: naga’s namer appends_to identifiers ending in a digit, which naga_oil rejects in composable modules — and the mirror matches field for field. - Layer
Composite Batch - The composite quad’s draw data on its render entity (mirrors
UiBatch). - Layer
Composite Meta - Vertex buffer + per-layer capture bind groups for the composite draws.
- Layer
Composite Pipeline - The composite pipeline: group 0 is the stock UI view uniform (so
SetUiViewBindGroupis reused verbatim), group 1 the capture texture. Blending is premultiplied (One/OneMinusSrcAlpha): capture content is premultiplied by construction (straight-alpha blending onto transparent black), and the shader multiplies rgb and alpha by the group alpha. - Layer
Composite Pipeline Key - Layer
Composite Vertex - One composite-quad vertex: physical screen position (the stock UI view projects it), capture UV, and the group alpha. Future composite params (per-rule) extend this struct — the pass stays rule-agnostic.
- Layer
Filter Meta - Per-frame filter staging: the uniform buffer (one entry per staged pass)
and the replay list, index-aligned with
ExtractedUiLayers::layers.runs[idx] = Nonemeans “no filter work this frame” — either the layer has no chain, or its cached output is still valid (the composite samplesFilterSlot.textures[output_index]either way). - Layer
Filter Pass - One staged filter pass, replayed by
ui_layer_capture_pass: set the pipeline, bind group 0 at the dynamic offset, render 3 vertices intotarget. - Layer
Filter Pipeline - The filter-pass pipeline: ONE bind group layout for every filter — group 0
is the source texture (the capture, or the previous pass’s ping-pong
output), a linear clamp-to-edge sampler, one dynamically-offset
FilterUniforms, and the layer’s original capture (always bound, so any pass can sample the unfiltered input) — plus the prelude shader, which is the vertex stage of every filter pipeline. - Layer
Filter Pipeline Key - Specialization key: the pass’s fragment shader plus the target format
(filter targets ride the capture’s format).
Handle<Shader>hashes by asset id, so it works as a key directly. - Layer
Filter Run - A layer’s staged filter run this frame.
- SetLayer
Atlas Bind Group
Functions§
- extract_
ui_ layers - Extracts promoted layers into the render world and spawns their synthetic
capture views. Must run after
extract_ui_camera_view: that system ends with aretainthat would drop any phase it didn’t create. - filter_
output_ index - Which ping-pong texture holds the final output of a
len-pass chain (the last pass’s target;lenis at least 1 for any staged run). - filter_
source_ index - Ping-pong source for pass
i:None= the layer’s capture texture (pass 0), otherwise the index of the previous pass’s target. - filter_
target_ index - Ping-pong target for pass
i. - init_
layer_ composite_ pipeline - init_
layer_ filter_ pipeline - needs_
filter_ run - Whether a layer’s filter passes must (re-)run this frame: fresh capture content, changed params, a time-driven chain, or an output that was never completed (startup, realloc, or a run whose execution was skipped).
- prepare_
layer_ composites - Builds composite-quad vertices + bind groups and stamps
LayerCompositeBatchonto the quad entities, writing each quad’s vertex range back into its phase item. - prepare_
layer_ filters - Stages every resource a layer’s filter passes need this frame: pipeline
specialization, one uniform entry per pass, and per-pass bind groups over
the capture/ping-pong textures. Execution happens in
ui_layer_capture_pass, which replaysLayerFilterMeta::runsright after each layer’s capture; this system also predicts that execution (phase 3) and writesFilterSlot::output_validaccordingly, so the downstreamprepare_layer_compositesgate is same-frame accurate. - redistribute_
ui_ layers - Moves promoted subtrees’ phase items from the camera’s UI phase into their layer’s synthetic phase, then injects one composite quad per layer. Runs after queueing, before the stock sort (which then sorts every phase, stolen items keeping their global stack-index sort keys).
- ui_
layer_ capture_ pass - Renders each layer’s synthetic phase into its capture texture, then
replays the layer’s staged filter run (if any) capture → ping-pong
textures. Runs in the camera’s schedule right before the stock
ui_passconsumes the composite quads.
Type Aliases§
- Draw
Layer Composite - The composite quad’s draw stack — view uniform reuse means the quad rides whatever view its phase belongs to (screen, or an outer layer’s capture).