webrender/frame_snap.rs
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! Frame-time pass that snaps prim, cluster, and clip-tree rects to the
6//! device pixel grid. Runs once near the start of frame building, after
7//! `spatial_tree.update_tree`, and writes the `snapped_*` rect fields that
8//! downstream visibility / prepare / batch consumers read.
9
10use api::units::{LayoutRect, RasterPixelScale};
11use crate::clip::ClipTree;
12use crate::prim_store::{PrimitiveInstance, PrimitiveStore};
13use crate::space::SpaceSnapper;
14use crate::spatial_tree::{SpatialNodeIndex, SpatialTree};
15use crate::util::MaxRect;
16use crate::visibility::PrimitiveDrawHeader;
17
18/// Snap all per-frame rect state that depends on the current spatial tree:
19/// each prim's `snapped_local_rect` (into `draws`), each cluster's
20/// `snapped_bounding_rect`, each prim's clip-leaf rect, and each clip-tree
21/// node's rect. All snapping happens against the root reference frame in
22/// the rect's own spatial-node space, mirroring the scene-build helper this
23/// replaces.
24///
25/// Per-prim clip leaves are snapped inside the cluster loop, against the
26/// cluster's spatial node — the leaf's local clip rect lives in the prim's
27/// local space, and clusters group prims by spatial node, so the cluster's
28/// (resolved) spatial node is the correct snap target. This matters for
29/// backdrop-filter capture leaves where the prim's clip-leaf spatial node
30/// would otherwise be `UNKNOWN`: the cluster is resolved by
31/// `finalize_picture` before this pass runs.
32pub fn snap_frame_rects(
33 prim_store: &mut PrimitiveStore,
34 prim_instances: &[PrimitiveInstance],
35 clip_tree: &mut ClipTree,
36 draws: &mut [PrimitiveDrawHeader],
37 spatial_tree: &SpatialTree,
38) {
39 profile_scope!("snap_frame_rects");
40
41 let root = spatial_tree.root_reference_frame_index();
42 let mut snapper = SpaceSnapper::new(root, RasterPixelScale::new(1.0));
43
44 for pic in &mut prim_store.pictures {
45 for cluster in &mut pic.prim_list.clusters {
46 snapper.set_target_spatial_node(cluster.spatial_node_index, spatial_tree);
47 cluster.snapped_bounding_rect = snapper.snap_rect(&cluster.unsnapped_bounding_rect);
48
49 for prim_idx in cluster.prim_range() {
50 draws[prim_idx].snapped_local_rect =
51 snapper.snap_rect(&prim_instances[prim_idx].unsnapped_prim_rect);
52
53 // Snap the prim's clip-leaf in the same spatial-node space.
54 // Picture / tile-cache leaves carry `max_rect`; snapping
55 // `max_rect` would overflow through the snapper's transforms,
56 // so pass those through unchanged.
57 let leaf = clip_tree.get_leaf_mut(prim_instances[prim_idx].clip_leaf_id);
58 if leaf.unsnapped_local_clip_rect == LayoutRect::max_rect() {
59 leaf.snapped_local_clip_rect = leaf.unsnapped_local_clip_rect;
60 } else {
61 let unsnapped = leaf.unsnapped_local_clip_rect;
62 leaf.snapped_local_clip_rect = snapper.snap_rect(&unsnapped);
63 }
64 }
65 }
66 }
67
68 for node in clip_tree.nodes_mut() {
69 if node.spatial_node_index == SpatialNodeIndex::INVALID {
70 node.snapped_clip_rect = node.unsnapped_clip_rect;
71 continue;
72 }
73 snapper.set_target_spatial_node(node.spatial_node_index, spatial_tree);
74 node.snapped_clip_rect = snapper.snap_rect(&node.unsnapped_clip_rect);
75 }
76}