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::precise_time_ns;
11use api::units::*;
12use crate::render_api::{ApiMsg, FrameMsg, SceneMsg, ResourceUpdate, TransactionMsg, MemoryReport};
13use crate::box_shadow::BoxShadow;
14#[cfg(feature = "capture")]
15use crate::capture::CaptureConfig;
16use crate::frame_builder::FrameBuilderConfig;
17use crate::scene_building::{SceneBuilder, SceneRecycler};
18use crate::clip::{ClipIntern, PolygonIntern};
19use crate::filterdata::FilterDataIntern;
20use glyph_rasterizer::SharedFontResources;
21use crate::intern::{Internable, Interner, UpdateList};
22use crate::internal_types::{FastHashMap, FastHashSet};
23use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
24use crate::prim_store::backdrop::{BackdropCapture, BackdropRender};
25use crate::prim_store::borders::{ImageBorder, NormalBorderPrim};
26use crate::prim_store::gradient::{LinearGradient, RadialGradient, ConicGradient};
27use crate::prim_store::image::{Image, YuvImage};
28use crate::prim_store::line_dec::LineDecoration;
29use crate::prim_store::picture::Picture;
30use crate::prim_store::text_run::TextRun;
31use crate::profiler::{self, TransactionProfile};
32use crate::render_backend::SceneView;
33use crate::renderer::{FullFrameStats, PipelineInfo};
34use crate::scene::{BuiltScene, Scene, SceneStats};
35use crate::spatial_tree::{SceneSpatialTree, SpatialTreeUpdates};
36use crate::telemetry::Telemetry;
37use crate::SceneBuilderHooks;
38use std::iter;
39use crate::util::drain_filter;
40use std::thread;
41use std::time::Duration;
42
43fn rasterize_blobs(txn: &mut TransactionMsg, is_low_priority: bool, tile_pool: &mut api::BlobTilePool) {
44 profile_scope!("rasterize_blobs");
45
46 if let Some(ref mut rasterizer) = txn.blob_rasterizer {
47 let mut rasterized_blobs = rasterizer.rasterize(&txn.blob_requests, is_low_priority, tile_pool);
48 if txn.rasterized_blobs.is_empty() {
50 txn.rasterized_blobs = rasterized_blobs;
51 } else {
52 txn.rasterized_blobs.append(&mut rasterized_blobs);
53 }
54 }
55}
56
57pub struct BuiltTransaction {
60 pub document_id: DocumentId,
61 pub built_scene: Option<BuiltScene>,
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 invalidate_rendered_frame: bool,
74 pub profile: TransactionProfile,
75 pub frame_stats: FullFrameStats,
76}
77
78#[cfg(feature = "replay")]
79pub struct LoadScene {
80 pub document_id: DocumentId,
81 pub scene: Scene,
82 pub fonts: SharedFontResources,
83 pub view: SceneView,
84 pub config: FrameBuilderConfig,
85 pub build_frame: bool,
86 pub interners: Interners,
87 pub spatial_tree: SceneSpatialTree,
88}
89
90pub enum SceneBuilderRequest {
92 Transactions(Vec<Box<TransactionMsg>>),
93 AddDocument(DocumentId, DeviceIntSize),
94 DeleteDocument(DocumentId),
95 GetGlyphDimensions(GlyphDimensionRequest),
96 GetGlyphIndices(GlyphIndexRequest),
97 ClearNamespace(IdNamespace),
98 SimulateLongSceneBuild(u32),
99 ExternalEvent(ExternalEvent),
100 WakeUp,
101 StopRenderBackend,
102 ShutDown(Option<Sender<()>>),
103 Flush(Sender<()>),
104 SetFlags(DebugFlags),
105 SetFrameBuilderConfig(FrameBuilderConfig),
106 SetParameter(Parameter),
107 ReportMemory(Box<MemoryReport>, Sender<Box<MemoryReport>>),
108 #[cfg(feature = "capture")]
109 SaveScene(CaptureConfig),
110 #[cfg(feature = "replay")]
111 LoadScenes(Vec<LoadScene>),
112 #[cfg(feature = "capture")]
113 StartCaptureSequence(CaptureConfig),
114 #[cfg(feature = "capture")]
115 StopCaptureSequence,
116}
117
118pub enum SceneBuilderResult {
120 Transactions(Vec<Box<BuiltTransaction>>, Option<Sender<SceneSwapResult>>),
121 ExternalEvent(ExternalEvent),
122 FlushComplete(Sender<()>),
123 DeleteDocument(DocumentId),
124 ClearNamespace(IdNamespace),
125 GetGlyphDimensions(GlyphDimensionRequest),
126 GetGlyphIndices(GlyphIndexRequest),
127 SetParameter(Parameter),
128 StopRenderBackend,
129 ShutDown(Option<Sender<()>>),
130
131 #[cfg(feature = "capture")]
132 CapturedTransactions(Vec<Box<BuiltTransaction>>, CaptureConfig, Option<Sender<SceneSwapResult>>),
136
137 #[cfg(feature = "capture")]
138 StopCaptureSequence,
141}
142
143pub enum SceneSwapResult {
147 Complete(Sender<()>),
148 Aborted,
149}
150
151macro_rules! declare_interners {
152 ( $( $name:ident : $ty:ident, )+ ) => {
153 #[cfg_attr(feature = "capture", derive(Serialize))]
160 #[cfg_attr(feature = "replay", derive(Deserialize))]
161 #[derive(Default)]
162 pub struct Interners {
163 $(
164 pub $name: Interner<$ty>,
165 )+
166 }
167
168 $(
169 impl AsMut<Interner<$ty>> for Interners {
170 fn as_mut(&mut self) -> &mut Interner<$ty> {
171 &mut self.$name
172 }
173 }
174 )+
175
176 pub struct InternerUpdates {
177 $(
178 pub $name: UpdateList<<$ty as Internable>::Key>,
179 )+
180 }
181
182 impl Interners {
183 fn report_memory(
185 &self,
186 ops: &mut MallocSizeOfOps,
187 r: &mut MemoryReport,
188 ) {
189 $(
190 r.interning.interners.$name += self.$name.size_of(ops);
191 )+
192 }
193
194 fn end_frame_and_get_pending_updates(&mut self) -> InternerUpdates {
195 InternerUpdates {
196 $(
197 $name: self.$name.end_frame_and_get_pending_updates(),
198 )+
199 }
200 }
201 }
202 }
203}
204
205crate::enumerate_interners!(declare_interners);
206
207struct Document {
212 scene: Scene,
213 interners: Interners,
214 stats: SceneStats,
215 view: SceneView,
216 spatial_tree: SceneSpatialTree,
217}
218
219impl Document {
220 fn new(device_rect: DeviceIntRect) -> Self {
221 Document {
222 scene: Scene::new(),
223 interners: Interners::default(),
224 stats: SceneStats::empty(),
225 spatial_tree: SceneSpatialTree::new(),
226 view: SceneView {
227 device_rect,
228 quality_settings: QualitySettings::default(),
229 },
230 }
231 }
232}
233
234pub struct SceneBuilderThread {
235 documents: FastHashMap<DocumentId, Document>,
236 rx: Receiver<SceneBuilderRequest>,
237 tx: Sender<ApiMsg>,
238 config: FrameBuilderConfig,
239 fonts: SharedFontResources,
240 size_of_ops: Option<MallocSizeOfOps>,
241 hooks: Option<Box<dyn SceneBuilderHooks + Send>>,
242 simulate_slow_ms: u32,
243 removed_pipelines: FastHashSet<PipelineId>,
244 #[cfg(feature = "capture")]
245 capture_config: Option<CaptureConfig>,
246 debug_flags: DebugFlags,
247 recycler: SceneRecycler,
248 tile_pool: api::BlobTilePool,
249}
250
251pub struct SceneBuilderThreadChannels {
252 rx: Receiver<SceneBuilderRequest>,
253 tx: Sender<ApiMsg>,
254}
255
256impl SceneBuilderThreadChannels {
257 pub fn new(
258 tx: Sender<ApiMsg>
259 ) -> (Self, Sender<SceneBuilderRequest>) {
260 let (in_tx, in_rx) = unbounded_channel();
261 (
262 Self {
263 rx: in_rx,
264 tx,
265 },
266 in_tx,
267 )
268 }
269}
270
271impl SceneBuilderThread {
272 pub fn new(
273 config: FrameBuilderConfig,
274 fonts: SharedFontResources,
275 size_of_ops: Option<MallocSizeOfOps>,
276 hooks: Option<Box<dyn SceneBuilderHooks + Send>>,
277 channels: SceneBuilderThreadChannels,
278 ) -> Self {
279 let SceneBuilderThreadChannels { rx, tx } = channels;
280
281 Self {
282 documents: Default::default(),
283 rx,
284 tx,
285 config,
286 fonts,
287 size_of_ops,
288 hooks,
289 simulate_slow_ms: 0,
290 removed_pipelines: FastHashSet::default(),
291 #[cfg(feature = "capture")]
292 capture_config: None,
293 debug_flags: DebugFlags::default(),
294 recycler: SceneRecycler::new(),
295 tile_pool: api::BlobTilePool::new(),
297 }
298 }
299
300 pub fn send(&self, msg: SceneBuilderResult) {
305 self.tx.send(ApiMsg::SceneBuilderResult(msg)).unwrap();
306 }
307
308 pub fn run(&mut self) {
310 if let Some(ref hooks) = self.hooks {
311 hooks.register();
312 }
313
314 loop {
315 tracy_begin_frame!("scene_builder_thread");
316
317 match self.rx.recv() {
318 Ok(SceneBuilderRequest::WakeUp) => {}
319 Ok(SceneBuilderRequest::Flush(tx)) => {
320 self.send(SceneBuilderResult::FlushComplete(tx));
321 }
322 Ok(SceneBuilderRequest::SetFlags(debug_flags)) => {
323 self.debug_flags = debug_flags;
324 }
325 Ok(SceneBuilderRequest::Transactions(txns)) => {
326 let built_txns : Vec<Box<BuiltTransaction>> = txns.into_iter()
327 .map(|txn| self.process_transaction(*txn))
328 .collect();
329 #[cfg(feature = "capture")]
330 match built_txns.iter().any(|txn| txn.built_scene.is_some()) {
331 true => self.save_capture_sequence(),
332 _ => {},
333 }
334 self.forward_built_transactions(built_txns);
335
336 self.recycler.recycle_built_scene();
338 self.tile_pool.cleanup();
339 }
340 Ok(SceneBuilderRequest::AddDocument(document_id, initial_size)) => {
341 let old = self.documents.insert(document_id, Document::new(
342 initial_size.into(),
343 ));
344 debug_assert!(old.is_none());
345 }
346 Ok(SceneBuilderRequest::DeleteDocument(document_id)) => {
347 self.documents.remove(&document_id);
348 self.send(SceneBuilderResult::DeleteDocument(document_id));
349 }
350 Ok(SceneBuilderRequest::ClearNamespace(id)) => {
351 self.documents.retain(|doc_id, _doc| doc_id.namespace_id != id);
352 self.send(SceneBuilderResult::ClearNamespace(id));
353 }
354 Ok(SceneBuilderRequest::ExternalEvent(evt)) => {
355 self.send(SceneBuilderResult::ExternalEvent(evt));
356 }
357 Ok(SceneBuilderRequest::GetGlyphDimensions(request)) => {
358 self.send(SceneBuilderResult::GetGlyphDimensions(request));
359 }
360 Ok(SceneBuilderRequest::GetGlyphIndices(request)) => {
361 self.send(SceneBuilderResult::GetGlyphIndices(request));
362 }
363 Ok(SceneBuilderRequest::StopRenderBackend) => {
364 self.send(SceneBuilderResult::StopRenderBackend);
365 }
366 Ok(SceneBuilderRequest::ShutDown(sync)) => {
367 self.send(SceneBuilderResult::ShutDown(sync));
368 break;
369 }
370 Ok(SceneBuilderRequest::SimulateLongSceneBuild(time_ms)) => {
371 self.simulate_slow_ms = time_ms
372 }
373 Ok(SceneBuilderRequest::ReportMemory(mut report, tx)) => {
374 (*report) += self.report_memory();
375 tx.send(report).unwrap();
376 }
377 Ok(SceneBuilderRequest::SetFrameBuilderConfig(cfg)) => {
378 self.config = cfg;
379 }
380 Ok(SceneBuilderRequest::SetParameter(prop)) => {
381 self.send(SceneBuilderResult::SetParameter(prop));
382 }
383 #[cfg(feature = "replay")]
384 Ok(SceneBuilderRequest::LoadScenes(msg)) => {
385 self.load_scenes(msg);
386 }
387 #[cfg(feature = "capture")]
388 Ok(SceneBuilderRequest::SaveScene(config)) => {
389 self.save_scene(config);
390 }
391 #[cfg(feature = "capture")]
392 Ok(SceneBuilderRequest::StartCaptureSequence(config)) => {
393 self.start_capture_sequence(config);
394 }
395 #[cfg(feature = "capture")]
396 Ok(SceneBuilderRequest::StopCaptureSequence) => {
397 self.capture_config = None;
400 self.send(SceneBuilderResult::StopCaptureSequence);
401 }
402 Err(_) => {
403 break;
404 }
405 }
406
407 if let Some(ref hooks) = self.hooks {
408 hooks.poke();
409 }
410
411 tracy_end_frame!("scene_builder_thread");
412 }
413
414 if let Some(ref hooks) = self.hooks {
415 hooks.deregister();
416 }
417 }
418
419 #[cfg(feature = "capture")]
420 fn save_scene(&mut self, config: CaptureConfig) {
421 for (id, doc) in &self.documents {
422 let interners_name = format!("interners-{}-{}", id.namespace_id.0, id.id);
423 config.serialize_for_scene(&doc.interners, interners_name);
424
425 let scene_spatial_tree_name = format!("scene-spatial-tree-{}-{}", id.namespace_id.0, id.id);
426 config.serialize_for_scene(&doc.spatial_tree, scene_spatial_tree_name);
427
428 use crate::render_api::CaptureBits;
429 if config.bits.contains(CaptureBits::SCENE) {
430 let file_name = format!("scene-{}-{}", id.namespace_id.0, id.id);
431 config.serialize_for_scene(&doc.scene, file_name);
432 }
433 }
434 }
435
436 #[cfg(feature = "replay")]
437 fn load_scenes(&mut self, scenes: Vec<LoadScene>) {
438 for mut item in scenes {
439 self.config = item.config;
440
441 let mut built_scene = None;
442 let mut interner_updates = None;
443 let mut spatial_tree_updates = None;
444
445 if item.scene.has_root_pipeline() {
446 built_scene = Some(SceneBuilder::build(
447 &item.scene,
448 item.fonts,
449 &item.view,
450 &self.config,
451 &mut item.interners,
452 &mut item.spatial_tree,
453 &mut self.recycler,
454 &SceneStats::empty(),
455 self.debug_flags,
456 ));
457
458 interner_updates = Some(
459 item.interners.end_frame_and_get_pending_updates()
460 );
461
462 spatial_tree_updates = Some(
463 item.spatial_tree.end_frame_and_get_pending_updates()
464 );
465 }
466
467 self.documents.insert(
468 item.document_id,
469 Document {
470 scene: item.scene,
471 interners: item.interners,
472 stats: SceneStats::empty(),
473 view: item.view.clone(),
474 spatial_tree: item.spatial_tree,
475 },
476 );
477
478 let txns = vec![Box::new(BuiltTransaction {
479 document_id: item.document_id,
480 render_frame: item.build_frame,
481 present: true,
482 invalidate_rendered_frame: false,
483 built_scene,
484 view: item.view,
485 resource_updates: Vec::new(),
486 rasterized_blobs: Vec::new(),
487 blob_rasterizer: None,
488 frame_ops: Vec::new(),
489 removed_pipelines: Vec::new(),
490 notifications: Vec::new(),
491 interner_updates,
492 spatial_tree_updates,
493 profile: TransactionProfile::new(),
494 frame_stats: FullFrameStats::default(),
495 })];
496
497 self.forward_built_transactions(txns);
498 }
499 }
500
501 #[cfg(feature = "capture")]
502 fn save_capture_sequence(
503 &mut self,
504 ) {
505 if let Some(ref mut config) = self.capture_config {
506 config.prepare_scene();
507 for (id, doc) in &self.documents {
508 let interners_name = format!("interners-{}-{}", id.namespace_id.0, id.id);
509 config.serialize_for_scene(&doc.interners, interners_name);
510
511 use crate::render_api::CaptureBits;
512 if config.bits.contains(CaptureBits::SCENE) {
513 let file_name = format!("scene-{}-{}", id.namespace_id.0, id.id);
514 config.serialize_for_scene(&doc.scene, file_name);
515 }
516 }
517 }
518 }
519
520 #[cfg(feature = "capture")]
521 fn start_capture_sequence(
522 &mut self,
523 config: CaptureConfig,
524 ) {
525 self.capture_config = Some(config);
526 self.save_capture_sequence();
527 }
528
529 fn process_transaction(&mut self, mut txn: TransactionMsg) -> Box<BuiltTransaction> {
531 profile_scope!("process_transaction");
532
533 if let Some(ref hooks) = self.hooks {
534 hooks.pre_scene_build();
535 }
536
537 let doc = self.documents.get_mut(&txn.document_id).unwrap();
538 let scene = &mut doc.scene;
539
540 let mut profile = txn.profile.take();
541
542 let scene_build_start = precise_time_ns();
543 let mut removed_pipelines = Vec::new();
544 let mut rebuild_scene = false;
545 let mut frame_stats = FullFrameStats::default();
546
547 for message in txn.scene_ops.drain(..) {
548 match message {
549 SceneMsg::UpdateEpoch(pipeline_id, epoch) => {
550 scene.update_epoch(pipeline_id, epoch);
551 }
552 SceneMsg::SetQualitySettings { settings } => {
553 doc.view.quality_settings = settings;
554 }
555 SceneMsg::SetDocumentView { device_rect } => {
556 doc.view.device_rect = device_rect;
557 }
558 SceneMsg::SetDisplayList {
559 epoch,
560 pipeline_id,
561 display_list,
562 } => {
563 let (builder_start_time_ns, builder_end_time_ns, send_time_ns) =
564 display_list.times();
565 let content_send_time = profiler::ns_to_ms(precise_time_ns() - send_time_ns);
566 let dl_build_time = profiler::ns_to_ms(builder_end_time_ns - builder_start_time_ns);
567 profile.set(profiler::CONTENT_SEND_TIME, content_send_time);
568 profile.set(profiler::DISPLAY_LIST_BUILD_TIME, dl_build_time);
569 profile.set(profiler::DISPLAY_LIST_MEM, profiler::bytes_to_mb(display_list.size_in_bytes()));
570
571 let (gecko_display_list_time, full_display_list) = display_list.gecko_display_list_stats();
572 frame_stats.full_display_list = full_display_list;
573 frame_stats.gecko_display_list_time = gecko_display_list_time;
574 frame_stats.wr_display_list_time += dl_build_time;
575
576 if self.removed_pipelines.contains(&pipeline_id) {
577 continue;
578 }
579
580 rebuild_scene = true;
584
585 scene.set_display_list(
586 pipeline_id,
587 epoch,
588 display_list,
589 );
590 }
591 SceneMsg::SetRootPipeline(pipeline_id) => {
592 if scene.root_pipeline_id != Some(pipeline_id) {
593 rebuild_scene = true;
594 scene.set_root_pipeline_id(pipeline_id);
595 }
596 }
597 SceneMsg::RemovePipeline(pipeline_id) => {
598 scene.remove_pipeline(pipeline_id);
599 self.removed_pipelines.insert(pipeline_id);
600 removed_pipelines.push((pipeline_id, txn.document_id));
601 }
602 }
603 }
604
605 self.removed_pipelines.clear();
606
607 let mut built_scene = None;
608 let mut interner_updates = None;
609 let mut spatial_tree_updates = None;
610
611 if scene.has_root_pipeline() && rebuild_scene {
612
613 let built = SceneBuilder::build(
614 &scene,
615 self.fonts.clone(),
616 &doc.view,
617 &self.config,
618 &mut doc.interners,
619 &mut doc.spatial_tree,
620 &mut self.recycler,
621 &doc.stats,
622 self.debug_flags,
623 );
624
625 doc.stats = built.get_stats();
627
628 interner_updates = Some(
630 doc.interners.end_frame_and_get_pending_updates()
631 );
632
633 spatial_tree_updates = Some(
634 doc.spatial_tree.end_frame_and_get_pending_updates()
635 );
636
637 built_scene = Some(built);
638 }
639
640 let scene_build_time_ms =
641 profiler::ns_to_ms(precise_time_ns() - scene_build_start);
642 profile.set(profiler::SCENE_BUILD_TIME, scene_build_time_ms);
643
644 frame_stats.scene_build_time += scene_build_time_ms;
645
646 if !txn.blob_requests.is_empty() {
647 profile.start_time(profiler::BLOB_RASTERIZATION_TIME);
648
649 let is_low_priority = false;
650 rasterize_blobs(&mut txn, is_low_priority, &mut self.tile_pool);
651
652 profile.end_time(profiler::BLOB_RASTERIZATION_TIME);
653 Telemetry::record_rasterize_blobs_time(Duration::from_micros((profile.get(profiler::BLOB_RASTERIZATION_TIME).unwrap() * 1000.00) as u64));
654 }
655
656 drain_filter(
657 &mut txn.notifications,
658 |n| { n.when() == Checkpoint::SceneBuilt },
659 |n| { n.notify(); },
660 );
661
662 if self.simulate_slow_ms > 0 {
663 thread::sleep(Duration::from_millis(self.simulate_slow_ms as u64));
664 }
665
666 Box::new(BuiltTransaction {
667 document_id: txn.document_id,
668 render_frame: txn.generate_frame.as_bool(),
669 present: txn.generate_frame.present(),
670 invalidate_rendered_frame: txn.invalidate_rendered_frame,
671 built_scene,
672 view: doc.view,
673 rasterized_blobs: txn.rasterized_blobs,
674 resource_updates: txn.resource_updates,
675 blob_rasterizer: txn.blob_rasterizer,
676 frame_ops: txn.frame_ops,
677 removed_pipelines,
678 notifications: txn.notifications,
679 interner_updates,
680 spatial_tree_updates,
681 profile,
682 frame_stats,
683 })
684 }
685
686 fn forward_built_transactions(&mut self, txns: Vec<Box<BuiltTransaction>>) {
688 let (pipeline_info, result_tx, result_rx) = match self.hooks {
689 Some(ref hooks) => {
690 if txns.iter().any(|txn| txn.built_scene.is_some()) {
691 let info = PipelineInfo {
692 epochs: txns.iter()
693 .filter(|txn| txn.built_scene.is_some())
694 .map(|txn| {
695 txn.built_scene.as_ref().unwrap()
696 .pipeline_epochs.iter()
697 .zip(iter::repeat(txn.document_id))
698 .map(|((&pipeline_id, &epoch), document_id)| ((pipeline_id, document_id), epoch))
699 }).flatten().collect(),
700 removed_pipelines: txns.iter()
701 .map(|txn| txn.removed_pipelines.clone())
702 .flatten().collect(),
703 };
704
705 let (tx, rx) = single_msg_channel();
706 let txn = txns.iter().find(|txn| txn.built_scene.is_some()).unwrap();
707 Telemetry::record_scenebuild_time(Duration::from_millis(txn.profile.get(profiler::SCENE_BUILD_TIME).unwrap() as u64));
708 hooks.pre_scene_swap();
709
710 (Some(info), Some(tx), Some(rx))
711 } else {
712 (None, None, None)
713 }
714 }
715 _ => (None, None, None)
716 };
717
718 let timer_id = Telemetry::start_sceneswap_time();
719 let document_ids = txns.iter().map(|txn| txn.document_id).collect();
720 let have_resources_updates : Vec<DocumentId> = if pipeline_info.is_none() {
721 txns.iter()
722 .filter(|txn| !txn.resource_updates.is_empty() || txn.invalidate_rendered_frame)
723 .map(|txn| txn.document_id)
724 .collect()
725 } else {
726 Vec::new()
727 };
728
729 let compositor_should_schedule_a_frame = !txns.iter().any(|txn| {
733 txn.render_frame
734 });
735
736 #[cfg(feature = "capture")]
737 match self.capture_config {
738 Some(ref config) => self.send(SceneBuilderResult::CapturedTransactions(txns, config.clone(), result_tx)),
739 None => self.send(SceneBuilderResult::Transactions(txns, result_tx)),
740 };
741
742 #[cfg(not(feature = "capture"))]
743 self.send(SceneBuilderResult::Transactions(txns, result_tx));
744
745 if let Some(pipeline_info) = pipeline_info {
746 let swap_result = result_rx.unwrap().recv();
748 Telemetry::stop_and_accumulate_sceneswap_time(timer_id);
749 self.hooks.as_ref().unwrap().post_scene_swap(&document_ids,
750 pipeline_info,
751 compositor_should_schedule_a_frame);
752 if let Ok(SceneSwapResult::Complete(resume_tx)) = swap_result {
754 resume_tx.send(()).ok();
755 }
756 } else {
757 Telemetry::cancel_sceneswap_time(timer_id);
758 if !have_resources_updates.is_empty() {
759 if let Some(ref hooks) = self.hooks {
760 hooks.post_resource_update(&have_resources_updates);
761 }
762 } else if let Some(ref hooks) = self.hooks {
763 hooks.post_empty_scene_build();
764 }
765 }
766 }
767
768 fn report_memory(&mut self) -> MemoryReport {
770 let ops = self.size_of_ops.as_mut().unwrap();
771 let mut report = MemoryReport::default();
772 for doc in self.documents.values() {
773 doc.interners.report_memory(ops, &mut report);
774 doc.scene.report_memory(ops, &mut report);
775 }
776
777 report
778 }
779}
780
781pub struct LowPrioritySceneBuilderThread {
787 pub rx: Receiver<SceneBuilderRequest>,
788 pub tx: Sender<SceneBuilderRequest>,
789 pub tile_pool: api::BlobTilePool,
790}
791
792impl LowPrioritySceneBuilderThread {
793 pub fn run(&mut self) {
794 loop {
795 match self.rx.recv() {
796 Ok(SceneBuilderRequest::Transactions(mut txns)) => {
797 let txns : Vec<Box<TransactionMsg>> = txns.drain(..)
798 .map(|txn| self.process_transaction(txn))
799 .collect();
800 self.tx.send(SceneBuilderRequest::Transactions(txns)).unwrap();
801 self.tile_pool.cleanup();
802 }
803 Ok(SceneBuilderRequest::ShutDown(sync)) => {
804 self.tx.send(SceneBuilderRequest::ShutDown(sync)).unwrap();
805 break;
806 }
807 Ok(other) => {
808 self.tx.send(other).unwrap();
809 }
810 Err(_) => {
811 break;
812 }
813 }
814 }
815 }
816
817 fn process_transaction(&mut self, mut txn: Box<TransactionMsg>) -> Box<TransactionMsg> {
818 let is_low_priority = true;
819 txn.profile.start_time(profiler::BLOB_RASTERIZATION_TIME);
820 rasterize_blobs(&mut txn, is_low_priority, &mut self.tile_pool);
821 txn.profile.end_time(profiler::BLOB_RASTERIZATION_TIME);
822 Telemetry::record_rasterize_blobs_time(Duration::from_micros((txn.profile.get(profiler::BLOB_RASTERIZATION_TIME).unwrap() * 1000.00) as u64));
823 txn.blob_requests = Vec::new();
824
825 txn
826 }
827}