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