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