ITADN

END_CLIP reads out-of-bounds draw data due to scene_offset mismatch

#1581Openkoubaa 创建于 2026-04-15
K
koubaacommented
## Summary `DrawTag::END_CLIP` is `0x21`, which encodes `scene_offset = (0x21 >> 2) & 7 = 8` u32s per the draw monoid. However, `encode_end_clip()` pushes **zero** words to `draw_data`. This means every END_CLIP's draw monoid `scene_offset` advances 8 words past the actual draw data boundary, causing the coarse shader to read blend mode and alpha from **uninitialized memory** (typically the transform stream). ## Details In `vello_encoding/src/draw.rs`: ```rust pub const END_CLIP: Self = Self(0x21); // scene_offset = (0x21 >> 2) & 7 = 8 ``` In `vello_encoding/src/encoding.rs`: ```rust pub fn encode_end_clip(&mut self) { if self.n_open_clips > 0 { self.draw_tags.push(DrawTag::END_CLIP); // No draw_data pushed! self.path_tags.push(PathTag::PATH); // ... } } ``` Compare with `BEGIN_CLIP = 0x49` which has `scene_offset = (0x49 >> 2) & 7 = 2` and correctly pushes 2 u32s (`DrawBeginClip` = blend_mode + alpha). In `coarse.wgsl`, the END_CLIP case reads: ```wgsl case DRAWTAG_END_CLIP: { clip_depth -= 1u; write_path(tile, tile_ix, draw_flags); let blend = scene[dd]; // OOB read let alpha = bitcast<f32>(scene[dd + 1u]); // OOB read write_end_clip(CmdEndClip(blend, alpha)); } ``` Where `dd = config.drawdata_base + draw_monoids[drawobj_ix].scene_offset` — but `scene_offset` has been inflated by 8 per END_CLIP instead of the 0 actual words, so `dd` points past the draw data into the transform stream. ## Impact - The blend mode and alpha for every clip/layer end are read from garbage memory. On most GPUs this "works" because the garbage blend value rarely equals `BLEND_CLIP` (32771), so `is_blend` is usually true, and the garbage alpha reinterpreted as `f32` from a transform value happens to be close to 1.0. - This is likely the root cause (or a contributing factor) of #1061 — layer compositing uses wrong blend/alpha values. - The `resolve.rs` sentinel END_CLIPs for unclosed clips also don't push draw data, compounding the offset drift. ## Suggested fix Either: 1. **Change `END_CLIP` tag to `0x09`** (scene_offset = 2) and push the matching `DrawBeginClip` words in `encode_end_clip()` — so the coarse shader reads correct blend/alpha. 2. Or have the coarse shader read blend/alpha from the **matching BEGIN_CLIP's** draw data offset instead of the END_CLIP's own offset. Option 1 is simpler and what we implemented in our fork (ekrano). The `resolve.rs` sentinel path also needs to emit matching draw data for unclosed clips.
0 条评论