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 //! The high-level module responsible for managing the pipeline and preparing 6 //! commands to be issued by the `Renderer`. 7 //! 8 //! See the comment at the top of the `renderer` module for a description of 9 //! how these two pieces interact. 10 11 use api::{DebugFlags, BlobImageHandler, Parameter, BoolParameter}; 12 use api::{DocumentId, ExternalScrollId, HitTestResult}; 13 use api::{IdNamespace, PipelineId, RenderNotifier, SampledScrollOffset}; 14 use api::{NotificationRequest, Checkpoint, QualitySettings}; 15 use api::{PrimitiveKeyKind, RenderReasons}; 16 use api::units::*; 17 use api::channel::{single_msg_channel, Sender, Receiver}; 18 #[cfg(any(feature = "capture", feature = "replay"))] 19 use crate::render_api::CaptureBits; 20 #[cfg(feature = "replay")] 21 use crate::render_api::CapturedDocument; 22 use crate::render_api::{MemoryReport, TransactionMsg, ResourceUpdate, ApiMsg, FrameMsg, ClearCache, DebugCommand}; 23 use crate::clip::{ClipIntern, PolygonIntern, ClipStoreScratchBuffer}; 24 use crate::filterdata::FilterDataIntern; 25 #[cfg(any(feature = "capture", feature = "replay"))] 26 use crate::capture::CaptureConfig; 27 use crate::composite::{CompositorKind, CompositeDescriptor}; 28 use crate::frame_builder::{FrameBuilder, FrameBuilderConfig, FrameScratchBuffer}; 29 use crate::glyph_rasterizer::{FontInstance}; 30 use crate::gpu_cache::GpuCache; 31 use crate::hit_test::{HitTest, HitTester, SharedHitTester}; 32 use crate::intern::DataStore; 33 #[cfg(any(feature = "capture", feature = "replay"))] 34 use crate::internal_types::{DebugOutput}; 35 use crate::internal_types::{FastHashMap, RenderedDocument, ResultMsg, FrameId, FrameStamp}; 36 use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; 37 use crate::picture::{PictureScratchBuffer, SliceId, TileCacheInstance, TileCacheParams, SurfaceInfo, RasterConfig}; 38 use crate::picture::{PicturePrimitive}; 39 use crate::prim_store::{PrimitiveScratchBuffer, PrimitiveInstance}; 40 use crate::prim_store::{PrimitiveInstanceKind, PrimTemplateCommonData}; 41 use crate::prim_store::interned::*; 42 use crate::profiler::{self, TransactionProfile}; 43 use crate::render_task_graph::RenderTaskGraphBuilder; 44 use crate::renderer::{AsyncPropertySampler, FullFrameStats, PipelineInfo}; 45 use crate::resource_cache::ResourceCache; 46 #[cfg(feature = "replay")] 47 use crate::resource_cache::PlainCacheOwn; 48 #[cfg(feature = "replay")] 49 use crate::resource_cache::PlainResources; 50 #[cfg(feature = "replay")] 51 use crate::scene::Scene; 52 use crate::scene::{BuiltScene, SceneProperties}; 53 use crate::scene_builder_thread::*; 54 use crate::spatial_tree::SpatialTree; 55 #[cfg(feature = "replay")] 56 use crate::spatial_tree::SceneSpatialTree; 57 #[cfg(feature = "serialize")] 58 use serde::{Serialize, Deserialize}; 59 #[cfg(feature = "replay")] 60 use std::collections::hash_map::Entry::{Occupied, Vacant}; 61 use std::sync::Arc; 62 use std::sync::atomic::{AtomicUsize, Ordering}; 63 use std::{mem, u32}; 64 #[cfg(feature = "capture")] 65 use std::path::PathBuf; 66 #[cfg(feature = "replay")] 67 use crate::frame_builder::Frame; 68 use time::precise_time_ns; 69 use crate::util::{Recycler, VecHelper, drain_filter}; 70 71 #[cfg_attr(feature = "capture", derive(Serialize))] 72 #[cfg_attr(feature = "replay", derive(Deserialize))] 73 #[derive(Copy, Clone)] 74 pub struct DocumentView { 75 scene: SceneView, 76 } 77 78 /// Some rendering parameters applying at the scene level. 79 #[cfg_attr(feature = "capture", derive(Serialize))] 80 #[cfg_attr(feature = "replay", derive(Deserialize))] 81 #[derive(Copy, Clone)] 82 pub struct SceneView { 83 pub device_rect: DeviceIntRect, 84 pub quality_settings: QualitySettings, 85 } 86 87 enum RenderBackendStatus { 88 Continue, 89 StopRenderBackend, 90 ShutDown(Option<Sender<()>>), 91 } 92 93 macro_rules! declare_data_stores { 94 ( $( $name:ident : $ty:ty, )+ ) => { 95 /// A collection of resources that are shared by clips, primitives 96 /// between display lists. 97 #[cfg_attr(feature = "capture", derive(Serialize))] 98 #[cfg_attr(feature = "replay", derive(Deserialize))] 99 #[derive(Default)] 100 pub struct DataStores { 101 $( 102 pub $name: DataStore<$ty>, 103 )+ 104 } 105 106 impl DataStores { 107 /// Reports CPU heap usage. 108 fn report_memory(&self, ops: &mut MallocSizeOfOps, r: &mut MemoryReport) { 109 $( 110 r.interning.data_stores.$name += self.$name.size_of(ops); 111 )+ 112 } 113 114 fn apply_updates( 115 &mut self, 116 updates: InternerUpdates, 117 profile: &mut TransactionProfile, 118 ) { 119 $( 120 self.$name.apply_updates( 121 updates.$name, 122 profile, 123 ); 124 )+ 125 } 126 } 127 } 128 } 129 130 crate::enumerate_interners!(declare_data_stores); 131 132 impl DataStores { 133 /// Returns the local rect for a primitive. For most primitives, this is 134 /// stored in the template. For pictures, this is stored inside the picture 135 /// primitive instance itself, since this is determined during frame building. get_local_prim_rect( &self, prim_instance: &PrimitiveInstance, pictures: &[PicturePrimitive], surfaces: &[SurfaceInfo], ) -> LayoutRect136 pub fn get_local_prim_rect( 137 &self, 138 prim_instance: &PrimitiveInstance, 139 pictures: &[PicturePrimitive], 140 surfaces: &[SurfaceInfo], 141 ) -> LayoutRect { 142 match prim_instance.kind { 143 PrimitiveInstanceKind::Picture { pic_index, .. } => { 144 let pic = &pictures[pic_index.0]; 145 146 match pic.raster_config { 147 Some(RasterConfig { surface_index, ref composite_mode, .. }) => { 148 let surface = &surfaces[surface_index.0]; 149 150 composite_mode.get_rect(surface, None) 151 } 152 None => { 153 panic!("bug: get_local_prim_rect should not be called for pass-through pictures"); 154 } 155 } 156 } 157 _ => { 158 self.as_common_data(prim_instance).prim_rect 159 } 160 } 161 } 162 163 /// Returns the local coverage (space occupied) for a primitive. For most primitives, 164 /// this is stored in the template. For pictures, this is stored inside the picture 165 /// primitive instance itself, since this is determined during frame building. get_local_prim_coverage_rect( &self, prim_instance: &PrimitiveInstance, pictures: &[PicturePrimitive], surfaces: &[SurfaceInfo], ) -> LayoutRect166 pub fn get_local_prim_coverage_rect( 167 &self, 168 prim_instance: &PrimitiveInstance, 169 pictures: &[PicturePrimitive], 170 surfaces: &[SurfaceInfo], 171 ) -> LayoutRect { 172 match prim_instance.kind { 173 PrimitiveInstanceKind::Picture { pic_index, .. } => { 174 let pic = &pictures[pic_index.0]; 175 176 match pic.raster_config { 177 Some(RasterConfig { surface_index, ref composite_mode, .. }) => { 178 let surface = &surfaces[surface_index.0]; 179 180 composite_mode.get_coverage(surface, None) 181 } 182 None => { 183 panic!("bug: get_local_prim_coverage_rect should not be called for pass-through pictures"); 184 } 185 } 186 } 187 _ => { 188 self.as_common_data(prim_instance).prim_rect 189 } 190 } 191 } 192 193 /// Returns true if this primitive might need repition. 194 // TODO(gw): This seems like the wrong place for this - maybe this flag should 195 // not be in the common prim template data? prim_may_need_repetition( &self, prim_instance: &PrimitiveInstance, ) -> bool196 pub fn prim_may_need_repetition( 197 &self, 198 prim_instance: &PrimitiveInstance, 199 ) -> bool { 200 match prim_instance.kind { 201 PrimitiveInstanceKind::Picture { .. } => { 202 false 203 } 204 _ => { 205 self.as_common_data(prim_instance).may_need_repetition 206 } 207 } 208 } 209 as_common_data( &self, prim_inst: &PrimitiveInstance ) -> &PrimTemplateCommonData210 pub fn as_common_data( 211 &self, 212 prim_inst: &PrimitiveInstance 213 ) -> &PrimTemplateCommonData { 214 match prim_inst.kind { 215 PrimitiveInstanceKind::Rectangle { data_handle, .. } | 216 PrimitiveInstanceKind::Clear { data_handle, .. } => { 217 let prim_data = &self.prim[data_handle]; 218 &prim_data.common 219 } 220 PrimitiveInstanceKind::Image { data_handle, .. } => { 221 let prim_data = &self.image[data_handle]; 222 &prim_data.common 223 } 224 PrimitiveInstanceKind::ImageBorder { data_handle, .. } => { 225 let prim_data = &self.image_border[data_handle]; 226 &prim_data.common 227 } 228 PrimitiveInstanceKind::LineDecoration { data_handle, .. } => { 229 let prim_data = &self.line_decoration[data_handle]; 230 &prim_data.common 231 } 232 PrimitiveInstanceKind::LinearGradient { data_handle, .. } 233 | PrimitiveInstanceKind::CachedLinearGradient { data_handle, .. } => { 234 let prim_data = &self.linear_grad[data_handle]; 235 &prim_data.common 236 } 237 PrimitiveInstanceKind::NormalBorder { data_handle, .. } => { 238 let prim_data = &self.normal_border[data_handle]; 239 &prim_data.common 240 } 241 PrimitiveInstanceKind::Picture { .. } => { 242 panic!("BUG: picture prims don't have common data!"); 243 } 244 PrimitiveInstanceKind::RadialGradient { data_handle, .. } => { 245 let prim_data = &self.radial_grad[data_handle]; 246 &prim_data.common 247 } 248 PrimitiveInstanceKind::ConicGradient { data_handle, .. } => { 249 let prim_data = &self.conic_grad[data_handle]; 250 &prim_data.common 251 } 252 PrimitiveInstanceKind::TextRun { data_handle, .. } => { 253 let prim_data = &self.text_run[data_handle]; 254 &prim_data.common 255 } 256 PrimitiveInstanceKind::YuvImage { data_handle, .. } => { 257 let prim_data = &self.yuv_image[data_handle]; 258 &prim_data.common 259 } 260 PrimitiveInstanceKind::Backdrop { data_handle, .. } => { 261 let prim_data = &self.backdrop[data_handle]; 262 &prim_data.common 263 } 264 } 265 } 266 } 267 268 #[derive(Default)] 269 pub struct ScratchBuffer { 270 pub primitive: PrimitiveScratchBuffer, 271 pub picture: PictureScratchBuffer, 272 pub frame: FrameScratchBuffer, 273 pub clip_store: ClipStoreScratchBuffer, 274 } 275 276 impl ScratchBuffer { begin_frame(&mut self)277 pub fn begin_frame(&mut self) { 278 self.primitive.begin_frame(); 279 self.picture.begin_frame(); 280 self.frame.begin_frame(); 281 } 282 end_frame(&mut self)283 pub fn end_frame(&mut self) { 284 self.primitive.end_frame(); 285 } 286 recycle(&mut self, recycler: &mut Recycler)287 pub fn recycle(&mut self, recycler: &mut Recycler) { 288 self.primitive.recycle(recycler); 289 self.picture.recycle(recycler); 290 } 291 memory_pressure(&mut self)292 pub fn memory_pressure(&mut self) { 293 // TODO: causes browser chrome test crashes on windows. 294 //self.primitive = Default::default(); 295 self.picture = Default::default(); 296 self.frame = Default::default(); 297 self.clip_store = Default::default(); 298 } 299 } 300 301 struct Document { 302 /// The id of this document 303 id: DocumentId, 304 305 /// Temporary list of removed pipelines received from the scene builder 306 /// thread and forwarded to the renderer. 307 removed_pipelines: Vec<(PipelineId, DocumentId)>, 308 309 view: DocumentView, 310 311 /// The id and time of the current frame. 312 stamp: FrameStamp, 313 314 /// The latest built scene, usable to build frames. 315 /// received from the scene builder thread. 316 scene: BuiltScene, 317 318 /// The builder object that prodces frames, kept around to preserve some retained state. 319 frame_builder: FrameBuilder, 320 321 /// Allows graphs of render tasks to be created, and then built into an immutable graph output. 322 rg_builder: RenderTaskGraphBuilder, 323 324 /// A data structure to allow hit testing against rendered frames. This is updated 325 /// every time we produce a fully rendered frame. 326 hit_tester: Option<Arc<HitTester>>, 327 /// To avoid synchronous messaging we update a shared hit-tester that other threads 328 /// can query. 329 shared_hit_tester: Arc<SharedHitTester>, 330 331 /// Properties that are resolved during frame building and can be changed at any time 332 /// without requiring the scene to be re-built. 333 dynamic_properties: SceneProperties, 334 335 /// Track whether the last built frame is up to date or if it will need to be re-built 336 /// before rendering again. 337 frame_is_valid: bool, 338 hit_tester_is_valid: bool, 339 rendered_frame_is_valid: bool, 340 /// We track this information to be able to display debugging information from the 341 /// renderer. 342 has_built_scene: bool, 343 344 data_stores: DataStores, 345 346 /// Retained frame-building version of the spatial tree 347 spatial_tree: SpatialTree, 348 349 /// Contains various vecs of data that is used only during frame building, 350 /// where we want to recycle the memory each new display list, to avoid constantly 351 /// re-allocating and moving memory around. 352 scratch: ScratchBuffer, 353 354 #[cfg(feature = "replay")] 355 loaded_scene: Scene, 356 357 /// Tracks the state of the picture cache tiles that were composited on the previous frame. 358 prev_composite_descriptor: CompositeDescriptor, 359 360 /// Tracks if we need to invalidate dirty rects for this document, due to the picture 361 /// cache slice configuration having changed when a new scene is swapped in. 362 dirty_rects_are_valid: bool, 363 364 profile: TransactionProfile, 365 frame_stats: Option<FullFrameStats>, 366 } 367 368 impl Document { new( id: DocumentId, size: DeviceIntSize, ) -> Self369 pub fn new( 370 id: DocumentId, 371 size: DeviceIntSize, 372 ) -> Self { 373 Document { 374 id, 375 removed_pipelines: Vec::new(), 376 view: DocumentView { 377 scene: SceneView { 378 device_rect: size.into(), 379 quality_settings: QualitySettings::default(), 380 }, 381 }, 382 stamp: FrameStamp::first(id), 383 scene: BuiltScene::empty(), 384 frame_builder: FrameBuilder::new(), 385 hit_tester: None, 386 shared_hit_tester: Arc::new(SharedHitTester::new()), 387 dynamic_properties: SceneProperties::new(), 388 frame_is_valid: false, 389 hit_tester_is_valid: false, 390 rendered_frame_is_valid: false, 391 has_built_scene: false, 392 data_stores: DataStores::default(), 393 spatial_tree: SpatialTree::new(), 394 scratch: ScratchBuffer::default(), 395 #[cfg(feature = "replay")] 396 loaded_scene: Scene::new(), 397 prev_composite_descriptor: CompositeDescriptor::empty(), 398 dirty_rects_are_valid: true, 399 profile: TransactionProfile::new(), 400 rg_builder: RenderTaskGraphBuilder::new(), 401 frame_stats: None, 402 } 403 } 404 can_render(&self) -> bool405 fn can_render(&self) -> bool { 406 self.scene.has_root_pipeline 407 } 408 has_pixels(&self) -> bool409 fn has_pixels(&self) -> bool { 410 !self.view.scene.device_rect.is_empty() 411 } 412 process_frame_msg( &mut self, message: FrameMsg, ) -> DocumentOps413 fn process_frame_msg( 414 &mut self, 415 message: FrameMsg, 416 ) -> DocumentOps { 417 match message { 418 FrameMsg::UpdateEpoch(pipeline_id, epoch) => { 419 self.scene.pipeline_epochs.insert(pipeline_id, epoch); 420 } 421 FrameMsg::HitTest(point, tx) => { 422 if !self.hit_tester_is_valid { 423 self.rebuild_hit_tester(); 424 } 425 426 let result = match self.hit_tester { 427 Some(ref hit_tester) => { 428 hit_tester.hit_test(HitTest::new(point)) 429 } 430 None => HitTestResult { items: Vec::new() }, 431 }; 432 433 tx.send(result).unwrap(); 434 } 435 FrameMsg::RequestHitTester(tx) => { 436 tx.send(self.shared_hit_tester.clone()).unwrap(); 437 } 438 FrameMsg::SetScrollOffsets(id, offset) => { 439 profile_scope!("SetScrollOffset"); 440 441 if self.set_scroll_offsets(id, offset) { 442 self.hit_tester_is_valid = false; 443 self.frame_is_valid = false; 444 } 445 446 return DocumentOps { 447 scroll: true, 448 ..DocumentOps::nop() 449 }; 450 } 451 FrameMsg::ResetDynamicProperties => { 452 self.dynamic_properties.reset_properties(); 453 } 454 FrameMsg::AppendDynamicProperties(property_bindings) => { 455 self.dynamic_properties.add_properties(property_bindings); 456 } 457 FrameMsg::AppendDynamicTransformProperties(property_bindings) => { 458 self.dynamic_properties.add_transforms(property_bindings); 459 } 460 FrameMsg::SetIsTransformAsyncZooming(is_zooming, animation_id) => { 461 if let Some(node_index) = self.spatial_tree.find_spatial_node_by_anim_id(animation_id) { 462 let node = self.spatial_tree.get_spatial_node_mut(node_index); 463 464 if node.is_async_zooming != is_zooming { 465 node.is_async_zooming = is_zooming; 466 self.frame_is_valid = false; 467 } 468 } 469 } 470 } 471 472 DocumentOps::nop() 473 } 474 build_frame( &mut self, resource_cache: &mut ResourceCache, gpu_cache: &mut GpuCache, debug_flags: DebugFlags, tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>, frame_stats: Option<FullFrameStats>, render_reasons: RenderReasons, ) -> RenderedDocument475 fn build_frame( 476 &mut self, 477 resource_cache: &mut ResourceCache, 478 gpu_cache: &mut GpuCache, 479 debug_flags: DebugFlags, 480 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>, 481 frame_stats: Option<FullFrameStats>, 482 render_reasons: RenderReasons, 483 ) -> RenderedDocument { 484 let frame_build_start_time = precise_time_ns(); 485 486 // Advance to the next frame. 487 self.stamp.advance(); 488 489 assert!(self.stamp.frame_id() != FrameId::INVALID, 490 "First frame increment must happen before build_frame()"); 491 492 let frame = { 493 let frame = self.frame_builder.build( 494 &mut self.scene, 495 resource_cache, 496 gpu_cache, 497 &mut self.rg_builder, 498 self.stamp, 499 self.view.scene.device_rect.min, 500 &self.dynamic_properties, 501 &mut self.data_stores, 502 &mut self.scratch, 503 debug_flags, 504 tile_caches, 505 &mut self.spatial_tree, 506 self.dirty_rects_are_valid, 507 &mut self.profile, 508 ); 509 510 frame 511 }; 512 513 self.frame_is_valid = true; 514 self.dirty_rects_are_valid = true; 515 516 let is_new_scene = self.has_built_scene; 517 self.has_built_scene = false; 518 519 let frame_build_time_ms = 520 profiler::ns_to_ms(precise_time_ns() - frame_build_start_time); 521 self.profile.set(profiler::FRAME_BUILDING_TIME, frame_build_time_ms); 522 523 let frame_stats = frame_stats.map(|mut stats| { 524 stats.frame_build_time += frame_build_time_ms; 525 stats 526 }); 527 528 RenderedDocument { 529 frame, 530 is_new_scene, 531 profile: self.profile.take_and_reset(), 532 frame_stats: frame_stats, 533 render_reasons, 534 } 535 } 536 rebuild_hit_tester(&mut self)537 fn rebuild_hit_tester(&mut self) { 538 self.spatial_tree.update_tree(&self.dynamic_properties); 539 540 let hit_tester = Arc::new(self.scene.create_hit_tester(&self.spatial_tree)); 541 self.hit_tester = Some(Arc::clone(&hit_tester)); 542 self.shared_hit_tester.update(hit_tester); 543 self.hit_tester_is_valid = true; 544 } 545 updated_pipeline_info(&mut self) -> PipelineInfo546 pub fn updated_pipeline_info(&mut self) -> PipelineInfo { 547 let removed_pipelines = self.removed_pipelines.take_and_preallocate(); 548 PipelineInfo { 549 epochs: self.scene.pipeline_epochs.iter() 550 .map(|(&pipeline_id, &epoch)| ((pipeline_id, self.id), epoch)).collect(), 551 removed_pipelines, 552 } 553 } 554 555 /// Returns true if the node actually changed position or false otherwise. set_scroll_offsets( &mut self, id: ExternalScrollId, offsets: Vec<SampledScrollOffset>, ) -> bool556 pub fn set_scroll_offsets( 557 &mut self, 558 id: ExternalScrollId, 559 offsets: Vec<SampledScrollOffset>, 560 ) -> bool { 561 self.spatial_tree.set_scroll_offsets(id, offsets) 562 } 563 564 /// Update the state of tile caches when a new scene is being swapped in to 565 /// the render backend. Retain / reuse existing caches if possible, and 566 /// destroy any now unused caches. update_tile_caches_for_new_scene( &mut self, mut requested_tile_caches: FastHashMap<SliceId, TileCacheParams>, tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>, resource_cache: &mut ResourceCache, )567 fn update_tile_caches_for_new_scene( 568 &mut self, 569 mut requested_tile_caches: FastHashMap<SliceId, TileCacheParams>, 570 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>, 571 resource_cache: &mut ResourceCache, 572 ) { 573 let mut new_tile_caches = FastHashMap::default(); 574 new_tile_caches.reserve(requested_tile_caches.len()); 575 576 // Step through the tile caches that are needed for the new scene, and see 577 // if we have an existing cache that can be reused. 578 for (slice_id, params) in requested_tile_caches.drain() { 579 let tile_cache = match tile_caches.remove(&slice_id) { 580 Some(mut existing_tile_cache) => { 581 // Found an existing cache - update the cache params and reuse it 582 existing_tile_cache.prepare_for_new_scene( 583 params, 584 resource_cache, 585 ); 586 existing_tile_cache 587 } 588 None => { 589 // No cache exists so create a new one 590 Box::new(TileCacheInstance::new(params)) 591 } 592 }; 593 594 new_tile_caches.insert(slice_id, tile_cache); 595 } 596 597 // Replace current tile cache map, and return what was left over, 598 // which are now unused. 599 let unused_tile_caches = mem::replace( 600 tile_caches, 601 new_tile_caches, 602 ); 603 604 if !unused_tile_caches.is_empty() { 605 // If the slice configuration changed, assume we can't rely on the 606 // current dirty rects for next composite 607 self.dirty_rects_are_valid = false; 608 609 // Destroy any native surfaces allocated by these unused caches 610 for (_, tile_cache) in unused_tile_caches { 611 tile_cache.destroy(resource_cache); 612 } 613 } 614 } 615 new_async_scene_ready( &mut self, mut built_scene: BuiltScene, recycler: &mut Recycler, tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>, resource_cache: &mut ResourceCache, )616 pub fn new_async_scene_ready( 617 &mut self, 618 mut built_scene: BuiltScene, 619 recycler: &mut Recycler, 620 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>, 621 resource_cache: &mut ResourceCache, 622 ) { 623 self.frame_is_valid = false; 624 self.hit_tester_is_valid = false; 625 626 self.update_tile_caches_for_new_scene( 627 mem::replace(&mut built_scene.tile_cache_config.tile_caches, FastHashMap::default()), 628 tile_caches, 629 resource_cache, 630 ); 631 632 self.scene = built_scene; 633 self.scratch.recycle(recycler); 634 } 635 } 636 637 struct DocumentOps { 638 scroll: bool, 639 } 640 641 impl DocumentOps { nop() -> Self642 fn nop() -> Self { 643 DocumentOps { 644 scroll: false, 645 } 646 } 647 } 648 649 /// The unique id for WR resource identification. 650 /// The namespace_id should start from 1. 651 static NEXT_NAMESPACE_ID: AtomicUsize = AtomicUsize::new(1); 652 653 #[cfg(any(feature = "capture", feature = "replay"))] 654 #[cfg_attr(feature = "capture", derive(Serialize))] 655 #[cfg_attr(feature = "replay", derive(Deserialize))] 656 struct PlainRenderBackend { 657 frame_config: FrameBuilderConfig, 658 documents: FastHashMap<DocumentId, DocumentView>, 659 resource_sequence_id: u32, 660 } 661 662 /// The render backend is responsible for transforming high level display lists into 663 /// GPU-friendly work which is then submitted to the renderer in the form of a frame::Frame. 664 /// 665 /// The render backend operates on its own thread. 666 pub struct RenderBackend { 667 api_rx: Receiver<ApiMsg>, 668 result_tx: Sender<ResultMsg>, 669 scene_tx: Sender<SceneBuilderRequest>, 670 671 gpu_cache: GpuCache, 672 resource_cache: ResourceCache, 673 674 frame_config: FrameBuilderConfig, 675 default_compositor_kind: CompositorKind, 676 documents: FastHashMap<DocumentId, Document>, 677 678 notifier: Box<dyn RenderNotifier>, 679 sampler: Option<Box<dyn AsyncPropertySampler + Send>>, 680 size_of_ops: Option<MallocSizeOfOps>, 681 debug_flags: DebugFlags, 682 namespace_alloc_by_client: bool, 683 684 // We keep one around to be able to call clear_namespace 685 // after the api object is deleted. For most purposes the 686 // api object's blob handler should be used instead. 687 blob_image_handler: Option<Box<dyn BlobImageHandler>>, 688 689 recycler: Recycler, 690 691 #[cfg(feature = "capture")] 692 /// If `Some`, do 'sequence capture' logging, recording updated documents, 693 /// frames, etc. This is set only through messages from the scene builder, 694 /// so all control of sequence capture goes through there. 695 capture_config: Option<CaptureConfig>, 696 697 #[cfg(feature = "replay")] 698 loaded_resource_sequence_id: u32, 699 700 /// A map of tile caches. These are stored in the backend as they are 701 /// persisted between both frame and scenes. 702 tile_caches: FastHashMap<SliceId, Box<TileCacheInstance>>, 703 } 704 705 impl RenderBackend { new( api_rx: Receiver<ApiMsg>, result_tx: Sender<ResultMsg>, scene_tx: Sender<SceneBuilderRequest>, resource_cache: ResourceCache, notifier: Box<dyn RenderNotifier>, blob_image_handler: Option<Box<dyn BlobImageHandler>>, frame_config: FrameBuilderConfig, sampler: Option<Box<dyn AsyncPropertySampler + Send>>, size_of_ops: Option<MallocSizeOfOps>, debug_flags: DebugFlags, namespace_alloc_by_client: bool, ) -> RenderBackend706 pub fn new( 707 api_rx: Receiver<ApiMsg>, 708 result_tx: Sender<ResultMsg>, 709 scene_tx: Sender<SceneBuilderRequest>, 710 resource_cache: ResourceCache, 711 notifier: Box<dyn RenderNotifier>, 712 blob_image_handler: Option<Box<dyn BlobImageHandler>>, 713 frame_config: FrameBuilderConfig, 714 sampler: Option<Box<dyn AsyncPropertySampler + Send>>, 715 size_of_ops: Option<MallocSizeOfOps>, 716 debug_flags: DebugFlags, 717 namespace_alloc_by_client: bool, 718 ) -> RenderBackend { 719 RenderBackend { 720 api_rx, 721 result_tx, 722 scene_tx, 723 resource_cache, 724 gpu_cache: GpuCache::new(), 725 frame_config, 726 default_compositor_kind : frame_config.compositor_kind, 727 documents: FastHashMap::default(), 728 notifier, 729 sampler, 730 size_of_ops, 731 debug_flags, 732 namespace_alloc_by_client, 733 recycler: Recycler::new(), 734 blob_image_handler, 735 #[cfg(feature = "capture")] 736 capture_config: None, 737 #[cfg(feature = "replay")] 738 loaded_resource_sequence_id: 0, 739 tile_caches: FastHashMap::default(), 740 } 741 } 742 next_namespace_id(&self) -> IdNamespace743 fn next_namespace_id(&self) -> IdNamespace { 744 IdNamespace(NEXT_NAMESPACE_ID.fetch_add(1, Ordering::Relaxed) as u32) 745 } 746 run(&mut self)747 pub fn run(&mut self) { 748 let mut frame_counter: u32 = 0; 749 let mut status = RenderBackendStatus::Continue; 750 751 if let Some(ref sampler) = self.sampler { 752 sampler.register(); 753 } 754 755 while let RenderBackendStatus::Continue = status { 756 status = match self.api_rx.recv() { 757 Ok(msg) => { 758 self.process_api_msg(msg, &mut frame_counter) 759 } 760 Err(..) => { RenderBackendStatus::ShutDown(None) } 761 }; 762 } 763 764 if let RenderBackendStatus::StopRenderBackend = status { 765 while let Ok(msg) = self.api_rx.recv() { 766 match msg { 767 ApiMsg::SceneBuilderResult(SceneBuilderResult::ExternalEvent(evt)) => { 768 self.notifier.external_event(evt); 769 } 770 ApiMsg::SceneBuilderResult(SceneBuilderResult::FlushComplete(tx)) => { 771 // If somebody's blocked waiting for a flush, how did they 772 // trigger the RB thread to shut down? This shouldn't happen 773 // but handle it gracefully anyway. 774 debug_assert!(false); 775 tx.send(()).ok(); 776 } 777 ApiMsg::SceneBuilderResult(SceneBuilderResult::ShutDown(sender)) => { 778 info!("Recycling stats: {:?}", self.recycler); 779 status = RenderBackendStatus::ShutDown(sender); 780 break; 781 } 782 _ => {}, 783 } 784 } 785 } 786 787 // Ensure we read everything the scene builder is sending us from 788 // inflight messages, otherwise the scene builder might panic. 789 while let Ok(msg) = self.api_rx.try_recv() { 790 match msg { 791 ApiMsg::SceneBuilderResult(SceneBuilderResult::FlushComplete(tx)) => { 792 // If somebody's blocked waiting for a flush, how did they 793 // trigger the RB thread to shut down? This shouldn't happen 794 // but handle it gracefully anyway. 795 debug_assert!(false); 796 tx.send(()).ok(); 797 } 798 _ => {}, 799 } 800 } 801 802 self.documents.clear(); 803 804 self.notifier.shut_down(); 805 806 if let Some(ref sampler) = self.sampler { 807 sampler.deregister(); 808 } 809 810 811 if let RenderBackendStatus::ShutDown(Some(sender)) = status { 812 let _ = sender.send(()); 813 } 814 } 815 process_transaction( &mut self, mut txns: Vec<Box<BuiltTransaction>>, result_tx: Option<Sender<SceneSwapResult>>, frame_counter: &mut u32, ) -> bool816 fn process_transaction( 817 &mut self, 818 mut txns: Vec<Box<BuiltTransaction>>, 819 result_tx: Option<Sender<SceneSwapResult>>, 820 frame_counter: &mut u32, 821 ) -> bool { 822 self.prepare_for_frames(); 823 self.maybe_force_nop_documents( 824 frame_counter, 825 |document_id| txns.iter().any(|txn| txn.document_id == document_id)); 826 827 let mut built_frame = false; 828 for mut txn in txns.drain(..) { 829 let has_built_scene = txn.built_scene.is_some(); 830 831 if let Some(doc) = self.documents.get_mut(&txn.document_id) { 832 doc.removed_pipelines.append(&mut txn.removed_pipelines); 833 doc.view.scene = txn.view; 834 doc.profile.merge(&mut txn.profile); 835 836 doc.frame_stats = if let Some(stats) = &doc.frame_stats { 837 Some(stats.merge(&txn.frame_stats)) 838 } else { 839 Some(txn.frame_stats) 840 }; 841 842 if let Some(updates) = txn.spatial_tree_updates.take() { 843 doc.spatial_tree.apply_updates(updates); 844 } 845 846 if let Some(built_scene) = txn.built_scene.take() { 847 doc.new_async_scene_ready( 848 built_scene, 849 &mut self.recycler, 850 &mut self.tile_caches, 851 &mut self.resource_cache, 852 ); 853 } 854 855 // If there are any additions or removals of clip modes 856 // during the scene build, apply them to the data store now. 857 // This needs to happen before we build the hit tester. 858 if let Some(updates) = txn.interner_updates.take() { 859 doc.data_stores.apply_updates(updates, &mut doc.profile); 860 } 861 862 // Build the hit tester while the APZ lock is held so that its content 863 // is in sync with the gecko APZ tree. 864 if !doc.hit_tester_is_valid { 865 doc.rebuild_hit_tester(); 866 } 867 868 if let Some(ref tx) = result_tx { 869 let (resume_tx, resume_rx) = single_msg_channel(); 870 tx.send(SceneSwapResult::Complete(resume_tx)).unwrap(); 871 // Block until the post-swap hook has completed on 872 // the scene builder thread. We need to do this before 873 // we can sample from the sampler hook which might happen 874 // in the update_document call below. 875 resume_rx.recv().ok(); 876 } 877 878 self.resource_cache.add_rasterized_blob_images( 879 txn.rasterized_blobs.take(), 880 &mut doc.profile, 881 ); 882 883 } else { 884 // The document was removed while we were building it, skip it. 885 // TODO: we might want to just ensure that removed documents are 886 // always forwarded to the scene builder thread to avoid this case. 887 if let Some(ref tx) = result_tx { 888 tx.send(SceneSwapResult::Aborted).unwrap(); 889 } 890 continue; 891 } 892 893 built_frame |= self.update_document( 894 txn.document_id, 895 txn.resource_updates.take(), 896 txn.frame_ops.take(), 897 txn.notifications.take(), 898 txn.render_frame, 899 RenderReasons::SCENE, 900 None, 901 txn.invalidate_rendered_frame, 902 frame_counter, 903 has_built_scene, 904 ); 905 } 906 907 built_frame 908 } 909 process_api_msg( &mut self, msg: ApiMsg, frame_counter: &mut u32, ) -> RenderBackendStatus910 fn process_api_msg( 911 &mut self, 912 msg: ApiMsg, 913 frame_counter: &mut u32, 914 ) -> RenderBackendStatus { 915 match msg { 916 ApiMsg::CloneApi(sender) => { 917 assert!(!self.namespace_alloc_by_client); 918 sender.send(self.next_namespace_id()).unwrap(); 919 } 920 ApiMsg::CloneApiByClient(namespace_id) => { 921 assert!(self.namespace_alloc_by_client); 922 debug_assert!(!self.documents.iter().any(|(did, _doc)| did.namespace_id == namespace_id)); 923 } 924 ApiMsg::AddDocument(document_id, initial_size) => { 925 let document = Document::new( 926 document_id, 927 initial_size, 928 ); 929 let old = self.documents.insert(document_id, document); 930 debug_assert!(old.is_none()); 931 } 932 ApiMsg::MemoryPressure => { 933 // This is drastic. It will basically flush everything out of the cache, 934 // and the next frame will have to rebuild all of its resources. 935 // We may want to look into something less extreme, but on the other hand this 936 // should only be used in situations where are running low enough on memory 937 // that we risk crashing if we don't do something about it. 938 // The advantage of clearing the cache completely is that it gets rid of any 939 // remaining fragmentation that could have persisted if we kept around the most 940 // recently used resources. 941 self.resource_cache.clear(ClearCache::all()); 942 943 self.gpu_cache.clear(); 944 945 for (_, doc) in &mut self.documents { 946 doc.scratch.memory_pressure(); 947 } 948 949 let resource_updates = self.resource_cache.pending_updates(); 950 let msg = ResultMsg::UpdateResources { 951 resource_updates, 952 memory_pressure: true, 953 }; 954 self.result_tx.send(msg).unwrap(); 955 self.notifier.wake_up(false); 956 } 957 ApiMsg::ReportMemory(tx) => { 958 self.report_memory(tx); 959 } 960 ApiMsg::DebugCommand(option) => { 961 let msg = match option { 962 DebugCommand::EnableDualSourceBlending(enable) => { 963 // Set in the config used for any future documents 964 // that are created. 965 self.frame_config 966 .dual_source_blending_is_enabled = enable; 967 self.update_frame_builder_config(); 968 969 // We don't want to forward this message to the renderer. 970 return RenderBackendStatus::Continue; 971 } 972 DebugCommand::SetPictureTileSize(tile_size) => { 973 self.frame_config.tile_size_override = tile_size; 974 self.update_frame_builder_config(); 975 976 return RenderBackendStatus::Continue; 977 } 978 #[cfg(feature = "capture")] 979 DebugCommand::SaveCapture(root, bits) => { 980 let output = self.save_capture(root, bits); 981 ResultMsg::DebugOutput(output) 982 }, 983 #[cfg(feature = "capture")] 984 DebugCommand::StartCaptureSequence(root, bits) => { 985 self.start_capture_sequence(root, bits); 986 return RenderBackendStatus::Continue; 987 }, 988 #[cfg(feature = "capture")] 989 DebugCommand::StopCaptureSequence => { 990 self.stop_capture_sequence(); 991 return RenderBackendStatus::Continue; 992 }, 993 #[cfg(feature = "replay")] 994 DebugCommand::LoadCapture(path, ids, tx) => { 995 NEXT_NAMESPACE_ID.fetch_add(1, Ordering::Relaxed); 996 *frame_counter += 1; 997 998 let mut config = CaptureConfig::new(path, CaptureBits::all()); 999 if let Some((scene_id, frame_id)) = ids { 1000 config.scene_id = scene_id; 1001 config.frame_id = frame_id; 1002 } 1003 1004 self.load_capture(config); 1005 1006 for (id, doc) in &self.documents { 1007 let captured = CapturedDocument { 1008 document_id: *id, 1009 root_pipeline_id: doc.loaded_scene.root_pipeline_id, 1010 }; 1011 tx.send(captured).unwrap(); 1012 } 1013 1014 // Note: we can't pass `LoadCapture` here since it needs to arrive 1015 // before the `PublishDocument` messages sent by `load_capture`. 1016 return RenderBackendStatus::Continue; 1017 } 1018 DebugCommand::ClearCaches(mask) => { 1019 self.resource_cache.clear(mask); 1020 return RenderBackendStatus::Continue; 1021 } 1022 DebugCommand::EnableNativeCompositor(enable) => { 1023 // Default CompositorKind should be Native 1024 if let CompositorKind::Draw { .. } = self.default_compositor_kind { 1025 unreachable!(); 1026 } 1027 1028 let compositor_kind = if enable { 1029 self.default_compositor_kind 1030 } else { 1031 CompositorKind::default() 1032 }; 1033 1034 for (_, doc) in &mut self.documents { 1035 doc.scene.config.compositor_kind = compositor_kind; 1036 doc.frame_is_valid = false; 1037 } 1038 1039 self.frame_config.compositor_kind = compositor_kind; 1040 self.update_frame_builder_config(); 1041 1042 // We don't want to forward this message to the renderer. 1043 return RenderBackendStatus::Continue; 1044 } 1045 DebugCommand::SetBatchingLookback(count) => { 1046 self.frame_config.batch_lookback_count = count as usize; 1047 self.update_frame_builder_config(); 1048 1049 return RenderBackendStatus::Continue; 1050 } 1051 DebugCommand::SimulateLongSceneBuild(time_ms) => { 1052 let _ = self.scene_tx.send(SceneBuilderRequest::SimulateLongSceneBuild(time_ms)); 1053 return RenderBackendStatus::Continue; 1054 } 1055 DebugCommand::SetFlags(flags) => { 1056 self.resource_cache.set_debug_flags(flags); 1057 self.gpu_cache.set_debug_flags(flags); 1058 1059 let force_invalidation = flags.contains(DebugFlags::FORCE_PICTURE_INVALIDATION); 1060 if self.frame_config.force_invalidation != force_invalidation { 1061 self.frame_config.force_invalidation = force_invalidation; 1062 self.update_frame_builder_config(); 1063 } 1064 1065 // If we're toggling on the GPU cache debug display, we 1066 // need to blow away the cache. This is because we only 1067 // send allocation/free notifications to the renderer 1068 // thread when the debug display is enabled, and thus 1069 // enabling it when the cache is partially populated will 1070 // give the renderer an incomplete view of the world. 1071 // And since we might as well drop all the debugging state 1072 // from the renderer when we disable the debug display, 1073 // we just clear the cache on toggle. 1074 let changed = self.debug_flags ^ flags; 1075 if changed.contains(DebugFlags::GPU_CACHE_DBG) { 1076 self.gpu_cache.clear(); 1077 } 1078 self.debug_flags = flags; 1079 1080 ResultMsg::DebugCommand(option) 1081 } 1082 _ => ResultMsg::DebugCommand(option), 1083 }; 1084 self.result_tx.send(msg).unwrap(); 1085 self.notifier.wake_up(true); 1086 } 1087 ApiMsg::UpdateDocuments(transaction_msgs) => { 1088 self.prepare_transactions( 1089 transaction_msgs, 1090 frame_counter, 1091 ); 1092 } 1093 ApiMsg::SceneBuilderResult(msg) => { 1094 return self.process_scene_builder_result(msg, frame_counter); 1095 } 1096 } 1097 1098 RenderBackendStatus::Continue 1099 } 1100 process_scene_builder_result( &mut self, msg: SceneBuilderResult, frame_counter: &mut u32, ) -> RenderBackendStatus1101 fn process_scene_builder_result( 1102 &mut self, 1103 msg: SceneBuilderResult, 1104 frame_counter: &mut u32, 1105 ) -> RenderBackendStatus { 1106 profile_scope!("sb_msg"); 1107 1108 match msg { 1109 SceneBuilderResult::Transactions(txns, result_tx) => { 1110 self.process_transaction( 1111 txns, 1112 result_tx, 1113 frame_counter, 1114 ); 1115 self.bookkeep_after_frames(); 1116 }, 1117 #[cfg(feature = "capture")] 1118 SceneBuilderResult::CapturedTransactions(txns, capture_config, result_tx) => { 1119 if let Some(ref mut old_config) = self.capture_config { 1120 assert!(old_config.scene_id <= capture_config.scene_id); 1121 if old_config.scene_id < capture_config.scene_id { 1122 old_config.scene_id = capture_config.scene_id; 1123 old_config.frame_id = 0; 1124 } 1125 } else { 1126 self.capture_config = Some(capture_config); 1127 } 1128 1129 let built_frame = self.process_transaction( 1130 txns, 1131 result_tx, 1132 frame_counter, 1133 ); 1134 1135 if built_frame { 1136 self.save_capture_sequence(); 1137 } 1138 1139 self.bookkeep_after_frames(); 1140 }, 1141 #[cfg(feature = "capture")] 1142 SceneBuilderResult::StopCaptureSequence => { 1143 self.capture_config = None; 1144 } 1145 SceneBuilderResult::GetGlyphDimensions(request) => { 1146 let mut glyph_dimensions = Vec::with_capacity(request.glyph_indices.len()); 1147 if let Some(base) = self.resource_cache.get_font_instance(request.key) { 1148 let font = FontInstance::from_base(Arc::clone(&base)); 1149 for glyph_index in &request.glyph_indices { 1150 let glyph_dim = self.resource_cache.get_glyph_dimensions(&font, *glyph_index); 1151 glyph_dimensions.push(glyph_dim); 1152 } 1153 } 1154 request.sender.send(glyph_dimensions).unwrap(); 1155 } 1156 SceneBuilderResult::GetGlyphIndices(request) => { 1157 let mut glyph_indices = Vec::with_capacity(request.text.len()); 1158 for ch in request.text.chars() { 1159 let index = self.resource_cache.get_glyph_index(request.key, ch); 1160 glyph_indices.push(index); 1161 } 1162 request.sender.send(glyph_indices).unwrap(); 1163 } 1164 SceneBuilderResult::FlushComplete(tx) => { 1165 tx.send(()).ok(); 1166 } 1167 SceneBuilderResult::ExternalEvent(evt) => { 1168 self.notifier.external_event(evt); 1169 } 1170 SceneBuilderResult::ClearNamespace(id) => { 1171 self.resource_cache.clear_namespace(id); 1172 self.documents.retain(|doc_id, _doc| doc_id.namespace_id != id); 1173 if let Some(handler) = &mut self.blob_image_handler { 1174 handler.clear_namespace(id); 1175 } 1176 } 1177 SceneBuilderResult::DeleteDocument(document_id) => { 1178 self.documents.remove(&document_id); 1179 } 1180 SceneBuilderResult::SetParameter(param) => { 1181 if let Parameter::Bool(BoolParameter::Multithreading, enabled) = param { 1182 self.resource_cache.enable_multithreading(enabled); 1183 } 1184 let _ = self.result_tx.send(ResultMsg::SetParameter(param)); 1185 } 1186 SceneBuilderResult::StopRenderBackend => { 1187 return RenderBackendStatus::StopRenderBackend; 1188 } 1189 SceneBuilderResult::ShutDown(sender) => { 1190 info!("Recycling stats: {:?}", self.recycler); 1191 return RenderBackendStatus::ShutDown(sender); 1192 } 1193 } 1194 1195 RenderBackendStatus::Continue 1196 } 1197 update_frame_builder_config(&self)1198 fn update_frame_builder_config(&self) { 1199 self.send_backend_message( 1200 SceneBuilderRequest::SetFrameBuilderConfig( 1201 self.frame_config.clone() 1202 ) 1203 ); 1204 } 1205 prepare_for_frames(&mut self)1206 fn prepare_for_frames(&mut self) { 1207 self.gpu_cache.prepare_for_frames(); 1208 } 1209 bookkeep_after_frames(&mut self)1210 fn bookkeep_after_frames(&mut self) { 1211 self.gpu_cache.bookkeep_after_frames(); 1212 } 1213 requires_frame_build(&mut self) -> bool1214 fn requires_frame_build(&mut self) -> bool { 1215 self.gpu_cache.requires_frame_build() 1216 } 1217 prepare_transactions( &mut self, txns: Vec<Box<TransactionMsg>>, frame_counter: &mut u32, )1218 fn prepare_transactions( 1219 &mut self, 1220 txns: Vec<Box<TransactionMsg>>, 1221 frame_counter: &mut u32, 1222 ) { 1223 self.prepare_for_frames(); 1224 self.maybe_force_nop_documents( 1225 frame_counter, 1226 |document_id| txns.iter().any(|txn| txn.document_id == document_id)); 1227 1228 let mut built_frame = false; 1229 for mut txn in txns { 1230 if txn.generate_frame.as_bool() { 1231 txn.profile.end_time(profiler::API_SEND_TIME); 1232 } 1233 1234 self.documents.get_mut(&txn.document_id).unwrap().profile.merge(&mut txn.profile); 1235 1236 built_frame |= self.update_document( 1237 txn.document_id, 1238 txn.resource_updates.take(), 1239 txn.frame_ops.take(), 1240 txn.notifications.take(), 1241 txn.generate_frame.as_bool(), 1242 txn.render_reasons, 1243 txn.generate_frame.id(), 1244 txn.invalidate_rendered_frame, 1245 frame_counter, 1246 false 1247 ); 1248 } 1249 if built_frame { 1250 #[cfg(feature = "capture")] 1251 self.save_capture_sequence(); 1252 } 1253 self.bookkeep_after_frames(); 1254 } 1255 1256 /// In certain cases, resources shared by multiple documents have to run 1257 /// maintenance operations, like cleaning up unused cache items. In those 1258 /// cases, we are forced to build frames for all documents, however we 1259 /// may not have a transaction ready for every document - this method 1260 /// calls update_document with the details of a fake, nop transaction just 1261 /// to force a frame build. maybe_force_nop_documents<F>(&mut self, frame_counter: &mut u32, document_already_present: F) where F: Fn(DocumentId) -> bool1262 fn maybe_force_nop_documents<F>(&mut self, 1263 frame_counter: &mut u32, 1264 document_already_present: F) where 1265 F: Fn(DocumentId) -> bool { 1266 if self.requires_frame_build() { 1267 let nop_documents : Vec<DocumentId> = self.documents.keys() 1268 .cloned() 1269 .filter(|key| !document_already_present(*key)) 1270 .collect(); 1271 #[allow(unused_variables)] 1272 let mut built_frame = false; 1273 for &document_id in &nop_documents { 1274 built_frame |= self.update_document( 1275 document_id, 1276 Vec::default(), 1277 Vec::default(), 1278 Vec::default(), 1279 false, 1280 RenderReasons::empty(), 1281 None, 1282 false, 1283 frame_counter, 1284 false); 1285 } 1286 #[cfg(feature = "capture")] 1287 match built_frame { 1288 true => self.save_capture_sequence(), 1289 _ => {}, 1290 } 1291 } 1292 } 1293 update_document( &mut self, document_id: DocumentId, resource_updates: Vec<ResourceUpdate>, mut frame_ops: Vec<FrameMsg>, mut notifications: Vec<NotificationRequest>, mut render_frame: bool, render_reasons: RenderReasons, generated_frame_id: Option<u64>, invalidate_rendered_frame: bool, frame_counter: &mut u32, has_built_scene: bool, ) -> bool1294 fn update_document( 1295 &mut self, 1296 document_id: DocumentId, 1297 resource_updates: Vec<ResourceUpdate>, 1298 mut frame_ops: Vec<FrameMsg>, 1299 mut notifications: Vec<NotificationRequest>, 1300 mut render_frame: bool, 1301 render_reasons: RenderReasons, 1302 generated_frame_id: Option<u64>, 1303 invalidate_rendered_frame: bool, 1304 frame_counter: &mut u32, 1305 has_built_scene: bool, 1306 ) -> bool { 1307 let requested_frame = render_frame; 1308 1309 let requires_frame_build = self.requires_frame_build(); 1310 let doc = self.documents.get_mut(&document_id).unwrap(); 1311 1312 // If we have a sampler, get more frame ops from it and add them 1313 // to the transaction. This is a hook to allow the WR user code to 1314 // fiddle with things after a potentially long scene build, but just 1315 // before rendering. This is useful for rendering with the latest 1316 // async transforms. 1317 if requested_frame { 1318 if let Some(ref sampler) = self.sampler { 1319 frame_ops.append(&mut sampler.sample(document_id, generated_frame_id)); 1320 } 1321 } 1322 1323 doc.has_built_scene |= has_built_scene; 1324 1325 // TODO: this scroll variable doesn't necessarily mean we scrolled. It is only used 1326 // for something wrench specific and we should remove it. 1327 let mut scroll = false; 1328 for frame_msg in frame_ops { 1329 let op = doc.process_frame_msg(frame_msg); 1330 scroll |= op.scroll; 1331 } 1332 1333 for update in &resource_updates { 1334 if let ResourceUpdate::UpdateImage(..) = update { 1335 doc.frame_is_valid = false; 1336 } 1337 } 1338 1339 self.resource_cache.post_scene_building_update( 1340 resource_updates, 1341 &mut doc.profile, 1342 ); 1343 1344 if doc.dynamic_properties.flush_pending_updates() { 1345 doc.frame_is_valid = false; 1346 doc.hit_tester_is_valid = false; 1347 } 1348 1349 if !doc.can_render() { 1350 // TODO: this happens if we are building the first scene asynchronously and 1351 // scroll at the same time. we should keep track of the fact that we skipped 1352 // composition here and do it as soon as we receive the scene. 1353 render_frame = false; 1354 } 1355 1356 // Avoid re-building the frame if the current built frame is still valid. 1357 // However, if the resource_cache requires a frame build, _always_ do that, unless 1358 // doc.can_render() is false, as in that case a frame build can't happen anyway. 1359 // We want to ensure we do this because even if the doc doesn't have pixels it 1360 // can still try to access stale texture cache items. 1361 let build_frame = (render_frame && !doc.frame_is_valid && doc.has_pixels()) || 1362 (requires_frame_build && doc.can_render()); 1363 1364 // Request composite is true when we want to composite frame even when 1365 // there is no frame update. This happens when video frame is updated under 1366 // external image with NativeTexture or when platform requested to composite frame. 1367 if invalidate_rendered_frame { 1368 doc.rendered_frame_is_valid = false; 1369 if doc.scene.config.compositor_kind.should_redraw_on_invalidation() { 1370 let msg = ResultMsg::ForceRedraw; 1371 self.result_tx.send(msg).unwrap(); 1372 } 1373 } 1374 1375 let mut frame_build_time = None; 1376 if build_frame { 1377 profile_scope!("generate frame"); 1378 1379 *frame_counter += 1; 1380 1381 // borrow ck hack for profile_counters 1382 let (pending_update, mut rendered_document) = { 1383 let frame_build_start_time = precise_time_ns(); 1384 1385 let frame_stats = doc.frame_stats.take(); 1386 1387 let rendered_document = doc.build_frame( 1388 &mut self.resource_cache, 1389 &mut self.gpu_cache, 1390 self.debug_flags, 1391 &mut self.tile_caches, 1392 frame_stats, 1393 render_reasons, 1394 ); 1395 1396 debug!("generated frame for document {:?} with {} passes", 1397 document_id, rendered_document.frame.passes.len()); 1398 1399 let msg = ResultMsg::UpdateGpuCache(self.gpu_cache.extract_updates()); 1400 self.result_tx.send(msg).unwrap(); 1401 1402 frame_build_time = Some(precise_time_ns() - frame_build_start_time); 1403 1404 let pending_update = self.resource_cache.pending_updates(); 1405 (pending_update, rendered_document) 1406 }; 1407 1408 // Invalidate dirty rects if the compositing config has changed significantly 1409 rendered_document 1410 .frame 1411 .composite_state 1412 .update_dirty_rect_validity(&doc.prev_composite_descriptor); 1413 1414 // Build a small struct that represents the state of the tiles to be composited. 1415 let composite_descriptor = rendered_document 1416 .frame 1417 .composite_state 1418 .descriptor 1419 .clone(); 1420 1421 // If there are texture cache updates to apply, or if the produced 1422 // frame is not a no-op, or the compositor state has changed, 1423 // then we cannot skip compositing this frame. 1424 if !pending_update.is_nop() || 1425 !rendered_document.frame.is_nop() || 1426 composite_descriptor != doc.prev_composite_descriptor { 1427 doc.rendered_frame_is_valid = false; 1428 } 1429 doc.prev_composite_descriptor = composite_descriptor; 1430 1431 #[cfg(feature = "capture")] 1432 match self.capture_config { 1433 Some(ref mut config) => { 1434 // FIXME(aosmond): document splitting causes multiple prepare frames 1435 config.prepare_frame(); 1436 1437 if config.bits.contains(CaptureBits::FRAME) { 1438 let file_name = format!("frame-{}-{}", document_id.namespace_id.0, document_id.id); 1439 config.serialize_for_frame(&rendered_document.frame, file_name); 1440 } 1441 1442 let data_stores_name = format!("data-stores-{}-{}", document_id.namespace_id.0, document_id.id); 1443 config.serialize_for_frame(&doc.data_stores, data_stores_name); 1444 1445 let frame_spatial_tree_name = format!("frame-spatial-tree-{}-{}", document_id.namespace_id.0, document_id.id); 1446 config.serialize_for_frame::<SpatialTree, _>(&doc.spatial_tree, frame_spatial_tree_name); 1447 1448 let properties_name = format!("properties-{}-{}", document_id.namespace_id.0, document_id.id); 1449 config.serialize_for_frame(&doc.dynamic_properties, properties_name); 1450 }, 1451 None => {}, 1452 } 1453 1454 let msg = ResultMsg::PublishPipelineInfo(doc.updated_pipeline_info()); 1455 self.result_tx.send(msg).unwrap(); 1456 1457 // Publish the frame 1458 let msg = ResultMsg::PublishDocument( 1459 document_id, 1460 rendered_document, 1461 pending_update, 1462 ); 1463 self.result_tx.send(msg).unwrap(); 1464 } else if requested_frame { 1465 // WR-internal optimization to avoid doing a bunch of render work if 1466 // there's no pixels. We still want to pretend to render and request 1467 // a render to make sure that the callbacks (particularly the 1468 // new_frame_ready callback below) has the right flags. 1469 let msg = ResultMsg::PublishPipelineInfo(doc.updated_pipeline_info()); 1470 self.result_tx.send(msg).unwrap(); 1471 } 1472 1473 drain_filter( 1474 &mut notifications, 1475 |n| { n.when() == Checkpoint::FrameBuilt }, 1476 |n| { n.notify(); }, 1477 ); 1478 1479 if !notifications.is_empty() { 1480 self.result_tx.send(ResultMsg::AppendNotificationRequests(notifications)).unwrap(); 1481 } 1482 1483 // Always forward the transaction to the renderer if a frame was requested, 1484 // otherwise gecko can get into a state where it waits (forever) for the 1485 // transaction to complete before sending new work. 1486 if requested_frame { 1487 // If rendered frame is already valid, there is no need to render frame. 1488 if doc.rendered_frame_is_valid { 1489 render_frame = false; 1490 } else if render_frame { 1491 doc.rendered_frame_is_valid = true; 1492 } 1493 self.notifier.new_frame_ready(document_id, scroll, render_frame, frame_build_time); 1494 } 1495 1496 if !doc.hit_tester_is_valid { 1497 doc.rebuild_hit_tester(); 1498 } 1499 1500 build_frame 1501 } 1502 send_backend_message(&self, msg: SceneBuilderRequest)1503 fn send_backend_message(&self, msg: SceneBuilderRequest) { 1504 self.scene_tx.send(msg).unwrap(); 1505 } 1506 report_memory(&mut self, tx: Sender<Box<MemoryReport>>)1507 fn report_memory(&mut self, tx: Sender<Box<MemoryReport>>) { 1508 let mut report = Box::new(MemoryReport::default()); 1509 let ops = self.size_of_ops.as_mut().unwrap(); 1510 let op = ops.size_of_op; 1511 report.gpu_cache_metadata = self.gpu_cache.size_of(ops); 1512 for doc in self.documents.values() { 1513 report.clip_stores += doc.scene.clip_store.size_of(ops); 1514 report.hit_testers += match &doc.hit_tester { 1515 Some(hit_tester) => hit_tester.size_of(ops), 1516 None => 0, 1517 }; 1518 1519 doc.data_stores.report_memory(ops, &mut report) 1520 } 1521 1522 (*report) += self.resource_cache.report_memory(op); 1523 report.texture_cache_structures = self.resource_cache 1524 .texture_cache 1525 .report_memory(ops); 1526 1527 // Send a message to report memory on the scene-builder thread, which 1528 // will add its report to this one and send the result back to the original 1529 // thread waiting on the request. 1530 self.send_backend_message( 1531 SceneBuilderRequest::ReportMemory(report, tx) 1532 ); 1533 } 1534 1535 #[cfg(feature = "capture")] save_capture_sequence(&mut self)1536 fn save_capture_sequence(&mut self) { 1537 if let Some(ref mut config) = self.capture_config { 1538 let deferred = self.resource_cache.save_capture_sequence(config); 1539 1540 let backend = PlainRenderBackend { 1541 frame_config: self.frame_config.clone(), 1542 resource_sequence_id: config.resource_id, 1543 documents: self.documents 1544 .iter() 1545 .map(|(id, doc)| (*id, doc.view)) 1546 .collect(), 1547 }; 1548 config.serialize_for_frame(&backend, "backend"); 1549 1550 if !deferred.is_empty() { 1551 let msg = ResultMsg::DebugOutput(DebugOutput::SaveCapture(config.clone(), deferred)); 1552 self.result_tx.send(msg).unwrap(); 1553 } 1554 } 1555 } 1556 } 1557 1558 impl RenderBackend { 1559 #[cfg(feature = "capture")] 1560 // Note: the mutable `self` is only needed here for resolving blob images save_capture( &mut self, root: PathBuf, bits: CaptureBits, ) -> DebugOutput1561 fn save_capture( 1562 &mut self, 1563 root: PathBuf, 1564 bits: CaptureBits, 1565 ) -> DebugOutput { 1566 use std::fs; 1567 use crate::render_task_graph::dump_render_tasks_as_svg; 1568 1569 debug!("capture: saving {:?}", root); 1570 if !root.is_dir() { 1571 if let Err(e) = fs::create_dir_all(&root) { 1572 panic!("Unable to create capture dir: {:?}", e); 1573 } 1574 } 1575 let config = CaptureConfig::new(root, bits); 1576 1577 if config.bits.contains(CaptureBits::FRAME) { 1578 self.prepare_for_frames(); 1579 } 1580 1581 for (&id, doc) in &mut self.documents { 1582 debug!("\tdocument {:?}", id); 1583 if config.bits.contains(CaptureBits::FRAME) { 1584 let rendered_document = doc.build_frame( 1585 &mut self.resource_cache, 1586 &mut self.gpu_cache, 1587 self.debug_flags, 1588 &mut self.tile_caches, 1589 None, 1590 RenderReasons::empty(), 1591 ); 1592 // After we rendered the frames, there are pending updates to both 1593 // GPU cache and resources. Instead of serializing them, we are going to make sure 1594 // they are applied on the `Renderer` side. 1595 let msg_update_gpu_cache = ResultMsg::UpdateGpuCache(self.gpu_cache.extract_updates()); 1596 self.result_tx.send(msg_update_gpu_cache).unwrap(); 1597 //TODO: write down doc's pipeline info? 1598 // it has `pipeline_epoch_map`, 1599 // which may capture necessary details for some cases. 1600 let file_name = format!("frame-{}-{}", id.namespace_id.0, id.id); 1601 config.serialize_for_frame(&rendered_document.frame, file_name); 1602 let file_name = format!("spatial-{}-{}", id.namespace_id.0, id.id); 1603 config.serialize_tree_for_frame(&doc.spatial_tree, file_name); 1604 let file_name = format!("built-primitives-{}-{}", id.namespace_id.0, id.id); 1605 config.serialize_for_frame(&doc.scene.prim_store, file_name); 1606 let file_name = format!("built-clips-{}-{}", id.namespace_id.0, id.id); 1607 config.serialize_for_frame(&doc.scene.clip_store, file_name); 1608 let file_name = format!("scratch-{}-{}", id.namespace_id.0, id.id); 1609 config.serialize_for_frame(&doc.scratch.primitive, file_name); 1610 let file_name = format!("render-tasks-{}-{}.svg", id.namespace_id.0, id.id); 1611 let mut render_tasks_file = fs::File::create(&config.file_path_for_frame(file_name, "svg")) 1612 .expect("Failed to open the SVG file."); 1613 dump_render_tasks_as_svg( 1614 &rendered_document.frame.render_tasks, 1615 &mut render_tasks_file 1616 ).unwrap(); 1617 1618 let file_name = format!("texture-cache-color-linear-{}-{}.svg", id.namespace_id.0, id.id); 1619 let mut texture_file = fs::File::create(&config.file_path_for_frame(file_name, "svg")) 1620 .expect("Failed to open the SVG file."); 1621 self.resource_cache.texture_cache.dump_color8_linear_as_svg(&mut texture_file).unwrap(); 1622 1623 let file_name = format!("texture-cache-color8-glyphs-{}-{}.svg", id.namespace_id.0, id.id); 1624 let mut texture_file = fs::File::create(&config.file_path_for_frame(file_name, "svg")) 1625 .expect("Failed to open the SVG file."); 1626 self.resource_cache.texture_cache.dump_color8_glyphs_as_svg(&mut texture_file).unwrap(); 1627 1628 let file_name = format!("texture-cache-alpha8-glyphs-{}-{}.svg", id.namespace_id.0, id.id); 1629 let mut texture_file = fs::File::create(&config.file_path_for_frame(file_name, "svg")) 1630 .expect("Failed to open the SVG file."); 1631 self.resource_cache.texture_cache.dump_alpha8_glyphs_as_svg(&mut texture_file).unwrap(); 1632 1633 let file_name = format!("texture-cache-alpha8-linear-{}-{}.svg", id.namespace_id.0, id.id); 1634 let mut texture_file = fs::File::create(&config.file_path_for_frame(file_name, "svg")) 1635 .expect("Failed to open the SVG file."); 1636 self.resource_cache.texture_cache.dump_alpha8_linear_as_svg(&mut texture_file).unwrap(); 1637 } 1638 1639 let data_stores_name = format!("data-stores-{}-{}", id.namespace_id.0, id.id); 1640 config.serialize_for_frame(&doc.data_stores, data_stores_name); 1641 1642 let frame_spatial_tree_name = format!("frame-spatial-tree-{}-{}", id.namespace_id.0, id.id); 1643 config.serialize_for_frame::<SpatialTree, _>(&doc.spatial_tree, frame_spatial_tree_name); 1644 1645 let properties_name = format!("properties-{}-{}", id.namespace_id.0, id.id); 1646 config.serialize_for_frame(&doc.dynamic_properties, properties_name); 1647 } 1648 1649 if config.bits.contains(CaptureBits::FRAME) { 1650 // TODO: there is no guarantee that we won't hit this case, but we want to 1651 // report it here if we do. If we don't, it will simply crash in 1652 // Renderer::render_impl and give us less information about the source. 1653 assert!(!self.requires_frame_build(), "Caches were cleared during a capture."); 1654 self.bookkeep_after_frames(); 1655 } 1656 1657 debug!("\tscene builder"); 1658 self.send_backend_message( 1659 SceneBuilderRequest::SaveScene(config.clone()) 1660 ); 1661 1662 debug!("\tresource cache"); 1663 let (resources, deferred) = self.resource_cache.save_capture(&config.root); 1664 1665 info!("\tbackend"); 1666 let backend = PlainRenderBackend { 1667 frame_config: self.frame_config.clone(), 1668 resource_sequence_id: 0, 1669 documents: self.documents 1670 .iter() 1671 .map(|(id, doc)| (*id, doc.view)) 1672 .collect(), 1673 }; 1674 1675 config.serialize_for_frame(&backend, "backend"); 1676 config.serialize_for_frame(&resources, "plain-resources"); 1677 1678 if config.bits.contains(CaptureBits::FRAME) { 1679 let msg_update_resources = ResultMsg::UpdateResources { 1680 resource_updates: self.resource_cache.pending_updates(), 1681 memory_pressure: false, 1682 }; 1683 self.result_tx.send(msg_update_resources).unwrap(); 1684 // Save the texture/glyph/image caches. 1685 info!("\tresource cache"); 1686 let caches = self.resource_cache.save_caches(&config.root); 1687 config.serialize_for_resource(&caches, "resource_cache"); 1688 info!("\tgpu cache"); 1689 config.serialize_for_resource(&self.gpu_cache, "gpu_cache"); 1690 } 1691 1692 DebugOutput::SaveCapture(config, deferred) 1693 } 1694 1695 #[cfg(feature = "capture")] start_capture_sequence( &mut self, root: PathBuf, bits: CaptureBits, )1696 fn start_capture_sequence( 1697 &mut self, 1698 root: PathBuf, 1699 bits: CaptureBits, 1700 ) { 1701 self.send_backend_message( 1702 SceneBuilderRequest::StartCaptureSequence(CaptureConfig::new(root, bits)) 1703 ); 1704 } 1705 1706 #[cfg(feature = "capture")] stop_capture_sequence( &mut self, )1707 fn stop_capture_sequence( 1708 &mut self, 1709 ) { 1710 self.send_backend_message( 1711 SceneBuilderRequest::StopCaptureSequence 1712 ); 1713 } 1714 1715 #[cfg(feature = "replay")] load_capture( &mut self, mut config: CaptureConfig, )1716 fn load_capture( 1717 &mut self, 1718 mut config: CaptureConfig, 1719 ) { 1720 debug!("capture: loading {:?}", config.frame_root()); 1721 let backend = config.deserialize_for_frame::<PlainRenderBackend, _>("backend") 1722 .expect("Unable to open backend.ron"); 1723 1724 // If this is a capture sequence, then the ID will be non-zero, and won't 1725 // match what is loaded, but for still captures, the ID will be zero. 1726 let first_load = backend.resource_sequence_id == 0; 1727 if self.loaded_resource_sequence_id != backend.resource_sequence_id || first_load { 1728 // FIXME(aosmond): We clear the documents because when we update the 1729 // resource cache, we actually wipe and reload, because we don't 1730 // know what is the same and what has changed. If we were to keep as 1731 // much of the resource cache state as possible, we could avoid 1732 // flushing the document state (which has its own dependecies on the 1733 // cache). 1734 // 1735 // FIXME(aosmond): If we try to load the next capture in the 1736 // sequence too quickly, we may lose resources we depend on in the 1737 // current frame. This can cause panics. Ideally we would not 1738 // advance to the next frame until the FrameRendered event for all 1739 // of the pipelines. 1740 self.documents.clear(); 1741 1742 config.resource_id = backend.resource_sequence_id; 1743 self.loaded_resource_sequence_id = backend.resource_sequence_id; 1744 1745 let plain_resources = config.deserialize_for_resource::<PlainResources, _>("plain-resources") 1746 .expect("Unable to open plain-resources.ron"); 1747 let caches_maybe = config.deserialize_for_resource::<PlainCacheOwn, _>("resource_cache"); 1748 1749 // Note: it would be great to have `RenderBackend` to be split 1750 // rather explicitly on what's used before and after scene building 1751 // so that, for example, we never miss anything in the code below: 1752 1753 let plain_externals = self.resource_cache.load_capture( 1754 plain_resources, 1755 caches_maybe, 1756 &config, 1757 ); 1758 1759 let msg_load = ResultMsg::DebugOutput( 1760 DebugOutput::LoadCapture(config.clone(), plain_externals) 1761 ); 1762 self.result_tx.send(msg_load).unwrap(); 1763 1764 self.gpu_cache = match config.deserialize_for_resource::<GpuCache, _>("gpu_cache") { 1765 Some(gpu_cache) => gpu_cache, 1766 None => GpuCache::new(), 1767 }; 1768 } 1769 1770 self.frame_config = backend.frame_config; 1771 1772 let mut scenes_to_build = Vec::new(); 1773 1774 for (id, view) in backend.documents { 1775 debug!("\tdocument {:?}", id); 1776 let scene_name = format!("scene-{}-{}", id.namespace_id.0, id.id); 1777 let scene = config.deserialize_for_scene::<Scene, _>(&scene_name) 1778 .expect(&format!("Unable to open {}.ron", scene_name)); 1779 1780 let scene_spatial_tree_name = format!("scene-spatial-tree-{}-{}", id.namespace_id.0, id.id); 1781 let scene_spatial_tree = config.deserialize_for_scene::<SceneSpatialTree, _>(&scene_spatial_tree_name) 1782 .expect(&format!("Unable to open {}.ron", scene_spatial_tree_name)); 1783 1784 let interners_name = format!("interners-{}-{}", id.namespace_id.0, id.id); 1785 let interners = config.deserialize_for_scene::<Interners, _>(&interners_name) 1786 .expect(&format!("Unable to open {}.ron", interners_name)); 1787 1788 let data_stores_name = format!("data-stores-{}-{}", id.namespace_id.0, id.id); 1789 let data_stores = config.deserialize_for_frame::<DataStores, _>(&data_stores_name) 1790 .expect(&format!("Unable to open {}.ron", data_stores_name)); 1791 1792 let properties_name = format!("properties-{}-{}", id.namespace_id.0, id.id); 1793 let properties = config.deserialize_for_frame::<SceneProperties, _>(&properties_name) 1794 .expect(&format!("Unable to open {}.ron", properties_name)); 1795 1796 let frame_spatial_tree_name = format!("frame-spatial-tree-{}-{}", id.namespace_id.0, id.id); 1797 let frame_spatial_tree = config.deserialize_for_frame::<SpatialTree, _>(&frame_spatial_tree_name) 1798 .expect(&format!("Unable to open {}.ron", frame_spatial_tree_name)); 1799 1800 // Update the document if it still exists, rather than replace it entirely. 1801 // This allows us to preserve state information such as the frame stamp, 1802 // which is necessary for cache sanity. 1803 match self.documents.entry(id) { 1804 Occupied(entry) => { 1805 let doc = entry.into_mut(); 1806 doc.view = view; 1807 doc.loaded_scene = scene.clone(); 1808 doc.data_stores = data_stores; 1809 doc.spatial_tree = frame_spatial_tree; 1810 doc.dynamic_properties = properties; 1811 doc.frame_is_valid = false; 1812 doc.rendered_frame_is_valid = false; 1813 doc.has_built_scene = false; 1814 doc.hit_tester_is_valid = false; 1815 } 1816 Vacant(entry) => { 1817 let doc = Document { 1818 id, 1819 scene: BuiltScene::empty(), 1820 removed_pipelines: Vec::new(), 1821 view, 1822 stamp: FrameStamp::first(id), 1823 frame_builder: FrameBuilder::new(), 1824 dynamic_properties: properties, 1825 hit_tester: None, 1826 shared_hit_tester: Arc::new(SharedHitTester::new()), 1827 frame_is_valid: false, 1828 hit_tester_is_valid: false, 1829 rendered_frame_is_valid: false, 1830 has_built_scene: false, 1831 data_stores, 1832 scratch: ScratchBuffer::default(), 1833 spatial_tree: frame_spatial_tree, 1834 loaded_scene: scene.clone(), 1835 prev_composite_descriptor: CompositeDescriptor::empty(), 1836 dirty_rects_are_valid: false, 1837 profile: TransactionProfile::new(), 1838 rg_builder: RenderTaskGraphBuilder::new(), 1839 frame_stats: None, 1840 }; 1841 entry.insert(doc); 1842 } 1843 }; 1844 1845 let frame_name = format!("frame-{}-{}", id.namespace_id.0, id.id); 1846 let frame = config.deserialize_for_frame::<Frame, _>(frame_name); 1847 let build_frame = match frame { 1848 Some(frame) => { 1849 info!("\tloaded a built frame with {} passes", frame.passes.len()); 1850 1851 let msg_update = ResultMsg::UpdateGpuCache(self.gpu_cache.extract_updates()); 1852 self.result_tx.send(msg_update).unwrap(); 1853 1854 let msg_publish = ResultMsg::PublishDocument( 1855 id, 1856 RenderedDocument { 1857 frame, 1858 is_new_scene: true, 1859 profile: TransactionProfile::new(), 1860 render_reasons: RenderReasons::empty(), 1861 frame_stats: None, 1862 }, 1863 self.resource_cache.pending_updates(), 1864 ); 1865 self.result_tx.send(msg_publish).unwrap(); 1866 1867 self.notifier.new_frame_ready(id, false, true, None); 1868 1869 // We deserialized the state of the frame so we don't want to build 1870 // it (but we do want to update the scene builder's state) 1871 false 1872 } 1873 None => true, 1874 }; 1875 1876 scenes_to_build.push(LoadScene { 1877 document_id: id, 1878 scene, 1879 view: view.scene.clone(), 1880 config: self.frame_config.clone(), 1881 font_instances: self.resource_cache.get_font_instances(), 1882 build_frame, 1883 interners, 1884 spatial_tree: scene_spatial_tree, 1885 }); 1886 } 1887 1888 if !scenes_to_build.is_empty() { 1889 self.send_backend_message( 1890 SceneBuilderRequest::LoadScenes(scenes_to_build) 1891 ); 1892 } 1893 } 1894 } 1895