1use api::{ColorF, DebugFlags, FontRenderMode, PremultipliedColorF};
6use api::units::*;
7use crate::batch::{BatchBuilder, AlphaBatchBuilder, AlphaBatchContainer};
8use crate::clip::{ClipStore, ClipChainStack};
9use crate::spatial_tree::{SpatialTree, ROOT_SPATIAL_NODE_INDEX, SpatialNodeIndex};
10use crate::composite::{CompositorKind, CompositeState, CompositeStatePreallocator};
11use crate::debug_item::DebugItem;
12use crate::gpu_cache::{GpuCache, GpuCacheHandle};
13use crate::gpu_types::{PrimitiveHeaders, TransformPalette, ZBufferIdGenerator};
14use crate::gpu_types::TransformData;
15use crate::internal_types::{FastHashMap, PlaneSplitter};
16use crate::picture::{DirtyRegion, PictureUpdateState, SliceId, TileCacheInstance};
17use crate::picture::{SurfaceInfo, SurfaceIndex, ROOT_SURFACE_INDEX, SurfaceRenderTasks, SubSliceIndex};
18use crate::picture::{BackdropKind, SubpixelMode, TileCacheLogger, RasterConfig, PictureCompositeMode};
19use crate::prepare::prepare_primitives;
20use crate::prim_store::{PictureIndex, PrimitiveDebugId};
21use crate::prim_store::{DeferredResolve};
22use crate::profiler::{self, TransactionProfile};
23use crate::render_backend::{DataStores, FrameStamp, FrameId, ScratchBuffer};
24use crate::render_target::{RenderTarget, PictureCacheTarget, TextureCacheRenderTarget};
25use crate::render_target::{RenderTargetContext, RenderTargetKind, AlphaRenderTarget, ColorRenderTarget};
26use crate::render_task_graph::{RenderTaskId, RenderTaskGraph, Pass, SubPassSurface};
27use crate::render_task_graph::{RenderPass, RenderTaskGraphBuilder};
28use crate::render_task::{RenderTaskLocation, RenderTaskKind, StaticRenderTaskSurface};
29use crate::resource_cache::{ResourceCache};
30use crate::scene::{BuiltScene, SceneProperties};
31use crate::space::SpaceMapper;
32use crate::segment::SegmentBuilder;
33use std::{f32, mem};
34use crate::util::{VecHelper, Recycler, Preallocator};
35use crate::visibility::{update_primitive_visibility, FrameVisibilityState, FrameVisibilityContext};
36
37
38#[derive(Clone, Copy, Debug, PartialEq)]
39#[cfg_attr(feature = "capture", derive(Serialize))]
40#[cfg_attr(feature = "replay", derive(Deserialize))]
41pub enum ChasePrimitive {
42 Nothing,
43 Id(PrimitiveDebugId),
44 LocalRect(LayoutRect),
45}
46
47impl Default for ChasePrimitive {
48 fn default() -> Self {
49 ChasePrimitive::Nothing
50 }
51}
52
53#[derive(Clone, Copy, Debug)]
54#[cfg_attr(feature = "capture", derive(Serialize))]
55#[cfg_attr(feature = "replay", derive(Deserialize))]
56pub struct FrameBuilderConfig {
57 pub default_font_render_mode: FontRenderMode,
58 pub dual_source_blending_is_supported: bool,
59 pub dual_source_blending_is_enabled: bool,
60 pub chase_primitive: ChasePrimitive,
61 pub testing: bool,
63 pub gpu_supports_fast_clears: bool,
64 pub gpu_supports_advanced_blend: bool,
65 pub advanced_blend_is_coherent: bool,
66 pub gpu_supports_render_target_partial_update: bool,
67 pub external_images_require_copy: bool,
70 pub batch_lookback_count: usize,
71 pub background_color: Option<ColorF>,
72 pub compositor_kind: CompositorKind,
73 pub tile_size_override: Option<DeviceIntSize>,
74 pub max_depth_ids: i32,
75 pub max_target_size: i32,
76 pub force_invalidation: bool,
77 pub is_software: bool,
78 pub low_quality_pinch_zoom: bool,
79}
80
81#[cfg_attr(feature = "capture", derive(Serialize))]
85pub struct FrameGlobalResources {
86 pub default_image_handle: GpuCacheHandle,
89
90 pub default_transparent_rect_handle: GpuCacheHandle,
94}
95
96impl FrameGlobalResources {
97 pub fn empty() -> Self {
98 FrameGlobalResources {
99 default_image_handle: GpuCacheHandle::new(),
100 default_transparent_rect_handle: GpuCacheHandle::new(),
101 }
102 }
103
104 pub fn update(
105 &mut self,
106 gpu_cache: &mut GpuCache,
107 ) {
108 if let Some(mut request) = gpu_cache.request(&mut self.default_image_handle) {
109 request.push(PremultipliedColorF::WHITE);
110 request.push(PremultipliedColorF::WHITE);
111 request.push([
112 -1.0, 0.0,
114 0.0,
115 0.0,
116 ]);
117 }
118
119 if let Some(mut request) = gpu_cache.request(&mut self.default_transparent_rect_handle) {
120 request.push(PremultipliedColorF::TRANSPARENT);
121 }
122 }
123}
124
125pub struct FrameScratchBuffer {
126 surfaces: Vec<SurfaceInfo>,
127 dirty_region_stack: Vec<DirtyRegion>,
128 surface_stack: Vec<SurfaceIndex>,
129 clip_chain_stack: ClipChainStack,
130}
131
132impl Default for FrameScratchBuffer {
133 fn default() -> Self {
134 FrameScratchBuffer {
135 surfaces: Vec::new(),
136 dirty_region_stack: Vec::new(),
137 surface_stack: Vec::new(),
138 clip_chain_stack: ClipChainStack::new(),
139 }
140 }
141}
142
143impl FrameScratchBuffer {
144 pub fn begin_frame(&mut self) {
145 self.surfaces.clear();
146 self.dirty_region_stack.clear();
147 self.surface_stack.clear();
148 self.clip_chain_stack.clear();
149 }
150
151 pub fn recycle(&mut self, recycler: &mut Recycler) {
152 recycler.recycle_vec(&mut self.surfaces);
153 }
160}
161
162#[cfg_attr(feature = "capture", derive(Serialize))]
164pub struct FrameBuilder {
165 pub globals: FrameGlobalResources,
166 #[cfg_attr(feature = "capture", serde(skip))]
167 prim_headers_prealloc: Preallocator,
168 #[cfg_attr(feature = "capture", serde(skip))]
169 composite_state_prealloc: CompositeStatePreallocator,
170}
171
172pub struct FrameBuildingContext<'a> {
173 pub global_device_pixel_scale: DevicePixelScale,
174 pub scene_properties: &'a SceneProperties,
175 pub global_screen_world_rect: WorldRect,
176 pub spatial_tree: &'a SpatialTree,
177 pub max_local_clip: LayoutRect,
178 pub debug_flags: DebugFlags,
179 pub fb_config: &'a FrameBuilderConfig,
180}
181
182pub struct FrameBuildingState<'a> {
183 pub rg_builder: &'a mut RenderTaskGraphBuilder,
184 pub clip_store: &'a mut ClipStore,
185 pub resource_cache: &'a mut ResourceCache,
186 pub gpu_cache: &'a mut GpuCache,
187 pub transforms: &'a mut TransformPalette,
188 pub segment_builder: SegmentBuilder,
189 pub surfaces: &'a mut Vec<SurfaceInfo>,
190 pub dirty_region_stack: Vec<DirtyRegion>,
191 pub composite_state: &'a mut CompositeState,
192 pub num_visible_primitives: u32,
193}
194
195impl<'a> FrameBuildingState<'a> {
196 pub fn current_dirty_region(&self) -> &DirtyRegion {
198 self.dirty_region_stack.last().unwrap()
199 }
200
201 pub fn push_dirty_region(&mut self, region: DirtyRegion) {
203 self.dirty_region_stack.push(region);
204 }
205
206 pub fn pop_dirty_region(&mut self) {
208 self.dirty_region_stack.pop().unwrap();
209 }
210
211 pub fn init_surface_tiled(
214 &mut self,
215 surface_index: SurfaceIndex,
216 tasks: Vec<RenderTaskId>,
217 raster_rect: DeviceRect,
218 ) {
219 let surface = &mut self.surfaces[surface_index.0];
220 assert!(surface.render_tasks.is_none());
221 surface.render_tasks = Some(SurfaceRenderTasks::Tiled(tasks));
222 surface.raster_rect = Some(raster_rect);
223 }
224
225 pub fn init_surface(
228 &mut self,
229 surface_index: SurfaceIndex,
230 task_id: RenderTaskId,
231 parent_surface_index: SurfaceIndex,
232 raster_rect: DeviceRect,
233 ) {
234 let surface = &mut self.surfaces[surface_index.0];
235 assert!(surface.render_tasks.is_none());
236 surface.render_tasks = Some(SurfaceRenderTasks::Simple(task_id));
237 surface.raster_rect = Some(raster_rect);
238
239 self.add_child_render_task(
240 parent_surface_index,
241 task_id,
242 );
243 }
244
245 pub fn init_surface_chain(
249 &mut self,
250 surface_index: SurfaceIndex,
251 root_task_id: RenderTaskId,
252 port_task_id: RenderTaskId,
253 parent_surface_index: SurfaceIndex,
254 raster_rect: DeviceRect,
255 ) {
256 let surface = &mut self.surfaces[surface_index.0];
257 assert!(surface.render_tasks.is_none());
258 surface.render_tasks = Some(SurfaceRenderTasks::Chained { root_task_id, port_task_id });
259 surface.raster_rect = Some(raster_rect);
260
261 self.add_child_render_task(
262 parent_surface_index,
263 root_task_id,
264 );
265 }
266
267 pub fn add_child_render_task(
269 &mut self,
270 surface_index: SurfaceIndex,
271 child_task_id: RenderTaskId,
272 ) {
273 add_child_render_task(
274 surface_index,
275 child_task_id,
276 self.surfaces,
277 self.rg_builder,
278 );
279 }
280}
281
282#[derive(Debug)]
284pub struct PictureContext {
285 pub pic_index: PictureIndex,
286 pub apply_local_clip_rect: bool,
287 pub surface_spatial_node_index: SpatialNodeIndex,
288 pub raster_spatial_node_index: SpatialNodeIndex,
289 pub surface_index: SurfaceIndex,
291 pub dirty_region_count: usize,
292 pub subpixel_mode: SubpixelMode,
293}
294
295pub struct PictureState {
298 pub map_local_to_pic: SpaceMapper<LayoutPixel, PicturePixel>,
299 pub map_pic_to_world: SpaceMapper<PicturePixel, WorldPixel>,
300 pub map_pic_to_raster: SpaceMapper<PicturePixel, RasterPixel>,
301 pub map_raster_to_world: SpaceMapper<RasterPixel, WorldPixel>,
302 pub plane_splitter: Option<PlaneSplitter>,
305}
306
307impl FrameBuilder {
308 pub fn new() -> Self {
309 FrameBuilder {
310 globals: FrameGlobalResources::empty(),
311 prim_headers_prealloc: Preallocator::new(0),
312 composite_state_prealloc: CompositeStatePreallocator::default(),
313 }
314 }
315
316 fn build_layer_screen_rects_and_cull_layers(
319 &mut self,
320 scene: &mut BuiltScene,
321 global_screen_world_rect: WorldRect,
322 resource_cache: &mut ResourceCache,
323 gpu_cache: &mut GpuCache,
324 rg_builder: &mut RenderTaskGraphBuilder,
325 global_device_pixel_scale: DevicePixelScale,
326 scene_properties: &SceneProperties,
327 transform_palette: &mut TransformPalette,
328 data_stores: &mut DataStores,
329 scratch: &mut ScratchBuffer,
330 debug_flags: DebugFlags,
331 composite_state: &mut CompositeState,
332 tile_cache_logger: &mut TileCacheLogger,
333 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
334 profile: &mut TransactionProfile,
335 ) {
336 profile_scope!("build_layer_screen_rects_and_cull_layers");
337
338 let root_spatial_node_index = scene.spatial_tree.root_reference_frame_index();
339
340 const MAX_CLIP_COORD: f32 = 1.0e9;
341
342 let frame_context = FrameBuildingContext {
343 global_device_pixel_scale,
344 scene_properties,
345 global_screen_world_rect,
346 spatial_tree: &scene.spatial_tree,
347 max_local_clip: LayoutRect {
348 min: LayoutPoint::new(-MAX_CLIP_COORD, -MAX_CLIP_COORD),
349 max: LayoutPoint::new(MAX_CLIP_COORD, MAX_CLIP_COORD),
350 },
351 debug_flags,
352 fb_config: &scene.config,
353 };
354
355 let root_surface = SurfaceInfo::new(
358 ROOT_SPATIAL_NODE_INDEX,
359 ROOT_SPATIAL_NODE_INDEX,
360 0.0,
361 global_screen_world_rect,
362 &scene.spatial_tree,
363 global_device_pixel_scale,
364 (1.0, 1.0),
365 );
366 let mut surfaces = scratch.frame.surfaces.take();
367 surfaces.push(root_surface);
368
369 for pic_index in &scene.tile_cache_pictures {
377 PictureUpdateState::update_all(
378 &mut scratch.picture,
379 &mut surfaces,
380 *pic_index,
381 &mut scene.prim_store.pictures,
382 &frame_context,
383 gpu_cache,
384 &scene.clip_store,
385 data_stores,
386 tile_caches,
387 );
388 }
389
390 {
391 profile_scope!("UpdateVisibility");
392 profile_marker!("UpdateVisibility");
393 profile.start_time(profiler::FRAME_VISIBILITY_TIME);
394
395 let visibility_context = FrameVisibilityContext {
396 global_device_pixel_scale,
397 spatial_tree: &scene.spatial_tree,
398 global_screen_world_rect,
399 surfaces: &mut surfaces,
400 debug_flags,
401 scene_properties,
402 config: scene.config,
403 };
404
405 let mut visibility_state = FrameVisibilityState {
406 clip_chain_stack: scratch.frame.clip_chain_stack.take(),
407 surface_stack: scratch.frame.surface_stack.take(),
408 resource_cache,
409 gpu_cache,
410 clip_store: &mut scene.clip_store,
411 scratch,
412 tile_cache: None,
413 data_stores,
414 composite_state,
415 };
416
417 for pic_index in scene.tile_cache_pictures.iter().rev() {
418 update_primitive_visibility(
419 &mut scene.prim_store,
420 *pic_index,
421 ROOT_SURFACE_INDEX,
422 &global_screen_world_rect,
423 &visibility_context,
424 &mut visibility_state,
425 tile_caches,
426 true,
427 );
428 }
429
430 visibility_state.scratch.frame.clip_chain_stack = visibility_state.clip_chain_stack.take();
431 visibility_state.scratch.frame.surface_stack = visibility_state.surface_stack.take();
432
433 profile.end_time(profiler::FRAME_VISIBILITY_TIME);
434 }
435
436 profile.start_time(profiler::FRAME_PREPARE_TIME);
437
438 let mut frame_state = FrameBuildingState {
439 rg_builder,
440 clip_store: &mut scene.clip_store,
441 resource_cache,
442 gpu_cache,
443 transforms: transform_palette,
444 segment_builder: SegmentBuilder::new(),
445 surfaces: &mut surfaces,
446 dirty_region_stack: scratch.frame.dirty_region_stack.take(),
447 composite_state,
448 num_visible_primitives: 0,
449 };
450
451 let mut default_dirty_region = DirtyRegion::new(
455 ROOT_SPATIAL_NODE_INDEX,
456 );
457 default_dirty_region.add_dirty_region(
458 frame_context.global_screen_world_rect.cast_unit(),
459 SubSliceIndex::DEFAULT,
460 frame_context.spatial_tree,
461 );
462 frame_state.push_dirty_region(default_dirty_region);
463
464 for pic_index in &scene.tile_cache_pictures {
465 if let Some((pic_context, mut pic_state, mut prim_list)) = scene
466 .prim_store
467 .pictures[pic_index.0]
468 .take_context(
469 *pic_index,
470 root_spatial_node_index,
471 root_spatial_node_index,
472 ROOT_SURFACE_INDEX,
473 SubpixelMode::Allow,
474 &mut frame_state,
475 &frame_context,
476 &mut scratch.primitive,
477 tile_cache_logger,
478 tile_caches,
479 )
480 {
481 profile_marker!("PreparePrims");
482
483 prepare_primitives(
484 &mut scene.prim_store,
485 &mut prim_list,
486 &pic_context,
487 &mut pic_state,
488 &frame_context,
489 &mut frame_state,
490 data_stores,
491 &mut scratch.primitive,
492 tile_cache_logger,
493 tile_caches,
494 );
495
496 let pic = &mut scene.prim_store.pictures[pic_index.0];
497 pic.restore_context(
498 prim_list,
499 pic_context,
500 pic_state,
501 &mut frame_state,
502 );
503 }
504 }
505
506 tile_cache_logger.advance();
507 frame_state.pop_dirty_region();
508 profile.end_time(profiler::FRAME_PREPARE_TIME);
509 profile.set(profiler::VISIBLE_PRIMITIVES, frame_state.num_visible_primitives);
510
511 scratch.frame.dirty_region_stack = frame_state.dirty_region_stack.take();
512 scratch.frame.surfaces = surfaces.take();
513
514 {
515 profile_marker!("BlockOnResources");
516
517 resource_cache.block_until_all_resources_added(
518 gpu_cache,
519 profile,
520 );
521 }
522 }
523
524 pub fn build(
525 &mut self,
526 scene: &mut BuiltScene,
527 resource_cache: &mut ResourceCache,
528 gpu_cache: &mut GpuCache,
529 rg_builder: &mut RenderTaskGraphBuilder,
530 stamp: FrameStamp,
531 device_origin: DeviceIntPoint,
532 scene_properties: &SceneProperties,
533 data_stores: &mut DataStores,
534 scratch: &mut ScratchBuffer,
535 debug_flags: DebugFlags,
536 tile_cache_logger: &mut TileCacheLogger,
537 tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
538 dirty_rects_are_valid: bool,
539 profile: &mut TransactionProfile,
540 ) -> Frame {
541 profile_scope!("build");
542 profile_marker!("BuildFrame");
543
544 profile.set(profiler::PRIMITIVES, scene.prim_store.prim_count());
545 profile.set(profiler::PICTURE_CACHE_SLICES, scene.tile_cache_config.picture_cache_slice_count);
546 scratch.begin_frame();
547 resource_cache.begin_frame(stamp, profile);
548 gpu_cache.begin_frame(stamp);
549
550 self.globals.update(gpu_cache);
551
552 scene.spatial_tree.update_tree(scene_properties);
553 let mut transform_palette = scene.spatial_tree.build_transform_palette();
554 scene.clip_store.begin_frame(&mut scratch.clip_store);
555
556 rg_builder.begin_frame(stamp.frame_id());
557
558 let global_device_pixel_scale = DevicePixelScale::new(1.0);
560
561 let output_size = scene.output_rect.size();
562 let screen_world_rect = (scene.output_rect.to_f32() / global_device_pixel_scale).round_out();
563
564 let mut composite_state = CompositeState::new(
565 scene.config.compositor_kind,
566 scene.config.max_depth_ids,
567 dirty_rects_are_valid,
568 scene.config.low_quality_pinch_zoom,
569 );
570
571 self.composite_state_prealloc.preallocate(&mut composite_state);
572
573 self.build_layer_screen_rects_and_cull_layers(
574 scene,
575 screen_world_rect,
576 resource_cache,
577 gpu_cache,
578 rg_builder,
579 global_device_pixel_scale,
580 scene_properties,
581 &mut transform_palette,
582 data_stores,
583 scratch,
584 debug_flags,
585 &mut composite_state,
586 tile_cache_logger,
587 tile_caches,
588 profile,
589 );
590
591 profile.start_time(profiler::FRAME_BATCHING_TIME);
592
593 let mut deferred_resolves = vec![];
594
595 let render_tasks = rg_builder.end_frame(
597 resource_cache,
598 gpu_cache,
599 &mut deferred_resolves,
600 );
601
602 let mut passes = Vec::new();
603 let mut has_texture_cache_tasks = false;
604 let mut prim_headers = PrimitiveHeaders::new();
605 self.prim_headers_prealloc.preallocate_vec(&mut prim_headers.headers_int);
606 self.prim_headers_prealloc.preallocate_vec(&mut prim_headers.headers_float);
607
608 {
609 profile_marker!("Batching");
610
611 let mut z_generator = ZBufferIdGenerator::new(scene.config.max_depth_ids);
613 let use_dual_source_blending = scene.config.dual_source_blending_is_enabled &&
614 scene.config.dual_source_blending_is_supported;
615
616 for pass in render_tasks.passes.iter().rev() {
617 let mut ctx = RenderTargetContext {
618 global_device_pixel_scale,
619 prim_store: &scene.prim_store,
620 resource_cache,
621 use_dual_source_blending,
622 use_advanced_blending: scene.config.gpu_supports_advanced_blend,
623 break_advanced_blend_batches: !scene.config.advanced_blend_is_coherent,
624 batch_lookback_count: scene.config.batch_lookback_count,
625 spatial_tree: &scene.spatial_tree,
626 data_stores,
627 surfaces: &scratch.frame.surfaces,
628 scratch: &mut scratch.primitive,
629 screen_world_rect,
630 globals: &self.globals,
631 tile_caches,
632 };
633
634 let pass = build_render_pass(
635 pass,
636 output_size,
637 &mut ctx,
638 gpu_cache,
639 &render_tasks,
640 &mut deferred_resolves,
641 &scene.clip_store,
642 &mut transform_palette,
643 &mut prim_headers,
644 &mut z_generator,
645 &mut composite_state,
646 scene.config.gpu_supports_fast_clears,
647 );
648
649 has_texture_cache_tasks |= !pass.texture_cache.is_empty();
650 has_texture_cache_tasks |= !pass.picture_cache.is_empty();
651
652 passes.push(pass);
653 }
654
655 let mut ctx = RenderTargetContext {
656 global_device_pixel_scale,
657 prim_store: &scene.prim_store,
658 resource_cache,
659 use_dual_source_blending,
660 use_advanced_blending: scene.config.gpu_supports_advanced_blend,
661 break_advanced_blend_batches: !scene.config.advanced_blend_is_coherent,
662 batch_lookback_count: scene.config.batch_lookback_count,
663 spatial_tree: &scene.spatial_tree,
664 data_stores,
665 surfaces: &scratch.frame.surfaces,
666 scratch: &mut scratch.primitive,
667 screen_world_rect,
668 globals: &self.globals,
669 tile_caches,
670 };
671
672 self.build_composite_pass(
673 scene,
674 &mut ctx,
675 gpu_cache,
676 &mut deferred_resolves,
677 &mut composite_state,
678 );
679 }
680
681 profile.end_time(profiler::FRAME_BATCHING_TIME);
682
683 let gpu_cache_frame_id = gpu_cache.end_frame(profile).frame_id();
684
685 resource_cache.end_frame(profile);
686
687 self.prim_headers_prealloc.record_vec(&mut prim_headers.headers_int);
688 self.composite_state_prealloc.record(&composite_state);
689
690 composite_state.end_frame();
691 scene.clip_store.end_frame(&mut scratch.clip_store);
692 scratch.end_frame();
693
694 Frame {
695 device_rect: DeviceIntRect::from_origin_and_size(
696 device_origin,
697 scene.output_rect.size(),
698 ),
699 passes,
700 transform_palette: transform_palette.finish(),
701 render_tasks,
702 deferred_resolves,
703 gpu_cache_frame_id,
704 has_been_rendered: false,
705 has_texture_cache_tasks,
706 prim_headers,
707 debug_items: mem::replace(&mut scratch.primitive.debug_items, Vec::new()),
708 composite_state,
709 }
710 }
711
712 fn build_composite_pass(
713 &self,
714 scene: &BuiltScene,
715 ctx: &RenderTargetContext,
716 gpu_cache: &mut GpuCache,
717 deferred_resolves: &mut Vec<DeferredResolve>,
718 composite_state: &mut CompositeState,
719 ) {
720 for pic_index in &scene.tile_cache_pictures {
721 let pic = &ctx.prim_store.pictures[pic_index.0];
722
723 match pic.raster_config {
724 Some(RasterConfig { composite_mode: PictureCompositeMode::TileCache { slice_id }, .. }) => {
725 let tile_cache = &ctx.tile_caches[&slice_id];
729 let map_local_to_world = SpaceMapper::new_with_target(
730 ROOT_SPATIAL_NODE_INDEX,
731 tile_cache.spatial_node_index,
732 ctx.screen_world_rect,
733 ctx.spatial_tree,
734 );
735 let world_clip_rect = map_local_to_world
736 .map(&tile_cache.local_clip_rect)
737 .expect("bug: unable to map clip rect");
738 let device_clip_rect = (world_clip_rect * ctx.global_device_pixel_scale).round();
739
740 composite_state.push_surface(
741 tile_cache,
742 device_clip_rect,
743 ctx.resource_cache,
744 gpu_cache,
745 deferred_resolves,
746 );
747 }
748 _ => {
749 panic!("bug: found a top-level prim that isn't a tile cache");
750 }
751 }
752 }
753 }
754}
755
756pub fn build_render_pass(
762 src_pass: &Pass,
763 screen_size: DeviceIntSize,
764 ctx: &mut RenderTargetContext,
765 gpu_cache: &mut GpuCache,
766 render_tasks: &RenderTaskGraph,
767 deferred_resolves: &mut Vec<DeferredResolve>,
768 clip_store: &ClipStore,
769 transforms: &mut TransformPalette,
770 prim_headers: &mut PrimitiveHeaders,
771 z_generator: &mut ZBufferIdGenerator,
772 composite_state: &mut CompositeState,
773 gpu_supports_fast_clears: bool,
774) -> RenderPass {
775 profile_scope!("build_render_pass");
776
777 let mut picture_cache_tasks = FastHashMap::default();
786 let mut pass = RenderPass::new(src_pass);
787
788 for sub_pass in &src_pass.sub_passes {
789 match sub_pass.surface {
790 SubPassSurface::Dynamic { target_kind, texture_id, used_rect } => {
791 match target_kind {
792 RenderTargetKind::Color => {
793 let mut target = ColorRenderTarget::new(
794 texture_id,
795 screen_size,
796 gpu_supports_fast_clears,
797 used_rect,
798 );
799
800 for task_id in &sub_pass.task_ids {
801 target.add_task(
802 *task_id,
803 ctx,
804 gpu_cache,
805 render_tasks,
806 clip_store,
807 transforms,
808 );
809 }
810
811 pass.color.targets.push(target);
812 }
813 RenderTargetKind::Alpha => {
814 let mut target = AlphaRenderTarget::new(
815 texture_id,
816 screen_size,
817 gpu_supports_fast_clears,
818 used_rect,
819 );
820
821 for task_id in &sub_pass.task_ids {
822 target.add_task(
823 *task_id,
824 ctx,
825 gpu_cache,
826 render_tasks,
827 clip_store,
828 transforms,
829 );
830 }
831
832 pass.alpha.targets.push(target);
833 }
834 }
835 }
836 SubPassSurface::Persistent { surface: StaticRenderTaskSurface::PictureCache { .. }, .. } => {
837 assert_eq!(sub_pass.task_ids.len(), 1);
838 let task_id = sub_pass.task_ids[0];
839 let task = &render_tasks[task_id];
840
841 let pic_index = match task.kind {
844 RenderTaskKind::Picture(ref info) => {
845 info.pic_index
846 }
847 _ => {
848 unreachable!();
849 }
850 };
851
852 picture_cache_tasks
853 .entry(pic_index)
854 .or_insert_with(Vec::new)
855 .push(task_id);
856 }
857 SubPassSurface::Persistent { surface: StaticRenderTaskSurface::TextureCache { target_kind, texture, .. } } => {
858 let texture = pass.texture_cache
859 .entry(texture)
860 .or_insert_with(||
861 TextureCacheRenderTarget::new(target_kind)
862 );
863 for task_id in &sub_pass.task_ids {
864 texture.add_task(*task_id, render_tasks, gpu_cache);
865 }
866 }
867 SubPassSurface::Persistent { surface: StaticRenderTaskSurface::ReadOnly { .. } } => {
868 panic!("Should not create a render pass for read-only task locations.");
869 }
870 }
871 }
872
873 for (pic_index, task_ids) in picture_cache_tasks {
877 profile_scope!("picture_cache_task");
878 let pic = &ctx.prim_store.pictures[pic_index.0];
879
880 let (root_spatial_node_index, surface_spatial_node_index, tile_cache) = match pic.raster_config {
882 Some(RasterConfig { surface_index, composite_mode: PictureCompositeMode::TileCache { slice_id }, .. }) => {
883 let surface = &ctx.surfaces[surface_index.0];
884 (
885 surface.raster_spatial_node_index,
886 surface.surface_spatial_node_index,
887 &ctx.tile_caches[&slice_id],
888 )
889 }
890 _ => {
891 unreachable!();
892 }
893 };
894
895 let mut batchers = Vec::new();
897 for task_id in &task_ids {
898 let task_id = *task_id;
899 let batch_filter = match render_tasks[task_id].kind {
900 RenderTaskKind::Picture(ref info) => info.batch_filter,
901 _ => unreachable!(),
902 };
903 batchers.push(AlphaBatchBuilder::new(
904 screen_size,
905 ctx.break_advanced_blend_batches,
906 ctx.batch_lookback_count,
907 task_id,
908 task_id.into(),
909 batch_filter,
910 0,
911 ));
912 }
913
914 let mut batch_builder = BatchBuilder::new(batchers);
917 {
918 profile_scope!("add_pic_to_batch");
919 batch_builder.add_pic_to_batch(
920 pic,
921 ctx,
922 gpu_cache,
923 render_tasks,
924 deferred_resolves,
925 prim_headers,
926 transforms,
927 root_spatial_node_index,
928 surface_spatial_node_index,
929 z_generator,
930 composite_state,
931 );
932 }
933
934 let batchers = batch_builder.finalize();
937 for (task_id, batcher) in task_ids.into_iter().zip(batchers.into_iter()) {
938 profile_scope!("task");
939 let task = &render_tasks[task_id];
940 let target_rect = task.get_target_rect();
941
942 match task.location {
943 RenderTaskLocation::Static { surface: StaticRenderTaskSurface::PictureCache { ref surface, .. }, .. } => {
944 let (scissor_rect, valid_rect, clear_color) = match render_tasks[task_id].kind {
949 RenderTaskKind::Picture(ref info) => {
950 let mut clear_color = ColorF::TRANSPARENT;
951
952 if let Some(batch_filter) = info.batch_filter {
954 if batch_filter.sub_slice_index.is_primary() {
955 if let Some(background_color) = tile_cache.background_color {
956 clear_color = background_color;
957 }
958
959 if let Some(BackdropKind::Color { color }) = tile_cache.backdrop.kind {
963 clear_color = color;
964 }
965 }
966 }
967
968 (
969 info.scissor_rect.expect("bug: must be set for cache tasks"),
970 info.valid_rect.expect("bug: must be set for cache tasks"),
971 clear_color,
972 )
973 }
974 _ => unreachable!(),
975 };
976 let mut batch_containers = Vec::new();
977 let mut alpha_batch_container = AlphaBatchContainer::new(Some(scissor_rect));
978 batcher.build(
979 &mut batch_containers,
980 &mut alpha_batch_container,
981 target_rect,
982 None,
983 );
984 debug_assert!(batch_containers.is_empty());
985
986 let target = PictureCacheTarget {
987 surface: surface.clone(),
988 clear_color: Some(clear_color),
989 alpha_batch_container,
990 dirty_rect: scissor_rect,
991 valid_rect,
992 };
993
994 pass.picture_cache.push(target);
995 }
996 _ => {
997 unreachable!()
998 }
999 }
1000 }
1001 }
1002
1003 pass.color.build(
1004 ctx,
1005 gpu_cache,
1006 render_tasks,
1007 deferred_resolves,
1008 prim_headers,
1009 transforms,
1010 z_generator,
1011 composite_state,
1012 );
1013 pass.alpha.build(
1014 ctx,
1015 gpu_cache,
1016 render_tasks,
1017 deferred_resolves,
1018 prim_headers,
1019 transforms,
1020 z_generator,
1021 composite_state,
1022 );
1023
1024 pass
1025}
1026
1027#[cfg_attr(feature = "capture", derive(Serialize))]
1030#[cfg_attr(feature = "replay", derive(Deserialize))]
1031pub struct Frame {
1032 pub device_rect: DeviceIntRect,
1034 pub passes: Vec<RenderPass>,
1035
1036 pub transform_palette: Vec<TransformData>,
1037 pub render_tasks: RenderTaskGraph,
1038 pub prim_headers: PrimitiveHeaders,
1039
1040 pub gpu_cache_frame_id: FrameId,
1042
1043 pub deferred_resolves: Vec<DeferredResolve>,
1048
1049 pub has_texture_cache_tasks: bool,
1052
1053 pub has_been_rendered: bool,
1056
1057 pub debug_items: Vec<DebugItem>,
1059
1060 pub composite_state: CompositeState,
1064}
1065
1066impl Frame {
1067 pub fn must_be_drawn(&self) -> bool {
1070 self.has_texture_cache_tasks && !self.has_been_rendered
1071 }
1072
1073 pub fn is_nop(&self) -> bool {
1075 self.passes.is_empty()
1081 }
1082}
1083
1084pub fn add_child_render_task(
1089 surface_index: SurfaceIndex,
1090 child_task_id: RenderTaskId,
1091 surfaces: &[SurfaceInfo],
1092 rg_builder: &mut RenderTaskGraphBuilder,
1093) {
1094 let surface_tasks = surfaces[surface_index.0]
1095 .render_tasks
1096 .as_ref()
1097 .expect("bug: no task for surface");
1098
1099 match surface_tasks {
1100 SurfaceRenderTasks::Tiled(ref tasks) => {
1101 for parent_id in tasks {
1103 rg_builder.add_dependency(*parent_id, child_task_id);
1104 }
1105 }
1106 SurfaceRenderTasks::Simple(parent_id) => {
1107 rg_builder.add_dependency(*parent_id, child_task_id);
1108 }
1109 SurfaceRenderTasks::Chained { port_task_id, .. } => {
1110 rg_builder.add_dependency(*port_task_id, child_task_id);
1113 }
1114 }
1115}