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