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