Expand description
ClearRect: the platform-view hole punch, hoisted to the frame root and
lowered to destination-out coverage.
frust_scene’s ClearRect erases an axis-aligned rectangle to full
transparency, colour and alpha both, so an OS view hosted behind a
translucent surface shows through a slot the app’s own opaque backdrop
would otherwise seal. It is a real destination-clearing composite, not a
skipped paint.
§Hoisting
A punch confined to the group it was recorded in would only erase that
group’s own accumulated content — an app-root backdrop painted outside a
scroll view’s clip survives the group composite and seals the hole again.
So the punch is hoisted past every enclosing clip, layer and snapshot
bracket to the frame root, bounded by the intersection of those brackets’
device-space bounds so a partially scrolled slot still clips to its
viewport (punch_rect). At the root there is nothing left to hoist past,
and the intersection is the punch itself.
§Destination-out, not a clear
The lowered form is coverage drawn with dst' = dst · (1 − src.a), which
erases colour and alpha exactly where the source covers and leaves an
uncovered pixel bit-identical. Deliberately not a clear op: a clear applies
at whole-tile granularity, which bleeds the punch up to a tile past a
tile-unaligned rectangle edge. Destination-out weights the erase by the
source’s own coverage instead, so a pixel-aligned edge lands pixel-exact
however it falls inside a tile, and a fully covered pixel reads exactly
(0, 0, 0, 0) on a target that carries alpha.
§The wiring contract
This module produces the lowered form and stops there — a
ClearPunch per surviving punch, naming the strips that
carry its coverage, the device bounds they cover, and the painter-order
depth it was hoisted from. Issuing them is the renderer’s, and is specified
here so the pass that grows it has one place to read:
-
One pass, at the punch’s own painter-order position. A punch is issued into the frame’s own target once everything recorded before the clear has been recorded, and before anything recorded after it is. The renderer does that by cutting the surface round at the punch’s depth — the ops before it end one pass, the punch pass follows, the ops after it resume in the next — so punches at one position are issued together and punches at different positions each get a pass. A punch past every op of the frame, which is what a
ClearRectrecorded last is, therefore lands after the last round exactly as an unconditionally-trailing pass would. They never touch an intermediate page: a punch inside an isolated layer was hoisted out of it. -
Fixed-function destination-out, over the strip program. A punch is a strip run like any other, so it goes through the same strip program and instance layout; only the blend state differs —
src_factor: Zero,dst_factor: OneMinusSrcAlpha,operation: Add, for the colour and the alpha component. That computesdst · (1 − src.a), which is theCOMPOSE_DEST_OUTarm ofshaders/blend.wgslevaluated for a premultiplied source, without a shader-side composite. It has to be fixed-function here: the blend module reads its backdrop withtextureLoad, and the frame’s own target is not readable inside the pass that writes it.shaders/blend.wgslremains the route for a composite between intermediate textures. -
Ordered by the cut, and depth-tested against the one pass the cut cannot order it against. Point 1’s cut is what orders the punch against everything drawn into the surface in a round: recorded before the clear, it is erased; recorded after it, it lands on top of the erase. That holds whether or not the content wrote depth, so an anti-aliased fringe, a translucent paint’s spans and a layer’s composite all survive a punch they were recorded over.
One pass escapes the cut, and it is why the punch still carries the depth it was hoisted from: the frame’s opaque strips are recorded once, ahead of every round (see
crate::renderer), so they hold post-clear coverage that no cut can put after the punch. The ordinaryLessEqualtest against the frame’s depth attachment restores exactly that ordering — opaque coverage recorded after the clear wrote a nearer depth and the punch fails against it, opaque coverage recorded before it is erased — and it is the only ordering the test is asked for. Everything else in the frame writes no depth, and needs none: the cut already put it on the correct side.Without a depth attachment at all there is no separate opaque pass to order against: every instance travels through the surface rounds in painter order, so the cut alone is the whole contract and nothing is erased that was recorded after the clear.
One shape the cut cannot express is a bracket that straddles the clear. An isolated layer reaches the surface as a single composite carrying the deepest index inside it, so a layer holding content recorded both before and after the clear composites after the punch as a whole — the half of it recorded before the clear survives where the reference renderer, which closes and reopens the bracket around the punch, erases it. That is the engine’s one-composite-per-layer model, not this pass’s ordering.
-
Skipped whole on a target that disregards alpha. Destination-out darkens colour as well as erasing alpha, so on an opaque presentation — where the erased alpha is disregarded — issuing the pass would leave a black rectangle where the display list says nothing should change. The punches are kept out of
CompiledFrame::drawsfor exactly this reason: dropping the pass restores the frame exactly, which is the no-op the display list mandates there.
Structs§
- Clear
Punch - One hoisted clear, ready to be issued as destination-out coverage.
- Staged
Punch - A punch the walk has hoisted, held until the frame’s draws are done.
Functions§
- device_
bounds - A device-space rectangle on the
u16grid the strip pipeline addresses. - punch_
rect - The device-space rectangle a clear punches, confined to every bracket open
around it, or
Nonewhen nothing of it survives.