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