tor-browser

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

scene_builder_thread.rs (33313B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Publi
      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 use api::{AsyncBlobImageRasterizer, BlobImageResult, DebugFlags, Parameter};
      6 use api::{DocumentId, PipelineId, ExternalEvent, BlobImageRequest};
      7 use api::{NotificationRequest, Checkpoint, IdNamespace, QualitySettings};
      8 use api::{PrimitiveKeyKind, GlyphDimensionRequest, GlyphIndexRequest};
      9 use api::channel::{unbounded_channel, single_msg_channel, Receiver, Sender};
     10 use api::units::*;
     11 use crate::render_api::{ApiMsg, FrameMsg, SceneMsg, ResourceUpdate, TransactionMsg, MemoryReport};
     12 use crate::box_shadow::BoxShadow;
     13 #[cfg(feature = "capture")]
     14 use crate::capture::CaptureConfig;
     15 use crate::frame_builder::FrameBuilderConfig;
     16 use crate::scene_building::{SceneBuilder, SceneRecycler};
     17 use crate::clip::{ClipIntern, PolygonIntern};
     18 use crate::filterdata::FilterDataIntern;
     19 use glyph_rasterizer::SharedFontResources;
     20 use crate::intern::{Internable, Interner, UpdateList};
     21 use crate::internal_types::{FastHashMap, FastHashSet};
     22 use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
     23 use crate::prim_store::backdrop::{BackdropCapture, BackdropRender};
     24 use crate::prim_store::borders::{ImageBorder, NormalBorderPrim};
     25 use crate::prim_store::gradient::{LinearGradient, RadialGradient, ConicGradient};
     26 use crate::prim_store::image::{Image, YuvImage};
     27 use crate::prim_store::line_dec::LineDecoration;
     28 use crate::prim_store::picture::Picture;
     29 use crate::prim_store::text_run::TextRun;
     30 use crate::profiler::{self, TransactionProfile};
     31 use crate::render_backend::SceneView;
     32 use crate::renderer::{FullFrameStats, PipelineInfo};
     33 use crate::scene::{BuiltScene, Scene, SceneStats};
     34 use crate::spatial_tree::{SceneSpatialTree, SpatialTreeUpdates};
     35 use crate::telemetry::Telemetry;
     36 use crate::SceneBuilderHooks;
     37 use std::iter;
     38 use crate::util::drain_filter;
     39 use std::thread;
     40 use std::time::Duration;
     41 
     42 fn rasterize_blobs(txn: &mut TransactionMsg, is_low_priority: bool, tile_pool: &mut api::BlobTilePool) {
     43    profile_scope!("rasterize_blobs");
     44 
     45    if let Some(ref mut rasterizer) = txn.blob_rasterizer {
     46        let mut rasterized_blobs = rasterizer.rasterize(&txn.blob_requests, is_low_priority, tile_pool);
     47        // try using the existing allocation if our current list is empty
     48        if txn.rasterized_blobs.is_empty() {
     49            txn.rasterized_blobs = rasterized_blobs;
     50        } else {
     51            txn.rasterized_blobs.append(&mut rasterized_blobs);
     52        }
     53    }
     54 }
     55 
     56 /// Represent the remaining work associated to a transaction after the scene building
     57 /// phase as well as the result of scene building itself if applicable.
     58 pub struct BuiltTransaction {
     59    pub document_id: DocumentId,
     60    pub built_scene: Option<BuiltScene>,
     61    pub offscreen_scenes: Vec<OffscreenBuiltScene>,
     62    pub view: SceneView,
     63    pub resource_updates: Vec<ResourceUpdate>,
     64    pub rasterized_blobs: Vec<(BlobImageRequest, BlobImageResult)>,
     65    pub blob_rasterizer: Option<Box<dyn AsyncBlobImageRasterizer>>,
     66    pub frame_ops: Vec<FrameMsg>,
     67    pub removed_pipelines: Vec<(PipelineId, DocumentId)>,
     68    pub notifications: Vec<NotificationRequest>,
     69    pub interner_updates: Option<InternerUpdates>,
     70    pub spatial_tree_updates: Option<SpatialTreeUpdates>,
     71    pub render_frame: bool,
     72    pub present: bool,
     73    pub tracked: bool,
     74    pub invalidate_rendered_frame: bool,
     75    pub profile: TransactionProfile,
     76    pub frame_stats: FullFrameStats,
     77 }
     78 
     79 pub struct OffscreenBuiltScene {
     80    pub scene: BuiltScene,
     81    pub interner_updates: InternerUpdates,
     82    pub spatial_tree_updates: SpatialTreeUpdates,
     83 }
     84 
     85 #[cfg(feature = "replay")]
     86 pub struct LoadScene {
     87    pub document_id: DocumentId,
     88    pub scene: Scene,
     89    pub fonts: SharedFontResources,
     90    pub view: SceneView,
     91    pub config: FrameBuilderConfig,
     92    pub build_frame: bool,
     93    pub interners: Interners,
     94    pub spatial_tree: SceneSpatialTree,
     95 }
     96 
     97 /// Message to the scene builder thread.
     98 pub enum SceneBuilderRequest {
     99    Transactions(Vec<Box<TransactionMsg>>),
    100    AddDocument(DocumentId, DeviceIntSize),
    101    DeleteDocument(DocumentId),
    102    GetGlyphDimensions(GlyphDimensionRequest),
    103    GetGlyphIndices(GlyphIndexRequest),
    104    ClearNamespace(IdNamespace),
    105    SimulateLongSceneBuild(u32),
    106    ExternalEvent(ExternalEvent),
    107    WakeUp,
    108    StopRenderBackend,
    109    ShutDown(Option<Sender<()>>),
    110    Flush(Sender<()>),
    111    SetFlags(DebugFlags),
    112    SetFrameBuilderConfig(FrameBuilderConfig),
    113    SetParameter(Parameter),
    114    ReportMemory(Box<MemoryReport>, Sender<Box<MemoryReport>>),
    115    #[cfg(feature = "capture")]
    116    SaveScene(CaptureConfig),
    117    #[cfg(feature = "replay")]
    118    LoadScenes(Vec<LoadScene>),
    119    #[cfg(feature = "capture")]
    120    StartCaptureSequence(CaptureConfig),
    121    #[cfg(feature = "capture")]
    122    StopCaptureSequence,
    123 }
    124 
    125 // Message from scene builder to render backend.
    126 pub enum SceneBuilderResult {
    127    Transactions(Vec<Box<BuiltTransaction>>, Option<Sender<SceneSwapResult>>),
    128    ExternalEvent(ExternalEvent),
    129    FlushComplete(Sender<()>),
    130    DeleteDocument(DocumentId),
    131    ClearNamespace(IdNamespace),
    132    GetGlyphDimensions(GlyphDimensionRequest),
    133    GetGlyphIndices(GlyphIndexRequest),
    134    SetParameter(Parameter),
    135    StopRenderBackend,
    136    ShutDown(Option<Sender<()>>),
    137 
    138    #[cfg(feature = "capture")]
    139    /// The same as `Transactions`, but also supplies a `CaptureConfig` that the
    140    /// render backend should use for sequence capture, until the next
    141    /// `CapturedTransactions` or `StopCaptureSequence` result.
    142    CapturedTransactions(Vec<Box<BuiltTransaction>>, CaptureConfig, Option<Sender<SceneSwapResult>>),
    143 
    144    #[cfg(feature = "capture")]
    145    /// The scene builder has stopped sequence capture, so the render backend
    146    /// should do the same.
    147    StopCaptureSequence,
    148 }
    149 
    150 // Message from render backend to scene builder to indicate the
    151 // scene swap was completed. We need a separate channel for this
    152 // so that they don't get mixed with SceneBuilderRequest messages.
    153 pub enum SceneSwapResult {
    154    Complete(Sender<()>),
    155    Aborted,
    156 }
    157 
    158 macro_rules! declare_interners {
    159    ( $( $name:ident : $ty:ident, )+ ) => {
    160        /// This struct contains all items that can be shared between
    161        /// display lists. We want to intern and share the same clips,
    162        /// primitives and other things between display lists so that:
    163        /// - GPU cache handles remain valid, reducing GPU cache updates.
    164        /// - Comparison of primitives and pictures between two
    165        ///   display lists is (a) fast (b) done during scene building.
    166        #[cfg_attr(feature = "capture", derive(Serialize))]
    167        #[cfg_attr(feature = "replay", derive(Deserialize))]
    168        #[derive(Default)]
    169        pub struct Interners {
    170            $(
    171                pub $name: Interner<$ty>,
    172            )+
    173        }
    174 
    175        $(
    176            impl AsMut<Interner<$ty>> for Interners {
    177                fn as_mut(&mut self) -> &mut Interner<$ty> {
    178                    &mut self.$name
    179                }
    180            }
    181        )+
    182 
    183        pub struct InternerUpdates {
    184            $(
    185                pub $name: UpdateList<<$ty as Internable>::Key>,
    186            )+
    187        }
    188 
    189        impl Interners {
    190            /// Reports CPU heap memory used by the interners.
    191            fn report_memory(
    192                &self,
    193                ops: &mut MallocSizeOfOps,
    194                r: &mut MemoryReport,
    195            ) {
    196                $(
    197                    r.interning.interners.$name += self.$name.size_of(ops);
    198                )+
    199            }
    200 
    201            fn end_frame_and_get_pending_updates(&mut self) -> InternerUpdates {
    202                InternerUpdates {
    203                    $(
    204                        $name: self.$name.end_frame_and_get_pending_updates(),
    205                    )+
    206                }
    207            }
    208        }
    209    }
    210 }
    211 
    212 crate::enumerate_interners!(declare_interners);
    213 
    214 // A document in the scene builder contains the current scene,
    215 // as well as a persistent clip interner. This allows clips
    216 // to be de-duplicated, and persisted in the GPU cache between
    217 // display lists.
    218 struct Document {
    219    scene: Scene,
    220    interners: Interners,
    221    stats: SceneStats,
    222    view: SceneView,
    223    spatial_tree: SceneSpatialTree,
    224 }
    225 
    226 impl Document {
    227    fn new(device_rect: DeviceIntRect) -> Self {
    228        Document {
    229            scene: Scene::new(),
    230            interners: Interners::default(),
    231            stats: SceneStats::empty(),
    232            spatial_tree: SceneSpatialTree::new(),
    233            view: SceneView {
    234                device_rect,
    235                quality_settings: QualitySettings::default(),
    236            },
    237        }
    238    }
    239 }
    240 
    241 pub struct SceneBuilderThread {
    242    documents: FastHashMap<DocumentId, Document>,
    243    rx: Receiver<SceneBuilderRequest>,
    244    tx: Sender<ApiMsg>,
    245    config: FrameBuilderConfig,
    246    fonts: SharedFontResources,
    247    size_of_ops: Option<MallocSizeOfOps>,
    248    hooks: Option<Box<dyn SceneBuilderHooks + Send>>,
    249    simulate_slow_ms: u32,
    250    removed_pipelines: FastHashSet<PipelineId>,
    251    #[cfg(feature = "capture")]
    252    capture_config: Option<CaptureConfig>,
    253    debug_flags: DebugFlags,
    254    recycler: SceneRecycler,
    255    tile_pool: api::BlobTilePool,
    256 }
    257 
    258 pub struct SceneBuilderThreadChannels {
    259    rx: Receiver<SceneBuilderRequest>,
    260    tx: Sender<ApiMsg>,
    261 }
    262 
    263 impl SceneBuilderThreadChannels {
    264    pub fn new(
    265        tx: Sender<ApiMsg>
    266    ) -> (Self, Sender<SceneBuilderRequest>) {
    267        let (in_tx, in_rx) = unbounded_channel();
    268        (
    269            Self {
    270                rx: in_rx,
    271                tx,
    272            },
    273            in_tx,
    274        )
    275    }
    276 }
    277 
    278 impl SceneBuilderThread {
    279    pub fn new(
    280        config: FrameBuilderConfig,
    281        fonts: SharedFontResources,
    282        size_of_ops: Option<MallocSizeOfOps>,
    283        hooks: Option<Box<dyn SceneBuilderHooks + Send>>,
    284        channels: SceneBuilderThreadChannels,
    285    ) -> Self {
    286        let SceneBuilderThreadChannels { rx, tx } = channels;
    287 
    288        Self {
    289            documents: Default::default(),
    290            rx,
    291            tx,
    292            config,
    293            fonts,
    294            size_of_ops,
    295            hooks,
    296            simulate_slow_ms: 0,
    297            removed_pipelines: FastHashSet::default(),
    298            #[cfg(feature = "capture")]
    299            capture_config: None,
    300            debug_flags: DebugFlags::default(),
    301            recycler: SceneRecycler::new(),
    302            // TODO: tile size is hard-coded here.
    303            tile_pool: api::BlobTilePool::new(),
    304        }
    305    }
    306 
    307    /// Send a message to the render backend thread.
    308    ///
    309    /// We first put something in the result queue and then send a wake-up
    310    /// message to the api queue that the render backend is blocking on.
    311    pub fn send(&self, msg: SceneBuilderResult) {
    312        self.tx.send(ApiMsg::SceneBuilderResult(msg)).unwrap();
    313    }
    314 
    315    /// The scene builder thread's event loop.
    316    pub fn run(&mut self) {
    317        if let Some(ref hooks) = self.hooks {
    318            hooks.register();
    319        }
    320 
    321        loop {
    322            tracy_begin_frame!("scene_builder_thread");
    323 
    324            match self.rx.recv() {
    325                Ok(SceneBuilderRequest::WakeUp) => {}
    326                Ok(SceneBuilderRequest::Flush(tx)) => {
    327                    self.send(SceneBuilderResult::FlushComplete(tx));
    328                }
    329                Ok(SceneBuilderRequest::SetFlags(debug_flags)) => {
    330                    self.debug_flags = debug_flags;
    331                }
    332                Ok(SceneBuilderRequest::Transactions(txns)) => {
    333                    let built_txns : Vec<Box<BuiltTransaction>> = txns.into_iter()
    334                        .map(|txn| self.process_transaction(*txn))
    335                        .collect();
    336                    #[cfg(feature = "capture")]
    337                    match built_txns.iter().any(|txn| txn.built_scene.is_some()) {
    338                        true => self.save_capture_sequence(),
    339                        _ => {},
    340                    }
    341                    self.forward_built_transactions(built_txns);
    342 
    343                    // Now that we off the critical path, do some memory bookkeeping.
    344                    self.recycler.recycle_built_scene();
    345                    self.tile_pool.cleanup();
    346                }
    347                Ok(SceneBuilderRequest::AddDocument(document_id, initial_size)) => {
    348                    let old = self.documents.insert(document_id, Document::new(
    349                        initial_size.into(),
    350                    ));
    351                    debug_assert!(old.is_none());
    352                }
    353                Ok(SceneBuilderRequest::DeleteDocument(document_id)) => {
    354                    self.documents.remove(&document_id);
    355                    self.send(SceneBuilderResult::DeleteDocument(document_id));
    356                }
    357                Ok(SceneBuilderRequest::ClearNamespace(id)) => {
    358                    self.documents.retain(|doc_id, _doc| doc_id.namespace_id != id);
    359                    self.send(SceneBuilderResult::ClearNamespace(id));
    360                }
    361                Ok(SceneBuilderRequest::ExternalEvent(evt)) => {
    362                    self.send(SceneBuilderResult::ExternalEvent(evt));
    363                }
    364                Ok(SceneBuilderRequest::GetGlyphDimensions(request)) => {
    365                    self.send(SceneBuilderResult::GetGlyphDimensions(request));
    366                }
    367                Ok(SceneBuilderRequest::GetGlyphIndices(request)) => {
    368                    self.send(SceneBuilderResult::GetGlyphIndices(request));
    369                }
    370                Ok(SceneBuilderRequest::StopRenderBackend) => {
    371                    self.send(SceneBuilderResult::StopRenderBackend);
    372                }
    373                Ok(SceneBuilderRequest::ShutDown(sync)) => {
    374                    self.send(SceneBuilderResult::ShutDown(sync));
    375                    break;
    376                }
    377                Ok(SceneBuilderRequest::SimulateLongSceneBuild(time_ms)) => {
    378                    self.simulate_slow_ms = time_ms
    379                }
    380                Ok(SceneBuilderRequest::ReportMemory(mut report, tx)) => {
    381                    (*report) += self.report_memory();
    382                    tx.send(report).unwrap();
    383                }
    384                Ok(SceneBuilderRequest::SetFrameBuilderConfig(cfg)) => {
    385                    self.config = cfg;
    386                }
    387                Ok(SceneBuilderRequest::SetParameter(prop)) => {
    388                    self.send(SceneBuilderResult::SetParameter(prop));
    389                }
    390                #[cfg(feature = "replay")]
    391                Ok(SceneBuilderRequest::LoadScenes(msg)) => {
    392                    self.load_scenes(msg);
    393                }
    394                #[cfg(feature = "capture")]
    395                Ok(SceneBuilderRequest::SaveScene(config)) => {
    396                    self.save_scene(config);
    397                }
    398                #[cfg(feature = "capture")]
    399                Ok(SceneBuilderRequest::StartCaptureSequence(config)) => {
    400                    self.start_capture_sequence(config);
    401                }
    402                #[cfg(feature = "capture")]
    403                Ok(SceneBuilderRequest::StopCaptureSequence) => {
    404                    // FIXME(aosmond): clear config for frames and resource cache without scene
    405                    // rebuild?
    406                    self.capture_config = None;
    407                    self.send(SceneBuilderResult::StopCaptureSequence);
    408                }
    409                Err(_) => {
    410                    break;
    411                }
    412            }
    413 
    414            if let Some(ref hooks) = self.hooks {
    415                hooks.poke();
    416            }
    417 
    418            tracy_end_frame!("scene_builder_thread");
    419        }
    420 
    421        if let Some(ref hooks) = self.hooks {
    422            hooks.deregister();
    423        }
    424    }
    425 
    426    #[cfg(feature = "capture")]
    427    fn save_scene(&mut self, config: CaptureConfig) {
    428        for (id, doc) in &self.documents {
    429            let interners_name = format!("interners-{}-{}", id.namespace_id.0, id.id);
    430            config.serialize_for_scene(&doc.interners, interners_name);
    431 
    432            let scene_spatial_tree_name = format!("scene-spatial-tree-{}-{}", id.namespace_id.0, id.id);
    433            config.serialize_for_scene(&doc.spatial_tree, scene_spatial_tree_name);
    434 
    435            use crate::render_api::CaptureBits;
    436            if config.bits.contains(CaptureBits::SCENE) {
    437                let file_name = format!("scene-{}-{}", id.namespace_id.0, id.id);
    438                config.serialize_for_scene(&doc.scene, file_name);
    439            }
    440        }
    441    }
    442 
    443    #[cfg(feature = "replay")]
    444    fn load_scenes(&mut self, scenes: Vec<LoadScene>) {
    445        for mut item in scenes {
    446            self.config = item.config;
    447 
    448            let mut built_scene = None;
    449            let mut interner_updates = None;
    450            let mut spatial_tree_updates = None;
    451 
    452            if item.scene.has_root_pipeline() {
    453                built_scene = Some(SceneBuilder::build(
    454                    &item.scene,
    455                    None,
    456                    item.fonts,
    457                    &item.view,
    458                    &self.config,
    459                    &mut item.interners,
    460                    &mut item.spatial_tree,
    461                    &mut self.recycler,
    462                    &SceneStats::empty(),
    463                    self.debug_flags,
    464                ));
    465 
    466                interner_updates = Some(
    467                    item.interners.end_frame_and_get_pending_updates()
    468                );
    469 
    470                spatial_tree_updates = Some(
    471                    item.spatial_tree.end_frame_and_get_pending_updates()
    472                );
    473            }
    474 
    475            self.documents.insert(
    476                item.document_id,
    477                Document {
    478                    scene: item.scene,
    479                    interners: item.interners,
    480                    stats: SceneStats::empty(),
    481                    view: item.view.clone(),
    482                    spatial_tree: item.spatial_tree,
    483                },
    484            );
    485 
    486            let txns = vec![Box::new(BuiltTransaction {
    487                document_id: item.document_id,
    488                render_frame: item.build_frame,
    489                tracked: false,
    490                present: true,
    491                invalidate_rendered_frame: false,
    492                built_scene,
    493                view: item.view,
    494                resource_updates: Vec::new(),
    495                rasterized_blobs: Vec::new(),
    496                blob_rasterizer: None,
    497                frame_ops: Vec::new(),
    498                removed_pipelines: Vec::new(),
    499                notifications: Vec::new(),
    500                interner_updates,
    501                spatial_tree_updates,
    502                profile: TransactionProfile::new(),
    503                frame_stats: FullFrameStats::default(),
    504                offscreen_scenes: Vec::new(),
    505            })];
    506 
    507            self.forward_built_transactions(txns);
    508        }
    509    }
    510 
    511    #[cfg(feature = "capture")]
    512    fn save_capture_sequence(
    513        &mut self,
    514    ) {
    515        if let Some(ref mut config) = self.capture_config {
    516            config.prepare_scene();
    517            for (id, doc) in &self.documents {
    518                let interners_name = format!("interners-{}-{}", id.namespace_id.0, id.id);
    519                config.serialize_for_scene(&doc.interners, interners_name);
    520 
    521                use crate::render_api::CaptureBits;
    522                if config.bits.contains(CaptureBits::SCENE) {
    523                    let file_name = format!("scene-{}-{}", id.namespace_id.0, id.id);
    524                    config.serialize_for_scene(&doc.scene, file_name);
    525                }
    526            }
    527        }
    528    }
    529 
    530    #[cfg(feature = "capture")]
    531    fn start_capture_sequence(
    532        &mut self,
    533        config: CaptureConfig,
    534    ) {
    535        self.capture_config = Some(config);
    536        self.save_capture_sequence();
    537    }
    538 
    539    /// Do the bulk of the work of the scene builder thread.
    540    fn process_transaction(&mut self, mut txn: TransactionMsg) -> Box<BuiltTransaction> {
    541        profile_scope!("process_transaction");
    542 
    543        if let Some(ref hooks) = self.hooks {
    544            hooks.pre_scene_build();
    545        }
    546 
    547        let doc = self.documents.get_mut(&txn.document_id).unwrap();
    548        let scene = &mut doc.scene;
    549 
    550        let mut profile = txn.profile.take();
    551 
    552        let scene_build_start = zeitstempel::now();
    553        let mut removed_pipelines = Vec::new();
    554        let mut rebuild_scene = false;
    555        let mut frame_stats = FullFrameStats::default();
    556        let mut offscreen_scenes = Vec::new();
    557 
    558        for message in txn.scene_ops.drain(..) {
    559            match message {
    560                SceneMsg::UpdateEpoch(pipeline_id, epoch) => {
    561                    scene.update_epoch(pipeline_id, epoch);
    562                }
    563                SceneMsg::SetQualitySettings { settings } => {
    564                    doc.view.quality_settings = settings;
    565                }
    566                SceneMsg::SetDocumentView { device_rect } => {
    567                    doc.view.device_rect = device_rect;
    568                }
    569                SceneMsg::SetDisplayList {
    570                    epoch,
    571                    pipeline_id,
    572                    display_list,
    573                } => {
    574                    let (builder_start_time_ns, builder_end_time_ns, send_time_ns) =
    575                      display_list.times();
    576                    let content_send_time = profiler::ns_to_ms(zeitstempel::now() - send_time_ns);
    577                    let dl_build_time = profiler::ns_to_ms(builder_end_time_ns - builder_start_time_ns);
    578                    profile.set(profiler::CONTENT_SEND_TIME, content_send_time);
    579                    profile.set(profiler::DISPLAY_LIST_BUILD_TIME, dl_build_time);
    580                    profile.set(profiler::DISPLAY_LIST_MEM, profiler::bytes_to_mb(display_list.size_in_bytes()));
    581 
    582                    let (gecko_display_list_time, full_display_list) = display_list.gecko_display_list_stats();
    583                    frame_stats.full_display_list = full_display_list;
    584                    frame_stats.gecko_display_list_time = gecko_display_list_time;
    585                    frame_stats.wr_display_list_time += dl_build_time;
    586 
    587                    if self.removed_pipelines.contains(&pipeline_id) {
    588                        continue;
    589                    }
    590 
    591                    // Note: We could further reduce the amount of unnecessary scene
    592                    // building by keeping track of which pipelines are used by the
    593                    // scene (bug 1490751).
    594                    rebuild_scene = true;
    595 
    596                    scene.set_display_list(
    597                        pipeline_id,
    598                        epoch,
    599                        display_list,
    600                    );
    601                }
    602                SceneMsg::RenderOffscreen(pipeline_id) => {
    603                    let mut interners = Interners::default();
    604                    let mut spatial_tree = SceneSpatialTree::new();
    605                    let built = SceneBuilder::build(
    606                        &scene,
    607                        Some(pipeline_id),
    608                        self.fonts.clone(),
    609                        &doc.view,
    610                        &self.config,
    611                        &mut interners,
    612                        &mut spatial_tree,
    613                        &mut self.recycler,
    614                        &doc.stats,
    615                        self.debug_flags,
    616                    );
    617                    let interner_updates = interners.end_frame_and_get_pending_updates();
    618                    let spatial_tree_updates = spatial_tree.end_frame_and_get_pending_updates();
    619                    offscreen_scenes.push(OffscreenBuiltScene {
    620                        scene: built,
    621                        interner_updates,
    622                        spatial_tree_updates,
    623                    });
    624                }
    625                SceneMsg::SetRootPipeline(pipeline_id) => {
    626                    if scene.root_pipeline_id != Some(pipeline_id) {
    627                        rebuild_scene = true;
    628                        scene.set_root_pipeline_id(pipeline_id);
    629                    }
    630                }
    631                SceneMsg::RemovePipeline(pipeline_id) => {
    632                    scene.remove_pipeline(pipeline_id);
    633                    self.removed_pipelines.insert(pipeline_id);
    634                    removed_pipelines.push((pipeline_id, txn.document_id));
    635                }
    636            }
    637        }
    638 
    639        self.removed_pipelines.clear();
    640 
    641        let mut built_scene = None;
    642        let mut interner_updates = None;
    643        let mut spatial_tree_updates = None;
    644 
    645        if scene.has_root_pipeline() && rebuild_scene {
    646 
    647            let built = SceneBuilder::build(
    648                &scene,
    649                None,
    650                self.fonts.clone(),
    651                &doc.view,
    652                &self.config,
    653                &mut doc.interners,
    654                &mut doc.spatial_tree,
    655                &mut self.recycler,
    656                &doc.stats,
    657                self.debug_flags,
    658            );
    659 
    660            // Update the allocation stats for next scene
    661            doc.stats = built.get_stats();
    662 
    663            // Retrieve the list of updates from the clip interner.
    664            interner_updates = Some(
    665                doc.interners.end_frame_and_get_pending_updates()
    666            );
    667 
    668            spatial_tree_updates = Some(
    669                doc.spatial_tree.end_frame_and_get_pending_updates()
    670            );
    671 
    672            built_scene = Some(built);
    673        }
    674 
    675        let scene_build_time_ms =
    676            profiler::ns_to_ms(zeitstempel::now() - scene_build_start);
    677        profile.set(profiler::SCENE_BUILD_TIME, scene_build_time_ms);
    678 
    679        frame_stats.scene_build_time += scene_build_time_ms;
    680 
    681        if !txn.blob_requests.is_empty() {
    682            profile.start_time(profiler::BLOB_RASTERIZATION_TIME);
    683 
    684            let is_low_priority = false;
    685            rasterize_blobs(&mut txn, is_low_priority, &mut self.tile_pool);
    686 
    687            profile.end_time(profiler::BLOB_RASTERIZATION_TIME);
    688            Telemetry::record_rasterize_blobs_time(Duration::from_micros((profile.get(profiler::BLOB_RASTERIZATION_TIME).unwrap() * 1000.00) as u64));
    689        }
    690 
    691        drain_filter(
    692            &mut txn.notifications,
    693            |n| { n.when() == Checkpoint::SceneBuilt },
    694            |n| { n.notify(); },
    695        );
    696 
    697        if self.simulate_slow_ms > 0 {
    698            thread::sleep(Duration::from_millis(self.simulate_slow_ms as u64));
    699        }
    700 
    701        Box::new(BuiltTransaction {
    702            document_id: txn.document_id,
    703            render_frame: txn.generate_frame.as_bool(),
    704            present: txn.generate_frame.present(),
    705            tracked: txn.generate_frame.tracked(),
    706            invalidate_rendered_frame: txn.invalidate_rendered_frame,
    707            built_scene,
    708            offscreen_scenes,
    709            view: doc.view,
    710            rasterized_blobs: txn.rasterized_blobs,
    711            resource_updates: txn.resource_updates,
    712            blob_rasterizer: txn.blob_rasterizer,
    713            frame_ops: txn.frame_ops,
    714            removed_pipelines,
    715            notifications: txn.notifications,
    716            interner_updates,
    717            spatial_tree_updates,
    718            profile,
    719            frame_stats,
    720        })
    721    }
    722 
    723    /// Send the results of process_transaction back to the render backend.
    724    fn forward_built_transactions(&mut self, txns: Vec<Box<BuiltTransaction>>) {
    725        let (pipeline_info, result_tx, result_rx) = match self.hooks {
    726            Some(ref hooks) => {
    727                if txns.iter().any(|txn| txn.built_scene.is_some()) {
    728                    let info = PipelineInfo {
    729                        epochs: txns.iter()
    730                            .filter(|txn| txn.built_scene.is_some())
    731                            .map(|txn| {
    732                                txn.built_scene.as_ref().unwrap()
    733                                    .pipeline_epochs.iter()
    734                                    .zip(iter::repeat(txn.document_id))
    735                                    .map(|((&pipeline_id, &epoch), document_id)| ((pipeline_id, document_id), epoch))
    736                            }).flatten().collect(),
    737                        removed_pipelines: txns.iter()
    738                            .map(|txn| txn.removed_pipelines.clone())
    739                            .flatten().collect(),
    740                    };
    741 
    742                    let (tx, rx) = single_msg_channel();
    743                    let txn = txns.iter().find(|txn| txn.built_scene.is_some()).unwrap();
    744                    Telemetry::record_scenebuild_time(Duration::from_millis(txn.profile.get(profiler::SCENE_BUILD_TIME).unwrap() as u64));
    745                    hooks.pre_scene_swap();
    746 
    747                    (Some(info), Some(tx), Some(rx))
    748                } else {
    749                    (None, None, None)
    750                }
    751            }
    752            _ => (None, None, None)
    753        };
    754 
    755        let timer_id = Telemetry::start_sceneswap_time();
    756        let document_ids = txns.iter().map(|txn| txn.document_id).collect();
    757        let have_resources_updates : Vec<DocumentId> = if pipeline_info.is_none() {
    758            txns.iter()
    759                .filter(|txn| !txn.resource_updates.is_empty() || txn.invalidate_rendered_frame)
    760                .map(|txn| txn.document_id)
    761                .collect()
    762        } else {
    763            Vec::new()
    764        };
    765 
    766        // Unless a transaction generates a frame immediately, the compositor should
    767        // schedule one whenever appropriate (probably at the next vsync) to present
    768        // the changes in the scene.
    769        let compositor_should_schedule_a_frame = !txns.iter().any(|txn| {
    770            txn.render_frame
    771        });
    772 
    773        #[cfg(feature = "capture")]
    774        match self.capture_config {
    775            Some(ref config) => self.send(SceneBuilderResult::CapturedTransactions(txns, config.clone(), result_tx)),
    776            None => self.send(SceneBuilderResult::Transactions(txns, result_tx)),
    777        };
    778 
    779        #[cfg(not(feature = "capture"))]
    780        self.send(SceneBuilderResult::Transactions(txns, result_tx));
    781 
    782        if let Some(pipeline_info) = pipeline_info {
    783            // Block until the swap is done, then invoke the hook.
    784            let swap_result = result_rx.unwrap().recv();
    785            Telemetry::stop_and_accumulate_sceneswap_time(timer_id);
    786            self.hooks.as_ref().unwrap().post_scene_swap(&document_ids,
    787                                                         pipeline_info,
    788                                                         compositor_should_schedule_a_frame);
    789            // Once the hook is done, allow the RB thread to resume
    790            if let Ok(SceneSwapResult::Complete(resume_tx)) = swap_result {
    791                resume_tx.send(()).ok();
    792            }
    793        } else {
    794            Telemetry::cancel_sceneswap_time(timer_id);
    795            if !have_resources_updates.is_empty() {
    796                if let Some(ref hooks) = self.hooks {
    797                    hooks.post_resource_update(&have_resources_updates);
    798                }
    799            } else if let Some(ref hooks) = self.hooks {
    800                hooks.post_empty_scene_build();
    801            }
    802        }
    803    }
    804 
    805    /// Reports CPU heap memory used by the SceneBuilder.
    806    fn report_memory(&mut self) -> MemoryReport {
    807        let ops = self.size_of_ops.as_mut().unwrap();
    808        let mut report = MemoryReport::default();
    809        for doc in self.documents.values() {
    810            doc.interners.report_memory(ops, &mut report);
    811            doc.scene.report_memory(ops, &mut report);
    812        }
    813 
    814        report
    815    }
    816 }
    817 
    818 /// A scene builder thread which executes expensive operations such as blob rasterization
    819 /// with a lower priority than the normal scene builder thread.
    820 ///
    821 /// After rasterizing blobs, the secene building request is forwarded to the normal scene
    822 /// builder where the FrameBuilder is generated.
    823 pub struct LowPrioritySceneBuilderThread {
    824    pub rx: Receiver<SceneBuilderRequest>,
    825    pub tx: Sender<SceneBuilderRequest>,
    826    pub tile_pool: api::BlobTilePool,
    827 }
    828 
    829 impl LowPrioritySceneBuilderThread {
    830    pub fn run(&mut self) {
    831        loop {
    832            match self.rx.recv() {
    833                Ok(SceneBuilderRequest::Transactions(mut txns)) => {
    834                    let txns : Vec<Box<TransactionMsg>> = txns.drain(..)
    835                        .map(|txn| self.process_transaction(txn))
    836                        .collect();
    837                    self.tx.send(SceneBuilderRequest::Transactions(txns)).unwrap();
    838                    self.tile_pool.cleanup();
    839                }
    840                Ok(SceneBuilderRequest::ShutDown(sync)) => {
    841                    self.tx.send(SceneBuilderRequest::ShutDown(sync)).unwrap();
    842                    break;
    843                }
    844                Ok(other) => {
    845                    self.tx.send(other).unwrap();
    846                }
    847                Err(_) => {
    848                    break;
    849                }
    850            }
    851        }
    852    }
    853 
    854    fn process_transaction(&mut self, mut txn: Box<TransactionMsg>) -> Box<TransactionMsg> {
    855        let is_low_priority = true;
    856        txn.profile.start_time(profiler::BLOB_RASTERIZATION_TIME);
    857        rasterize_blobs(&mut txn, is_low_priority, &mut self.tile_pool);
    858        txn.profile.end_time(profiler::BLOB_RASTERIZATION_TIME);
    859        Telemetry::record_rasterize_blobs_time(Duration::from_micros((txn.profile.get(profiler::BLOB_RASTERIZATION_TIME).unwrap() * 1000.00) as u64));
    860        txn.blob_requests = Vec::new();
    861 
    862        txn
    863    }
    864 }