Skip to main content

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}