1use api::{ColorF, DebugFlags, ExternalScrollId, FontRenderMode, ImageKey, MinimapData, PremultipliedColorF};
6use api::units::*;
7use plane_split::BspSplitter;
8use crate::batch::{BatchBuilder, AlphaBatchBuilder, AlphaBatchContainer};
9use crate::clip::{ClipStore, ClipTree};
10use crate::command_buffer::{PrimitiveCommand, CommandBufferList, CommandBufferIndex};
11use crate::{debug_colors, ChunkPool};
12use crate::spatial_node::SpatialNodeType;
13use crate::spatial_tree::{SpatialTree, SpatialNodeIndex};
14use crate::composite::{CompositorKind, CompositeState, CompositeStatePreallocator};
15use crate::debug_item::DebugItem;
16use crate::gpu_types::{ImageBrushPrimitiveData, PrimitiveHeaders, ZBufferIdGenerator};
17use crate::gpu_types::QuadSegment;
18use crate::internal_types::{FastHashMap, PlaneSplitter, FrameStamp};
19use crate::invalidation::DirtyRegion;
20use crate::tile_cache::{SliceId, TileCacheInstance};
21use crate::picture::PictureInstance;
22use crate::picture::{SurfaceInfo, SurfaceIndex, ResolvedSurfaceTexture};
23use crate::picture::{SubpixelMode, RasterConfig, PictureCompositeMode, PictureScratch};
24use crate::prepare::prepare_picture;
25use crate::prim_store::{PictureIndex, PrimitiveScratchBuffer};
26use crate::prim_store::{DeferredResolve, PrimitiveInstance};
27use crate::prim_store::storage;
28use crate::profiler::{self, TransactionProfile};
29use crate::render_backend::{DataStores, ScratchBuffer};
30use crate::renderer::{GpuBufferAddress, GpuBufferBuilder, GpuBufferBuilderF, GpuBufferBuilderI, GpuBufferF, GpuBufferI, GpuBufferDataF};
31use crate::render_target::{PictureCacheTarget, PictureCacheTargetKind};
32use crate::render_target::{RenderTargetContext, RenderTargetKind, RenderTarget};
33use crate::render_task_graph::{Pass, RenderTaskGraph, RenderTaskId, SubPassSurface};
34use crate::render_task_graph::{RenderPass, RenderTaskGraphBuilder};
35use crate::render_task::{RenderTaskKind, StaticRenderTaskSurface};
36use crate::resource_cache::ResourceCache;
37use crate::scene::{BuiltScene, SceneProperties};
38use crate::space::SpaceMapper;
39use crate::segment::SegmentBuilder;
40use crate::surface::SurfaceBuilder;
41use crate::transform::{TransformPalette, TransformData};
42use std::sync::Arc;
43use std::{f32, mem};
44use crate::util::{MaxRect, VecHelper, Preallocator};
45use crate::visibility::{update_prim_visibility, FrameVisibilityState, FrameVisibilityContext};
46use crate::internal_types::{FrameVec, FrameMemory};
47
48#[derive(Clone, Copy, Debug)]
49#[cfg_attr(feature = "capture", derive(Serialize))]
50#[cfg_attr(feature = "replay", derive(Deserialize))]
51pub struct FrameBuilderConfig {
52 pub default_font_render_mode: FontRenderMode,
53 pub dual_source_blending_is_supported: bool,
54 pub testing: bool,
56 pub gpu_supports_fast_clears: bool,
57 pub gpu_supports_advanced_blend: bool,
58 pub advanced_blend_is_coherent: bool,
59 pub gpu_supports_render_target_partial_update: bool,
60 pub external_images_require_copy: bool,
63 pub batch_lookback_count: usize,
64 pub background_color: Option<ColorF>,
65 pub compositor_kind: CompositorKind,
66 pub tile_size_override: Option<DeviceIntSize>,
67 pub max_surface_override: Option<usize>,
68 pub max_depth_ids: i32,
69 pub max_target_size: i32,
70 pub force_invalidation: bool,
71 pub is_software: bool,
72 pub low_quality_pinch_zoom: bool,
73 pub max_shared_surface_size: i32,
74 pub enable_dithering: bool,
75}
76
77#[cfg_attr(feature = "capture", derive(Serialize))]
79pub struct FrameGlobalResources {
80 pub default_image_data: GpuBufferAddress,
83
84 pub default_black_rect_address: GpuBufferAddress,
88}
89
90impl FrameGlobalResources {
91 pub fn new(gpu_buffers: &mut GpuBufferBuilder) -> Self {
92 let mut writer = gpu_buffers.f32.write_blocks(ImageBrushPrimitiveData::NUM_BLOCKS);
93 writer.push(&ImageBrushPrimitiveData {
94 color: PremultipliedColorF::WHITE,
95 background_color: PremultipliedColorF::WHITE,
96 stretch_size: LayoutSize::new(-1.0, 0.0),
98 });
99 let default_image_data = writer.finish();
100
101 let mut writer = gpu_buffers.f32.write_blocks(1);
102 writer.push_one(PremultipliedColorF::BLACK);
103 let default_black_rect_address = writer.finish();
104
105 FrameGlobalResources {
106 default_image_data,
107 default_black_rect_address,
108 }
109 }
110}
111
112pub struct FrameScratchBuffer {
113 dirty_region_stack: Vec<DirtyRegion>,
114 surface_stack: Vec<(PictureIndex, SurfaceIndex)>,
115}
116
117impl Default for FrameScratchBuffer {
118 fn default() -> Self {
119 FrameScratchBuffer {
120 dirty_region_stack: Vec::new(),
121 surface_stack: Vec::new(),
122 }
123 }
124}
125
126impl FrameScratchBuffer {
127 pub fn begin_frame(&mut self) {
128 self.dirty_region_stack.clear();
129 self.surface_stack.clear();
130 }
131}
132
133#[cfg_attr(feature = "capture", derive(Serialize))]
135pub struct FrameBuilder {
136 #[cfg_attr(feature = "capture", serde(skip))]
137 prim_headers_prealloc: Preallocator,
138 #[cfg_attr(feature = "capture", serde(skip))]
139 composite_state_prealloc: CompositeStatePreallocator,
140 #[cfg_attr(feature = "capture", serde(skip))]
141 plane_splitters: Vec<PlaneSplitter>,
142}
143
144pub struct FrameBuildingContext<'a> {
145 pub global_device_pixel_scale: DevicePixelScale,
146 pub scene_properties: &'a SceneProperties,
147 pub global_screen_world_rect: WorldRect,
148 pub spatial_tree: &'a SpatialTree,
149 pub max_local_clip: LayoutRect,
150 pub debug_flags: DebugFlags,
151 pub fb_config: &'a FrameBuilderConfig,
152 pub root_spatial_node_index: SpatialNodeIndex,
153}
154
155pub struct FrameBuildingState<'a> {
156 pub rg_builder: &'a mut RenderTaskGraphBuilder,
157 pub clip_store: &'a mut ClipStore,
158 pub resource_cache: &'a mut ResourceCache,
159 pub transforms: &'a mut TransformPalette,
160 pub segment_builder: SegmentBuilder,
161 pub surfaces: &'a mut Vec<SurfaceInfo>,
162 pub dirty_region_stack: Vec<DirtyRegion>,
163 pub composite_state: &'a mut CompositeState,
164 pub num_visible_primitives: u32,
165 pub plane_splitters: &'a mut [PlaneSplitter],
166 pub surface_builder: SurfaceBuilder,
167 pub cmd_buffers: &'a mut CommandBufferList,
168 pub clip_tree: &'a ClipTree,
169 pub frame_gpu_data: &'a mut GpuBufferBuilder,
170 pub image_dependencies: FastHashMap<ImageKey, RenderTaskId>,
180 pub picture_scratch_handles: &'a mut [Option<storage::Index<PictureScratch>>],
188}
189
190impl<'a> FrameBuildingState<'a> {
191 pub fn current_dirty_region(&self) -> &DirtyRegion {
193 self.dirty_region_stack.last().unwrap()
194 }
195
196 pub fn push_dirty_region(&mut self, region: DirtyRegion) {
198 self.dirty_region_stack.push(region);
199 }
200
201 pub fn pop_dirty_region(&mut self) {
203 self.dirty_region_stack.pop().unwrap();
204 }
205
206 pub fn push_prim(
208 &mut self,
209 cmd: &PrimitiveCommand,
210 spatial_node_index: SpatialNodeIndex,
211 targets: &[CommandBufferIndex],
212 ) {
213 for cmd_buffer_index in targets {
214 let cmd_buffer = self.cmd_buffers.get_mut(*cmd_buffer_index);
215 cmd_buffer.add_prim(cmd, spatial_node_index);
216 }
217 }
218
219 pub fn push_cmd(
221 &mut self,
222 cmd: &PrimitiveCommand,
223 targets: &[CommandBufferIndex],
224 ) {
225 for cmd_buffer_index in targets {
226 let cmd_buffer = self.cmd_buffers.get_mut(*cmd_buffer_index);
227 cmd_buffer.add_cmd(cmd);
228 }
229 }
230
231 pub fn set_segments(
233 &mut self,
234 segments: &[QuadSegment],
235 targets: &[CommandBufferIndex],
236 ) {
237 for cmd_buffer_index in targets {
238 let cmd_buffer = self.cmd_buffers.get_mut(*cmd_buffer_index);
239 cmd_buffer.set_segments(segments);
240 }
241 }
242}
243
244#[derive(Debug)]
246pub struct PictureContext {
247 pub pic_index: PictureIndex,
248 pub surface_spatial_node_index: SpatialNodeIndex,
249 pub raster_spatial_node_index: SpatialNodeIndex,
250 pub visibility_spatial_node_index: SpatialNodeIndex,
251 pub surface_index: SurfaceIndex,
253 pub dirty_region_count: usize,
254 pub subpixel_mode: SubpixelMode,
255}
256
257pub struct PictureState {
260 pub map_local_to_pic: SpaceMapper<LayoutPixel, PicturePixel>,
261 pub map_pic_to_vis: SpaceMapper<PicturePixel, VisPixel>,
262}
263
264impl FrameBuilder {
265 pub fn new() -> Self {
266 FrameBuilder {
267 prim_headers_prealloc: Preallocator::new(0),
268 composite_state_prealloc: CompositeStatePreallocator::default(),
269 plane_splitters: Vec::new(),
270 }
271 }
272
273 fn build_layer_screen_rects_and_cull_layers(
276 &mut self,
277 scene: &mut BuiltScene,
278 present: bool,
279 global_screen_world_rect: WorldRect,
280 resource_cache: &mut ResourceCache,
281 rg_builder: &mut RenderTaskGraphBuilder,
282 global_device_pixel_scale: DevicePixelScale,
283 scene_properties: &SceneProperties,
284 transform_palette: &mut TransformPalette,
285 data_stores: &mut DataStores,
286 scratch: &mut ScratchBuffer,
287 debug_flags: DebugFlags,
288 composite_state: &mut CompositeState,
289 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
290 spatial_tree: &SpatialTree,
291 cmd_buffers: &mut CommandBufferList,
292 frame_gpu_data: &mut GpuBufferBuilder,
293 frame_memory: &FrameMemory,
294 profile: &mut TransactionProfile,
295 ) {
296 profile_scope!("build_layer_screen_rects_and_cull_layers");
297
298 let render_picture_cache_slices = present;
299
300 let root_spatial_node_index = spatial_tree.root_reference_frame_index();
301
302 const MAX_CLIP_COORD: f32 = 1.0e9;
303
304 self.plane_splitters.resize_with(scene.num_plane_splitters, BspSplitter::new);
307 for splitter in &mut self.plane_splitters {
308 splitter.reset();
309 }
310
311 let frame_context = FrameBuildingContext {
312 global_device_pixel_scale,
313 scene_properties,
314 global_screen_world_rect,
315 spatial_tree,
316 max_local_clip: LayoutRect {
317 min: LayoutPoint::new(-MAX_CLIP_COORD, -MAX_CLIP_COORD),
318 max: LayoutPoint::new(MAX_CLIP_COORD, MAX_CLIP_COORD),
319 },
320 debug_flags,
321 fb_config: &scene.config,
322 root_spatial_node_index,
323 };
324
325 scene.picture_graph.build_update_passes(
326 &mut scene.prim_store.pictures,
327 &frame_context,
328 );
329
330 scene.picture_graph.assign_surfaces(
331 &mut scene.prim_store.pictures,
332 &mut scene.surfaces,
333 tile_caches,
334 &frame_context,
335 );
336
337 let root_spatial_node = frame_context.spatial_tree.root_reference_frame_index();
340 let snapshot_surface = SurfaceIndex(scene.surfaces.len());
341 scene.surfaces.push(SurfaceInfo::new(
342 root_spatial_node,
343 root_spatial_node,
344 WorldRect::max_rect(),
345 &frame_context.spatial_tree,
346 euclid::Scale::new(1.0),
347 (1.0, 1.0),
348 (1.0, 1.0),
349 false,
350 false,
351 ));
352
353 scratch.primitive.frame.draws.clear();
358 scratch.primitive.frame.draws.resize_with(
359 scene.prim_instances.len(),
360 crate::visibility::PrimitiveDrawHeader::new,
361 );
362
363 crate::frame_snap::snap_frame_rects(
369 &mut scene.prim_store,
370 &scene.prim_instances,
371 &mut scene.clip_tree,
372 &mut scratch.primitive.frame.draws,
373 spatial_tree,
374 );
375
376 scene.picture_graph.propagate_bounding_rects(
377 &mut scene.prim_store.pictures,
378 &mut scene.surfaces,
379 &frame_context,
380 );
381
382 let n_pics = scene.prim_store.pictures.len();
391 let mut visited_pictures = frame_memory.new_vec_with_capacity(n_pics);
392 for _ in 0..n_pics {
393 visited_pictures.push(false);
394 }
395
396 {
397 profile_scope!("UpdateVisibility");
398 profile_marker!("UpdateVisibility");
399 profile.start_time(profiler::FRAME_VISIBILITY_TIME);
400
401 let visibility_context = FrameVisibilityContext {
402 global_device_pixel_scale,
403 spatial_tree,
404 global_screen_world_rect,
405 debug_flags,
406 scene_properties,
407 config: scene.config,
408 root_spatial_node_index,
409 };
410
411 for pic_index in scene.snapshot_pictures.iter() {
412 let mut visibility_state = FrameVisibilityState {
413 clip_store: &mut scene.clip_store,
414 resource_cache,
415 frame_gpu_data,
416 data_stores,
417 clip_tree: &mut scene.clip_tree,
418 composite_state,
419 rg_builder,
420 prim_instances: &mut scene.prim_instances,
421 surfaces: &mut scene.surfaces,
422 surface_stack: scratch.frame.surface_stack.take(),
423 profile,
424 scratch,
425 visited_pictures: &mut visited_pictures,
426 };
427
428 let world_culling_rect = WorldRect::max_rect();
429
430 let pic = &scene.prim_store.pictures[pic_index.0];
436 let snapshot = pic.snapshot
437 .unwrap();
438 let key = snapshot.key.as_image();
439 visibility_state.resource_cache
440 .increment_image_generation(key);
441
442 if let Some(node) = pic.clip_root {
443 visibility_state.clip_tree.push_clip_root_node(node);
444 }
445 update_prim_visibility(
446 *pic_index,
447 None,
448 &world_culling_rect,
449 &scene.prim_store,
450 true,
451 &visibility_context,
452 &mut visibility_state,
453 &mut None,
454 );
455 if scene.prim_store.pictures[pic_index.0].clip_root.is_some() {
456 visibility_state.clip_tree.pop_clip_root();
457 }
458 }
459
460 for pic_index in scene.tile_cache_pictures.iter().rev() {
461 if !render_picture_cache_slices {
462 break;
463 }
464 let pic = &mut scene.prim_store.pictures[pic_index.0];
465
466 match pic.raster_config {
467 Some(RasterConfig { surface_index, composite_mode: PictureCompositeMode::TileCache { slice_id }, .. }) => {
468 let tile_cache = tile_caches
469 .get_mut(&slice_id)
470 .expect("bug: non-existent tile cache");
471
472 let mut visibility_state = FrameVisibilityState {
473 clip_store: &mut scene.clip_store,
474 resource_cache,
475 frame_gpu_data,
476 data_stores,
477 clip_tree: &mut scene.clip_tree,
478 composite_state,
479 rg_builder,
480 prim_instances: &mut scene.prim_instances,
481 surfaces: &mut scene.surfaces,
482 surface_stack: scratch.frame.surface_stack.take(),
483 profile,
484 scratch,
485 visited_pictures: &mut visited_pictures,
486 };
487
488 let world_culling_rect = tile_cache.pre_update(
492 surface_index,
493 &visibility_context,
494 &mut visibility_state,
495 );
496
497 visibility_state.push_surface(
500 *pic_index,
501 surface_index,
502 );
503 visibility_state.clip_tree.push_clip_root_node(tile_cache.shared_clip_node_id);
504
505 update_prim_visibility(
506 *pic_index,
507 None,
508 &world_culling_rect,
509 &scene.prim_store,
510 true,
511 &visibility_context,
512 &mut visibility_state,
513 &mut Some(tile_cache),
514 );
515
516 tile_cache.post_update(
518 &visibility_context,
519 &mut visibility_state.prim_instances,
520 &mut visibility_state.composite_state,
521 &mut visibility_state.resource_cache,
522 &mut visibility_state.scratch.primitive,
523 );
524
525 visibility_state.clip_tree.pop_clip_root();
526 visibility_state.pop_surface();
527 visibility_state.scratch.frame.surface_stack = visibility_state.surface_stack.take();
528 }
529 _ => {
530 panic!("bug: not a tile cache");
531 }
532 }
533 }
534
535 profile.end_time(profiler::FRAME_VISIBILITY_TIME);
536 }
537
538 self.skip_occluded_pictures_with_clips(
539 &scene.tile_cache_pictures,
540 &mut scene.prim_store.pictures,
541 tile_caches,
542 &frame_context,
543 composite_state);
544
545 profile.start_time(profiler::FRAME_PREPARE_TIME);
546
547 let mut picture_scratch_handles = frame_memory.new_vec_with_capacity(n_pics);
548 for _ in 0..n_pics {
549 picture_scratch_handles.push(None);
550 }
551 let mut frame_state = FrameBuildingState {
552 rg_builder,
553 clip_store: &mut scene.clip_store,
554 resource_cache,
555 transforms: transform_palette,
556 segment_builder: SegmentBuilder::new(),
557 surfaces: &mut scene.surfaces,
558 dirty_region_stack: scratch.frame.dirty_region_stack.take(),
559 composite_state,
560 num_visible_primitives: 0,
561 plane_splitters: &mut self.plane_splitters,
562 surface_builder: SurfaceBuilder::new(),
563 cmd_buffers,
564 clip_tree: &mut scene.clip_tree,
565 frame_gpu_data,
566 image_dependencies: FastHashMap::default(),
567 picture_scratch_handles: &mut picture_scratch_handles,
568 };
569
570
571 if !scene.snapshot_pictures.is_empty() {
572 let mut default_dirty_region = DirtyRegion::new(
575 root_spatial_node_index,
576 root_spatial_node_index,
577 );
578 default_dirty_region.add_dirty_region(
579 PictureRect::max_rect(),
580 frame_context.spatial_tree,
581 );
582 frame_state.push_dirty_region(default_dirty_region);
583
584 frame_state.surface_builder.push_surface(
585 snapshot_surface,
586 false,
587 PictureRect::max_rect(),
588 None,
589 frame_state.surfaces,
590 frame_state.rg_builder,
591 );
592 }
593
594 for pic_index in &scene.snapshot_pictures {
595
596 prepare_picture(
597 *pic_index,
598 &mut scene.prim_store,
599 Some(snapshot_surface),
600 SubpixelMode::Allow,
601 &frame_context,
602 &mut frame_state,
603 data_stores,
604 &mut scratch.primitive,
605 tile_caches,
606 &mut scene.prim_instances
607 );
608 }
609
610 if !scene.snapshot_pictures.is_empty() {
611 frame_state.surface_builder.pop_empty_surface();
612 frame_state.pop_dirty_region();
613 }
614
615 let mut default_dirty_region = DirtyRegion::new(
619 root_spatial_node_index,
620 root_spatial_node_index,
621 );
622 default_dirty_region.add_dirty_region(
623 frame_context.global_screen_world_rect.cast_unit(),
624 frame_context.spatial_tree,
625 );
626 frame_state.push_dirty_region(default_dirty_region);
627
628 for pic_index in &scene.tile_cache_pictures {
629 if !render_picture_cache_slices {
630 break;
631 }
632
633 prepare_picture(
634 *pic_index,
635 &mut scene.prim_store,
636 None,
637 SubpixelMode::Allow,
638 &frame_context,
639 &mut frame_state,
640 data_stores,
641 &mut scratch.primitive,
642 tile_caches,
643 &mut scene.prim_instances
644 );
645 }
646
647 frame_state.pop_dirty_region();
648 frame_state.surface_builder.finalize();
649 profile.end_time(profiler::FRAME_PREPARE_TIME);
650 profile.set(profiler::VISIBLE_PRIMITIVES, frame_state.num_visible_primitives);
651
652 scratch.frame.dirty_region_stack = frame_state.dirty_region_stack.take();
653
654 {
655 profile_marker!("BlockOnResources");
656
657 resource_cache.block_until_all_resources_added(
658 frame_gpu_data,
659 profile,
660 );
661 }
662 }
663
664 pub fn build(
665 &mut self,
666 scene: &mut BuiltScene,
667 present: bool,
668 resource_cache: &mut ResourceCache,
669 rg_builder: &mut RenderTaskGraphBuilder,
670 stamp: FrameStamp,
671 device_origin: DeviceIntPoint,
672 scene_properties: &SceneProperties,
673 data_stores: &mut DataStores,
674 scratch: &mut ScratchBuffer,
675 debug_flags: DebugFlags,
676 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
677 spatial_tree: &mut SpatialTree,
678 dirty_rects_are_valid: bool,
679 profile: &mut TransactionProfile,
680 minimap_data: FastHashMap<ExternalScrollId, MinimapData>,
681 chunk_pool: Arc<ChunkPool>,
682 ) -> Frame {
683 profile_scope!("build");
684 profile_marker!("BuildFrame");
685
686 let mut frame_memory = FrameMemory::new(chunk_pool, stamp.frame_id());
687 let mut gpu_buffer_builder = GpuBufferBuilder {
689 f32: GpuBufferBuilderF::new(&frame_memory, 8 * 1024, stamp.frame_id()),
690 i32: GpuBufferBuilderI::new(&frame_memory, 2 * 1024, stamp.frame_id()),
691 };
692
693 profile.set(profiler::PRIMITIVES, scene.prim_instances.len());
694 profile.set(profiler::PICTURE_CACHE_SLICES, scene.tile_cache_config.picture_cache_slice_count);
695 scratch.begin_frame();
696 resource_cache.begin_frame(stamp, profile);
697
698 scene.surfaces.clear();
701
702 let globals = FrameGlobalResources::new(&mut gpu_buffer_builder);
703
704 spatial_tree.update_tree(scene_properties);
705 let mut transform_palette = spatial_tree.build_transform_palette(&frame_memory);
706 scene.clip_store.begin_frame(&mut scratch.clip_store);
707
708 rg_builder.begin_frame(stamp.frame_id());
709
710 let global_device_pixel_scale = DevicePixelScale::new(1.0);
712
713 let output_size = scene.output_rect.size();
714 let screen_world_rect = (scene.output_rect.to_f32() / global_device_pixel_scale).round_out();
715
716 let mut composite_state = CompositeState::new(
717 scene.config.compositor_kind,
718 scene.config.max_depth_ids,
719 dirty_rects_are_valid,
720 scene.config.low_quality_pinch_zoom,
721 &frame_memory,
722 );
723
724 self.composite_state_prealloc.preallocate(&mut composite_state);
725
726 let mut cmd_buffers = CommandBufferList::new();
727
728 self.build_layer_screen_rects_and_cull_layers(
729 scene,
730 present,
731 screen_world_rect,
732 resource_cache,
733 rg_builder,
734 global_device_pixel_scale,
735 scene_properties,
736 &mut transform_palette,
737 data_stores,
738 scratch,
739 debug_flags,
740 &mut composite_state,
741 tile_caches,
742 spatial_tree,
743 &mut cmd_buffers,
744 &mut gpu_buffer_builder,
745 &frame_memory,
746 profile,
747 );
748
749 self.render_minimap(&mut scratch.primitive, &spatial_tree, minimap_data);
750
751 profile.start_time(profiler::FRAME_BATCHING_TIME);
752
753 let mut deferred_resolves = frame_memory.new_vec();
754
755 let render_tasks = rg_builder.end_frame(
757 resource_cache,
758 &mut gpu_buffer_builder,
759 &mut deferred_resolves,
760 scene.config.max_shared_surface_size,
761 &frame_memory,
762 );
763
764 let mut passes = frame_memory.new_vec();
765 let mut has_texture_cache_tasks = false;
766 let mut prim_headers = PrimitiveHeaders::new(&frame_memory);
767 self.prim_headers_prealloc.preallocate_framevec(&mut prim_headers.headers_int);
768 self.prim_headers_prealloc.preallocate_framevec(&mut prim_headers.headers_float);
769
770 {
771 profile_marker!("Batching");
772
773 let mut z_generator = ZBufferIdGenerator::new(scene.config.max_depth_ids);
775 let use_dual_source_blending = scene.config.dual_source_blending_is_supported;
776
777 for pass in render_tasks.passes.iter().rev() {
778 let mut ctx = RenderTargetContext {
779 global_device_pixel_scale,
780 prim_store: &scene.prim_store,
781 resource_cache,
782 use_dual_source_blending,
783 use_advanced_blending: scene.config.gpu_supports_advanced_blend,
784 break_advanced_blend_batches: !scene.config.advanced_blend_is_coherent,
785 batch_lookback_count: scene.config.batch_lookback_count,
786 spatial_tree,
787 data_stores,
788 surfaces: &scene.surfaces,
789 scratch: &mut scratch.primitive,
790 screen_world_rect,
791 globals: &globals,
792 tile_caches,
793 root_spatial_node_index: spatial_tree.root_reference_frame_index(),
794 frame_memory: &mut frame_memory,
795 };
796
797 let pass = build_render_pass(
798 pass,
799 output_size,
800 &mut ctx,
801 &mut gpu_buffer_builder,
802 &render_tasks,
803 &scene.clip_store,
804 &mut transform_palette,
805 &mut prim_headers,
806 &mut z_generator,
807 scene.config.gpu_supports_fast_clears,
808 &scene.prim_instances,
809 &cmd_buffers,
810 );
811
812 has_texture_cache_tasks |= !pass.texture_cache.is_empty();
813 has_texture_cache_tasks |= !pass.picture_cache.is_empty();
814
815 passes.push(pass);
816 }
817
818 if present {
819 let mut ctx = RenderTargetContext {
820 global_device_pixel_scale,
821 prim_store: &scene.prim_store,
822 resource_cache,
823 use_dual_source_blending,
824 use_advanced_blending: scene.config.gpu_supports_advanced_blend,
825 break_advanced_blend_batches: !scene.config.advanced_blend_is_coherent,
826 batch_lookback_count: scene.config.batch_lookback_count,
827 spatial_tree,
828 data_stores,
829 surfaces: &scene.surfaces,
830 scratch: &mut scratch.primitive,
831 screen_world_rect,
832 globals: &globals,
833 tile_caches,
834 root_spatial_node_index: spatial_tree.root_reference_frame_index(),
835 frame_memory: &mut frame_memory,
836 };
837
838 self.build_composite_pass(
839 scene,
840 &mut ctx,
841 &mut gpu_buffer_builder,
842 &mut deferred_resolves,
843 &mut composite_state,
844 );
845 }
846 }
847
848 profile.end_time(profiler::FRAME_BATCHING_TIME);
849
850 resource_cache.end_frame(profile);
851
852 self.prim_headers_prealloc.record_vec(&prim_headers.headers_int);
853 self.composite_state_prealloc.record(&composite_state);
854
855 composite_state.end_frame();
856 scene.clip_store.end_frame(&mut scratch.clip_store);
857 scratch.end_frame();
858
859 let gpu_buffer_f = gpu_buffer_builder.f32.finalize(&render_tasks);
860 let gpu_buffer_i = gpu_buffer_builder.i32.finalize(&render_tasks);
861
862 Frame {
863 device_rect: DeviceIntRect::from_origin_and_size(
864 device_origin,
865 scene.output_rect.size(),
866 ),
867 present,
868 passes,
869 transform_palette: transform_palette.finish(),
870 render_tasks,
871 deferred_resolves,
872 has_been_rendered: false,
873 has_texture_cache_tasks,
874 prim_headers,
875 debug_items: mem::replace(&mut scratch.primitive.frame.debug_items, Vec::new()),
876 composite_state,
877 gpu_buffer_f,
878 gpu_buffer_i,
879 allocator_memory: frame_memory,
880 }
881 }
882
883 fn render_minimap(
884 &self,
885 scratch: &mut PrimitiveScratchBuffer,
886 spatial_tree: &SpatialTree,
887 minimap_data_store: FastHashMap<ExternalScrollId, MinimapData>) {
888 if minimap_data_store.is_empty() {
890 return
891 }
892
893 struct RootContentInfo {
899 transform: LayoutToWorldTransform,
900 clip: LayoutRect
901 }
902 let mut root_content_info = FastHashMap::<ExternalScrollId, RootContentInfo>::default();
903 spatial_tree.visit_nodes(|index, node| {
904 if let SpatialNodeType::ScrollFrame(ref scroll_frame_info) = node.node_type {
905 if let Some(minimap_data) = minimap_data_store.get(&scroll_frame_info.external_id) {
906 if minimap_data.is_root_content {
907 let transform = spatial_tree.get_world_viewport_transform(index).into_transform();
908 root_content_info.insert(scroll_frame_info.external_id, RootContentInfo{
909 transform,
910 clip: scroll_frame_info.viewport_rect
911 });
912 }
913 }
914 }
915 });
916
917 spatial_tree.visit_nodes(|index, node| {
921 if let SpatialNodeType::ScrollFrame(ref scroll_frame_info) = node.node_type {
922 if let Some(minimap_data) = minimap_data_store.get(&scroll_frame_info.external_id) {
923 const HORIZONTAL_PADDING: f32 = 5.0;
924 const VERTICAL_PADDING: f32 = 10.0;
925 const PAGE_BORDER_COLOR: ColorF = debug_colors::BLACK;
926 const BACKGROUND_COLOR: ColorF = ColorF { r: 0.3, g: 0.3, b: 0.3, a: 0.3};
927 const DISPLAYPORT_BACKGROUND_COLOR: ColorF = ColorF { r: 1.0, g: 1.0, b: 1.0, a: 0.4};
928 const LAYOUT_PORT_COLOR: ColorF = debug_colors::RED;
929 const VISUAL_PORT_COLOR: ColorF = debug_colors::BLUE;
930 const DISPLAYPORT_COLOR: ColorF = debug_colors::LIME;
931
932 let viewport = scroll_frame_info.viewport_rect;
933
934 let scale_factor_x = 100f32.min(viewport.width() - (2.0 * HORIZONTAL_PADDING))
938 / minimap_data.scrollable_rect.width();
939 let scale_factor_y = (viewport.height() - (2.0 * VERTICAL_PADDING))
940 / minimap_data.scrollable_rect.height();
941 if scale_factor_x <= 0.0 || scale_factor_y <= 0.0 {
942 return;
943 }
944 let transform = LayoutTransform::scale(scale_factor_x, scale_factor_y, 1.0)
945 .then_translate(LayoutVector3D::new(HORIZONTAL_PADDING, VERTICAL_PADDING, 0.0))
946 .then_translate(LayoutVector3D::new(viewport.min.x, viewport.min.y, 0.0));
947
948 let world_transform = spatial_tree
954 .get_world_viewport_transform(index)
955 .into_transform();
956 let mut local_to_root_content =
957 world_transform.with_destination::<LayoutPixel>();
958 let mut root_content_to_world = LayoutToWorldTransform::default();
959 let mut root_content_clip = None;
960 if minimap_data.root_content_scroll_id != 0 {
961 if let Some(RootContentInfo{transform: root_content_transform, clip}) = root_content_info.get(&ExternalScrollId(minimap_data.root_content_scroll_id, minimap_data.root_content_pipeline_id)) {
962 let zoom_transform = minimap_data.zoom_transform;
967 local_to_root_content = world_transform
968 .then(&root_content_transform.inverse().unwrap())
969 .then(&zoom_transform.inverse().unwrap());
970 root_content_to_world = root_content_transform.clone();
971 root_content_clip = Some(clip);
972 }
973 }
974
975 let mut add_rect = |rect, border, fill| -> Option<()> {
976 const STROKE_WIDTH: f32 = 2.0;
977 let transformed_rect = transform.outer_transformed_box2d(&rect)?;
979
980 let mut root_content_rect = local_to_root_content.outer_transformed_box2d(&transformed_rect)?;
982 if let Some(clip) = root_content_clip {
988 root_content_rect = root_content_rect.intersection(clip)?;
989 }
990 let world_rect = root_content_to_world.outer_transformed_box2d(&root_content_rect)?;
991
992 scratch.push_debug_rect_with_stroke_width(world_rect, border, STROKE_WIDTH);
993
994 if let Some(fill_color) = fill {
996 let interior_world_rect = WorldRect::new(
997 world_rect.min + WorldVector2D::new(STROKE_WIDTH, STROKE_WIDTH),
998 world_rect.max - WorldVector2D::new(STROKE_WIDTH, STROKE_WIDTH)
999 );
1000 scratch.push_debug_rect(interior_world_rect * DevicePixelScale::new(1.0), 1, border, fill_color);
1001 }
1002
1003 Some(())
1004 };
1005
1006 add_rect(minimap_data.scrollable_rect, PAGE_BORDER_COLOR, Some(BACKGROUND_COLOR));
1007 add_rect(minimap_data.displayport, DISPLAYPORT_COLOR, Some(DISPLAYPORT_BACKGROUND_COLOR));
1008 if minimap_data.is_root_content {
1011 add_rect(minimap_data.layout_viewport, LAYOUT_PORT_COLOR, None);
1012 }
1013 add_rect(minimap_data.visual_viewport, VISUAL_PORT_COLOR, None);
1014 }
1015 }
1016 });
1017 }
1018
1019 fn skip_occluded_pictures_with_clips(
1026 &self,
1027 tile_cache_pictures: &Vec<PictureIndex>,
1028 pictures: &mut [PictureInstance],
1029 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
1030 frame_context: &FrameBuildingContext,
1031 composite_state: &mut CompositeState,
1032 ) {
1033 let mut current_opaque_clip = None;
1034
1035 for pic_index in tile_cache_pictures.iter().rev() {
1036 let pic = &mut pictures[pic_index.0];
1037
1038 match pic.raster_config {
1039 Some(RasterConfig { composite_mode: PictureCompositeMode::TileCache { slice_id }, .. }) => {
1040 let tile_cache = tile_caches
1041 .get_mut(&slice_id)
1042 .expect("bug: non-existent tile cache");
1043 if tile_cache.compositor_clip.is_none() {
1046 continue;
1047 }
1048
1049 let (rounded_clip_rect, rounded_clip_radii) = composite_state.compositor_clip_params(
1051 tile_cache.compositor_clip,
1052 DeviceRect::max_rect(),
1053 );
1054
1055 if let Some((current_clip_rect, current_clip_radius)) = current_opaque_clip {
1057 if current_clip_rect == rounded_clip_rect &&
1058 current_clip_radius == rounded_clip_radii {
1059 for sub_slice in tile_cache.sub_slices.iter_mut() {
1060 for tile in sub_slice.tiles.values_mut() {
1061 tile.is_visible = false;
1062 }
1063 }
1064 }
1065 }
1066
1067 let backdrop_rect = tile_cache.backdrop.backdrop_rect
1068 .intersection(&tile_cache.local_rect)
1069 .and_then(|r| {
1070 r.intersection(&tile_cache.local_clip_rect)
1071 });
1072
1073 if let Some(backdrop_rect) = backdrop_rect {
1074 let map_local_to_world = SpaceMapper::new_with_target(
1075 frame_context.root_spatial_node_index,
1076 tile_cache.spatial_node_index,
1077 frame_context.global_screen_world_rect,
1078 frame_context.spatial_tree,
1079 );
1080 let world_backdrop_rect = map_local_to_world
1081 .map(&backdrop_rect)
1082 .expect("bug: unable to map backdrop rect");
1083 let device_backdrop_rect = (world_backdrop_rect * frame_context.global_device_pixel_scale).round();
1084
1085 if device_backdrop_rect.contains_box(&rounded_clip_rect) {
1086 current_opaque_clip = Some((rounded_clip_rect, rounded_clip_radii));
1088 }
1089 }
1090 }
1091 _ => {
1092 panic!("bug: found a top-level prim that isn't a tile cache");
1093 }
1094 }
1095 }
1096 }
1097
1098 fn build_composite_pass(
1099 &self,
1100 scene: &BuiltScene,
1101 ctx: &RenderTargetContext,
1102 gpu_buffers: &mut GpuBufferBuilder,
1103 deferred_resolves: &mut FrameVec<DeferredResolve>,
1104 composite_state: &mut CompositeState,
1105 ) {
1106 for pic_index in &scene.tile_cache_pictures {
1107 let pic = &ctx.prim_store.pictures[pic_index.0];
1108
1109 match pic.raster_config {
1110 Some(RasterConfig { composite_mode: PictureCompositeMode::TileCache { slice_id }, .. }) => {
1111 let tile_cache = &ctx.tile_caches[&slice_id];
1115 let map_local_to_world = SpaceMapper::new_with_target(
1116 ctx.root_spatial_node_index,
1117 tile_cache.spatial_node_index,
1118 ctx.screen_world_rect,
1119 ctx.spatial_tree,
1120 );
1121 let world_clip_rect = map_local_to_world
1122 .map(&tile_cache.local_clip_rect)
1123 .expect("bug: unable to map clip rect");
1124 let device_clip_rect = (world_clip_rect * ctx.global_device_pixel_scale).round();
1125
1126 composite_state.push_surface(
1127 tile_cache,
1128 device_clip_rect,
1129 ctx.resource_cache,
1130 &mut gpu_buffers.f32,
1131 deferred_resolves,
1132 );
1133 }
1134 _ => {
1135 panic!("bug: found a top-level prim that isn't a tile cache");
1136 }
1137 }
1138 }
1139 }
1140}
1141
1142pub fn build_render_pass(
1148 src_pass: &Pass,
1149 screen_size: DeviceIntSize,
1150 ctx: &mut RenderTargetContext,
1151 gpu_buffer_builder: &mut GpuBufferBuilder,
1152 render_tasks: &RenderTaskGraph,
1153 clip_store: &ClipStore,
1154 transforms: &mut TransformPalette,
1155 prim_headers: &mut PrimitiveHeaders,
1156 z_generator: &mut ZBufferIdGenerator,
1157 gpu_supports_fast_clears: bool,
1158 prim_instances: &[PrimitiveInstance],
1159 cmd_buffers: &CommandBufferList,
1160) -> RenderPass {
1161 profile_scope!("build_render_pass");
1162
1163 let mut pass = RenderPass::new(src_pass, ctx.frame_memory);
1168
1169 for sub_pass in &src_pass.sub_passes {
1170 match sub_pass.surface {
1171 SubPassSurface::Dynamic { target_kind, texture_id, used_rect } => {
1172 match target_kind {
1173 RenderTargetKind::Color => {
1174 let mut target = RenderTarget::new(
1175 RenderTargetKind::Color,
1176 false,
1177 texture_id,
1178 screen_size,
1179 gpu_supports_fast_clears,
1180 Some(used_rect),
1181 &ctx.frame_memory,
1182 );
1183
1184 for task_id in &sub_pass.task_ids {
1185 target.add_task(
1186 *task_id,
1187 ctx,
1188 gpu_buffer_builder,
1189 render_tasks,
1190 clip_store,
1191 transforms,
1192 );
1193 }
1194
1195 pass.color.targets.push(target);
1196 }
1197 RenderTargetKind::Alpha => {
1198 let mut target = RenderTarget::new(
1199 RenderTargetKind::Alpha,
1200 false,
1201 texture_id,
1202 screen_size,
1203 gpu_supports_fast_clears,
1204 Some(used_rect),
1205 &ctx.frame_memory,
1206 );
1207
1208 for task_id in &sub_pass.task_ids {
1209 target.add_task(
1210 *task_id,
1211 ctx,
1212 gpu_buffer_builder,
1213 render_tasks,
1214 clip_store,
1215 transforms,
1216 );
1217 }
1218
1219 pass.alpha.targets.push(target);
1220 }
1221 }
1222 }
1223 SubPassSurface::Persistent { surface: StaticRenderTaskSurface::PictureCache { ref surface, .. }, .. } => {
1224 assert_eq!(sub_pass.task_ids.len(), 1);
1225 let task_id = sub_pass.task_ids[0];
1226 let task = &render_tasks[task_id];
1227 let target_rect = task.get_target_rect();
1228
1229 match task.kind {
1230 RenderTaskKind::Picture(ref pic_task) => {
1231 let cmd_buffer = cmd_buffers.get(pic_task.cmd_buffer_index);
1232 let mut dirty_rect = pic_task.scissor_rect.expect("bug: must be set for cache tasks");
1233 let mut valid_rect = pic_task.valid_rect.expect("bug: must be set for cache tasks");
1234
1235 if let ResolvedSurfaceTexture::Native { size, .. } = surface {
1239 let surface_size_rect = <DeviceIntRect>::from_size(*size);
1240 dirty_rect = dirty_rect.intersection(&surface_size_rect).unwrap_or_default();
1241 valid_rect = valid_rect.intersection(&surface_size_rect).unwrap_or_default();
1242 }
1243
1244 let batcher = AlphaBatchBuilder::new(
1245 screen_size,
1246 ctx.break_advanced_blend_batches,
1247 ctx.batch_lookback_count,
1248 task_id,
1249 task_id.into(),
1250 &ctx.frame_memory,
1251 );
1252
1253 let mut batch_builder = BatchBuilder::new(batcher);
1254
1255 cmd_buffer.iter_prims(&mut |cmd, spatial_node_index, segments| {
1256 batch_builder.add_prim_to_batch(
1257 cmd,
1258 spatial_node_index,
1259 ctx,
1260 render_tasks,
1261 prim_headers,
1262 transforms,
1263 pic_task.raster_spatial_node_index,
1264 pic_task.surface_spatial_node_index,
1265 z_generator,
1266 prim_instances,
1267 gpu_buffer_builder,
1268 segments,
1269 );
1270 });
1271
1272 let batcher = batch_builder.finalize();
1273
1274 let mut batch_containers = ctx.frame_memory.new_vec();
1275 let mut alpha_batch_container = AlphaBatchContainer::new(
1276 Some(dirty_rect),
1277 &ctx.frame_memory
1278 );
1279
1280 batcher.build(
1281 &mut batch_containers,
1282 &mut alpha_batch_container,
1283 target_rect,
1284 None,
1285 );
1286 debug_assert!(batch_containers.is_empty());
1287
1288 let target = PictureCacheTarget {
1289 surface: surface.clone(),
1290 clear_color: pic_task.clear_color,
1291 kind: PictureCacheTargetKind::Draw {
1292 alpha_batch_container,
1293 },
1294 dirty_rect,
1295 valid_rect,
1296 };
1297
1298 pass.picture_cache.push(target);
1299 }
1300 RenderTaskKind::TileComposite(ref tile_task) => {
1301 let mut dirty_rect = tile_task.scissor_rect;
1302 let mut valid_rect = tile_task.valid_rect;
1303 if let ResolvedSurfaceTexture::Native { size, .. } = surface {
1307 let surface_size_rect = <DeviceIntRect>::from_size(*size);
1308 dirty_rect = dirty_rect.intersection(&surface_size_rect).unwrap_or_default();
1309 valid_rect = valid_rect.intersection(&surface_size_rect).unwrap_or_default();
1310 }
1311
1312 let target = PictureCacheTarget {
1313 surface: surface.clone(),
1314 clear_color: Some(tile_task.clear_color),
1315 kind: PictureCacheTargetKind::Blit {
1316 task_id: tile_task.task_id.expect("bug: no source task_id set"),
1317 sub_rect_offset: tile_task.sub_rect_offset,
1318 },
1319 dirty_rect,
1320 valid_rect,
1321 };
1322
1323 pass.picture_cache.push(target);
1324 }
1325 _ => {
1326 unreachable!();
1327 }
1328 };
1329 }
1330 SubPassSurface::Persistent { surface: StaticRenderTaskSurface::TextureCache { target_kind, texture, .. } } => {
1331 let texture = pass.texture_cache
1332 .entry(texture)
1333 .or_insert_with(||
1334 RenderTarget::new(
1335 target_kind,
1336 true,
1337 texture,
1338 screen_size,
1339 gpu_supports_fast_clears,
1340 None,
1341 &ctx.frame_memory
1342 )
1343 );
1344 for task_id in &sub_pass.task_ids {
1345 texture.add_task(
1346 *task_id,
1347 ctx,
1348 gpu_buffer_builder,
1349 render_tasks,
1350 clip_store,
1351 transforms,
1352 );
1353 }
1354 }
1355 SubPassSurface::Persistent { surface: StaticRenderTaskSurface::ReadOnly { .. } } => {
1356 panic!("Should not create a render pass for read-only task locations.");
1357 }
1358 }
1359 }
1360
1361 pass.color.build(
1362 ctx,
1363 render_tasks,
1364 prim_headers,
1365 transforms,
1366 z_generator,
1367 prim_instances,
1368 cmd_buffers,
1369 gpu_buffer_builder,
1370 );
1371 pass.alpha.build(
1372 ctx,
1373 render_tasks,
1374 prim_headers,
1375 transforms,
1376 z_generator,
1377 prim_instances,
1378 cmd_buffers,
1379 gpu_buffer_builder,
1380 );
1381
1382 for target in &mut pass.texture_cache.values_mut() {
1383 target.build(
1384 ctx,
1385 render_tasks,
1386 prim_headers,
1387 transforms,
1388 z_generator,
1389 prim_instances,
1390 cmd_buffers,
1391 gpu_buffer_builder,
1392 );
1393 }
1394
1395 pass
1396}
1397
1398#[cfg_attr(feature = "capture", derive(Serialize))]
1406#[cfg_attr(feature = "replay", derive(Deserialize))]
1407pub struct Frame {
1408 pub device_rect: DeviceIntRect,
1410 pub present: bool,
1411 pub passes: FrameVec<RenderPass>,
1412
1413 pub transform_palette: FrameVec<TransformData>,
1414 pub render_tasks: RenderTaskGraph,
1415 pub prim_headers: PrimitiveHeaders,
1416
1417 pub deferred_resolves: FrameVec<DeferredResolve>,
1422
1423 pub has_texture_cache_tasks: bool,
1426
1427 pub has_been_rendered: bool,
1430
1431 pub debug_items: Vec<DebugItem>,
1433
1434 pub composite_state: CompositeState,
1438
1439 pub gpu_buffer_f: GpuBufferF,
1442 pub gpu_buffer_i: GpuBufferI,
1443
1444 pub allocator_memory: FrameMemory,
1456}
1457
1458impl Frame {
1459 pub fn must_be_drawn(&self) -> bool {
1462 self.has_texture_cache_tasks && !self.has_been_rendered
1463 }
1464
1465 pub fn is_nop(&self) -> bool {
1467 self.passes.is_empty()
1473 }
1474}