tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

render_backend.rs (84995B)


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