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 http://mozilla.org/MPL/2.0/. */
4
5 use crate::frame_builder::FrameBuildingContext;
6 use crate::internal_types::FastHashMap;
7 use crate::prim_store::{PictureIndex, PrimitiveInstance};
8 use crate::picture::{PicturePrimitive, SurfaceIndex, SurfaceInfo};
9 use crate::picture::{TileCacheInstance, SliceId};
10 use crate::render_backend::DataStores;
11 use smallvec::SmallVec;
12
13 #[derive(Debug)]
14 pub struct PictureInfo {
15 pub update_pass: Option<usize>,
16 pub surface_index: Option<SurfaceIndex>,
17 pub parent: Option<PictureIndex>,
18 }
19
20 /// A graph of picture dependencies, allowing updates to be processed without recursion
21 /// by building a list of passes.
22 pub struct PictureGraph {
23 roots: Vec<PictureIndex>,
24 pic_info: Vec<PictureInfo>,
25 update_passes: Vec<Vec<PictureIndex>>,
26 }
27
28 impl PictureGraph {
new() -> Self29 pub fn new() -> Self {
30 PictureGraph {
31 roots: Vec::new(),
32 pic_info: Vec::new(),
33 update_passes: Vec::new(),
34 }
35 }
36
37 /// Add a root picture to the graph
add_root( &mut self, pic_index: PictureIndex, )38 pub fn add_root(
39 &mut self,
40 pic_index: PictureIndex,
41 ) {
42 self.roots.push(pic_index);
43 }
44
45 /// Build a list of update passes based on the dependencies between pictures
build_update_passes( &mut self, pictures: &mut [PicturePrimitive], frame_context: &FrameBuildingContext )46 pub fn build_update_passes(
47 &mut self,
48 pictures: &mut [PicturePrimitive],
49 frame_context: &FrameBuildingContext
50 ) {
51 self.pic_info.clear();
52 self.pic_info.reserve(pictures.len());
53
54 for _ in 0 .. pictures.len() {
55 self.pic_info.push(PictureInfo {
56 update_pass: None,
57 parent: None,
58 surface_index: None,
59 })
60 };
61
62 let mut max_pass_index = 0;
63
64 for pic_index in &self.roots {
65 assign_update_pass(
66 *pic_index,
67 None,
68 0,
69 pictures,
70 &mut self.pic_info,
71 &mut max_pass_index,
72 frame_context,
73 );
74 }
75
76 let pass_count = max_pass_index + 1;
77
78 self.update_passes.clear();
79 self.update_passes.resize_with(pass_count, Vec::new);
80
81 for (pic_index, info) in self.pic_info.iter().enumerate() {
82 if let Some(update_pass) = info.update_pass {
83 let pass = &mut self.update_passes[update_pass];
84 pass.push(PictureIndex(pic_index));
85 }
86 }
87 }
88
89 /// Assign surfaces and scale factors to each picture (root -> leaf ordered pass)
assign_surfaces( &mut self, pictures: &mut [PicturePrimitive], surfaces: &mut Vec<SurfaceInfo>, tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>, frame_context: &FrameBuildingContext, )90 pub fn assign_surfaces(
91 &mut self,
92 pictures: &mut [PicturePrimitive],
93 surfaces: &mut Vec<SurfaceInfo>,
94 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
95 frame_context: &FrameBuildingContext,
96 ) {
97 for pass in &self.update_passes {
98 for pic_index in pass {
99 let parent = self.pic_info[pic_index.0].parent;
100
101 let parent_surface_index = parent.map(|parent| {
102 // Can unwrap here as by the time we have a parent that parent's
103 // surface must have been assigned.
104 self.pic_info[parent.0].surface_index.unwrap()
105 });
106
107 let info = &mut self.pic_info[pic_index.0];
108
109 match pictures[pic_index.0].assign_surface(
110 frame_context,
111 parent_surface_index,
112 tile_caches,
113 surfaces,
114 ) {
115 Some(surface_index) => {
116 info.surface_index = Some(surface_index);
117 }
118 None => {
119 info.surface_index = Some(parent_surface_index.unwrap());
120 }
121 }
122 }
123 }
124 }
125
126 /// Propegate bounding rects from pictures to parents (leaf -> root ordered pass)
propagate_bounding_rects( &mut self, pictures: &mut [PicturePrimitive], surfaces: &mut [SurfaceInfo], frame_context: &FrameBuildingContext, data_stores: &mut DataStores, prim_instances: &mut Vec<PrimitiveInstance>, )127 pub fn propagate_bounding_rects(
128 &mut self,
129 pictures: &mut [PicturePrimitive],
130 surfaces: &mut [SurfaceInfo],
131 frame_context: &FrameBuildingContext,
132 data_stores: &mut DataStores,
133 prim_instances: &mut Vec<PrimitiveInstance>,
134 ) {
135 for pass in self.update_passes.iter().rev() {
136 for pic_index in pass {
137 let parent = self.pic_info[pic_index.0].parent;
138
139 let surface_index = self.pic_info[pic_index.0]
140 .surface_index
141 .expect("bug: no surface assigned during propagate_bounding_rects");
142
143 let parent_surface_index = parent.map(|parent| {
144 // Can unwrap here as by the time we have a parent that parent's
145 // surface must have been assigned.
146 self.pic_info[parent.0].surface_index.unwrap()
147 });
148
149 pictures[pic_index.0].propagate_bounding_rect(
150 surface_index,
151 parent_surface_index,
152 surfaces,
153 frame_context,
154 data_stores,
155 prim_instances,
156 );
157 }
158 }
159 }
160 }
161
162 /// Recursive function that assigns pictures to the earliest pass possible that they
163 /// can be processed in, while maintaining dependency ordering.
assign_update_pass( pic_index: PictureIndex, parent_pic_index: Option<PictureIndex>, pass: usize, pictures: &mut [PicturePrimitive], pic_info: &mut [PictureInfo], max_pass_index: &mut usize, frame_context: &FrameBuildingContext )164 fn assign_update_pass(
165 pic_index: PictureIndex,
166 parent_pic_index: Option<PictureIndex>,
167 pass: usize,
168 pictures: &mut [PicturePrimitive],
169 pic_info: &mut [PictureInfo],
170 max_pass_index: &mut usize,
171 frame_context: &FrameBuildingContext
172 ) {
173 let pic = &mut pictures[pic_index.0];
174 let info = &mut pic_info[pic_index.0];
175
176 info.parent = parent_pic_index;
177
178 // Run pre-update to resolve animation properties etc
179 pic.pre_update(frame_context);
180
181 let can_be_drawn = match info.update_pass {
182 Some(update_pass) => {
183 // No point in recursing into paths in the graph if this picture already
184 // has been set to update after this pass.
185 if update_pass > pass {
186 return;
187 }
188
189 true
190 }
191 None => {
192 // Check if this picture can be dropped from the graph we're building this frame
193 pic.is_visible(frame_context.spatial_tree)
194 }
195 };
196
197 if can_be_drawn {
198 info.update_pass = Some(pass);
199
200 *max_pass_index = pass.max(*max_pass_index);
201
202 let mut child_pictures: SmallVec<[PictureIndex; 8]> = SmallVec::new();
203 child_pictures.extend_from_slice(&pic.prim_list.child_pictures);
204
205 for child_pic_index in child_pictures {
206 assign_update_pass(
207 child_pic_index,
208 Some(pic_index),
209 pass + 1,
210 pictures,
211 pic_info,
212 max_pass_index,
213 frame_context,
214 );
215 }
216 }
217 }
218