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, RenderReasons};
16use api::units::*;
17use api::channel::{single_msg_channel, Sender, Receiver};
18use crate::bump_allocator::ChunkPool;
19use crate::AsyncPropertySampler;
20use crate::box_shadow::BoxShadow;
21use crate::prim_store::rectangle::RectanglePrim;
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::hit_test::{HitTest, HitTester, SharedHitTester};
35use crate::intern::DataStore;
36#[cfg(any(feature = "capture", feature = "replay"))]
37use crate::internal_types::DebugOutput;
38use crate::internal_types::{FastHashMap, FrameId, FrameStamp, RenderedDocument, ResultMsg};
39use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
40use crate::picture::{PictureScratchBuffer, SurfaceInfo, RasterConfig};
41use crate::tile_cache::{SliceId, TileCacheInstance, TileCacheParams};
42use crate::picture::PictureInstance;
43use crate::prim_store::{PrimitiveScratchBuffer, PrimitiveInstance};
44use crate::prim_store::{PrimitiveKind, 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#[cfg(feature = "debugger")]
78use crate::debugger::DebugQueryKind;
79
80#[cfg_attr(feature = "capture", derive(Serialize))]
81#[cfg_attr(feature = "replay", derive(Deserialize))]
82#[derive(Copy, Clone)]
83pub struct DocumentView {
84 scene: SceneView,
85}
86
87#[cfg_attr(feature = "capture", derive(Serialize))]
89#[cfg_attr(feature = "replay", derive(Deserialize))]
90#[derive(Copy, Clone)]
91pub struct SceneView {
92 pub device_rect: DeviceIntRect,
93 pub quality_settings: QualitySettings,
94}
95
96enum RenderBackendStatus {
97 Continue,
98 StopRenderBackend,
99 ShutDown(Option<Sender<()>>),
100}
101
102macro_rules! declare_data_stores {
103 ( $( $name:ident : $ty:ty, )+ ) => {
104 #[cfg_attr(feature = "capture", derive(Serialize))]
107 #[cfg_attr(feature = "replay", derive(Deserialize))]
108 #[derive(Default)]
109 pub struct DataStores {
110 $(
111 pub $name: DataStore<$ty>,
112 )+
113 }
114
115 impl DataStores {
116 fn report_memory(&self, ops: &mut MallocSizeOfOps, r: &mut MemoryReport) {
118 $(
119 r.interning.data_stores.$name += self.$name.size_of(ops);
120 )+
121 }
122
123 fn apply_updates(
124 &mut self,
125 updates: InternerUpdates,
126 profile: &mut TransactionProfile,
127 ) {
128 $(
129 self.$name.apply_updates(
130 updates.$name,
131 profile,
132 );
133 )+
134 }
135 }
136 }
137}
138
139crate::enumerate_interners!(declare_data_stores);
140
141impl DataStores {
142 pub fn get_local_prim_rect(
147 &self,
148 prim_instance: &PrimitiveInstance,
149 snapped_local_rect: LayoutRect,
150 pictures: &[PictureInstance],
151 surfaces: &[SurfaceInfo],
152 ) -> LayoutRect {
153 match prim_instance.kind {
154 PrimitiveKind::Picture { pic_index, .. } => {
155 let pic = &pictures[pic_index.0];
156
157 match pic.raster_config {
158 Some(RasterConfig { surface_index, ref composite_mode, .. }) => {
159 let surface = &surfaces[surface_index.0];
160
161 composite_mode.get_rect(surface, None)
162 }
163 None => {
164 panic!("bug: get_local_prim_rect should not be called for pass-through pictures");
165 }
166 }
167 }
168 _ => snapped_local_rect,
169 }
170 }
171
172 pub fn get_local_prim_coverage_rect(
177 &self,
178 prim_instance: &PrimitiveInstance,
179 snapped_local_rect: LayoutRect,
180 pictures: &[PictureInstance],
181 surfaces: &[SurfaceInfo],
182 ) -> LayoutRect {
183 match prim_instance.kind {
184 PrimitiveKind::Picture { pic_index, .. } => {
185 let pic = &pictures[pic_index.0];
186
187 match pic.raster_config {
188 Some(RasterConfig { surface_index, ref composite_mode, .. }) => {
189 let surface = &surfaces[surface_index.0];
190
191 composite_mode.get_coverage(surface, None)
192 }
193 None => {
194 panic!("bug: get_local_prim_coverage_rect should not be called for pass-through pictures");
195 }
196 }
197 }
198 _ => snapped_local_rect,
199 }
200 }
201
202 pub fn prim_has_anti_aliasing(
204 &self,
205 prim_instance: &PrimitiveInstance,
206 ) -> bool {
207 match prim_instance.kind {
208 PrimitiveKind::Picture { .. } => {
209 false
210 }
211 _ => {
212 self.as_common_data(prim_instance).flags.contains(PrimitiveFlags::ANTIALISED)
213 }
214 }
215 }
216
217 pub fn as_common_data(
218 &self,
219 prim_inst: &PrimitiveInstance
220 ) -> &PrimTemplateCommonData {
221 match prim_inst.kind {
222 PrimitiveKind::Rectangle { data_handle, .. } => {
223 let prim_data = &self.prim[data_handle];
224 &prim_data.common
225 }
226 PrimitiveKind::Image { data_handle, .. } => {
227 let prim_data = &self.image[data_handle];
228 &prim_data.common
229 }
230 PrimitiveKind::ImageBorder { data_handle, .. } => {
231 let prim_data = &self.image_border[data_handle];
232 &prim_data.common
233 }
234 PrimitiveKind::LineDecoration { data_handle, .. } => {
235 let prim_data = &self.line_decoration[data_handle];
236 &prim_data.common
237 }
238 PrimitiveKind::LinearGradient { data_handle, .. } => {
239 let prim_data = &self.linear_grad[data_handle];
240 &prim_data.common
241 }
242 PrimitiveKind::NormalBorder { data_handle, .. } => {
243 let prim_data = &self.normal_border[data_handle];
244 &prim_data.common
245 }
246 PrimitiveKind::Picture { .. } => {
247 panic!("BUG: picture prims don't have common data!");
248 }
249 PrimitiveKind::RadialGradient { data_handle, .. } => {
250 let prim_data = &self.radial_grad[data_handle];
251 &prim_data.common
252 }
253 PrimitiveKind::ConicGradient { data_handle, .. } => {
254 let prim_data = &self.conic_grad[data_handle];
255 &prim_data.common
256 }
257 PrimitiveKind::TextRun { data_handle, .. } => {
258 let prim_data = &self.text_run[data_handle];
259 &prim_data.common
260 }
261 PrimitiveKind::YuvImage { data_handle, .. } => {
262 let prim_data = &self.yuv_image[data_handle];
263 &prim_data.common
264 }
265 PrimitiveKind::BackdropCapture { data_handle, .. } => {
266 let prim_data = &self.backdrop_capture[data_handle];
267 &prim_data.common
268 }
269 PrimitiveKind::BackdropRender { data_handle, .. } => {
270 let prim_data = &self.backdrop_render[data_handle];
271 &prim_data.common
272 }
273 PrimitiveKind::BoxShadow { data_handle, .. } => {
274 let prim_data = &self.box_shadow[data_handle];
275 &prim_data.common
276 }
277 }
278 }
279}
280
281#[derive(Default)]
282pub struct ScratchBuffer {
283 pub primitive: PrimitiveScratchBuffer,
284 pub picture: PictureScratchBuffer,
285 pub frame: FrameScratchBuffer,
286 pub clip_store: ClipStoreScratchBuffer,
287}
288
289impl ScratchBuffer {
290 pub fn begin_frame(&mut self) {
291 self.primitive.begin_frame();
292 self.picture.begin_frame();
293 self.frame.begin_frame();
294 }
295
296 pub fn end_frame(&mut self) {
297 self.primitive.end_frame();
298 }
299
300 pub fn recycle(&mut self, recycler: &mut Recycler) {
301 self.primitive.recycle(recycler);
302 self.picture.recycle(recycler);
303 }
304
305 pub fn memory_pressure(&mut self) {
306 self.picture = Default::default();
309 self.frame = Default::default();
310 self.clip_store = Default::default();
311 }
312}
313
314struct Document {
315 id: DocumentId,
317
318 removed_pipelines: Vec<(PipelineId, DocumentId)>,
321
322 view: DocumentView,
323
324 stamp: FrameStamp,
326
327 scene: BuiltScene,
330
331 frame_builder: FrameBuilder,
333
334 rg_builder: RenderTaskGraphBuilder,
336
337 hit_tester: Option<Arc<HitTester>>,
340 shared_hit_tester: Arc<SharedHitTester>,
343
344 dynamic_properties: SceneProperties,
347
348 frame_is_valid: bool,
351 hit_tester_is_valid: bool,
352 rendered_frame_is_valid: bool,
353 has_built_scene: bool,
356
357 data_stores: DataStores,
358
359 spatial_tree: SpatialTree,
361
362 minimap_data: FastHashMap<ExternalScrollId, MinimapData>,
363
364 scratch: ScratchBuffer,
368
369 #[cfg(feature = "replay")]
370 loaded_scene: Scene,
371
372 prev_composite_descriptor: CompositeDescriptor,
374
375 dirty_rects_are_valid: bool,
378
379 profile: TransactionProfile,
380 frame_stats: Option<FullFrameStats>,
381}
382
383impl Document {
384 pub fn new(
385 id: DocumentId,
386 size: DeviceIntSize,
387 ) -> Self {
388 Document {
389 id,
390 removed_pipelines: Vec::new(),
391 view: DocumentView {
392 scene: SceneView {
393 device_rect: size.into(),
394 quality_settings: QualitySettings::default(),
395 },
396 },
397 stamp: FrameStamp::first(id),
398 scene: BuiltScene::empty(),
399 frame_builder: FrameBuilder::new(),
400 hit_tester: None,
401 shared_hit_tester: Arc::new(SharedHitTester::new()),
402 dynamic_properties: SceneProperties::new(),
403 frame_is_valid: false,
404 hit_tester_is_valid: false,
405 rendered_frame_is_valid: false,
406 has_built_scene: false,
407 data_stores: DataStores::default(),
408 spatial_tree: SpatialTree::new(),
409 minimap_data: FastHashMap::default(),
410 scratch: ScratchBuffer::default(),
411 #[cfg(feature = "replay")]
412 loaded_scene: Scene::new(),
413 prev_composite_descriptor: CompositeDescriptor::empty(),
414 dirty_rects_are_valid: true,
415 profile: TransactionProfile::new(),
416 rg_builder: RenderTaskGraphBuilder::new(),
417 frame_stats: None,
418 }
419 }
420
421 fn can_render(&self) -> bool {
422 self.scene.has_root_pipeline
423 }
424
425 fn has_pixels(&self) -> bool {
426 !self.view.scene.device_rect.is_empty()
427 }
428
429 fn process_frame_msg(
430 &mut self,
431 message: FrameMsg,
432 ) -> DocumentOps {
433 match message {
434 FrameMsg::UpdateEpoch(pipeline_id, epoch) => {
435 self.scene.pipeline_epochs.insert(pipeline_id, epoch);
436 }
437 FrameMsg::HitTest(point, tx) => {
438 if !self.hit_tester_is_valid {
439 self.rebuild_hit_tester();
440 }
441
442 let result = match self.hit_tester {
443 Some(ref hit_tester) => {
444 hit_tester.hit_test(HitTest::new(point))
445 }
446 None => HitTestResult { items: Vec::new() },
447 };
448
449 tx.send(result).unwrap();
450 }
451 FrameMsg::RequestHitTester(tx) => {
452 tx.send(self.shared_hit_tester.clone()).unwrap();
453 }
454 FrameMsg::SetScrollOffsets(id, offset) => {
455 profile_scope!("SetScrollOffset");
456
457 if self.set_scroll_offsets(id, offset) {
458 self.hit_tester_is_valid = false;
459 self.frame_is_valid = false;
460 }
461
462 return DocumentOps {
463 scroll: true,
464 ..DocumentOps::nop()
465 };
466 }
467 FrameMsg::ResetDynamicProperties => {
468 self.dynamic_properties.reset_properties();
469 }
470 FrameMsg::AppendDynamicProperties(property_bindings) => {
471 self.dynamic_properties.add_properties(property_bindings);
472 }
473 FrameMsg::AppendDynamicTransformProperties(property_bindings) => {
474 self.dynamic_properties.add_transforms(property_bindings);
475 }
476 FrameMsg::SetIsTransformAsyncZooming(is_zooming, animation_id) => {
477 if let Some(node_index) = self.spatial_tree.find_spatial_node_by_anim_id(animation_id) {
478 let node = self.spatial_tree.get_spatial_node_mut(node_index);
479
480 if node.is_async_zooming != is_zooming {
481 node.is_async_zooming = is_zooming;
482 self.frame_is_valid = false;
483 }
484 }
485 }
486 FrameMsg::SetMinimapData(id, minimap_data) => {
487 self.minimap_data.insert(id, minimap_data);
488 }
489 }
490
491 DocumentOps::nop()
492 }
493
494 fn build_frame(
495 &mut self,
496 resource_cache: &mut ResourceCache,
497 debug_flags: DebugFlags,
498 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
499 frame_stats: Option<FullFrameStats>,
500 present: bool,
501 render_reasons: RenderReasons,
502 chunk_pool: Arc<ChunkPool>,
503 ) -> RenderedDocument {
504 let frame_build_start_time = zeitstempel::now();
505
506 self.stamp.advance();
508
509 assert!(self.stamp.frame_id() != FrameId::INVALID,
510 "First frame increment must happen before build_frame()");
511
512 let frame = {
513 let frame = self.frame_builder.build(
514 &mut self.scene,
515 present,
516 resource_cache,
517 &mut self.rg_builder,
518 self.stamp,
519 self.view.scene.device_rect.min,
520 &self.dynamic_properties,
521 &mut self.data_stores,
522 &mut self.scratch,
523 debug_flags,
524 tile_caches,
525 &mut self.spatial_tree,
526 self.dirty_rects_are_valid,
527 &mut self.profile,
528 mem::take(&mut self.minimap_data),
532 chunk_pool,
533 );
534
535 frame
536 };
537
538 self.frame_is_valid = true;
539 self.dirty_rects_are_valid = true;
540
541 self.has_built_scene = false;
542
543 let frame_build_time_ms =
544 profiler::ns_to_ms(zeitstempel::now() - frame_build_start_time);
545 self.profile.set(profiler::FRAME_BUILDING_TIME, frame_build_time_ms);
546 self.profile.start_time(profiler::FRAME_SEND_TIME);
547
548 let frame_stats = frame_stats.map(|mut stats| {
549 stats.frame_build_time += frame_build_time_ms;
550 stats
551 });
552
553 RenderedDocument {
554 frame,
555 profile: self.profile.take_and_reset(),
556 frame_stats: frame_stats,
557 render_reasons,
558 }
559 }
560
561 fn process_offscreen_scene(
567 &mut self,
568 mut txn: OffscreenBuiltScene,
569 resource_cache: &mut ResourceCache,
570 chunk_pool: Arc<ChunkPool>,
571 debug_flags: DebugFlags,
572 ) -> RenderedDocument {
573 let mut profile = TransactionProfile::new();
574 self.stamp.advance();
575
576 let mut data_stores = DataStores::default();
577 data_stores.apply_updates(txn.interner_updates, &mut profile);
578
579 let mut spatial_tree = SpatialTree::new();
580 spatial_tree.apply_updates(txn.spatial_tree_updates);
581
582 let mut tile_caches = FastHashMap::default();
583 self.update_tile_caches_for_new_scene(
584 mem::take(&mut txn.scene.tile_cache_config.tile_caches),
585 &mut tile_caches,
586 resource_cache,
587 );
588
589 let present = false;
590
591 let frame = self.frame_builder.build(
592 &mut txn.scene,
593 present,
594 resource_cache,
595 &mut self.rg_builder,
596 self.stamp, self.view.scene.device_rect.min,
598 &self.dynamic_properties,
599 &mut data_stores,
600 &mut self.scratch,
601 debug_flags,
602 &mut tile_caches,
603 &mut spatial_tree,
604 self.dirty_rects_are_valid,
605 &mut profile,
606 mem::take(&mut self.minimap_data),
610 chunk_pool,
611 );
612
613 RenderedDocument {
614 frame,
615 profile,
616 render_reasons: RenderReasons::SNAPSHOT,
617 frame_stats: None,
618 }
619 }
620
621
622 fn rebuild_hit_tester(&mut self) {
623 self.spatial_tree.update_tree(&self.dynamic_properties);
624
625 let hit_tester = Arc::new(self.scene.create_hit_tester(&self.spatial_tree));
626 self.hit_tester = Some(Arc::clone(&hit_tester));
627 self.shared_hit_tester.update(hit_tester);
628 self.hit_tester_is_valid = true;
629 }
630
631 pub fn updated_pipeline_info(&mut self) -> PipelineInfo {
632 let removed_pipelines = self.removed_pipelines.take_and_preallocate();
633 PipelineInfo {
634 epochs: self.scene.pipeline_epochs.iter()
635 .map(|(&pipeline_id, &epoch)| ((pipeline_id, self.id), epoch)).collect(),
636 removed_pipelines,
637 }
638 }
639
640 pub fn set_scroll_offsets(
642 &mut self,
643 id: ExternalScrollId,
644 offsets: Vec<SampledScrollOffset>,
645 ) -> bool {
646 self.spatial_tree.set_scroll_offsets(id, offsets)
647 }
648
649 fn update_tile_caches_for_new_scene(
653 &mut self,
654 mut requested_tile_caches: FastHashMap<SliceId, TileCacheParams>,
655 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
656 resource_cache: &mut ResourceCache,
657 ) {
658 let mut new_tile_caches = FastHashMap::default();
659 new_tile_caches.reserve(requested_tile_caches.len());
660
661 for (slice_id, params) in requested_tile_caches.drain() {
664 let tile_cache = match tile_caches.remove(&slice_id) {
665 Some(mut existing_tile_cache) => {
666 existing_tile_cache.prepare_for_new_scene(
668 params,
669 resource_cache,
670 );
671 existing_tile_cache
672 }
673 None => {
674 Box::new(TileCacheInstance::new(params))
676 }
677 };
678
679 new_tile_caches.insert(slice_id, tile_cache);
680 }
681
682 let unused_tile_caches = mem::replace(
685 tile_caches,
686 new_tile_caches,
687 );
688
689 if !unused_tile_caches.is_empty() {
690 self.dirty_rects_are_valid = false;
693
694 for (_, tile_cache) in unused_tile_caches {
696 tile_cache.destroy(resource_cache);
697 }
698 }
699 }
700
701 pub fn new_async_scene_ready(
702 &mut self,
703 mut built_scene: BuiltScene,
704 recycler: &mut Recycler,
705 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
706 resource_cache: &mut ResourceCache,
707 ) {
708 self.frame_is_valid = false;
709 self.hit_tester_is_valid = false;
710
711 self.update_tile_caches_for_new_scene(
712 mem::replace(&mut built_scene.tile_cache_config.tile_caches, FastHashMap::default()),
713 tile_caches,
714 resource_cache,
715 );
716
717
718 let old_scene = std::mem::replace(&mut self.scene, built_scene);
719 old_scene.recycle();
720
721 self.scratch.recycle(recycler);
722 }
723}
724
725struct DocumentOps {
726 scroll: bool,
727}
728
729impl DocumentOps {
730 fn nop() -> Self {
731 DocumentOps {
732 scroll: false,
733 }
734 }
735}
736
737static NEXT_NAMESPACE_ID: AtomicUsize = AtomicUsize::new(1);
740
741#[cfg(any(feature = "capture", feature = "replay"))]
742#[cfg_attr(feature = "capture", derive(Serialize))]
743#[cfg_attr(feature = "replay", derive(Deserialize))]
744struct PlainRenderBackend {
745 frame_config: FrameBuilderConfig,
746 documents: FastHashMap<DocumentId, DocumentView>,
747 resource_sequence_id: u32,
748}
749
750pub struct RenderBackend {
755 api_rx: Receiver<ApiMsg>,
756 result_tx: Sender<ResultMsg>,
757 scene_tx: Sender<SceneBuilderRequest>,
758
759 resource_cache: ResourceCache,
760 chunk_pool: Arc<ChunkPool>,
761
762 frame_config: FrameBuilderConfig,
763 default_compositor_kind: CompositorKind,
764 documents: FastHashMap<DocumentId, Document>,
765
766 notifier: Box<dyn RenderNotifier>,
767 sampler: Option<Box<dyn AsyncPropertySampler + Send>>,
768 size_of_ops: Option<MallocSizeOfOps>,
769 debug_flags: DebugFlags,
770 namespace_alloc_by_client: bool,
771
772 recycler: Recycler,
773
774 #[cfg(feature = "capture")]
775 capture_config: Option<CaptureConfig>,
779
780 #[cfg(feature = "replay")]
781 loaded_resource_sequence_id: u32,
782
783 tile_caches: FastHashMap<SliceId, Box<TileCacheInstance>>,
786
787 frame_publish_id: FramePublishId,
789}
790
791impl RenderBackend {
792 pub fn new(
793 api_rx: Receiver<ApiMsg>,
794 result_tx: Sender<ResultMsg>,
795 scene_tx: Sender<SceneBuilderRequest>,
796 resource_cache: ResourceCache,
797 chunk_pool: Arc<ChunkPool>,
798 notifier: Box<dyn RenderNotifier>,
799 frame_config: FrameBuilderConfig,
800 sampler: Option<Box<dyn AsyncPropertySampler + Send>>,
801 size_of_ops: Option<MallocSizeOfOps>,
802 debug_flags: DebugFlags,
803 namespace_alloc_by_client: bool,
804 ) -> RenderBackend {
805 RenderBackend {
806 api_rx,
807 result_tx,
808 scene_tx,
809 resource_cache,
810 chunk_pool,
811 frame_config,
812 default_compositor_kind : frame_config.compositor_kind,
813 documents: FastHashMap::default(),
814 notifier,
815 sampler,
816 size_of_ops,
817 debug_flags,
818 namespace_alloc_by_client,
819 recycler: Recycler::new(),
820 #[cfg(feature = "capture")]
821 capture_config: None,
822 #[cfg(feature = "replay")]
823 loaded_resource_sequence_id: 0,
824 tile_caches: FastHashMap::default(),
825 frame_publish_id: FramePublishId::first(),
826 }
827 }
828
829 pub fn next_namespace_id() -> IdNamespace {
830 IdNamespace(NEXT_NAMESPACE_ID.fetch_add(1, Ordering::Relaxed) as u32)
831 }
832
833 pub fn run(&mut self) {
834 let mut frame_counter: u32 = 0;
835 let mut status = RenderBackendStatus::Continue;
836
837 if let Some(ref sampler) = self.sampler {
838 sampler.register();
839 }
840
841 while let RenderBackendStatus::Continue = status {
842 status = match self.api_rx.recv() {
843 Ok(msg) => {
844 self.process_api_msg(msg, &mut frame_counter)
845 }
846 Err(..) => { RenderBackendStatus::ShutDown(None) }
847 };
848 }
849
850 if let RenderBackendStatus::StopRenderBackend = status {
851 while let Ok(msg) = self.api_rx.recv() {
852 match msg {
853 ApiMsg::SceneBuilderResult(SceneBuilderResult::ExternalEvent(evt)) => {
854 self.notifier.external_event(evt);
855 }
856 ApiMsg::SceneBuilderResult(SceneBuilderResult::FlushComplete(tx)) => {
857 debug_assert!(false);
861 tx.send(()).ok();
862 }
863 ApiMsg::SceneBuilderResult(SceneBuilderResult::ShutDown(sender)) => {
864 info!("Recycling stats: {:?}", self.recycler);
865 status = RenderBackendStatus::ShutDown(sender);
866 break;
867 }
868 _ => {},
869 }
870 }
871 }
872
873 while let Ok(msg) = self.api_rx.try_recv() {
876 match msg {
877 ApiMsg::SceneBuilderResult(SceneBuilderResult::FlushComplete(tx)) => {
878 debug_assert!(false);
882 tx.send(()).ok();
883 }
884 _ => {},
885 }
886 }
887
888 self.documents.clear();
889
890 self.notifier.shut_down();
891
892 if let Some(ref sampler) = self.sampler {
893 sampler.deregister();
894 }
895
896
897 if let RenderBackendStatus::ShutDown(Some(sender)) = status {
898 let _ = sender.send(());
899 }
900 }
901
902 fn process_transaction(
903 &mut self,
904 mut txns: Vec<Box<BuiltTransaction>>,
905 result_tx: Option<Sender<SceneSwapResult>>,
906 frame_counter: &mut u32,
907 ) -> bool {
908 self.maybe_force_nop_documents(
909 frame_counter,
910 |document_id| txns.iter().any(|txn| txn.document_id == document_id));
911
912 let mut built_frame = false;
913 for mut txn in txns.drain(..) {
914 let has_built_scene = txn.built_scene.is_some();
915
916 if let Some(doc) = self.documents.get_mut(&txn.document_id) {
917 doc.removed_pipelines.append(&mut txn.removed_pipelines);
918 doc.view.scene = txn.view;
919 doc.profile.merge(&mut txn.profile);
920
921 doc.frame_stats = if let Some(stats) = &doc.frame_stats {
922 Some(stats.merge(&txn.frame_stats))
923 } else {
924 Some(txn.frame_stats)
925 };
926
927 let last_sampled_scroll_offsets = if self.sampler.is_some() {
930 Some(doc.spatial_tree.get_last_sampled_scroll_offsets())
931 } else {
932 None
933 };
934
935 if let Some(updates) = txn.spatial_tree_updates.take() {
936 doc.spatial_tree.apply_updates(updates);
937 }
938
939 if let Some(built_scene) = txn.built_scene.take() {
940 doc.new_async_scene_ready(
941 built_scene,
942 &mut self.recycler,
943 &mut self.tile_caches,
944 &mut self.resource_cache,
945 );
946 }
947
948 if let Some(updates) = txn.interner_updates.take() {
952 doc.data_stores.apply_updates(updates, &mut doc.profile);
953 }
954
955 if let Some(last_sampled) = last_sampled_scroll_offsets {
962 doc.spatial_tree
963 .apply_last_sampled_scroll_offsets(last_sampled);
964 }
965
966 if !doc.hit_tester_is_valid {
969 doc.rebuild_hit_tester();
970 }
971
972 if let Some(ref tx) = result_tx {
973 let (resume_tx, resume_rx) = single_msg_channel();
974 tx.send(SceneSwapResult::Complete(resume_tx)).unwrap();
975 resume_rx.recv().ok();
980 }
981
982 self.resource_cache.add_rasterized_blob_images(
983 txn.rasterized_blobs.take(),
984 &mut doc.profile,
985 );
986
987 for offscreen_scene in txn.offscreen_scenes.drain(..) {
988 self.resource_cache.post_scene_building_update(
989 txn.resource_updates.take(),
990 &mut doc.profile,
991 );
992
993 let rendered_document = doc.process_offscreen_scene(
994 offscreen_scene,
995 &mut self.resource_cache,
996 self.chunk_pool.clone(),
997 self.debug_flags,
998 );
999
1000 let pending_update = self.resource_cache.pending_updates();
1001
1002 let msg = ResultMsg::PublishDocument(
1003 self.frame_publish_id,
1004 txn.document_id,
1005 rendered_document,
1006 pending_update,
1007 );
1008 self.result_tx.send(msg).unwrap();
1009
1010 let params = api::FrameReadyParams {
1011 present: false,
1012 render: true,
1013 scrolled: false,
1014 tracked: false,
1015 };
1016
1017 self.notifier.new_frame_ready(
1018 txn.document_id,
1019 self.frame_publish_id,
1020 ¶ms
1021 );
1022 }
1023 } else {
1024 if let Some(ref tx) = result_tx {
1028 tx.send(SceneSwapResult::Aborted).unwrap();
1029 }
1030 continue;
1031 }
1032
1033 built_frame |= self.update_document(
1034 txn.document_id,
1035 txn.resource_updates.take(),
1036 txn.frame_ops.take(),
1037 txn.notifications.take(),
1038 txn.render_frame,
1039 txn.present,
1040 txn.tracked,
1041 RenderReasons::SCENE,
1042 None,
1043 txn.invalidate_rendered_frame,
1044 frame_counter,
1045 has_built_scene,
1046 None,
1047 );
1048
1049 if self.debug_flags.contains(DebugFlags::DUMP_SPATIAL_TREE) {
1050 if let Some(doc) = self.documents.get(&txn.document_id) {
1051 let spatial_tree = doc.spatial_tree.print_to_string();
1052 if !spatial_tree.is_empty() {
1053 eprintln!(
1054 "-- WebRender spatial tree ({:?}) --\n{}",
1055 txn.document_id, spatial_tree
1056 );
1057 }
1058 }
1059 }
1060 }
1061
1062 built_frame
1063 }
1064
1065 fn process_api_msg(
1066 &mut self,
1067 msg: ApiMsg,
1068 frame_counter: &mut u32,
1069 ) -> RenderBackendStatus {
1070 match msg {
1071 ApiMsg::CloneApi(sender) => {
1072 assert!(!self.namespace_alloc_by_client);
1073 sender.send(Self::next_namespace_id()).unwrap();
1074 }
1075 ApiMsg::CloneApiByClient(namespace_id) => {
1076 assert!(self.namespace_alloc_by_client);
1077 debug_assert!(!self.documents.iter().any(|(did, _doc)| did.namespace_id == namespace_id));
1078 }
1079 ApiMsg::AddDocument(document_id, initial_size) => {
1080 let document = Document::new(
1081 document_id,
1082 initial_size,
1083 );
1084 let old = self.documents.insert(document_id, document);
1085 debug_assert!(old.is_none());
1086 }
1087 ApiMsg::MemoryPressure => {
1088 self.resource_cache.clear(ClearCache::all());
1097
1098 for (_, doc) in &mut self.documents {
1099 doc.scratch.memory_pressure();
1100 for tile_cache in self.tile_caches.values_mut() {
1101 tile_cache.memory_pressure(&mut self.resource_cache);
1102 }
1103 }
1104
1105 let resource_updates = self.resource_cache.pending_updates();
1106 let msg = ResultMsg::UpdateResources {
1107 resource_updates,
1108 memory_pressure: true,
1109 };
1110 self.result_tx.send(msg).unwrap();
1111 self.notifier.wake_up(false);
1112
1113 self.chunk_pool.purge_all_chunks();
1114 }
1115 ApiMsg::ReportMemory(tx) => {
1116 self.report_memory(tx);
1117 }
1118 ApiMsg::DebugCommand(option) => {
1119 let msg = match option {
1120 DebugCommand::SetPictureTileSize(tile_size) => {
1121 self.frame_config.tile_size_override = tile_size;
1122 self.update_frame_builder_config();
1123
1124 return RenderBackendStatus::Continue;
1125 }
1126 DebugCommand::SetMaximumSurfaceSize(surface_size) => {
1127 self.frame_config.max_surface_override = surface_size;
1128 self.update_frame_builder_config();
1129
1130 return RenderBackendStatus::Continue;
1131 }
1132 DebugCommand::GenerateFrame => {
1133 let documents: Vec<DocumentId> = self.documents.keys()
1134 .cloned()
1135 .collect();
1136 for document_id in documents {
1137 let mut invalidation_config = false;
1138 if let Some(doc) = self.documents.get_mut(&document_id) {
1139 doc.frame_is_valid = false;
1140 invalidation_config = doc.scene.config.force_invalidation;
1141 doc.scene.config.force_invalidation = true;
1142 }
1143
1144 self.update_document(
1145 document_id,
1146 Vec::default(),
1147 Vec::default(),
1148 Vec::default(),
1149 true,
1150 true,
1151 false,
1152 RenderReasons::empty(),
1153 None,
1154 true,
1155 frame_counter,
1156 false,
1157 None,
1158 );
1159
1160 if let Some(doc) = self.documents.get_mut(&document_id) {
1161 doc.scene.config.force_invalidation = invalidation_config;
1162 }
1163 }
1164
1165 return RenderBackendStatus::Continue;
1166 }
1167 #[cfg(feature = "capture")]
1168 DebugCommand::SaveCapture(root, bits) => {
1169 let output = self.save_capture(root, bits);
1170 ResultMsg::DebugOutput(output)
1171 },
1172 #[cfg(feature = "capture")]
1173 DebugCommand::StartCaptureSequence(root, bits) => {
1174 self.start_capture_sequence(root, bits);
1175 return RenderBackendStatus::Continue;
1176 },
1177 #[cfg(feature = "capture")]
1178 DebugCommand::StopCaptureSequence => {
1179 self.stop_capture_sequence();
1180 return RenderBackendStatus::Continue;
1181 },
1182 #[cfg(feature = "replay")]
1183 DebugCommand::LoadCapture(path, ids, tx) => {
1184 NEXT_NAMESPACE_ID.fetch_add(1, Ordering::Relaxed);
1185 *frame_counter += 1;
1186
1187 let mut config = CaptureConfig::new(path, CaptureBits::all());
1188 if let Some((scene_id, frame_id)) = ids {
1189 config.scene_id = scene_id;
1190 config.frame_id = frame_id;
1191 }
1192
1193 self.load_capture(config);
1194
1195 for (id, doc) in &self.documents {
1196 let captured = CapturedDocument {
1197 document_id: *id,
1198 root_pipeline_id: doc.loaded_scene.root_pipeline_id,
1199 };
1200 tx.send(captured).unwrap();
1201 }
1202
1203 return RenderBackendStatus::Continue;
1206 }
1207 #[cfg(feature = "debugger")]
1208 DebugCommand::Query(ref query) => {
1209 match query.kind {
1210 DebugQueryKind::SpatialTree { .. } => {
1211 if let Some(doc) = self.documents.values().next() {
1212 let result = doc.spatial_tree.print_to_string();
1213 query.result.send(result).ok();
1214 }
1215 return RenderBackendStatus::Continue;
1216 }
1217 DebugQueryKind::CompositorView { .. } |
1218 DebugQueryKind::CompositorConfig { .. } |
1219 DebugQueryKind::Textures { .. } => {
1220 ResultMsg::DebugCommand(option)
1221 }
1222 }
1223 }
1224 DebugCommand::ClearCaches(mask) => {
1225 self.resource_cache.clear(mask);
1226 return RenderBackendStatus::Continue;
1227 }
1228 DebugCommand::EnableNativeCompositor(enable) => {
1229 if let CompositorKind::Draw { .. } = self.default_compositor_kind {
1231 unreachable!();
1232 }
1233
1234 let compositor_kind = if enable {
1235 self.default_compositor_kind
1236 } else {
1237 CompositorKind::default()
1238 };
1239
1240 for (_, doc) in &mut self.documents {
1241 doc.scene.config.compositor_kind = compositor_kind;
1242 doc.frame_is_valid = false;
1243 }
1244
1245 self.frame_config.compositor_kind = compositor_kind;
1246 self.update_frame_builder_config();
1247
1248 return RenderBackendStatus::Continue;
1250 }
1251 DebugCommand::SetBatchingLookback(count) => {
1252 self.frame_config.batch_lookback_count = count as usize;
1253 self.update_frame_builder_config();
1254
1255 return RenderBackendStatus::Continue;
1256 }
1257 DebugCommand::SimulateLongSceneBuild(time_ms) => {
1258 let _ = self.scene_tx.send(SceneBuilderRequest::SimulateLongSceneBuild(time_ms));
1259 return RenderBackendStatus::Continue;
1260 }
1261 DebugCommand::SetFlags(flags) => {
1262 self.resource_cache.set_debug_flags(flags);
1263
1264 let force_invalidation = flags.contains(DebugFlags::FORCE_PICTURE_INVALIDATION);
1265 if self.frame_config.force_invalidation != force_invalidation {
1266 self.frame_config.force_invalidation = force_invalidation;
1267 for doc in self.documents.values_mut() {
1268 doc.scene.config.force_invalidation = force_invalidation;
1269 }
1270 self.update_frame_builder_config();
1271 }
1272
1273 self.debug_flags = flags;
1274
1275 ResultMsg::DebugCommand(option)
1276 }
1277 _ => ResultMsg::DebugCommand(option),
1278 };
1279 self.result_tx.send(msg).unwrap();
1280 self.notifier.wake_up(true);
1281 }
1282 ApiMsg::UpdateDocuments(transaction_msgs) => {
1283 self.prepare_transactions(
1284 transaction_msgs,
1285 frame_counter,
1286 );
1287 }
1288 ApiMsg::SceneBuilderResult(msg) => {
1289 return self.process_scene_builder_result(msg, frame_counter);
1290 }
1291 }
1292
1293 self.chunk_pool.purge_chunks(2, 3);
1298
1299 RenderBackendStatus::Continue
1300 }
1301
1302 fn process_scene_builder_result(
1303 &mut self,
1304 msg: SceneBuilderResult,
1305 frame_counter: &mut u32,
1306 ) -> RenderBackendStatus {
1307 profile_scope!("sb_msg");
1308
1309 match msg {
1310 SceneBuilderResult::Transactions(txns, result_tx) => {
1311 self.process_transaction(
1312 txns,
1313 result_tx,
1314 frame_counter,
1315 );
1316 },
1317 #[cfg(feature = "capture")]
1318 SceneBuilderResult::CapturedTransactions(txns, capture_config, result_tx) => {
1319 if let Some(ref mut old_config) = self.capture_config {
1320 assert!(old_config.scene_id <= capture_config.scene_id);
1321 if old_config.scene_id < capture_config.scene_id {
1322 old_config.scene_id = capture_config.scene_id;
1323 old_config.frame_id = 0;
1324 }
1325 } else {
1326 self.capture_config = Some(capture_config);
1327 }
1328
1329 let built_frame = self.process_transaction(
1330 txns,
1331 result_tx,
1332 frame_counter,
1333 );
1334
1335 if built_frame {
1336 self.save_capture_sequence();
1337 }
1338 },
1339 #[cfg(feature = "capture")]
1340 SceneBuilderResult::StopCaptureSequence => {
1341 self.capture_config = None;
1342 }
1343 SceneBuilderResult::GetGlyphDimensions(request) => {
1344 let mut glyph_dimensions = Vec::with_capacity(request.glyph_indices.len());
1345 let instance_key = self.resource_cache.map_font_instance_key(request.key);
1346 if let Some(base) = self.resource_cache.get_font_instance(instance_key) {
1347 let font = FontInstance::from_base(Arc::clone(&base));
1348 for glyph_index in &request.glyph_indices {
1349 let glyph_dim = self.resource_cache.get_glyph_dimensions(&font, *glyph_index);
1350 glyph_dimensions.push(glyph_dim);
1351 }
1352 }
1353 request.sender.send(glyph_dimensions).unwrap();
1354 }
1355 SceneBuilderResult::GetGlyphIndices(request) => {
1356 let mut glyph_indices = Vec::with_capacity(request.text.len());
1357 let font_key = self.resource_cache.map_font_key(request.key);
1358 for ch in request.text.chars() {
1359 let index = self.resource_cache.get_glyph_index(font_key, ch);
1360 glyph_indices.push(index);
1361 }
1362 request.sender.send(glyph_indices).unwrap();
1363 }
1364 SceneBuilderResult::FlushComplete(tx) => {
1365 tx.send(()).ok();
1366 }
1367 SceneBuilderResult::ExternalEvent(evt) => {
1368 self.notifier.external_event(evt);
1369 }
1370 SceneBuilderResult::ClearNamespace(id) => {
1371 self.resource_cache.clear_namespace(id);
1372 self.documents.retain(|doc_id, _doc| doc_id.namespace_id != id);
1373 }
1374 SceneBuilderResult::DeleteDocument(document_id) => {
1375 self.documents.remove(&document_id);
1376 }
1377 SceneBuilderResult::SetParameter(param) => {
1378 if let Parameter::Bool(BoolParameter::Multithreading, enabled) = param {
1379 self.resource_cache.enable_multithreading(enabled);
1380 }
1381 let _ = self.result_tx.send(ResultMsg::SetParameter(param));
1382 }
1383 SceneBuilderResult::StopRenderBackend => {
1384 return RenderBackendStatus::StopRenderBackend;
1385 }
1386 SceneBuilderResult::ShutDown(sender) => {
1387 info!("Recycling stats: {:?}", self.recycler);
1388 return RenderBackendStatus::ShutDown(sender);
1389 }
1390 }
1391
1392 RenderBackendStatus::Continue
1393 }
1394
1395 fn update_frame_builder_config(&self) {
1396 self.send_backend_message(
1397 SceneBuilderRequest::SetFrameBuilderConfig(
1398 self.frame_config.clone()
1399 )
1400 );
1401 }
1402
1403 fn requires_frame_build(&mut self) -> bool {
1404 false }
1406
1407 fn prepare_transactions(
1408 &mut self,
1409 txns: Vec<Box<TransactionMsg>>,
1410 frame_counter: &mut u32,
1411 ) {
1412 self.maybe_force_nop_documents(
1413 frame_counter,
1414 |document_id| txns.iter().any(|txn| txn.document_id == document_id));
1415
1416 let mut built_frame = false;
1417 for mut txn in txns {
1418 if txn.generate_frame.as_bool() {
1419 txn.profile.end_time(profiler::API_SEND_TIME);
1420 }
1421
1422 self.documents.get_mut(&txn.document_id).unwrap().profile.merge(&mut txn.profile);
1423
1424 built_frame |= self.update_document(
1425 txn.document_id,
1426 txn.resource_updates.take(),
1427 txn.frame_ops.take(),
1428 txn.notifications.take(),
1429 txn.generate_frame.as_bool(),
1430 txn.generate_frame.present(),
1431 txn.generate_frame.tracked(),
1432 txn.render_reasons,
1433 txn.generate_frame.id(),
1434 txn.invalidate_rendered_frame,
1435 frame_counter,
1436 false,
1437 txn.creation_time,
1438 );
1439 }
1440 if built_frame {
1441 #[cfg(feature = "capture")]
1442 self.save_capture_sequence();
1443 }
1444 }
1445
1446 fn maybe_force_nop_documents<F>(&mut self,
1453 frame_counter: &mut u32,
1454 document_already_present: F) where
1455 F: Fn(DocumentId) -> bool {
1456 if self.requires_frame_build() {
1457 let nop_documents : Vec<DocumentId> = self.documents.keys()
1458 .cloned()
1459 .filter(|key| !document_already_present(*key))
1460 .collect();
1461 let mut built_frame = false;
1462 #[cfg_attr(not(feature = "capture"), allow(unused_assignments))]
1463 for &document_id in &nop_documents {
1464 built_frame |= self.update_document(
1465 document_id,
1466 Vec::default(),
1467 Vec::default(),
1468 Vec::default(),
1469 false,
1470 false,
1471 false,
1472 RenderReasons::empty(),
1473 None,
1474 false,
1475 frame_counter,
1476 false,
1477 None);
1478 }
1479 match built_frame {
1480 true =>
1481 {
1482 #[cfg(feature = "capture")]
1483 self.save_capture_sequence()
1484 }
1485 _ => {},
1486 }
1487 }
1488 }
1489
1490 fn update_document(
1491 &mut self,
1492 document_id: DocumentId,
1493 resource_updates: Vec<ResourceUpdate>,
1494 mut frame_ops: Vec<FrameMsg>,
1495 mut notifications: Vec<NotificationRequest>,
1496 mut render_frame: bool,
1497 mut present: bool,
1498 tracked: bool,
1499 render_reasons: RenderReasons,
1500 generated_frame_id: Option<u64>,
1501 invalidate_rendered_frame: bool,
1502 frame_counter: &mut u32,
1503 has_built_scene: bool,
1504 start_time: Option<u64>
1505 ) -> bool {
1506 let update_doc_start = zeitstempel::now();
1507
1508 let requested_frame = render_frame || self.frame_config.force_invalidation;
1509
1510 let requires_frame_build = self.requires_frame_build();
1511 let doc = self.documents.get_mut(&document_id).unwrap();
1512
1513 if requested_frame {
1519 if let Some(ref sampler) = self.sampler {
1520 frame_ops.append(&mut sampler.sample(document_id, generated_frame_id));
1521 }
1522 }
1523
1524 doc.has_built_scene |= has_built_scene;
1525
1526 let mut scroll = false;
1529 for frame_msg in frame_ops {
1530 let op = doc.process_frame_msg(frame_msg);
1531 scroll |= op.scroll;
1532 }
1533
1534 for update in &resource_updates {
1535 if let ResourceUpdate::UpdateImage(..) = update {
1536 doc.frame_is_valid = false;
1537 }
1538 }
1539
1540 self.resource_cache.post_scene_building_update(
1541 resource_updates,
1542 &mut doc.profile,
1543 );
1544
1545 if doc.dynamic_properties.flush_pending_updates() {
1546 doc.frame_is_valid = false;
1547 doc.hit_tester_is_valid = false;
1548 }
1549
1550 if !doc.can_render() {
1551 render_frame = false;
1555 }
1556
1557 let build_frame = (render_frame && !doc.frame_is_valid && doc.has_pixels()) ||
1563 (requires_frame_build && doc.can_render());
1564
1565 if invalidate_rendered_frame {
1569 doc.rendered_frame_is_valid = false;
1570 if doc.scene.config.compositor_kind.should_redraw_on_invalidation() {
1571 let msg = ResultMsg::ForceRedraw;
1572 self.result_tx.send(msg).unwrap();
1573 }
1574 }
1575
1576 if build_frame {
1577 if !requested_frame {
1578 present = true;
1583 }
1584
1585 if start_time.is_some() {
1586 Telemetry::record_time_to_frame_build(Duration::from_nanos(zeitstempel::now() - start_time.unwrap()));
1587 }
1588 profile_scope!("generate frame");
1589
1590 *frame_counter += 1;
1591
1592 let (pending_update, mut rendered_document) = {
1594 let timer_id = Telemetry::start_framebuild_time();
1595
1596 let frame_stats = doc.frame_stats.take();
1597
1598 let rendered_document = doc.build_frame(
1599 &mut self.resource_cache,
1600 self.debug_flags,
1601 &mut self.tile_caches,
1602 frame_stats,
1603 present,
1604 render_reasons,
1605 self.chunk_pool.clone(),
1606 );
1607
1608 debug!("generated frame for document {:?} with {} passes",
1609 document_id, rendered_document.frame.passes.len());
1610
1611 Telemetry::stop_and_accumulate_framebuild_time(timer_id);
1612
1613 let pending_update = self.resource_cache.pending_updates();
1614 (pending_update, rendered_document)
1615 };
1616
1617 rendered_document
1619 .frame
1620 .composite_state
1621 .update_dirty_rect_validity(&doc.prev_composite_descriptor);
1622
1623 let composite_descriptor = rendered_document
1625 .frame
1626 .composite_state
1627 .descriptor
1628 .clone();
1629
1630 if !pending_update.is_nop() ||
1634 !rendered_document.frame.is_nop() ||
1635 composite_descriptor != doc.prev_composite_descriptor {
1636 doc.rendered_frame_is_valid = false;
1637 }
1638 doc.prev_composite_descriptor = composite_descriptor;
1639
1640 #[cfg(feature = "capture")]
1641 match self.capture_config {
1642 Some(ref mut config) => {
1643 config.prepare_frame();
1645
1646 if config.bits.contains(CaptureBits::FRAME) {
1647 let file_name = format!("frame-{}-{}", document_id.namespace_id.0, document_id.id);
1648 config.serialize_for_frame(&rendered_document.frame, file_name);
1649 }
1650
1651 let data_stores_name = format!("data-stores-{}-{}", document_id.namespace_id.0, document_id.id);
1652 config.serialize_for_frame(&doc.data_stores, data_stores_name);
1653
1654 let frame_spatial_tree_name = format!("frame-spatial-tree-{}-{}", document_id.namespace_id.0, document_id.id);
1655 config.serialize_for_frame::<SpatialTree, _>(&doc.spatial_tree, frame_spatial_tree_name);
1656
1657 let properties_name = format!("properties-{}-{}", document_id.namespace_id.0, document_id.id);
1658 config.serialize_for_frame(&doc.dynamic_properties, properties_name);
1659 },
1660 None => {},
1661 }
1662
1663 let update_doc_time = profiler::ns_to_ms(zeitstempel::now() - update_doc_start);
1664 rendered_document.profile.set(profiler::UPDATE_DOCUMENT_TIME, update_doc_time);
1665
1666 let msg = ResultMsg::PublishPipelineInfo(doc.updated_pipeline_info());
1667 self.result_tx.send(msg).unwrap();
1668
1669 self.frame_publish_id.advance();
1671 let msg = ResultMsg::PublishDocument(
1672 self.frame_publish_id,
1673 document_id,
1674 rendered_document,
1675 pending_update,
1676 );
1677 self.result_tx.send(msg).unwrap();
1678 } else if requested_frame {
1679 let msg = ResultMsg::PublishPipelineInfo(doc.updated_pipeline_info());
1684 self.result_tx.send(msg).unwrap();
1685 }
1686
1687 drain_filter(
1688 &mut notifications,
1689 |n| { n.when() == Checkpoint::FrameBuilt },
1690 |n| { n.notify(); },
1691 );
1692
1693 if !notifications.is_empty() {
1694 self.result_tx.send(ResultMsg::AppendNotificationRequests(notifications)).unwrap();
1695 }
1696
1697 if requested_frame {
1701 if doc.rendered_frame_is_valid {
1703 render_frame = false;
1704 } else if render_frame {
1705 doc.rendered_frame_is_valid = true;
1706 }
1707 let params = api::FrameReadyParams {
1708 present,
1709 render: render_frame,
1710 scrolled: scroll,
1711 tracked,
1712 };
1713 self.notifier.new_frame_ready(document_id, self.frame_publish_id, ¶ms);
1714 }
1715
1716 if !doc.hit_tester_is_valid {
1717 doc.rebuild_hit_tester();
1718 }
1719
1720 build_frame
1721 }
1722
1723 fn send_backend_message(&self, msg: SceneBuilderRequest) {
1724 self.scene_tx.send(msg).unwrap();
1725 }
1726
1727 fn report_memory(&mut self, tx: Sender<Box<MemoryReport>>) {
1728 let mut report = Box::new(MemoryReport::default());
1729 let ops = self.size_of_ops.as_mut().unwrap();
1730 let op = ops.size_of_op;
1731 for doc in self.documents.values() {
1732 report.clip_stores += doc.scene.clip_store.size_of(ops);
1733 report.hit_testers += match &doc.hit_tester {
1734 Some(hit_tester) => hit_tester.size_of(ops),
1735 None => 0,
1736 };
1737
1738 doc.data_stores.report_memory(ops, &mut report)
1739 }
1740
1741 (*report) += self.resource_cache.report_memory(op);
1742 report.texture_cache_structures = self.resource_cache
1743 .texture_cache
1744 .report_memory(ops);
1745
1746 self.send_backend_message(
1750 SceneBuilderRequest::ReportMemory(report, tx)
1751 );
1752 }
1753
1754 #[cfg(feature = "capture")]
1755 fn save_capture_sequence(&mut self) {
1756 if let Some(ref mut config) = self.capture_config {
1757 let deferred = self.resource_cache.save_capture_sequence(config);
1758
1759 let backend = PlainRenderBackend {
1760 frame_config: self.frame_config.clone(),
1761 resource_sequence_id: config.resource_id,
1762 documents: self.documents
1763 .iter()
1764 .map(|(id, doc)| (*id, doc.view))
1765 .collect(),
1766 };
1767 config.serialize_for_frame(&backend, "backend");
1768
1769 if !deferred.is_empty() {
1770 let msg = ResultMsg::DebugOutput(DebugOutput::SaveCapture(config.clone(), deferred));
1771 self.result_tx.send(msg).unwrap();
1772 }
1773 }
1774 }
1775}
1776
1777impl RenderBackend {
1778 #[cfg(feature = "capture")]
1779 fn save_capture(
1781 &mut self,
1782 root: PathBuf,
1783 bits: CaptureBits,
1784 ) -> DebugOutput {
1785 use std::fs;
1786 use crate::render_task_graph::dump_render_tasks_as_svg;
1787
1788 debug!("capture: saving {:?}", root);
1789 if !root.is_dir() {
1790 if let Err(e) = fs::create_dir_all(&root) {
1791 panic!("Unable to create capture dir: {:?}", e);
1792 }
1793 }
1794 let config = CaptureConfig::new(root, bits);
1795
1796 for (&id, doc) in &mut self.documents {
1797 debug!("\tdocument {:?}", id);
1798 if config.bits.contains(CaptureBits::FRAME) {
1799 let force_invalidation = std::mem::replace(&mut doc.scene.config.force_invalidation, true);
1801 let rendered_document = doc.build_frame(
1802 &mut self.resource_cache,
1803 self.debug_flags,
1804 &mut self.tile_caches,
1805 None,
1806 true,
1807 RenderReasons::empty(),
1808 self.chunk_pool.clone(),
1809 );
1810
1811 doc.scene.config.force_invalidation = force_invalidation;
1812
1813 let file_name = format!("frame-{}-{}", id.namespace_id.0, id.id);
1817 config.serialize_for_frame(&rendered_document.frame, file_name);
1818 let file_name = format!("spatial-{}-{}", id.namespace_id.0, id.id);
1819 config.serialize_tree_for_frame(&doc.spatial_tree, file_name);
1820 let file_name = format!("built-primitives-{}-{}", id.namespace_id.0, id.id);
1821 config.serialize_for_frame(&doc.scene.prim_store, file_name);
1822 let file_name = format!("built-clips-{}-{}", id.namespace_id.0, id.id);
1823 config.serialize_for_frame(&doc.scene.clip_store, file_name);
1824 let file_name = format!("scratch-{}-{}", id.namespace_id.0, id.id);
1825 config.serialize_for_frame(&doc.scratch.primitive, file_name);
1826 let file_name = format!("render-tasks-{}-{}.svg", id.namespace_id.0, id.id);
1827 let mut render_tasks_file = fs::File::create(&config.file_path_for_frame(file_name, "svg"))
1828 .expect("Failed to open the SVG file.");
1829 dump_render_tasks_as_svg(
1830 &rendered_document.frame.render_tasks,
1831 &mut render_tasks_file
1832 ).unwrap();
1833
1834 let file_name = format!("texture-cache-color-linear-{}-{}.svg", id.namespace_id.0, id.id);
1835 let mut texture_file = fs::File::create(&config.file_path_for_frame(file_name, "svg"))
1836 .expect("Failed to open the SVG file.");
1837 self.resource_cache.texture_cache.dump_color8_linear_as_svg(&mut texture_file).unwrap();
1838
1839 let file_name = format!("texture-cache-color8-glyphs-{}-{}.svg", id.namespace_id.0, id.id);
1840 let mut texture_file = fs::File::create(&config.file_path_for_frame(file_name, "svg"))
1841 .expect("Failed to open the SVG file.");
1842 self.resource_cache.texture_cache.dump_color8_glyphs_as_svg(&mut texture_file).unwrap();
1843
1844 let file_name = format!("texture-cache-alpha8-glyphs-{}-{}.svg", id.namespace_id.0, id.id);
1845 let mut texture_file = fs::File::create(&config.file_path_for_frame(file_name, "svg"))
1846 .expect("Failed to open the SVG file.");
1847 self.resource_cache.texture_cache.dump_alpha8_glyphs_as_svg(&mut texture_file).unwrap();
1848
1849 let file_name = format!("texture-cache-alpha8-linear-{}-{}.svg", id.namespace_id.0, id.id);
1850 let mut texture_file = fs::File::create(&config.file_path_for_frame(file_name, "svg"))
1851 .expect("Failed to open the SVG file.");
1852 self.resource_cache.texture_cache.dump_alpha8_linear_as_svg(&mut texture_file).unwrap();
1853 }
1854
1855 let data_stores_name = format!("data-stores-{}-{}", id.namespace_id.0, id.id);
1856 config.serialize_for_frame(&doc.data_stores, data_stores_name);
1857
1858 let frame_spatial_tree_name = format!("frame-spatial-tree-{}-{}", id.namespace_id.0, id.id);
1859 config.serialize_for_frame::<SpatialTree, _>(&doc.spatial_tree, frame_spatial_tree_name);
1860
1861 let properties_name = format!("properties-{}-{}", id.namespace_id.0, id.id);
1862 config.serialize_for_frame(&doc.dynamic_properties, properties_name);
1863 }
1864
1865 if config.bits.contains(CaptureBits::FRAME) {
1866 assert!(!self.requires_frame_build(), "Caches were cleared during a capture.");
1870 }
1871
1872 debug!("\tscene builder");
1873 self.send_backend_message(
1874 SceneBuilderRequest::SaveScene(config.clone())
1875 );
1876
1877 debug!("\tresource cache");
1878 let (resources, deferred) = self.resource_cache.save_capture(&config.root);
1879
1880 info!("\tbackend");
1881 let backend = PlainRenderBackend {
1882 frame_config: self.frame_config.clone(),
1883 resource_sequence_id: 0,
1884 documents: self.documents
1885 .iter()
1886 .map(|(id, doc)| (*id, doc.view))
1887 .collect(),
1888 };
1889
1890 config.serialize_for_frame(&backend, "backend");
1891 config.serialize_for_frame(&resources, "plain-resources");
1892
1893 if config.bits.contains(CaptureBits::FRAME) {
1894 let msg_update_resources = ResultMsg::UpdateResources {
1895 resource_updates: self.resource_cache.pending_updates(),
1896 memory_pressure: false,
1897 };
1898 self.result_tx.send(msg_update_resources).unwrap();
1899 info!("\tresource cache");
1901 let caches = self.resource_cache.save_caches(&config.root);
1902 config.serialize_for_resource(&caches, "resource_cache");
1903 }
1904
1905 DebugOutput::SaveCapture(config, deferred)
1906 }
1907
1908 #[cfg(feature = "capture")]
1909 fn start_capture_sequence(
1910 &mut self,
1911 root: PathBuf,
1912 bits: CaptureBits,
1913 ) {
1914 self.send_backend_message(
1915 SceneBuilderRequest::StartCaptureSequence(CaptureConfig::new(root, bits))
1916 );
1917 }
1918
1919 #[cfg(feature = "capture")]
1920 fn stop_capture_sequence(
1921 &mut self,
1922 ) {
1923 self.send_backend_message(
1924 SceneBuilderRequest::StopCaptureSequence
1925 );
1926 }
1927
1928 #[cfg(feature = "replay")]
1929 fn load_capture(
1930 &mut self,
1931 mut config: CaptureConfig,
1932 ) {
1933 debug!("capture: loading {:?}", config.frame_root());
1934 let backend = config.deserialize_for_frame::<PlainRenderBackend, _>("backend")
1935 .expect("Unable to open backend.ron");
1936
1937 let first_load = backend.resource_sequence_id == 0;
1940 if self.loaded_resource_sequence_id != backend.resource_sequence_id || first_load {
1941 self.documents.clear();
1954
1955 config.resource_id = backend.resource_sequence_id;
1956 self.loaded_resource_sequence_id = backend.resource_sequence_id;
1957
1958 let plain_resources = config.deserialize_for_resource::<PlainResources, _>("plain-resources")
1959 .expect("Unable to open plain-resources.ron");
1960 let caches_maybe = config.deserialize_for_resource::<PlainCacheOwn, _>("resource_cache");
1961
1962 let plain_externals = self.resource_cache.load_capture(
1967 plain_resources,
1968 caches_maybe,
1969 &config,
1970 );
1971
1972 let msg_load = ResultMsg::DebugOutput(
1973 DebugOutput::LoadCapture(config.clone(), plain_externals)
1974 );
1975 self.result_tx.send(msg_load).unwrap();
1976 }
1977
1978 self.frame_config = backend.frame_config;
1979
1980 let mut scenes_to_build = Vec::new();
1981
1982 for (id, view) in backend.documents {
1983 debug!("\tdocument {:?}", id);
1984 let scene_name = format!("scene-{}-{}", id.namespace_id.0, id.id);
1985 let scene = config.deserialize_for_scene::<Scene, _>(&scene_name)
1986 .expect(&format!("Unable to open {}.ron", scene_name));
1987
1988 let scene_spatial_tree_name = format!("scene-spatial-tree-{}-{}", id.namespace_id.0, id.id);
1989 let scene_spatial_tree = config.deserialize_for_scene::<SceneSpatialTree, _>(&scene_spatial_tree_name)
1990 .expect(&format!("Unable to open {}.ron", scene_spatial_tree_name));
1991
1992 let interners_name = format!("interners-{}-{}", id.namespace_id.0, id.id);
1993 let interners = config.deserialize_for_scene::<Interners, _>(&interners_name)
1994 .expect(&format!("Unable to open {}.ron", interners_name));
1995
1996 let data_stores_name = format!("data-stores-{}-{}", id.namespace_id.0, id.id);
1997 let data_stores = config.deserialize_for_frame::<DataStores, _>(&data_stores_name)
1998 .expect(&format!("Unable to open {}.ron", data_stores_name));
1999
2000 let properties_name = format!("properties-{}-{}", id.namespace_id.0, id.id);
2001 let properties = config.deserialize_for_frame::<SceneProperties, _>(&properties_name)
2002 .expect(&format!("Unable to open {}.ron", properties_name));
2003
2004 let frame_spatial_tree_name = format!("frame-spatial-tree-{}-{}", id.namespace_id.0, id.id);
2005 let frame_spatial_tree = config.deserialize_for_frame::<SpatialTree, _>(&frame_spatial_tree_name)
2006 .expect(&format!("Unable to open {}.ron", frame_spatial_tree_name));
2007
2008 match self.documents.entry(id) {
2012 Occupied(entry) => {
2013 let doc = entry.into_mut();
2014 doc.view = view;
2015 doc.loaded_scene = scene.clone();
2016 doc.data_stores = data_stores;
2017 doc.spatial_tree = frame_spatial_tree;
2018 doc.dynamic_properties = properties;
2019 doc.frame_is_valid = false;
2020 doc.rendered_frame_is_valid = false;
2021 doc.has_built_scene = false;
2022 doc.hit_tester_is_valid = false;
2023 }
2024 Vacant(entry) => {
2025 let doc = Document {
2026 id,
2027 scene: BuiltScene::empty(),
2028 removed_pipelines: Vec::new(),
2029 view,
2030 stamp: FrameStamp::first(id),
2031 frame_builder: FrameBuilder::new(),
2032 dynamic_properties: properties,
2033 hit_tester: None,
2034 shared_hit_tester: Arc::new(SharedHitTester::new()),
2035 frame_is_valid: false,
2036 hit_tester_is_valid: false,
2037 rendered_frame_is_valid: false,
2038 has_built_scene: false,
2039 data_stores,
2040 scratch: ScratchBuffer::default(),
2041 spatial_tree: frame_spatial_tree,
2042 minimap_data: FastHashMap::default(),
2043 loaded_scene: scene.clone(),
2044 prev_composite_descriptor: CompositeDescriptor::empty(),
2045 dirty_rects_are_valid: false,
2046 profile: TransactionProfile::new(),
2047 rg_builder: RenderTaskGraphBuilder::new(),
2048 frame_stats: None,
2049 };
2050 entry.insert(doc);
2051 }
2052 };
2053
2054 let frame_name = format!("frame-{}-{}", id.namespace_id.0, id.id);
2055 let frame = config.deserialize_for_frame::<Frame, _>(frame_name);
2056 let build_frame = match frame {
2057 Some(frame) => {
2058 info!("\tloaded a built frame with {} passes", frame.passes.len());
2059
2060 self.frame_publish_id.advance();
2061 let msg_publish = ResultMsg::PublishDocument(
2062 self.frame_publish_id,
2063 id,
2064 RenderedDocument {
2065 frame,
2066 profile: TransactionProfile::new(),
2067 render_reasons: RenderReasons::empty(),
2068 frame_stats: None,
2069 },
2070 self.resource_cache.pending_updates(),
2071 );
2072 self.result_tx.send(msg_publish).unwrap();
2073
2074 let params = api::FrameReadyParams {
2075 present: true,
2076 render: true,
2077 scrolled: false,
2078 tracked: false,
2079 };
2080 self.notifier.new_frame_ready(id, self.frame_publish_id, ¶ms);
2081
2082 false
2085 }
2086 None => true,
2087 };
2088
2089 scenes_to_build.push(LoadScene {
2090 document_id: id,
2091 scene,
2092 view: view.scene.clone(),
2093 config: self.frame_config.clone(),
2094 fonts: self.resource_cache.get_fonts(),
2095 build_frame,
2096 interners,
2097 spatial_tree: scene_spatial_tree,
2098 });
2099 }
2100
2101 if !scenes_to_build.is_empty() {
2102 self.send_backend_message(
2103 SceneBuilderRequest::LoadScenes(scenes_to_build)
2104 );
2105 }
2106 }
2107}