1use api::{DebugFlags, Parameter, BoolParameter, PrimitiveFlags, MinimapData};
12use api::{DocumentId, ExternalScrollId, HitTestResult};
13use api::{IdNamespace, PipelineId, RenderNotifier, SampledScrollOffset};
14use api::{NotificationRequest, Checkpoint, QualitySettings};
15use api::{FramePublishId, PrimitiveKeyKind, RenderReasons};
16use api::precise_time_ns;
17use api::units::*;
18use api::channel::{single_msg_channel, Sender, Receiver};
19use crate::bump_allocator::ChunkPool;
20use crate::AsyncPropertySampler;
21use crate::box_shadow::BoxShadow;
22#[cfg(any(feature = "capture", feature = "replay"))]
23use crate::render_api::CaptureBits;
24#[cfg(feature = "replay")]
25use crate::render_api::CapturedDocument;
26use crate::render_api::{MemoryReport, TransactionMsg, ResourceUpdate, ApiMsg, FrameMsg, ClearCache, DebugCommand};
27use crate::clip::{ClipIntern, PolygonIntern, ClipStoreScratchBuffer};
28use crate::filterdata::FilterDataIntern;
29#[cfg(any(feature = "capture", feature = "replay"))]
30use crate::capture::CaptureConfig;
31use crate::composite::{CompositorKind, CompositeDescriptor};
32use crate::frame_builder::{FrameBuilder, FrameBuilderConfig, FrameScratchBuffer};
33use glyph_rasterizer::FontInstance;
34use crate::gpu_cache::GpuCache;
35use crate::hit_test::{HitTest, HitTester, SharedHitTester};
36use crate::intern::DataStore;
37#[cfg(any(feature = "capture", feature = "replay"))]
38use crate::internal_types::DebugOutput;
39use crate::internal_types::{FastHashMap, FrameId, FrameMemory, FrameStamp, RenderedDocument, ResultMsg};
40use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
41use crate::picture::{PictureScratchBuffer, SliceId, TileCacheInstance, TileCacheParams, SurfaceInfo, RasterConfig};
42use crate::picture::PicturePrimitive;
43use crate::prim_store::{PrimitiveScratchBuffer, PrimitiveInstance};
44use crate::prim_store::{PrimitiveInstanceKind, PrimTemplateCommonData};
45use crate::prim_store::interned::*;
46use crate::profiler::{self, TransactionProfile};
47use crate::render_task_graph::RenderTaskGraphBuilder;
48use crate::renderer::{FullFrameStats, PipelineInfo};
49use crate::resource_cache::ResourceCache;
50#[cfg(feature = "replay")]
51use crate::resource_cache::PlainCacheOwn;
52#[cfg(feature = "replay")]
53use crate::resource_cache::PlainResources;
54#[cfg(feature = "replay")]
55use crate::scene::Scene;
56use crate::scene::{BuiltScene, SceneProperties};
57use crate::scene_builder_thread::*;
58use crate::spatial_tree::SpatialTree;
59#[cfg(feature = "replay")]
60use crate::spatial_tree::SceneSpatialTree;
61use crate::telemetry::Telemetry;
62#[cfg(feature = "capture")]
63use serde::Serialize;
64#[cfg(feature = "replay")]
65use serde::Deserialize;
66#[cfg(feature = "replay")]
67use std::collections::hash_map::Entry::{Occupied, Vacant};
68use std::sync::Arc;
69use std::sync::atomic::{AtomicUsize, Ordering};
70use std::{mem, u32};
71#[cfg(feature = "capture")]
72use std::path::PathBuf;
73#[cfg(feature = "replay")]
74use crate::frame_builder::Frame;
75use core::time::Duration;
76use crate::util::{Recycler, VecHelper, drain_filter};
77
78#[cfg_attr(feature = "capture", derive(Serialize))]
79#[cfg_attr(feature = "replay", derive(Deserialize))]
80#[derive(Copy, Clone)]
81pub struct DocumentView {
82 scene: SceneView,
83}
84
85#[cfg_attr(feature = "capture", derive(Serialize))]
87#[cfg_attr(feature = "replay", derive(Deserialize))]
88#[derive(Copy, Clone)]
89pub struct SceneView {
90 pub device_rect: DeviceIntRect,
91 pub quality_settings: QualitySettings,
92}
93
94enum RenderBackendStatus {
95 Continue,
96 StopRenderBackend,
97 ShutDown(Option<Sender<()>>),
98}
99
100macro_rules! declare_data_stores {
101 ( $( $name:ident : $ty:ty, )+ ) => {
102 #[cfg_attr(feature = "capture", derive(Serialize))]
105 #[cfg_attr(feature = "replay", derive(Deserialize))]
106 #[derive(Default)]
107 pub struct DataStores {
108 $(
109 pub $name: DataStore<$ty>,
110 )+
111 }
112
113 impl DataStores {
114 fn report_memory(&self, ops: &mut MallocSizeOfOps, r: &mut MemoryReport) {
116 $(
117 r.interning.data_stores.$name += self.$name.size_of(ops);
118 )+
119 }
120
121 fn apply_updates(
122 &mut self,
123 updates: InternerUpdates,
124 profile: &mut TransactionProfile,
125 ) {
126 $(
127 self.$name.apply_updates(
128 updates.$name,
129 profile,
130 );
131 )+
132 }
133 }
134 }
135}
136
137crate::enumerate_interners!(declare_data_stores);
138
139impl DataStores {
140 pub fn get_local_prim_rect(
144 &self,
145 prim_instance: &PrimitiveInstance,
146 pictures: &[PicturePrimitive],
147 surfaces: &[SurfaceInfo],
148 ) -> LayoutRect {
149 match prim_instance.kind {
150 PrimitiveInstanceKind::Picture { pic_index, .. } => {
151 let pic = &pictures[pic_index.0];
152
153 match pic.raster_config {
154 Some(RasterConfig { surface_index, ref composite_mode, .. }) => {
155 let surface = &surfaces[surface_index.0];
156
157 composite_mode.get_rect(surface, None)
158 }
159 None => {
160 panic!("bug: get_local_prim_rect should not be called for pass-through pictures");
161 }
162 }
163 }
164 _ => {
165 self.as_common_data(prim_instance).prim_rect
166 }
167 }
168 }
169
170 pub fn get_local_prim_coverage_rect(
174 &self,
175 prim_instance: &PrimitiveInstance,
176 pictures: &[PicturePrimitive],
177 surfaces: &[SurfaceInfo],
178 ) -> LayoutRect {
179 match prim_instance.kind {
180 PrimitiveInstanceKind::Picture { pic_index, .. } => {
181 let pic = &pictures[pic_index.0];
182
183 match pic.raster_config {
184 Some(RasterConfig { surface_index, ref composite_mode, .. }) => {
185 let surface = &surfaces[surface_index.0];
186
187 composite_mode.get_coverage(surface, None)
188 }
189 None => {
190 panic!("bug: get_local_prim_coverage_rect should not be called for pass-through pictures");
191 }
192 }
193 }
194 _ => {
195 self.as_common_data(prim_instance).prim_rect
196 }
197 }
198 }
199
200 pub fn prim_may_need_repetition(
204 &self,
205 prim_instance: &PrimitiveInstance,
206 ) -> bool {
207 match prim_instance.kind {
208 PrimitiveInstanceKind::Picture { .. } => {
209 false
210 }
211 _ => {
212 self.as_common_data(prim_instance).may_need_repetition
213 }
214 }
215 }
216
217 pub fn prim_has_anti_aliasing(
219 &self,
220 prim_instance: &PrimitiveInstance,
221 ) -> bool {
222 match prim_instance.kind {
223 PrimitiveInstanceKind::Picture { .. } => {
224 false
225 }
226 _ => {
227 self.as_common_data(prim_instance).flags.contains(PrimitiveFlags::ANTIALISED)
228 }
229 }
230 }
231
232 pub fn as_common_data(
233 &self,
234 prim_inst: &PrimitiveInstance
235 ) -> &PrimTemplateCommonData {
236 match prim_inst.kind {
237 PrimitiveInstanceKind::Rectangle { data_handle, .. } |
238 PrimitiveInstanceKind::Clear { 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)]
299pub struct ScratchBuffer {
300 pub primitive: PrimitiveScratchBuffer,
301 pub picture: PictureScratchBuffer,
302 pub frame: FrameScratchBuffer,
303 pub clip_store: ClipStoreScratchBuffer,
304}
305
306impl 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 self.picture = Default::default();
326 self.frame = Default::default();
327 self.clip_store = Default::default();
328 }
329}
330
331struct Document {
332 id: DocumentId,
334
335 removed_pipelines: Vec<(PipelineId, DocumentId)>,
338
339 view: DocumentView,
340
341 stamp: FrameStamp,
343
344 scene: BuiltScene,
347
348 frame_builder: FrameBuilder,
350
351 rg_builder: RenderTaskGraphBuilder,
353
354 hit_tester: Option<Arc<HitTester>>,
357 shared_hit_tester: Arc<SharedHitTester>,
360
361 dynamic_properties: SceneProperties,
364
365 frame_is_valid: bool,
368 hit_tester_is_valid: bool,
369 rendered_frame_is_valid: bool,
370 has_built_scene: bool,
373
374 data_stores: DataStores,
375
376 spatial_tree: SpatialTree,
378
379 minimap_data: FastHashMap<ExternalScrollId, MinimapData>,
380
381 scratch: ScratchBuffer,
385
386 #[cfg(feature = "replay")]
387 loaded_scene: Scene,
388
389 prev_composite_descriptor: CompositeDescriptor,
391
392 dirty_rects_are_valid: bool,
395
396 profile: TransactionProfile,
397 frame_stats: Option<FullFrameStats>,
398}
399
400impl 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(pipeline_id, point, flags, 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(pipeline_id, point, flags))
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 gpu_cache: &mut GpuCache,
515 debug_flags: DebugFlags,
516 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
517 frame_stats: Option<FullFrameStats>,
518 present: bool,
519 render_reasons: RenderReasons,
520 frame_memory: FrameMemory,
521 ) -> RenderedDocument {
522 let frame_build_start_time = precise_time_ns();
523
524 self.stamp.advance();
526
527 assert!(self.stamp.frame_id() != FrameId::INVALID,
528 "First frame increment must happen before build_frame()");
529
530 let frame = {
531 let frame = self.frame_builder.build(
532 &mut self.scene,
533 present,
534 resource_cache,
535 gpu_cache,
536 &mut self.rg_builder,
537 self.stamp,
538 self.view.scene.device_rect.min,
539 &self.dynamic_properties,
540 &mut self.data_stores,
541 &mut self.scratch,
542 debug_flags,
543 tile_caches,
544 &mut self.spatial_tree,
545 self.dirty_rects_are_valid,
546 &mut self.profile,
547 mem::take(&mut self.minimap_data),
551 frame_memory,
552 );
553
554 frame
555 };
556
557 self.frame_is_valid = true;
558 self.dirty_rects_are_valid = true;
559
560 self.has_built_scene = false;
561
562 let frame_build_time_ms =
563 profiler::ns_to_ms(precise_time_ns() - frame_build_start_time);
564 self.profile.set(profiler::FRAME_BUILDING_TIME, frame_build_time_ms);
565 self.profile.start_time(profiler::FRAME_SEND_TIME);
566
567 let frame_stats = frame_stats.map(|mut stats| {
568 stats.frame_build_time += frame_build_time_ms;
569 stats
570 });
571
572 RenderedDocument {
573 frame,
574 profile: self.profile.take_and_reset(),
575 frame_stats: frame_stats,
576 render_reasons,
577 }
578 }
579
580 fn rebuild_hit_tester(&mut self) {
581 self.spatial_tree.update_tree(&self.dynamic_properties);
582
583 let hit_tester = Arc::new(self.scene.create_hit_tester(&self.spatial_tree));
584 self.hit_tester = Some(Arc::clone(&hit_tester));
585 self.shared_hit_tester.update(hit_tester);
586 self.hit_tester_is_valid = true;
587 }
588
589 pub fn updated_pipeline_info(&mut self) -> PipelineInfo {
590 let removed_pipelines = self.removed_pipelines.take_and_preallocate();
591 PipelineInfo {
592 epochs: self.scene.pipeline_epochs.iter()
593 .map(|(&pipeline_id, &epoch)| ((pipeline_id, self.id), epoch)).collect(),
594 removed_pipelines,
595 }
596 }
597
598 pub fn set_scroll_offsets(
600 &mut self,
601 id: ExternalScrollId,
602 offsets: Vec<SampledScrollOffset>,
603 ) -> bool {
604 self.spatial_tree.set_scroll_offsets(id, offsets)
605 }
606
607 fn update_tile_caches_for_new_scene(
611 &mut self,
612 mut requested_tile_caches: FastHashMap<SliceId, TileCacheParams>,
613 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
614 resource_cache: &mut ResourceCache,
615 ) {
616 let mut new_tile_caches = FastHashMap::default();
617 new_tile_caches.reserve(requested_tile_caches.len());
618
619 for (slice_id, params) in requested_tile_caches.drain() {
622 let tile_cache = match tile_caches.remove(&slice_id) {
623 Some(mut existing_tile_cache) => {
624 existing_tile_cache.prepare_for_new_scene(
626 params,
627 resource_cache,
628 );
629 existing_tile_cache
630 }
631 None => {
632 Box::new(TileCacheInstance::new(params))
634 }
635 };
636
637 new_tile_caches.insert(slice_id, tile_cache);
638 }
639
640 let unused_tile_caches = mem::replace(
643 tile_caches,
644 new_tile_caches,
645 );
646
647 if !unused_tile_caches.is_empty() {
648 self.dirty_rects_are_valid = false;
651
652 for (_, tile_cache) in unused_tile_caches {
654 tile_cache.destroy(resource_cache);
655 }
656 }
657 }
658
659 pub fn new_async_scene_ready(
660 &mut self,
661 mut built_scene: BuiltScene,
662 recycler: &mut Recycler,
663 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
664 resource_cache: &mut ResourceCache,
665 ) {
666 self.frame_is_valid = false;
667 self.hit_tester_is_valid = false;
668
669 self.update_tile_caches_for_new_scene(
670 mem::replace(&mut built_scene.tile_cache_config.tile_caches, FastHashMap::default()),
671 tile_caches,
672 resource_cache,
673 );
674
675
676 let old_scene = std::mem::replace(&mut self.scene, built_scene);
677 old_scene.recycle();
678
679 self.scratch.recycle(recycler);
680 }
681}
682
683struct DocumentOps {
684 scroll: bool,
685}
686
687impl DocumentOps {
688 fn nop() -> Self {
689 DocumentOps {
690 scroll: false,
691 }
692 }
693}
694
695static NEXT_NAMESPACE_ID: AtomicUsize = AtomicUsize::new(1);
698
699#[cfg(any(feature = "capture", feature = "replay"))]
700#[cfg_attr(feature = "capture", derive(Serialize))]
701#[cfg_attr(feature = "replay", derive(Deserialize))]
702struct PlainRenderBackend {
703 frame_config: FrameBuilderConfig,
704 documents: FastHashMap<DocumentId, DocumentView>,
705 resource_sequence_id: u32,
706}
707
708pub struct RenderBackend {
713 api_rx: Receiver<ApiMsg>,
714 result_tx: Sender<ResultMsg>,
715 scene_tx: Sender<SceneBuilderRequest>,
716
717 gpu_cache: GpuCache,
718 resource_cache: ResourceCache,
719 chunk_pool: Arc<ChunkPool>,
720
721 frame_config: FrameBuilderConfig,
722 default_compositor_kind: CompositorKind,
723 documents: FastHashMap<DocumentId, Document>,
724
725 notifier: Box<dyn RenderNotifier>,
726 sampler: Option<Box<dyn AsyncPropertySampler + Send>>,
727 size_of_ops: Option<MallocSizeOfOps>,
728 debug_flags: DebugFlags,
729 namespace_alloc_by_client: bool,
730
731 recycler: Recycler,
732
733 #[cfg(feature = "capture")]
734 capture_config: Option<CaptureConfig>,
738
739 #[cfg(feature = "replay")]
740 loaded_resource_sequence_id: u32,
741
742 tile_caches: FastHashMap<SliceId, Box<TileCacheInstance>>,
745
746 frame_publish_id: FramePublishId,
748}
749
750impl RenderBackend {
751 pub fn new(
752 api_rx: Receiver<ApiMsg>,
753 result_tx: Sender<ResultMsg>,
754 scene_tx: Sender<SceneBuilderRequest>,
755 resource_cache: ResourceCache,
756 chunk_pool: Arc<ChunkPool>,
757 notifier: Box<dyn RenderNotifier>,
758 frame_config: FrameBuilderConfig,
759 sampler: Option<Box<dyn AsyncPropertySampler + Send>>,
760 size_of_ops: Option<MallocSizeOfOps>,
761 debug_flags: DebugFlags,
762 namespace_alloc_by_client: bool,
763 ) -> RenderBackend {
764 RenderBackend {
765 api_rx,
766 result_tx,
767 scene_tx,
768 resource_cache,
769 gpu_cache: GpuCache::new(),
770 chunk_pool,
771 frame_config,
772 default_compositor_kind : frame_config.compositor_kind,
773 documents: FastHashMap::default(),
774 notifier,
775 sampler,
776 size_of_ops,
777 debug_flags,
778 namespace_alloc_by_client,
779 recycler: Recycler::new(),
780 #[cfg(feature = "capture")]
781 capture_config: None,
782 #[cfg(feature = "replay")]
783 loaded_resource_sequence_id: 0,
784 tile_caches: FastHashMap::default(),
785 frame_publish_id: FramePublishId::first(),
786 }
787 }
788
789 pub fn next_namespace_id() -> IdNamespace {
790 IdNamespace(NEXT_NAMESPACE_ID.fetch_add(1, Ordering::Relaxed) as u32)
791 }
792
793 pub fn run(&mut self) {
794 let mut frame_counter: u32 = 0;
795 let mut status = RenderBackendStatus::Continue;
796
797 if let Some(ref sampler) = self.sampler {
798 sampler.register();
799 }
800
801 while let RenderBackendStatus::Continue = status {
802 status = match self.api_rx.recv() {
803 Ok(msg) => {
804 self.process_api_msg(msg, &mut frame_counter)
805 }
806 Err(..) => { RenderBackendStatus::ShutDown(None) }
807 };
808 }
809
810 if let RenderBackendStatus::StopRenderBackend = status {
811 while let Ok(msg) = self.api_rx.recv() {
812 match msg {
813 ApiMsg::SceneBuilderResult(SceneBuilderResult::ExternalEvent(evt)) => {
814 self.notifier.external_event(evt);
815 }
816 ApiMsg::SceneBuilderResult(SceneBuilderResult::FlushComplete(tx)) => {
817 debug_assert!(false);
821 tx.send(()).ok();
822 }
823 ApiMsg::SceneBuilderResult(SceneBuilderResult::ShutDown(sender)) => {
824 info!("Recycling stats: {:?}", self.recycler);
825 status = RenderBackendStatus::ShutDown(sender);
826 break;
827 }
828 _ => {},
829 }
830 }
831 }
832
833 while let Ok(msg) = self.api_rx.try_recv() {
836 match msg {
837 ApiMsg::SceneBuilderResult(SceneBuilderResult::FlushComplete(tx)) => {
838 debug_assert!(false);
842 tx.send(()).ok();
843 }
844 _ => {},
845 }
846 }
847
848 self.documents.clear();
849
850 self.notifier.shut_down();
851
852 if let Some(ref sampler) = self.sampler {
853 sampler.deregister();
854 }
855
856
857 if let RenderBackendStatus::ShutDown(Some(sender)) = status {
858 let _ = sender.send(());
859 }
860 }
861
862 fn process_transaction(
863 &mut self,
864 mut txns: Vec<Box<BuiltTransaction>>,
865 result_tx: Option<Sender<SceneSwapResult>>,
866 frame_counter: &mut u32,
867 ) -> bool {
868 self.prepare_for_frames();
869 self.maybe_force_nop_documents(
870 frame_counter,
871 |document_id| txns.iter().any(|txn| txn.document_id == document_id));
872
873 let mut built_frame = false;
874 for mut txn in txns.drain(..) {
875 let has_built_scene = txn.built_scene.is_some();
876
877 if let Some(doc) = self.documents.get_mut(&txn.document_id) {
878 doc.removed_pipelines.append(&mut txn.removed_pipelines);
879 doc.view.scene = txn.view;
880 doc.profile.merge(&mut txn.profile);
881
882 doc.frame_stats = if let Some(stats) = &doc.frame_stats {
883 Some(stats.merge(&txn.frame_stats))
884 } else {
885 Some(txn.frame_stats)
886 };
887
888 let last_sampled_scroll_offsets = if self.sampler.is_some() {
891 Some(doc.spatial_tree.get_last_sampled_scroll_offsets())
892 } else {
893 None
894 };
895
896 if let Some(updates) = txn.spatial_tree_updates.take() {
897 doc.spatial_tree.apply_updates(updates);
898 }
899
900 if let Some(built_scene) = txn.built_scene.take() {
901 doc.new_async_scene_ready(
902 built_scene,
903 &mut self.recycler,
904 &mut self.tile_caches,
905 &mut self.resource_cache,
906 );
907 }
908
909 if let Some(updates) = txn.interner_updates.take() {
913 doc.data_stores.apply_updates(updates, &mut doc.profile);
914 }
915
916 if let Some(last_sampled) = last_sampled_scroll_offsets {
923 doc.spatial_tree
924 .apply_last_sampled_scroll_offsets(last_sampled);
925 }
926
927 if !doc.hit_tester_is_valid {
930 doc.rebuild_hit_tester();
931 }
932
933 if let Some(ref tx) = result_tx {
934 let (resume_tx, resume_rx) = single_msg_channel();
935 tx.send(SceneSwapResult::Complete(resume_tx)).unwrap();
936 resume_rx.recv().ok();
941 }
942
943 self.resource_cache.add_rasterized_blob_images(
944 txn.rasterized_blobs.take(),
945 &mut doc.profile,
946 );
947
948 } else {
949 if let Some(ref tx) = result_tx {
953 tx.send(SceneSwapResult::Aborted).unwrap();
954 }
955 continue;
956 }
957
958 built_frame |= self.update_document(
959 txn.document_id,
960 txn.resource_updates.take(),
961 txn.frame_ops.take(),
962 txn.notifications.take(),
963 txn.render_frame,
964 txn.present,
965 RenderReasons::SCENE,
966 None,
967 txn.invalidate_rendered_frame,
968 frame_counter,
969 has_built_scene,
970 None,
971 );
972 }
973
974 built_frame
975 }
976
977 fn process_api_msg(
978 &mut self,
979 msg: ApiMsg,
980 frame_counter: &mut u32,
981 ) -> RenderBackendStatus {
982 match msg {
983 ApiMsg::CloneApi(sender) => {
984 assert!(!self.namespace_alloc_by_client);
985 sender.send(Self::next_namespace_id()).unwrap();
986 }
987 ApiMsg::CloneApiByClient(namespace_id) => {
988 assert!(self.namespace_alloc_by_client);
989 debug_assert!(!self.documents.iter().any(|(did, _doc)| did.namespace_id == namespace_id));
990 }
991 ApiMsg::AddDocument(document_id, initial_size) => {
992 let document = Document::new(
993 document_id,
994 initial_size,
995 );
996 let old = self.documents.insert(document_id, document);
997 debug_assert!(old.is_none());
998 }
999 ApiMsg::MemoryPressure => {
1000 self.resource_cache.clear(ClearCache::all());
1009
1010 self.gpu_cache.clear();
1011
1012 for (_, doc) in &mut self.documents {
1013 doc.scratch.memory_pressure();
1014 for tile_cache in self.tile_caches.values_mut() {
1015 tile_cache.memory_pressure(&mut self.resource_cache);
1016 }
1017 }
1018
1019 let resource_updates = self.resource_cache.pending_updates();
1020 let msg = ResultMsg::UpdateResources {
1021 resource_updates,
1022 memory_pressure: true,
1023 };
1024 self.result_tx.send(msg).unwrap();
1025 self.notifier.wake_up(false);
1026
1027 self.chunk_pool.purge_all_chunks();
1028 }
1029 ApiMsg::ReportMemory(tx) => {
1030 self.report_memory(tx);
1031 }
1032 ApiMsg::DebugCommand(option) => {
1033 let msg = match option {
1034 DebugCommand::SetPictureTileSize(tile_size) => {
1035 self.frame_config.tile_size_override = tile_size;
1036 self.update_frame_builder_config();
1037
1038 return RenderBackendStatus::Continue;
1039 }
1040 DebugCommand::SetMaximumSurfaceSize(surface_size) => {
1041 self.frame_config.max_surface_override = surface_size;
1042 self.update_frame_builder_config();
1043
1044 return RenderBackendStatus::Continue;
1045 }
1046 #[cfg(feature = "capture")]
1047 DebugCommand::SaveCapture(root, bits) => {
1048 let output = self.save_capture(root, bits);
1049 ResultMsg::DebugOutput(output)
1050 },
1051 #[cfg(feature = "capture")]
1052 DebugCommand::StartCaptureSequence(root, bits) => {
1053 self.start_capture_sequence(root, bits);
1054 return RenderBackendStatus::Continue;
1055 },
1056 #[cfg(feature = "capture")]
1057 DebugCommand::StopCaptureSequence => {
1058 self.stop_capture_sequence();
1059 return RenderBackendStatus::Continue;
1060 },
1061 #[cfg(feature = "replay")]
1062 DebugCommand::LoadCapture(path, ids, tx) => {
1063 NEXT_NAMESPACE_ID.fetch_add(1, Ordering::Relaxed);
1064 *frame_counter += 1;
1065
1066 let mut config = CaptureConfig::new(path, CaptureBits::all());
1067 if let Some((scene_id, frame_id)) = ids {
1068 config.scene_id = scene_id;
1069 config.frame_id = frame_id;
1070 }
1071
1072 self.load_capture(config);
1073
1074 for (id, doc) in &self.documents {
1075 let captured = CapturedDocument {
1076 document_id: *id,
1077 root_pipeline_id: doc.loaded_scene.root_pipeline_id,
1078 };
1079 tx.send(captured).unwrap();
1080 }
1081
1082 return RenderBackendStatus::Continue;
1085 }
1086 DebugCommand::ClearCaches(mask) => {
1087 self.resource_cache.clear(mask);
1088 return RenderBackendStatus::Continue;
1089 }
1090 DebugCommand::EnableNativeCompositor(enable) => {
1091 if let CompositorKind::Draw { .. } = self.default_compositor_kind {
1093 unreachable!();
1094 }
1095
1096 let compositor_kind = if enable {
1097 self.default_compositor_kind
1098 } else {
1099 CompositorKind::default()
1100 };
1101
1102 for (_, doc) in &mut self.documents {
1103 doc.scene.config.compositor_kind = compositor_kind;
1104 doc.frame_is_valid = false;
1105 }
1106
1107 self.frame_config.compositor_kind = compositor_kind;
1108 self.update_frame_builder_config();
1109
1110 return RenderBackendStatus::Continue;
1112 }
1113 DebugCommand::SetBatchingLookback(count) => {
1114 self.frame_config.batch_lookback_count = count as usize;
1115 self.update_frame_builder_config();
1116
1117 return RenderBackendStatus::Continue;
1118 }
1119 DebugCommand::SimulateLongSceneBuild(time_ms) => {
1120 let _ = self.scene_tx.send(SceneBuilderRequest::SimulateLongSceneBuild(time_ms));
1121 return RenderBackendStatus::Continue;
1122 }
1123 DebugCommand::SetFlags(flags) => {
1124 self.resource_cache.set_debug_flags(flags);
1125 self.gpu_cache.set_debug_flags(flags);
1126
1127 let force_invalidation = flags.contains(DebugFlags::FORCE_PICTURE_INVALIDATION);
1128 if self.frame_config.force_invalidation != force_invalidation {
1129 self.frame_config.force_invalidation = force_invalidation;
1130 self.update_frame_builder_config();
1131 }
1132
1133 let changed = self.debug_flags ^ flags;
1143 if changed.contains(DebugFlags::GPU_CACHE_DBG) {
1144 self.gpu_cache.clear();
1145 }
1146 self.debug_flags = flags;
1147
1148 ResultMsg::DebugCommand(option)
1149 }
1150 _ => ResultMsg::DebugCommand(option),
1151 };
1152 self.result_tx.send(msg).unwrap();
1153 self.notifier.wake_up(true);
1154 }
1155 ApiMsg::UpdateDocuments(transaction_msgs) => {
1156 self.prepare_transactions(
1157 transaction_msgs,
1158 frame_counter,
1159 );
1160 }
1161 ApiMsg::SceneBuilderResult(msg) => {
1162 return self.process_scene_builder_result(msg, frame_counter);
1163 }
1164 }
1165
1166 self.chunk_pool.purge_chunks(2, 3);
1171
1172 RenderBackendStatus::Continue
1173 }
1174
1175 fn process_scene_builder_result(
1176 &mut self,
1177 msg: SceneBuilderResult,
1178 frame_counter: &mut u32,
1179 ) -> RenderBackendStatus {
1180 profile_scope!("sb_msg");
1181
1182 match msg {
1183 SceneBuilderResult::Transactions(txns, result_tx) => {
1184 self.process_transaction(
1185 txns,
1186 result_tx,
1187 frame_counter,
1188 );
1189 self.bookkeep_after_frames();
1190 },
1191 #[cfg(feature = "capture")]
1192 SceneBuilderResult::CapturedTransactions(txns, capture_config, result_tx) => {
1193 if let Some(ref mut old_config) = self.capture_config {
1194 assert!(old_config.scene_id <= capture_config.scene_id);
1195 if old_config.scene_id < capture_config.scene_id {
1196 old_config.scene_id = capture_config.scene_id;
1197 old_config.frame_id = 0;
1198 }
1199 } else {
1200 self.capture_config = Some(capture_config);
1201 }
1202
1203 let built_frame = self.process_transaction(
1204 txns,
1205 result_tx,
1206 frame_counter,
1207 );
1208
1209 if built_frame {
1210 self.save_capture_sequence();
1211 }
1212
1213 self.bookkeep_after_frames();
1214 },
1215 #[cfg(feature = "capture")]
1216 SceneBuilderResult::StopCaptureSequence => {
1217 self.capture_config = None;
1218 }
1219 SceneBuilderResult::GetGlyphDimensions(request) => {
1220 let mut glyph_dimensions = Vec::with_capacity(request.glyph_indices.len());
1221 let instance_key = self.resource_cache.map_font_instance_key(request.key);
1222 if let Some(base) = self.resource_cache.get_font_instance(instance_key) {
1223 let font = FontInstance::from_base(Arc::clone(&base));
1224 for glyph_index in &request.glyph_indices {
1225 let glyph_dim = self.resource_cache.get_glyph_dimensions(&font, *glyph_index);
1226 glyph_dimensions.push(glyph_dim);
1227 }
1228 }
1229 request.sender.send(glyph_dimensions).unwrap();
1230 }
1231 SceneBuilderResult::GetGlyphIndices(request) => {
1232 let mut glyph_indices = Vec::with_capacity(request.text.len());
1233 let font_key = self.resource_cache.map_font_key(request.key);
1234 for ch in request.text.chars() {
1235 let index = self.resource_cache.get_glyph_index(font_key, ch);
1236 glyph_indices.push(index);
1237 }
1238 request.sender.send(glyph_indices).unwrap();
1239 }
1240 SceneBuilderResult::FlushComplete(tx) => {
1241 tx.send(()).ok();
1242 }
1243 SceneBuilderResult::ExternalEvent(evt) => {
1244 self.notifier.external_event(evt);
1245 }
1246 SceneBuilderResult::ClearNamespace(id) => {
1247 self.resource_cache.clear_namespace(id);
1248 self.documents.retain(|doc_id, _doc| doc_id.namespace_id != id);
1249 }
1250 SceneBuilderResult::DeleteDocument(document_id) => {
1251 self.documents.remove(&document_id);
1252 }
1253 SceneBuilderResult::SetParameter(param) => {
1254 if let Parameter::Bool(BoolParameter::Multithreading, enabled) = param {
1255 self.resource_cache.enable_multithreading(enabled);
1256 }
1257 let _ = self.result_tx.send(ResultMsg::SetParameter(param));
1258 }
1259 SceneBuilderResult::StopRenderBackend => {
1260 return RenderBackendStatus::StopRenderBackend;
1261 }
1262 SceneBuilderResult::ShutDown(sender) => {
1263 info!("Recycling stats: {:?}", self.recycler);
1264 return RenderBackendStatus::ShutDown(sender);
1265 }
1266 }
1267
1268 RenderBackendStatus::Continue
1269 }
1270
1271 fn update_frame_builder_config(&self) {
1272 self.send_backend_message(
1273 SceneBuilderRequest::SetFrameBuilderConfig(
1274 self.frame_config.clone()
1275 )
1276 );
1277 }
1278
1279 fn prepare_for_frames(&mut self) {
1280 self.gpu_cache.prepare_for_frames();
1281 }
1282
1283 fn bookkeep_after_frames(&mut self) {
1284 self.gpu_cache.bookkeep_after_frames();
1285 }
1286
1287 fn requires_frame_build(&mut self) -> bool {
1288 self.gpu_cache.requires_frame_build()
1289 }
1290
1291 fn prepare_transactions(
1292 &mut self,
1293 txns: Vec<Box<TransactionMsg>>,
1294 frame_counter: &mut u32,
1295 ) {
1296 self.prepare_for_frames();
1297 self.maybe_force_nop_documents(
1298 frame_counter,
1299 |document_id| txns.iter().any(|txn| txn.document_id == document_id));
1300
1301 let mut built_frame = false;
1302 for mut txn in txns {
1303 if txn.generate_frame.as_bool() {
1304 txn.profile.end_time(profiler::API_SEND_TIME);
1305 }
1306
1307 self.documents.get_mut(&txn.document_id).unwrap().profile.merge(&mut txn.profile);
1308
1309 built_frame |= self.update_document(
1310 txn.document_id,
1311 txn.resource_updates.take(),
1312 txn.frame_ops.take(),
1313 txn.notifications.take(),
1314 txn.generate_frame.as_bool(),
1315 txn.generate_frame.present(),
1316 txn.render_reasons,
1317 txn.generate_frame.id(),
1318 txn.invalidate_rendered_frame,
1319 frame_counter,
1320 false,
1321 txn.creation_time,
1322 );
1323 }
1324 if built_frame {
1325 #[cfg(feature = "capture")]
1326 self.save_capture_sequence();
1327 }
1328 self.bookkeep_after_frames();
1329 }
1330
1331 fn maybe_force_nop_documents<F>(&mut self,
1338 frame_counter: &mut u32,
1339 document_already_present: F) where
1340 F: Fn(DocumentId) -> bool {
1341 if self.requires_frame_build() {
1342 let nop_documents : Vec<DocumentId> = self.documents.keys()
1343 .cloned()
1344 .filter(|key| !document_already_present(*key))
1345 .collect();
1346 #[allow(unused_variables)]
1347 let mut built_frame = false;
1348 for &document_id in &nop_documents {
1349 built_frame |= self.update_document(
1350 document_id,
1351 Vec::default(),
1352 Vec::default(),
1353 Vec::default(),
1354 false,
1355 false,
1356 RenderReasons::empty(),
1357 None,
1358 false,
1359 frame_counter,
1360 false,
1361 None);
1362 }
1363 #[cfg(feature = "capture")]
1364 match built_frame {
1365 true => self.save_capture_sequence(),
1366 _ => {},
1367 }
1368 }
1369 }
1370
1371 fn update_document(
1372 &mut self,
1373 document_id: DocumentId,
1374 resource_updates: Vec<ResourceUpdate>,
1375 mut frame_ops: Vec<FrameMsg>,
1376 mut notifications: Vec<NotificationRequest>,
1377 mut render_frame: bool,
1378 mut present: bool,
1379 render_reasons: RenderReasons,
1380 generated_frame_id: Option<u64>,
1381 invalidate_rendered_frame: bool,
1382 frame_counter: &mut u32,
1383 has_built_scene: bool,
1384 start_time: Option<u64>
1385 ) -> bool {
1386 let update_doc_start = precise_time_ns();
1387
1388 let requested_frame = render_frame;
1389
1390 let requires_frame_build = self.requires_frame_build();
1391 let doc = self.documents.get_mut(&document_id).unwrap();
1392
1393 if requested_frame {
1399 if let Some(ref sampler) = self.sampler {
1400 frame_ops.append(&mut sampler.sample(document_id, generated_frame_id));
1401 }
1402 }
1403
1404 doc.has_built_scene |= has_built_scene;
1405
1406 let mut scroll = false;
1409 for frame_msg in frame_ops {
1410 let op = doc.process_frame_msg(frame_msg);
1411 scroll |= op.scroll;
1412 }
1413
1414 for update in &resource_updates {
1415 if let ResourceUpdate::UpdateImage(..) = update {
1416 doc.frame_is_valid = false;
1417 }
1418 }
1419
1420 self.resource_cache.post_scene_building_update(
1421 resource_updates,
1422 &mut doc.profile,
1423 );
1424
1425 if doc.dynamic_properties.flush_pending_updates() {
1426 doc.frame_is_valid = false;
1427 doc.hit_tester_is_valid = false;
1428 }
1429
1430 if !doc.can_render() {
1431 render_frame = false;
1435 }
1436
1437 let build_frame = (render_frame && !doc.frame_is_valid && doc.has_pixels()) ||
1443 (requires_frame_build && doc.can_render());
1444
1445 if invalidate_rendered_frame {
1449 doc.rendered_frame_is_valid = false;
1450 if doc.scene.config.compositor_kind.should_redraw_on_invalidation() {
1451 let msg = ResultMsg::ForceRedraw;
1452 self.result_tx.send(msg).unwrap();
1453 }
1454 }
1455
1456 if build_frame {
1457 if !requested_frame {
1458 present = true;
1463 }
1464
1465 if start_time.is_some() {
1466 Telemetry::record_time_to_frame_build(Duration::from_nanos(precise_time_ns() - start_time.unwrap()));
1467 }
1468 profile_scope!("generate frame");
1469
1470 *frame_counter += 1;
1471
1472 let (pending_update, mut rendered_document) = {
1474 let timer_id = Telemetry::start_framebuild_time();
1475
1476 let frame_stats = doc.frame_stats.take();
1477
1478 let frame_memory = FrameMemory::new(self.chunk_pool.clone());
1479
1480 let rendered_document = doc.build_frame(
1481 &mut self.resource_cache,
1482 &mut self.gpu_cache,
1483 self.debug_flags,
1484 &mut self.tile_caches,
1485 frame_stats,
1486 present,
1487 render_reasons,
1488 frame_memory,
1489 );
1490
1491 debug!("generated frame for document {:?} with {} passes",
1492 document_id, rendered_document.frame.passes.len());
1493
1494 let msg = ResultMsg::UpdateGpuCache(self.gpu_cache.extract_updates());
1495 self.result_tx.send(msg).unwrap();
1496
1497 Telemetry::stop_and_accumulate_framebuild_time(timer_id);
1498
1499 let pending_update = self.resource_cache.pending_updates();
1500 (pending_update, rendered_document)
1501 };
1502
1503 rendered_document
1505 .frame
1506 .composite_state
1507 .update_dirty_rect_validity(&doc.prev_composite_descriptor);
1508
1509 let composite_descriptor = rendered_document
1511 .frame
1512 .composite_state
1513 .descriptor
1514 .clone();
1515
1516 if !pending_update.is_nop() ||
1520 !rendered_document.frame.is_nop() ||
1521 composite_descriptor != doc.prev_composite_descriptor {
1522 doc.rendered_frame_is_valid = false;
1523 }
1524 doc.prev_composite_descriptor = composite_descriptor;
1525
1526 #[cfg(feature = "capture")]
1527 match self.capture_config {
1528 Some(ref mut config) => {
1529 config.prepare_frame();
1531
1532 if config.bits.contains(CaptureBits::FRAME) {
1533 let file_name = format!("frame-{}-{}", document_id.namespace_id.0, document_id.id);
1534 config.serialize_for_frame(&rendered_document.frame, file_name);
1535 }
1536
1537 let data_stores_name = format!("data-stores-{}-{}", document_id.namespace_id.0, document_id.id);
1538 config.serialize_for_frame(&doc.data_stores, data_stores_name);
1539
1540 let frame_spatial_tree_name = format!("frame-spatial-tree-{}-{}", document_id.namespace_id.0, document_id.id);
1541 config.serialize_for_frame::<SpatialTree, _>(&doc.spatial_tree, frame_spatial_tree_name);
1542
1543 let properties_name = format!("properties-{}-{}", document_id.namespace_id.0, document_id.id);
1544 config.serialize_for_frame(&doc.dynamic_properties, properties_name);
1545 },
1546 None => {},
1547 }
1548
1549 let update_doc_time = profiler::ns_to_ms(precise_time_ns() - update_doc_start);
1550 rendered_document.profile.set(profiler::UPDATE_DOCUMENT_TIME, update_doc_time);
1551
1552 let msg = ResultMsg::PublishPipelineInfo(doc.updated_pipeline_info());
1553 self.result_tx.send(msg).unwrap();
1554
1555 self.frame_publish_id.advance();
1557 let msg = ResultMsg::PublishDocument(
1558 self.frame_publish_id,
1559 document_id,
1560 rendered_document,
1561 pending_update,
1562 );
1563 self.result_tx.send(msg).unwrap();
1564 } else if requested_frame {
1565 let msg = ResultMsg::PublishPipelineInfo(doc.updated_pipeline_info());
1570 self.result_tx.send(msg).unwrap();
1571 }
1572
1573 drain_filter(
1574 &mut notifications,
1575 |n| { n.when() == Checkpoint::FrameBuilt },
1576 |n| { n.notify(); },
1577 );
1578
1579 if !notifications.is_empty() {
1580 self.result_tx.send(ResultMsg::AppendNotificationRequests(notifications)).unwrap();
1581 }
1582
1583 if requested_frame {
1587 if doc.rendered_frame_is_valid {
1589 render_frame = false;
1590 } else if render_frame {
1591 doc.rendered_frame_is_valid = true;
1592 }
1593 let params = api::FrameReadyParams {
1594 present,
1595 render: render_frame,
1596 scrolled: scroll,
1597 };
1598 self.notifier.new_frame_ready(document_id, self.frame_publish_id, ¶ms);
1599 }
1600
1601 if !doc.hit_tester_is_valid {
1602 doc.rebuild_hit_tester();
1603 }
1604
1605 build_frame
1606 }
1607
1608 fn send_backend_message(&self, msg: SceneBuilderRequest) {
1609 self.scene_tx.send(msg).unwrap();
1610 }
1611
1612 fn report_memory(&mut self, tx: Sender<Box<MemoryReport>>) {
1613 let mut report = Box::new(MemoryReport::default());
1614 let ops = self.size_of_ops.as_mut().unwrap();
1615 let op = ops.size_of_op;
1616 report.gpu_cache_metadata = self.gpu_cache.size_of(ops);
1617 for doc in self.documents.values() {
1618 report.clip_stores += doc.scene.clip_store.size_of(ops);
1619 report.hit_testers += match &doc.hit_tester {
1620 Some(hit_tester) => hit_tester.size_of(ops),
1621 None => 0,
1622 };
1623
1624 doc.data_stores.report_memory(ops, &mut report)
1625 }
1626
1627 (*report) += self.resource_cache.report_memory(op);
1628 report.texture_cache_structures = self.resource_cache
1629 .texture_cache
1630 .report_memory(ops);
1631
1632 self.send_backend_message(
1636 SceneBuilderRequest::ReportMemory(report, tx)
1637 );
1638 }
1639
1640 #[cfg(feature = "capture")]
1641 fn save_capture_sequence(&mut self) {
1642 if let Some(ref mut config) = self.capture_config {
1643 let deferred = self.resource_cache.save_capture_sequence(config);
1644
1645 let backend = PlainRenderBackend {
1646 frame_config: self.frame_config.clone(),
1647 resource_sequence_id: config.resource_id,
1648 documents: self.documents
1649 .iter()
1650 .map(|(id, doc)| (*id, doc.view))
1651 .collect(),
1652 };
1653 config.serialize_for_frame(&backend, "backend");
1654
1655 if !deferred.is_empty() {
1656 let msg = ResultMsg::DebugOutput(DebugOutput::SaveCapture(config.clone(), deferred));
1657 self.result_tx.send(msg).unwrap();
1658 }
1659 }
1660 }
1661}
1662
1663impl RenderBackend {
1664 #[cfg(feature = "capture")]
1665 fn save_capture(
1667 &mut self,
1668 root: PathBuf,
1669 bits: CaptureBits,
1670 ) -> DebugOutput {
1671 use std::fs;
1672 use crate::render_task_graph::dump_render_tasks_as_svg;
1673
1674 debug!("capture: saving {:?}", root);
1675 if !root.is_dir() {
1676 if let Err(e) = fs::create_dir_all(&root) {
1677 panic!("Unable to create capture dir: {:?}", e);
1678 }
1679 }
1680 let config = CaptureConfig::new(root, bits);
1681
1682 if config.bits.contains(CaptureBits::FRAME) {
1683 self.prepare_for_frames();
1684 }
1685
1686 for (&id, doc) in &mut self.documents {
1687 debug!("\tdocument {:?}", id);
1688 if config.bits.contains(CaptureBits::FRAME) {
1689 let force_invalidation = std::mem::replace(&mut doc.scene.config.force_invalidation, true);
1691 let frame_memory = FrameMemory::new(self.chunk_pool.clone());
1692 let rendered_document = doc.build_frame(
1693 &mut self.resource_cache,
1694 &mut self.gpu_cache,
1695 self.debug_flags,
1696 &mut self.tile_caches,
1697 None,
1698 true,
1699 RenderReasons::empty(),
1700 frame_memory,
1701 );
1702
1703 doc.scene.config.force_invalidation = force_invalidation;
1704
1705 let msg_update_gpu_cache = ResultMsg::UpdateGpuCache(self.gpu_cache.extract_updates());
1709 self.result_tx.send(msg_update_gpu_cache).unwrap();
1710 let file_name = format!("frame-{}-{}", id.namespace_id.0, id.id);
1714 config.serialize_for_frame(&rendered_document.frame, file_name);
1715 let file_name = format!("spatial-{}-{}", id.namespace_id.0, id.id);
1716 config.serialize_tree_for_frame(&doc.spatial_tree, file_name);
1717 let file_name = format!("built-primitives-{}-{}", id.namespace_id.0, id.id);
1718 config.serialize_for_frame(&doc.scene.prim_store, file_name);
1719 let file_name = format!("built-clips-{}-{}", id.namespace_id.0, id.id);
1720 config.serialize_for_frame(&doc.scene.clip_store, file_name);
1721 let file_name = format!("scratch-{}-{}", id.namespace_id.0, id.id);
1722 config.serialize_for_frame(&doc.scratch.primitive, file_name);
1723 let file_name = format!("render-tasks-{}-{}.svg", id.namespace_id.0, id.id);
1724 let mut render_tasks_file = fs::File::create(&config.file_path_for_frame(file_name, "svg"))
1725 .expect("Failed to open the SVG file.");
1726 dump_render_tasks_as_svg(
1727 &rendered_document.frame.render_tasks,
1728 &mut render_tasks_file
1729 ).unwrap();
1730
1731 let file_name = format!("texture-cache-color-linear-{}-{}.svg", id.namespace_id.0, id.id);
1732 let mut texture_file = fs::File::create(&config.file_path_for_frame(file_name, "svg"))
1733 .expect("Failed to open the SVG file.");
1734 self.resource_cache.texture_cache.dump_color8_linear_as_svg(&mut texture_file).unwrap();
1735
1736 let file_name = format!("texture-cache-color8-glyphs-{}-{}.svg", id.namespace_id.0, id.id);
1737 let mut texture_file = fs::File::create(&config.file_path_for_frame(file_name, "svg"))
1738 .expect("Failed to open the SVG file.");
1739 self.resource_cache.texture_cache.dump_color8_glyphs_as_svg(&mut texture_file).unwrap();
1740
1741 let file_name = format!("texture-cache-alpha8-glyphs-{}-{}.svg", id.namespace_id.0, id.id);
1742 let mut texture_file = fs::File::create(&config.file_path_for_frame(file_name, "svg"))
1743 .expect("Failed to open the SVG file.");
1744 self.resource_cache.texture_cache.dump_alpha8_glyphs_as_svg(&mut texture_file).unwrap();
1745
1746 let file_name = format!("texture-cache-alpha8-linear-{}-{}.svg", id.namespace_id.0, id.id);
1747 let mut texture_file = fs::File::create(&config.file_path_for_frame(file_name, "svg"))
1748 .expect("Failed to open the SVG file.");
1749 self.resource_cache.texture_cache.dump_alpha8_linear_as_svg(&mut texture_file).unwrap();
1750 }
1751
1752 let data_stores_name = format!("data-stores-{}-{}", id.namespace_id.0, id.id);
1753 config.serialize_for_frame(&doc.data_stores, data_stores_name);
1754
1755 let frame_spatial_tree_name = format!("frame-spatial-tree-{}-{}", id.namespace_id.0, id.id);
1756 config.serialize_for_frame::<SpatialTree, _>(&doc.spatial_tree, frame_spatial_tree_name);
1757
1758 let properties_name = format!("properties-{}-{}", id.namespace_id.0, id.id);
1759 config.serialize_for_frame(&doc.dynamic_properties, properties_name);
1760 }
1761
1762 if config.bits.contains(CaptureBits::FRAME) {
1763 assert!(!self.requires_frame_build(), "Caches were cleared during a capture.");
1767 self.bookkeep_after_frames();
1768 }
1769
1770 debug!("\tscene builder");
1771 self.send_backend_message(
1772 SceneBuilderRequest::SaveScene(config.clone())
1773 );
1774
1775 debug!("\tresource cache");
1776 let (resources, deferred) = self.resource_cache.save_capture(&config.root);
1777
1778 info!("\tbackend");
1779 let backend = PlainRenderBackend {
1780 frame_config: self.frame_config.clone(),
1781 resource_sequence_id: 0,
1782 documents: self.documents
1783 .iter()
1784 .map(|(id, doc)| (*id, doc.view))
1785 .collect(),
1786 };
1787
1788 config.serialize_for_frame(&backend, "backend");
1789 config.serialize_for_frame(&resources, "plain-resources");
1790
1791 if config.bits.contains(CaptureBits::FRAME) {
1792 let msg_update_resources = ResultMsg::UpdateResources {
1793 resource_updates: self.resource_cache.pending_updates(),
1794 memory_pressure: false,
1795 };
1796 self.result_tx.send(msg_update_resources).unwrap();
1797 info!("\tresource cache");
1799 let caches = self.resource_cache.save_caches(&config.root);
1800 config.serialize_for_resource(&caches, "resource_cache");
1801 info!("\tgpu cache");
1802 config.serialize_for_resource(&self.gpu_cache, "gpu_cache");
1803 }
1804
1805 DebugOutput::SaveCapture(config, deferred)
1806 }
1807
1808 #[cfg(feature = "capture")]
1809 fn start_capture_sequence(
1810 &mut self,
1811 root: PathBuf,
1812 bits: CaptureBits,
1813 ) {
1814 self.send_backend_message(
1815 SceneBuilderRequest::StartCaptureSequence(CaptureConfig::new(root, bits))
1816 );
1817 }
1818
1819 #[cfg(feature = "capture")]
1820 fn stop_capture_sequence(
1821 &mut self,
1822 ) {
1823 self.send_backend_message(
1824 SceneBuilderRequest::StopCaptureSequence
1825 );
1826 }
1827
1828 #[cfg(feature = "replay")]
1829 fn load_capture(
1830 &mut self,
1831 mut config: CaptureConfig,
1832 ) {
1833 debug!("capture: loading {:?}", config.frame_root());
1834 let backend = config.deserialize_for_frame::<PlainRenderBackend, _>("backend")
1835 .expect("Unable to open backend.ron");
1836
1837 let first_load = backend.resource_sequence_id == 0;
1840 if self.loaded_resource_sequence_id != backend.resource_sequence_id || first_load {
1841 self.documents.clear();
1854
1855 config.resource_id = backend.resource_sequence_id;
1856 self.loaded_resource_sequence_id = backend.resource_sequence_id;
1857
1858 let plain_resources = config.deserialize_for_resource::<PlainResources, _>("plain-resources")
1859 .expect("Unable to open plain-resources.ron");
1860 let caches_maybe = config.deserialize_for_resource::<PlainCacheOwn, _>("resource_cache");
1861
1862 let plain_externals = self.resource_cache.load_capture(
1867 plain_resources,
1868 caches_maybe,
1869 &config,
1870 );
1871
1872 let msg_load = ResultMsg::DebugOutput(
1873 DebugOutput::LoadCapture(config.clone(), plain_externals)
1874 );
1875 self.result_tx.send(msg_load).unwrap();
1876
1877 self.gpu_cache = match config.deserialize_for_resource::<GpuCache, _>("gpu_cache") {
1878 Some(gpu_cache) => gpu_cache,
1879 None => GpuCache::new(),
1880 };
1881 }
1882
1883 self.frame_config = backend.frame_config;
1884
1885 let mut scenes_to_build = Vec::new();
1886
1887 for (id, view) in backend.documents {
1888 debug!("\tdocument {:?}", id);
1889 let scene_name = format!("scene-{}-{}", id.namespace_id.0, id.id);
1890 let scene = config.deserialize_for_scene::<Scene, _>(&scene_name)
1891 .expect(&format!("Unable to open {}.ron", scene_name));
1892
1893 let scene_spatial_tree_name = format!("scene-spatial-tree-{}-{}", id.namespace_id.0, id.id);
1894 let scene_spatial_tree = config.deserialize_for_scene::<SceneSpatialTree, _>(&scene_spatial_tree_name)
1895 .expect(&format!("Unable to open {}.ron", scene_spatial_tree_name));
1896
1897 let interners_name = format!("interners-{}-{}", id.namespace_id.0, id.id);
1898 let interners = config.deserialize_for_scene::<Interners, _>(&interners_name)
1899 .expect(&format!("Unable to open {}.ron", interners_name));
1900
1901 let data_stores_name = format!("data-stores-{}-{}", id.namespace_id.0, id.id);
1902 let data_stores = config.deserialize_for_frame::<DataStores, _>(&data_stores_name)
1903 .expect(&format!("Unable to open {}.ron", data_stores_name));
1904
1905 let properties_name = format!("properties-{}-{}", id.namespace_id.0, id.id);
1906 let properties = config.deserialize_for_frame::<SceneProperties, _>(&properties_name)
1907 .expect(&format!("Unable to open {}.ron", properties_name));
1908
1909 let frame_spatial_tree_name = format!("frame-spatial-tree-{}-{}", id.namespace_id.0, id.id);
1910 let frame_spatial_tree = config.deserialize_for_frame::<SpatialTree, _>(&frame_spatial_tree_name)
1911 .expect(&format!("Unable to open {}.ron", frame_spatial_tree_name));
1912
1913 match self.documents.entry(id) {
1917 Occupied(entry) => {
1918 let doc = entry.into_mut();
1919 doc.view = view;
1920 doc.loaded_scene = scene.clone();
1921 doc.data_stores = data_stores;
1922 doc.spatial_tree = frame_spatial_tree;
1923 doc.dynamic_properties = properties;
1924 doc.frame_is_valid = false;
1925 doc.rendered_frame_is_valid = false;
1926 doc.has_built_scene = false;
1927 doc.hit_tester_is_valid = false;
1928 }
1929 Vacant(entry) => {
1930 let doc = Document {
1931 id,
1932 scene: BuiltScene::empty(),
1933 removed_pipelines: Vec::new(),
1934 view,
1935 stamp: FrameStamp::first(id),
1936 frame_builder: FrameBuilder::new(),
1937 dynamic_properties: properties,
1938 hit_tester: None,
1939 shared_hit_tester: Arc::new(SharedHitTester::new()),
1940 frame_is_valid: false,
1941 hit_tester_is_valid: false,
1942 rendered_frame_is_valid: false,
1943 has_built_scene: false,
1944 data_stores,
1945 scratch: ScratchBuffer::default(),
1946 spatial_tree: frame_spatial_tree,
1947 minimap_data: FastHashMap::default(),
1948 loaded_scene: scene.clone(),
1949 prev_composite_descriptor: CompositeDescriptor::empty(),
1950 dirty_rects_are_valid: false,
1951 profile: TransactionProfile::new(),
1952 rg_builder: RenderTaskGraphBuilder::new(),
1953 frame_stats: None,
1954 };
1955 entry.insert(doc);
1956 }
1957 };
1958
1959 let frame_name = format!("frame-{}-{}", id.namespace_id.0, id.id);
1960 let frame = config.deserialize_for_frame::<Frame, _>(frame_name);
1961 let build_frame = match frame {
1962 Some(frame) => {
1963 info!("\tloaded a built frame with {} passes", frame.passes.len());
1964
1965 let msg_update = ResultMsg::UpdateGpuCache(self.gpu_cache.extract_updates());
1966 self.result_tx.send(msg_update).unwrap();
1967
1968 self.frame_publish_id.advance();
1969 let msg_publish = ResultMsg::PublishDocument(
1970 self.frame_publish_id,
1971 id,
1972 RenderedDocument {
1973 frame,
1974 profile: TransactionProfile::new(),
1975 render_reasons: RenderReasons::empty(),
1976 frame_stats: None,
1977 },
1978 self.resource_cache.pending_updates(),
1979 );
1980 self.result_tx.send(msg_publish).unwrap();
1981
1982 let params = api::FrameReadyParams {
1983 present: true,
1984 render: true,
1985 scrolled: false,
1986 };
1987 self.notifier.new_frame_ready(id, self.frame_publish_id, ¶ms);
1988
1989 false
1992 }
1993 None => true,
1994 };
1995
1996 scenes_to_build.push(LoadScene {
1997 document_id: id,
1998 scene,
1999 view: view.scene.clone(),
2000 config: self.frame_config.clone(),
2001 fonts: self.resource_cache.get_fonts(),
2002 build_frame,
2003 interners,
2004 spatial_tree: scene_spatial_tree,
2005 });
2006 }
2007
2008 if !scenes_to_build.is_empty() {
2009 self.send_backend_message(
2010 SceneBuilderRequest::LoadScenes(scenes_to_build)
2011 );
2012 }
2013 }
2014}