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