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