webrender/
render_backend.rs

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