1use api::{ColorF, DebugFlags, DocumentLayer, FontRenderMode, PremultipliedColorF};
6use api::units::*;
7use crate::batch::{BatchBuilder, AlphaBatchBuilder, AlphaBatchContainer};
8use crate::clip::{ClipStore, ClipChainStack};
9use crate::clip_scroll_tree::{ClipScrollTree, ROOT_SPATIAL_NODE_INDEX, SpatialNodeIndex, CoordinateSystemId};
10use crate::composite::{CompositorKind, CompositeState};
11use crate::debug_render::DebugItem;
12use crate::gpu_cache::{GpuCache, GpuCacheHandle};
13use crate::gpu_types::{PrimitiveHeaders, TransformPalette, UvRectKind, ZBufferIdGenerator};
14use crate::gpu_types::TransformData;
15use crate::internal_types::{FastHashMap, PlaneSplitter, SavedTargetIndex};
16use crate::picture::{PictureUpdateState, SurfaceInfo, ROOT_SURFACE_INDEX, SurfaceIndex, RecordedDirtyRegion};
17use crate::picture::{RetainedTiles, TileCacheInstance, DirtyRegion, SurfaceRenderTasks, SubpixelMode};
18use crate::prim_store::{SpaceMapper, PictureIndex, PrimitiveDebugId, PrimitiveScratchBuffer};
19use crate::prim_store::{DeferredResolve, PrimitiveVisibilityMask};
20use crate::profiler::{FrameProfileCounters, TextureCacheProfileCounters, ResourceProfileCounters};
21use crate::render_backend::{DataStores, FrameStamp, FrameId};
22use crate::render_target::{RenderTarget, PictureCacheTarget, TextureCacheRenderTarget};
23use crate::render_target::{RenderTargetContext, RenderTargetKind};
24use crate::render_task_graph::{RenderTaskId, RenderTaskGraph, RenderTaskGraphCounters};
25use crate::render_task_graph::{RenderPassKind, RenderPass};
26use crate::render_task::{RenderTask, RenderTaskLocation, RenderTaskKind};
27use crate::resource_cache::{ResourceCache};
28use crate::scene::{BuiltScene, SceneProperties};
29use crate::segment::SegmentBuilder;
30use std::{f32, mem};
31use crate::util::MaxRect;
32
33
34#[derive(Clone, Copy, Debug, PartialEq)]
35#[cfg_attr(feature = "capture", derive(Serialize))]
36#[cfg_attr(feature = "replay", derive(Deserialize))]
37pub enum ChasePrimitive {
38 Nothing,
39 Id(PrimitiveDebugId),
40 LocalRect(LayoutRect),
41}
42
43impl Default for ChasePrimitive {
44 fn default() -> Self {
45 ChasePrimitive::Nothing
46 }
47}
48
49#[derive(Clone, Copy, Debug)]
50#[cfg_attr(feature = "capture", derive(Serialize))]
51#[cfg_attr(feature = "replay", derive(Deserialize))]
52pub struct FrameBuilderConfig {
53 pub default_font_render_mode: FontRenderMode,
54 pub dual_source_blending_is_supported: bool,
55 pub dual_source_blending_is_enabled: bool,
56 pub chase_primitive: ChasePrimitive,
57 pub global_enable_picture_caching: bool,
59 pub testing: bool,
61 pub gpu_supports_fast_clears: bool,
62 pub gpu_supports_advanced_blend: bool,
63 pub advanced_blend_is_coherent: bool,
64 pub batch_lookback_count: usize,
65 pub background_color: Option<ColorF>,
66 pub compositor_kind: CompositorKind,
67}
68
69#[cfg_attr(feature = "capture", derive(Serialize))]
73pub struct FrameGlobalResources {
74 pub default_image_handle: GpuCacheHandle,
77}
78
79impl FrameGlobalResources {
80 pub fn empty() -> Self {
81 FrameGlobalResources {
82 default_image_handle: GpuCacheHandle::new(),
83 }
84 }
85
86 pub fn update(
87 &mut self,
88 gpu_cache: &mut GpuCache,
89 ) {
90 if let Some(mut request) = gpu_cache.request(&mut self.default_image_handle) {
91 request.push(PremultipliedColorF::WHITE);
92 request.push(PremultipliedColorF::WHITE);
93 request.push([
94 -1.0, 0.0,
96 0.0,
97 0.0,
98 ]);
99 }
100 }
101}
102
103#[cfg_attr(feature = "capture", derive(Serialize))]
105pub struct FrameBuilder {
106 pending_retained_tiles: RetainedTiles,
109 pub globals: FrameGlobalResources,
110}
111
112pub struct FrameVisibilityContext<'a> {
113 pub clip_scroll_tree: &'a ClipScrollTree,
114 pub global_screen_world_rect: WorldRect,
115 pub global_device_pixel_scale: DevicePixelScale,
116 pub surfaces: &'a [SurfaceInfo],
117 pub debug_flags: DebugFlags,
118 pub scene_properties: &'a SceneProperties,
119 pub config: &'a FrameBuilderConfig,
120}
121
122pub struct FrameVisibilityState<'a> {
123 pub clip_store: &'a mut ClipStore,
124 pub resource_cache: &'a mut ResourceCache,
125 pub gpu_cache: &'a mut GpuCache,
126 pub scratch: &'a mut PrimitiveScratchBuffer,
127 pub tile_cache: Option<Box<TileCacheInstance>>,
128 pub retained_tiles: &'a mut RetainedTiles,
129 pub data_stores: &'a mut DataStores,
130 pub clip_chain_stack: ClipChainStack,
131 pub render_tasks: &'a mut RenderTaskGraph,
132 pub composite_state: &'a mut CompositeState,
133}
134
135pub struct FrameBuildingContext<'a> {
136 pub global_device_pixel_scale: DevicePixelScale,
137 pub scene_properties: &'a SceneProperties,
138 pub global_screen_world_rect: WorldRect,
139 pub clip_scroll_tree: &'a ClipScrollTree,
140 pub max_local_clip: LayoutRect,
141 pub debug_flags: DebugFlags,
142 pub fb_config: &'a FrameBuilderConfig,
143}
144
145pub struct FrameBuildingState<'a> {
146 pub render_tasks: &'a mut RenderTaskGraph,
147 pub profile_counters: &'a mut FrameProfileCounters,
148 pub clip_store: &'a mut ClipStore,
149 pub resource_cache: &'a mut ResourceCache,
150 pub gpu_cache: &'a mut GpuCache,
151 pub transforms: &'a mut TransformPalette,
152 pub segment_builder: SegmentBuilder,
153 pub surfaces: &'a mut Vec<SurfaceInfo>,
154 pub dirty_region_stack: Vec<DirtyRegion>,
155 pub composite_state: &'a mut CompositeState,
156}
157
158impl<'a> FrameBuildingState<'a> {
159 pub fn current_dirty_region(&self) -> &DirtyRegion {
161 self.dirty_region_stack.last().unwrap()
162 }
163
164 pub fn push_dirty_region(&mut self, region: DirtyRegion) {
166 self.dirty_region_stack.push(region);
167 }
168
169 pub fn pop_dirty_region(&mut self) {
171 self.dirty_region_stack.pop().unwrap();
172 }
173}
174
175#[derive(Debug)]
177pub struct PictureContext {
178 pub pic_index: PictureIndex,
179 pub apply_local_clip_rect: bool,
180 pub is_passthrough: bool,
181 pub surface_spatial_node_index: SpatialNodeIndex,
182 pub raster_spatial_node_index: SpatialNodeIndex,
183 pub surface_index: SurfaceIndex,
185 pub dirty_region_count: usize,
186 pub subpixel_mode: SubpixelMode,
187}
188
189pub struct PictureState {
192 pub map_local_to_pic: SpaceMapper<LayoutPixel, PicturePixel>,
193 pub map_pic_to_world: SpaceMapper<PicturePixel, WorldPixel>,
194 pub map_pic_to_raster: SpaceMapper<PicturePixel, RasterPixel>,
195 pub map_raster_to_world: SpaceMapper<RasterPixel, WorldPixel>,
196 pub plane_splitter: Option<PlaneSplitter>,
199}
200
201impl FrameBuilder {
202 pub fn new() -> Self {
203 FrameBuilder {
204 pending_retained_tiles: RetainedTiles::new(),
205 globals: FrameGlobalResources::empty(),
206 }
207 }
208
209 pub fn set_retained_resources(&mut self, retained_tiles: RetainedTiles) {
213 self.pending_retained_tiles.merge(retained_tiles);
222 }
223
224 fn build_layer_screen_rects_and_cull_layers(
227 &mut self,
228 scene: &mut BuiltScene,
229 global_screen_world_rect: WorldRect,
230 resource_cache: &mut ResourceCache,
231 gpu_cache: &mut GpuCache,
232 render_tasks: &mut RenderTaskGraph,
233 profile_counters: &mut FrameProfileCounters,
234 global_device_pixel_scale: DevicePixelScale,
235 scene_properties: &SceneProperties,
236 transform_palette: &mut TransformPalette,
237 data_stores: &mut DataStores,
238 surfaces: &mut Vec<SurfaceInfo>,
239 scratch: &mut PrimitiveScratchBuffer,
240 debug_flags: DebugFlags,
241 texture_cache_profile: &mut TextureCacheProfileCounters,
242 composite_state: &mut CompositeState,
243 ) -> Option<RenderTaskId> {
244 profile_scope!("cull");
245
246 if scene.prim_store.pictures.is_empty() {
247 return None
248 }
249
250 scratch.begin_frame();
251
252 let root_spatial_node_index = scene.clip_scroll_tree.root_reference_frame_index();
253
254 const MAX_CLIP_COORD: f32 = 1.0e9;
255
256 let frame_context = FrameBuildingContext {
257 global_device_pixel_scale,
258 scene_properties,
259 global_screen_world_rect,
260 clip_scroll_tree: &scene.clip_scroll_tree,
261 max_local_clip: LayoutRect::new(
262 LayoutPoint::new(-MAX_CLIP_COORD, -MAX_CLIP_COORD),
263 LayoutSize::new(2.0 * MAX_CLIP_COORD, 2.0 * MAX_CLIP_COORD),
264 ),
265 debug_flags,
266 fb_config: &scene.config,
267 };
268
269 let root_render_task = RenderTask::new_picture(
270 RenderTaskLocation::Fixed(scene.output_rect),
271 scene.output_rect.size.to_f32(),
272 scene.root_pic_index,
273 DeviceIntPoint::zero(),
274 UvRectKind::Rect,
275 ROOT_SPATIAL_NODE_INDEX,
276 global_device_pixel_scale,
277 PrimitiveVisibilityMask::all(),
278 None,
279 );
280
281 let root_render_task_id = render_tasks.add(root_render_task);
282
283 let root_surface = SurfaceInfo::new(
286 ROOT_SPATIAL_NODE_INDEX,
287 ROOT_SPATIAL_NODE_INDEX,
288 0.0,
289 global_screen_world_rect,
290 &scene.clip_scroll_tree,
291 global_device_pixel_scale,
292 );
293 surfaces.push(root_surface);
294
295 let mut retained_tiles = mem::replace(
296 &mut self.pending_retained_tiles,
297 RetainedTiles::new(),
298 );
299
300 PictureUpdateState::update_all(
308 surfaces,
309 scene.root_pic_index,
310 &mut scene.prim_store.pictures,
311 &frame_context,
312 gpu_cache,
313 &scene.clip_store,
314 data_stores,
315 composite_state,
316 );
317
318 {
319 profile_marker!("UpdateVisibility");
320
321 let visibility_context = FrameVisibilityContext {
322 global_device_pixel_scale,
323 clip_scroll_tree: &scene.clip_scroll_tree,
324 global_screen_world_rect,
325 surfaces,
326 debug_flags,
327 scene_properties,
328 config: &scene.config,
329 };
330
331 let mut visibility_state = FrameVisibilityState {
332 resource_cache,
333 gpu_cache,
334 clip_store: &mut scene.clip_store,
335 scratch,
336 tile_cache: None,
337 retained_tiles: &mut retained_tiles,
338 data_stores,
339 clip_chain_stack: ClipChainStack::new(),
340 render_tasks,
341 composite_state,
342 };
343
344 scene.prim_store.update_visibility(
345 scene.root_pic_index,
346 ROOT_SURFACE_INDEX,
347 &global_screen_world_rect,
348 &visibility_context,
349 &mut visibility_state,
350 );
351
352 for (_, mut cache_state) in visibility_state.retained_tiles.caches.drain() {
363 if let Some(native_surface_id) = cache_state.native_surface_id.take() {
364 visibility_state.resource_cache.destroy_compositor_surface(native_surface_id);
365 }
366 }
367 }
368
369 let mut frame_state = FrameBuildingState {
370 render_tasks,
371 profile_counters,
372 clip_store: &mut scene.clip_store,
373 resource_cache,
374 gpu_cache,
375 transforms: transform_palette,
376 segment_builder: SegmentBuilder::new(),
377 surfaces,
378 dirty_region_stack: Vec::new(),
379 composite_state,
380 };
381
382 frame_state
383 .surfaces
384 .first_mut()
385 .unwrap()
386 .render_tasks = Some(SurfaceRenderTasks {
387 root: root_render_task_id,
388 port: root_render_task_id,
389 });
390
391 let mut default_dirty_region = DirtyRegion::new();
395 default_dirty_region.push(
396 frame_context.global_screen_world_rect,
397 PrimitiveVisibilityMask::all(),
398 );
399 frame_state.push_dirty_region(default_dirty_region);
400
401 let (pic_context, mut pic_state, mut prim_list) = scene
402 .prim_store
403 .pictures[scene.root_pic_index.0]
404 .take_context(
405 scene.root_pic_index,
406 WorldRect::max_rect(),
407 root_spatial_node_index,
408 root_spatial_node_index,
409 ROOT_SURFACE_INDEX,
410 SubpixelMode::Allow,
411 &mut frame_state,
412 &frame_context,
413 scratch,
414 )
415 .unwrap();
416
417 {
418 profile_marker!("PreparePrims");
419
420 scene.prim_store.prepare_primitives(
421 &mut prim_list,
422 &pic_context,
423 &mut pic_state,
424 &frame_context,
425 &mut frame_state,
426 data_stores,
427 scratch,
428 );
429 }
430
431 let pic = &mut scene.prim_store.pictures[scene.root_pic_index.0];
432 pic.restore_context(
433 prim_list,
434 pic_context,
435 pic_state,
436 &mut frame_state,
437 );
438
439 frame_state.pop_dirty_region();
440
441 {
442 profile_marker!("BlockOnResources");
443
444 resource_cache.block_until_all_resources_added(gpu_cache,
445 render_tasks,
446 texture_cache_profile);
447 }
448
449 Some(root_render_task_id)
450 }
451
452 pub fn build(
453 &mut self,
454 scene: &mut BuiltScene,
455 resource_cache: &mut ResourceCache,
456 gpu_cache: &mut GpuCache,
457 stamp: FrameStamp,
458 global_device_pixel_scale: DevicePixelScale,
459 layer: DocumentLayer,
460 device_origin: DeviceIntPoint,
461 pan: WorldPoint,
462 resource_profile: &mut ResourceProfileCounters,
463 scene_properties: &SceneProperties,
464 data_stores: &mut DataStores,
465 scratch: &mut PrimitiveScratchBuffer,
466 render_task_counters: &mut RenderTaskGraphCounters,
467 debug_flags: DebugFlags,
468 ) -> Frame {
469 profile_scope!("build");
470 profile_marker!("BuildFrame");
471
472 let mut profile_counters = FrameProfileCounters::new();
473 profile_counters
474 .total_primitives
475 .set(scene.prim_store.prim_count());
476 resource_profile.content_slices.set(scene.content_slice_count);
477 resource_cache.begin_frame(stamp);
478 gpu_cache.begin_frame(stamp);
479
480 self.globals.update(gpu_cache);
481
482 scene.clip_scroll_tree.update_tree(
483 pan,
484 global_device_pixel_scale,
485 scene_properties,
486 );
487 let mut transform_palette = scene.clip_scroll_tree.build_transform_palette();
488 scene.clip_store.clear_old_instances();
489
490 let mut render_tasks = RenderTaskGraph::new(
491 stamp.frame_id(),
492 render_task_counters,
493 );
494 let mut surfaces = Vec::new();
495
496 let output_size = scene.output_rect.size.to_i32();
497 let screen_world_rect = (scene.output_rect.to_f32() / global_device_pixel_scale).round_out();
498
499 let picture_caching_is_enabled =
505 scene.config.global_enable_picture_caching &&
506 !debug_flags.contains(DebugFlags::DISABLE_PICTURE_CACHING) &&
507 !scene.picture_cache_spatial_nodes.iter().any(|spatial_node_index| {
508 let spatial_node = &scene
509 .clip_scroll_tree
510 .spatial_nodes[spatial_node_index.0 as usize];
511 spatial_node.coordinate_system_id != CoordinateSystemId::root() ||
512 spatial_node.is_ancestor_or_self_zooming
513 });
514
515 let mut composite_state = CompositeState::new(
516 scene.config.compositor_kind,
517 picture_caching_is_enabled,
518 global_device_pixel_scale,
519 );
520
521 let main_render_task_id = self.build_layer_screen_rects_and_cull_layers(
522 scene,
523 screen_world_rect,
524 resource_cache,
525 gpu_cache,
526 &mut render_tasks,
527 &mut profile_counters,
528 global_device_pixel_scale,
529 scene_properties,
530 &mut transform_palette,
531 data_stores,
532 &mut surfaces,
533 scratch,
534 debug_flags,
535 &mut resource_profile.texture_cache,
536 &mut composite_state,
537 );
538
539 let mut passes;
540 let mut deferred_resolves = vec![];
541 let mut has_texture_cache_tasks = false;
542 let mut prim_headers = PrimitiveHeaders::new();
543
544 {
545 profile_marker!("Batching");
546
547 passes = render_tasks.generate_passes(
548 main_render_task_id,
549 output_size,
550 scene.config.gpu_supports_fast_clears,
551 );
552
553 let mut z_generator = ZBufferIdGenerator::new(layer);
555 let use_dual_source_blending = scene.config.dual_source_blending_is_enabled &&
556 scene.config.dual_source_blending_is_supported;
557
558 for pass in &mut passes {
559 let mut ctx = RenderTargetContext {
560 global_device_pixel_scale,
561 prim_store: &scene.prim_store,
562 resource_cache,
563 use_dual_source_blending,
564 use_advanced_blending: scene.config.gpu_supports_advanced_blend,
565 break_advanced_blend_batches: !scene.config.advanced_blend_is_coherent,
566 batch_lookback_count: scene.config.batch_lookback_count,
567 clip_scroll_tree: &scene.clip_scroll_tree,
568 data_stores,
569 surfaces: &surfaces,
570 scratch,
571 screen_world_rect,
572 globals: &self.globals,
573 };
574
575 build_render_pass(
576 pass,
577 &mut ctx,
578 gpu_cache,
579 &mut render_tasks,
580 &mut deferred_resolves,
581 &scene.clip_store,
582 &mut transform_palette,
583 &mut prim_headers,
584 &mut z_generator,
585 &mut composite_state,
586 );
587
588 match pass.kind {
589 RenderPassKind::MainFramebuffer { .. } => {}
590 RenderPassKind::OffScreen {
591 ref texture_cache,
592 ref picture_cache,
593 ..
594 } => {
595 has_texture_cache_tasks |= !texture_cache.is_empty();
596 has_texture_cache_tasks |= !picture_cache.is_empty();
597 }
598 }
599 }
600 }
601
602 let gpu_cache_frame_id = gpu_cache.end_frame(&mut resource_profile.gpu_cache).frame_id();
603
604 render_tasks.write_task_data();
605 *render_task_counters = render_tasks.counters();
606 resource_cache.end_frame(&mut resource_profile.texture_cache);
607
608 Frame {
609 content_origin: scene.output_rect.origin,
610 device_rect: DeviceIntRect::new(
611 device_origin,
612 scene.output_rect.size,
613 ),
614 layer,
615 profile_counters,
616 passes,
617 transform_palette: transform_palette.finish(),
618 render_tasks,
619 deferred_resolves,
620 gpu_cache_frame_id,
621 has_been_rendered: false,
622 has_texture_cache_tasks,
623 prim_headers,
624 recorded_dirty_regions: mem::replace(&mut scratch.recorded_dirty_regions, Vec::new()),
625 debug_items: mem::replace(&mut scratch.debug_items, Vec::new()),
626 composite_state,
627 }
628 }
629}
630
631pub fn build_render_pass(
637 pass: &mut RenderPass,
638 ctx: &mut RenderTargetContext,
639 gpu_cache: &mut GpuCache,
640 render_tasks: &mut RenderTaskGraph,
641 deferred_resolves: &mut Vec<DeferredResolve>,
642 clip_store: &ClipStore,
643 transforms: &mut TransformPalette,
644 prim_headers: &mut PrimitiveHeaders,
645 z_generator: &mut ZBufferIdGenerator,
646 composite_state: &mut CompositeState,
647) {
648 profile_scope!("RenderPass::build");
649
650 match pass.kind {
651 RenderPassKind::MainFramebuffer { ref mut main_target, .. } => {
652 for &task_id in &pass.tasks {
653 assert_eq!(render_tasks[task_id].target_kind(), RenderTargetKind::Color);
654 main_target.add_task(
655 task_id,
656 ctx,
657 gpu_cache,
658 render_tasks,
659 clip_store,
660 transforms,
661 deferred_resolves,
662 );
663 }
664 main_target.build(
665 ctx,
666 gpu_cache,
667 render_tasks,
668 deferred_resolves,
669 prim_headers,
670 transforms,
671 z_generator,
672 composite_state,
673 );
674 }
675 RenderPassKind::OffScreen {
676 ref mut color,
677 ref mut alpha,
678 ref mut texture_cache,
679 ref mut picture_cache,
680 } => {
681 let saved_color = if pass.tasks.iter().any(|&task_id| {
682 let t = &render_tasks[task_id];
683 t.target_kind() == RenderTargetKind::Color && t.saved_index.is_some()
684 }) {
685 Some(render_tasks.save_target())
686 } else {
687 None
688 };
689 let saved_alpha = if pass.tasks.iter().any(|&task_id| {
690 let t = &render_tasks[task_id];
691 t.target_kind() == RenderTargetKind::Alpha && t.saved_index.is_some()
692 }) {
693 Some(render_tasks.save_target())
694 } else {
695 None
696 };
697
698 let mut picture_cache_tasks = FastHashMap::default();
702
703 for &task_id in &pass.tasks {
705 let (target_kind, texture_target, layer) = {
706 let task = &mut render_tasks[task_id];
707 let target_kind = task.target_kind();
708
709 let (texture_target, layer) = match task.location {
712 RenderTaskLocation::TextureCache { texture, layer, .. } => {
713 (Some(texture), layer)
714 }
715 RenderTaskLocation::Fixed(..) => {
716 (None, 0)
717 }
718 RenderTaskLocation::Dynamic(ref mut origin, size) => {
719 let (target_index, alloc_origin) = match target_kind {
720 RenderTargetKind::Color => color.allocate(size),
721 RenderTargetKind::Alpha => alpha.allocate(size),
722 };
723 *origin = Some((alloc_origin, target_index));
724 (None, target_index.0)
725 }
726 RenderTaskLocation::PictureCache { .. } => {
727 let pic_index = match task.kind {
730 RenderTaskKind::Picture(ref info) => {
731 info.pic_index
732 }
733 _ => {
734 unreachable!();
735 }
736 };
737
738 picture_cache_tasks
739 .entry(pic_index)
740 .or_insert_with(Vec::new)
741 .push(task_id);
742
743 continue;
744 }
745 };
746
747 if let Some(index) = task.saved_index {
749 assert_eq!(index, SavedTargetIndex::PENDING);
750 task.saved_index = match target_kind {
751 RenderTargetKind::Color => saved_color,
752 RenderTargetKind::Alpha => saved_alpha,
753 };
754 }
755
756 task.write_gpu_blocks(gpu_cache);
759
760 (target_kind, texture_target, layer)
761 };
762
763 match texture_target {
764 Some(texture_target) => {
765 let texture = texture_cache
766 .entry((texture_target, layer))
767 .or_insert_with(||
768 TextureCacheRenderTarget::new(target_kind)
769 );
770 texture.add_task(task_id, render_tasks);
771 }
772 None => {
773 match target_kind {
774 RenderTargetKind::Color => {
775 color.targets[layer].add_task(
776 task_id,
777 ctx,
778 gpu_cache,
779 render_tasks,
780 clip_store,
781 transforms,
782 deferred_resolves,
783 )
784 }
785 RenderTargetKind::Alpha => {
786 alpha.targets[layer].add_task(
787 task_id,
788 ctx,
789 gpu_cache,
790 render_tasks,
791 clip_store,
792 transforms,
793 deferred_resolves,
794 )
795 }
796 }
797 }
798 }
799 }
800
801 for (pic_index, task_ids) in picture_cache_tasks {
805 let pic = &ctx.prim_store.pictures[pic_index.0];
806 let tile_cache = pic.tile_cache.as_ref().expect("bug");
807
808 let (root_spatial_node_index, surface_spatial_node_index) = match pic.raster_config {
810 Some(ref rc) => {
811 let surface = &ctx.surfaces[rc.surface_index.0];
812 (surface.raster_spatial_node_index, surface.surface_spatial_node_index)
813 }
814 None => {
815 unreachable!();
816 }
817 };
818
819 let forced_opaque = match tile_cache.background_color {
827 Some(color) => color.a >= 1.0,
828 None => false,
829 };
830 let clear_color = if forced_opaque {
833 Some(ColorF::WHITE)
834 } else {
835 Some(ColorF::TRANSPARENT)
836 };
837
838 let mut batchers = Vec::new();
840 for task_id in &task_ids {
841 let task_id = *task_id;
842 let vis_mask = match render_tasks[task_id].kind {
843 RenderTaskKind::Picture(ref info) => info.vis_mask,
844 _ => unreachable!(),
845 };
846 batchers.push(AlphaBatchBuilder::new(
847 pass.screen_size,
848 ctx.break_advanced_blend_batches,
849 ctx.batch_lookback_count,
850 task_id,
851 render_tasks.get_task_address(task_id),
852 vis_mask,
853 ));
854 }
855
856 let mut batch_builder = BatchBuilder::new(batchers);
859 batch_builder.add_pic_to_batch(
860 pic,
861 ctx,
862 gpu_cache,
863 render_tasks,
864 deferred_resolves,
865 prim_headers,
866 transforms,
867 root_spatial_node_index,
868 surface_spatial_node_index,
869 z_generator,
870 composite_state,
871 );
872
873 let batchers = batch_builder.finalize();
876 for (task_id, batcher) in task_ids.into_iter().zip(batchers.into_iter()) {
877 let task = &render_tasks[task_id];
878 let (target_rect, _) = task.get_target_rect();
879
880 match task.location {
881 RenderTaskLocation::PictureCache { ref surface, .. } => {
882 let scissor_rect = match render_tasks[task_id].kind {
887 RenderTaskKind::Picture(ref info) => info.scissor_rect,
888 _ => unreachable!(),
889 }.expect("bug: dirty rect must be set for picture cache tasks");
890 let mut batch_containers = Vec::new();
891 let mut alpha_batch_container = AlphaBatchContainer::new(Some(scissor_rect));
892 batcher.build(
893 &mut batch_containers,
894 &mut alpha_batch_container,
895 target_rect,
896 None,
897 );
898 debug_assert!(batch_containers.is_empty());
899
900 let target = PictureCacheTarget {
901 surface: surface.clone(),
902 clear_color,
903 alpha_batch_container,
904 dirty_rect: scissor_rect,
905 };
906
907 picture_cache.push(target);
908 }
909 _ => {
910 unreachable!()
911 }
912 }
913 }
914 }
915
916 color.build(
917 ctx,
918 gpu_cache,
919 render_tasks,
920 deferred_resolves,
921 saved_color,
922 prim_headers,
923 transforms,
924 z_generator,
925 composite_state,
926 );
927 alpha.build(
928 ctx,
929 gpu_cache,
930 render_tasks,
931 deferred_resolves,
932 saved_alpha,
933 prim_headers,
934 transforms,
935 z_generator,
936 composite_state,
937 );
938 }
939 }
940}
941
942#[cfg_attr(feature = "capture", derive(Serialize))]
945#[cfg_attr(feature = "replay", derive(Deserialize))]
946pub struct Frame {
947 pub content_origin: DeviceIntPoint,
949 pub device_rect: DeviceIntRect,
951 pub layer: DocumentLayer,
952 pub passes: Vec<RenderPass>,
953 #[cfg_attr(any(feature = "capture", feature = "replay"), serde(default = "FrameProfileCounters::new", skip))]
954 pub profile_counters: FrameProfileCounters,
955
956 pub transform_palette: Vec<TransformData>,
957 pub render_tasks: RenderTaskGraph,
958 pub prim_headers: PrimitiveHeaders,
959
960 pub gpu_cache_frame_id: FrameId,
962
963 pub deferred_resolves: Vec<DeferredResolve>,
968
969 pub has_texture_cache_tasks: bool,
972
973 pub has_been_rendered: bool,
976
977 #[cfg_attr(feature = "serde", serde(skip))]
980 pub recorded_dirty_regions: Vec<RecordedDirtyRegion>,
981
982 pub debug_items: Vec<DebugItem>,
984
985 pub composite_state: CompositeState,
989}
990
991impl Frame {
992 pub fn must_be_drawn(&self) -> bool {
995 self.has_texture_cache_tasks && !self.has_been_rendered
996 }
997
998 pub fn is_nop(&self) -> bool {
1000 if !self.composite_state.picture_caching_is_enabled {
1003 return false;
1004 }
1005
1006 if self.passes.len() > 1 {
1014 return false;
1015 }
1016
1017 true
1018 }
1019}