1use api::{AsyncBlobImageRasterizer, BlobImageResult, DebugFlags, Parameter};
6use api::{DocumentId, PipelineId, ExternalEvent, BlobImageRequest};
7use api::{NotificationRequest, Checkpoint, IdNamespace, QualitySettings};
8use api::{PrimitiveKeyKind, GlyphDimensionRequest, GlyphIndexRequest};
9use api::channel::{unbounded_channel, single_msg_channel, Receiver, Sender};
10use api::units::*;
11use crate::render_api::{ApiMsg, FrameMsg, SceneMsg, ResourceUpdate, TransactionMsg, MemoryReport};
12use crate::box_shadow::BoxShadow;
13#[cfg(feature = "capture")]
14use crate::capture::CaptureConfig;
15use crate::frame_builder::FrameBuilderConfig;
16use crate::scene_building::{SceneBuilder, SceneRecycler};
17use crate::clip::{ClipIntern, PolygonIntern};
18use crate::filterdata::FilterDataIntern;
19use glyph_rasterizer::SharedFontResources;
20use crate::intern::{Internable, Interner, UpdateList};
21use crate::internal_types::{FastHashMap, FastHashSet};
22use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
23use crate::prim_store::backdrop::{BackdropCapture, BackdropRender};
24use crate::prim_store::borders::{ImageBorder, NormalBorderPrim};
25use crate::prim_store::gradient::{LinearGradient, RadialGradient, ConicGradient};
26use crate::prim_store::image::{Image, YuvImage};
27use crate::prim_store::line_dec::LineDecoration;
28use crate::prim_store::picture::Picture;
29use crate::prim_store::text_run::TextRun;
30use crate::profiler::{self, TransactionProfile};
31use crate::render_backend::SceneView;
32use crate::renderer::{FullFrameStats, PipelineInfo};
33use crate::scene::{BuiltScene, Scene, SceneStats};
34use crate::spatial_tree::{SceneSpatialTree, SpatialTreeUpdates};
35use crate::telemetry::Telemetry;
36use crate::SceneBuilderHooks;
37use std::iter;
38use crate::util::drain_filter;
39use std::thread;
40use std::time::Duration;
41
42fn 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 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
56pub 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
79pub struct OffscreenBuiltScene {
80 pub scene: BuiltScene,
81 pub interner_updates: InternerUpdates,
82 pub spatial_tree_updates: SpatialTreeUpdates,
83}
84
85#[cfg(feature = "replay")]
86pub 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
97pub 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
125pub 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 CapturedTransactions(Vec<Box<BuiltTransaction>>, CaptureConfig, Option<Sender<SceneSwapResult>>),
143
144 #[cfg(feature = "capture")]
145 StopCaptureSequence,
148}
149
150pub enum SceneSwapResult {
154 Complete(Sender<()>),
155 Aborted,
156}
157
158macro_rules! declare_interners {
159 ( $( $name:ident : $ty:ident, )+ ) => {
160 #[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 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
212crate::enumerate_interners!(declare_interners);
213
214struct Document {
219 scene: Scene,
220 interners: Interners,
221 stats: SceneStats,
222 view: SceneView,
223 spatial_tree: SceneSpatialTree,
224}
225
226impl 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
241pub 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
258pub struct SceneBuilderThreadChannels {
259 rx: Receiver<SceneBuilderRequest>,
260 tx: Sender<ApiMsg>,
261}
262
263impl 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
278impl 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 tile_pool: api::BlobTilePool::new(),
304 }
305 }
306
307 pub fn send(&self, msg: SceneBuilderResult) {
312 self.tx.send(ApiMsg::SceneBuilderResult(msg)).unwrap();
313 }
314
315 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 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 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 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 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 doc.stats = built.get_stats();
662
663 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 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 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 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 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 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
818pub struct LowPrioritySceneBuilderThread {
824 pub rx: Receiver<SceneBuilderRequest>,
825 pub tx: Sender<SceneBuilderRequest>,
826 pub tile_pool: api::BlobTilePool,
827}
828
829impl 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}