1use api::DebugFlags;
11use api::units::*;
12use std::usize;
13use crate::clip::ClipStore;
14use crate::composite::CompositeState;
15use crate::profiler::TransactionProfile;
16use crate::renderer::GpuBufferBuilder;
17use crate::spatial_tree::{SpatialTree, SpatialNodeIndex};
18use crate::clip::{ClipChainInstance, ClipTree};
19use crate::composite::CompositorSurfaceKind;
20use crate::frame_builder::FrameBuilderConfig;
21use crate::picture::{PictureCompositeMode, ClusterFlags, SurfaceInfo};
22use crate::tile_cache::TileCacheInstance;
23use crate::picture::{PictureScratch, SurfaceIndex, RasterConfig};
24use crate::tile_cache::SubSliceIndex;
25use crate::prim_store::{ClipTaskIndex, PictureIndex, PrimitiveKind, SegmentInstanceIndex};
26use crate::prim_store::{PrimitiveStore, PrimitiveInstance, PrimitiveInstanceIndex};
27use crate::prim_store::backdrop::BackdropRenderScratch;
28use crate::prim_store::borders::{ImageBorderScratch, NormalBorderScratch};
29use crate::prim_store::image::ImageScratch;
30use crate::prim_store::line_dec::LineDecorationScratch;
31use crate::prim_store::storage;
32use crate::prim_store::text_run::TextRunScratch;
33use crate::render_backend::{DataStores, ScratchBuffer};
34use crate::render_task_graph::RenderTaskGraphBuilder;
35use crate::resource_cache::ResourceCache;
36use crate::scene::SceneProperties;
37use crate::space::SpaceMapper;
38use crate::util::MaxRect;
39
40pub struct FrameVisibilityContext<'a> {
41 pub spatial_tree: &'a SpatialTree,
42 pub global_screen_world_rect: WorldRect,
43 pub global_device_pixel_scale: DevicePixelScale,
44 pub debug_flags: DebugFlags,
45 pub scene_properties: &'a SceneProperties,
46 pub config: FrameBuilderConfig,
47 pub root_spatial_node_index: SpatialNodeIndex,
48}
49
50pub struct FrameVisibilityState<'a> {
51 pub clip_store: &'a mut ClipStore,
52 pub resource_cache: &'a mut ResourceCache,
53 pub frame_gpu_data: &'a mut GpuBufferBuilder,
54 pub data_stores: &'a mut DataStores,
55 pub clip_tree: &'a mut ClipTree,
56 pub composite_state: &'a mut CompositeState,
57 pub rg_builder: &'a mut RenderTaskGraphBuilder,
58 pub prim_instances: &'a mut [PrimitiveInstance],
59 pub surfaces: &'a mut [SurfaceInfo],
60 pub surface_stack: Vec<(PictureIndex, SurfaceIndex)>,
63 pub profile: &'a mut TransactionProfile,
64 pub scratch: &'a mut ScratchBuffer,
65 pub visited_pictures: &'a mut[bool],
66}
67
68impl<'a> FrameVisibilityState<'a> {
69 pub fn push_surface(
70 &mut self,
71 pic_index: PictureIndex,
72 surface_index: SurfaceIndex,
73 ) {
74 self.surface_stack.push((pic_index, surface_index));
75 }
76
77 pub fn pop_surface(&mut self) {
78 self.surface_stack.pop().unwrap();
79 }
80}
81
82bitflags! {
83 #[cfg_attr(feature = "capture", derive(Serialize))]
89 #[derive(Debug, Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
90 pub struct PrimitiveVisibilityFlags: u8 {
91 const IS_BACKDROP = 1;
94 }
95}
96
97#[derive(Debug, Copy, Clone)]
99#[cfg_attr(feature = "capture", derive(Serialize))]
100pub enum DrawState {
101 Unset,
103 Culled,
105 PassThrough,
108 Visible {
110 vis_flags: PrimitiveVisibilityFlags,
113
114 sub_slice_index: SubSliceIndex,
116 },
117}
118
119#[derive(Debug, Copy, Clone)]
124#[cfg_attr(feature = "capture", derive(Serialize))]
125pub enum KindScratchHandle {
126 None,
127 LineDecoration(storage::Index<LineDecorationScratch>),
128 NormalBorder(storage::Index<NormalBorderScratch>),
129 ImageBorder(storage::Index<ImageBorderScratch>),
130 Image(storage::Index<ImageScratch>),
131 TextRun(storage::Index<TextRunScratch>),
132 Picture(storage::Index<PictureScratch>),
133 BackdropRender(storage::Index<BackdropRenderScratch>),
134}
135
136impl KindScratchHandle {
137 pub fn unwrap_line_decoration(&self) -> storage::Index<LineDecorationScratch> {
141 match *self {
142 KindScratchHandle::LineDecoration(h) => h,
143 _ => panic!("kind_scratch mismatch: expected LineDecoration, got {:?}", self),
144 }
145 }
146 pub fn unwrap_normal_border(&self) -> storage::Index<NormalBorderScratch> {
147 match *self {
148 KindScratchHandle::NormalBorder(h) => h,
149 _ => panic!("kind_scratch mismatch: expected NormalBorder, got {:?}", self),
150 }
151 }
152 pub fn unwrap_image_border(&self) -> storage::Index<ImageBorderScratch> {
153 match *self {
154 KindScratchHandle::ImageBorder(h) => h,
155 _ => panic!("kind_scratch mismatch: expected ImageBorder, got {:?}", self),
156 }
157 }
158 pub fn unwrap_image(&self) -> storage::Index<ImageScratch> {
159 match *self {
160 KindScratchHandle::Image(h) => h,
161 _ => panic!("kind_scratch mismatch: expected Image, got {:?}", self),
162 }
163 }
164 pub fn unwrap_text_run(&self) -> storage::Index<TextRunScratch> {
165 match *self {
166 KindScratchHandle::TextRun(h) => h,
167 _ => panic!("kind_scratch mismatch: expected TextRun, got {:?}", self),
168 }
169 }
170 pub fn unwrap_picture(&self) -> storage::Index<PictureScratch> {
171 match *self {
172 KindScratchHandle::Picture(h) => h,
173 _ => panic!("kind_scratch mismatch: expected Picture, got {:?}", self),
174 }
175 }
176 pub fn unwrap_backdrop_render(&self) -> storage::Index<BackdropRenderScratch> {
177 match *self {
178 KindScratchHandle::BackdropRender(h) => h,
179 _ => panic!("kind_scratch mismatch: expected BackdropRender, got {:?}", self),
180 }
181 }
182}
183
184#[derive(Debug, Copy, Clone)]
187#[cfg_attr(feature = "capture", derive(Serialize))]
188pub struct PrimitiveDrawHeader {
189 pub prim_instance_index: PrimitiveInstanceIndex,
196
197 pub clip_chain: ClipChainInstance,
199
200 pub state: DrawState,
204
205 pub clip_task_index: ClipTaskIndex,
211
212 pub kind_scratch: KindScratchHandle,
217
218 pub segment_instance_index: SegmentInstanceIndex,
224
225 pub compositor_surface_kind: CompositorSurfaceKind,
230
231 pub snapped_local_rect: LayoutRect,
237}
238
239impl PrimitiveDrawHeader {
240 pub fn new() -> Self {
243 PrimitiveDrawHeader {
244 prim_instance_index: PrimitiveInstanceIndex::INVALID,
245 state: DrawState::Unset,
246 clip_chain: ClipChainInstance::empty(),
247 clip_task_index: ClipTaskIndex::INVALID,
248 kind_scratch: KindScratchHandle::None,
249 segment_instance_index: SegmentInstanceIndex::UNUSED,
250 compositor_surface_kind: CompositorSurfaceKind::Blit,
251 snapped_local_rect: LayoutRect::zero(),
252 }
253 }
254
255 pub fn reset(&mut self) {
256 self.state = DrawState::Culled;
257 self.clip_task_index = ClipTaskIndex::INVALID;
258 self.kind_scratch = KindScratchHandle::None;
259 self.segment_instance_index = SegmentInstanceIndex::UNUSED;
260 self.compositor_surface_kind = CompositorSurfaceKind::Blit;
261 }
262}
263
264pub fn update_prim_visibility(
265 pic_index: PictureIndex,
266 parent_surface_index: Option<SurfaceIndex>,
267 world_culling_rect: &WorldRect,
268 store: &PrimitiveStore,
269 is_root_tile_cache: bool,
270 frame_context: &FrameVisibilityContext,
271 frame_state: &mut FrameVisibilityState,
272 tile_cache: &mut Option<&mut TileCacheInstance>,
273 ) {
274 if frame_state.visited_pictures[pic_index.0] {
275 return;
276 }
277 frame_state.visited_pictures[pic_index.0] = true;
278 let pic = &store.pictures[pic_index.0];
279
280 let (surface_index, pop_surface) = match pic.raster_config {
281 Some(RasterConfig { surface_index, composite_mode: PictureCompositeMode::TileCache { .. }, .. }) => {
282 (surface_index, false)
283 }
284 Some(ref raster_config) => {
285 frame_state.push_surface(
286 pic_index,
287 raster_config.surface_index,
288 );
289
290 if let Some(parent_surface_index) = parent_surface_index {
291 let parent_culling_rect = frame_state
292 .surfaces[parent_surface_index.0]
293 .culling_rect;
294
295 let surface = &mut frame_state
296 .surfaces[raster_config.surface_index.0 as usize];
297
298 surface.update_culling_rect(
299 parent_culling_rect,
300 &raster_config.composite_mode,
301 frame_context,
302 );
303 }
304
305 let surface_local_rect = frame_state.surfaces[raster_config.surface_index.0]
306 .unclipped_local_rect
307 .cast_unit();
308
309 if let Some(tile_cache) = tile_cache {
312 tile_cache.push_surface(
313 surface_local_rect,
314 pic.spatial_node_index,
315 frame_context.spatial_tree,
316 );
317 }
318
319 (raster_config.surface_index, true)
320 }
321 None => {
322 (parent_surface_index.expect("bug: pass-through with no parent"), false)
323 }
324 };
325
326 let surface = &frame_state.surfaces[surface_index.0 as usize];
327 let surface_culling_rect = surface.culling_rect;
328
329 let mut map_local_to_picture = surface.map_local_to_picture.clone();
330
331 let map_surface_to_vis = SpaceMapper::new_with_target(
332 frame_context.root_spatial_node_index,
334 surface.surface_spatial_node_index,
335 surface.culling_rect,
336 frame_context.spatial_tree,
337 );
338 let visibility_spatial_node_index = surface.visibility_spatial_node_index;
339
340 for cluster in &pic.prim_list.clusters {
341 profile_scope!("cluster");
342
343 for idx in cluster.prim_range() {
356 frame_state.scratch.primitive.frame.draws[idx].reset();
357 frame_state.scratch.primitive.frame.draws[idx].prim_instance_index =
358 PrimitiveInstanceIndex(idx as u32);
359 }
360
361 if !cluster.flags.contains(ClusterFlags::IS_VISIBLE) {
363 continue;
364 }
365
366 map_local_to_picture.set_target_spatial_node(
367 cluster.spatial_node_index,
368 frame_context.spatial_tree,
369 );
370
371 for prim_instance_index in cluster.prim_range() {
372 if let PrimitiveKind::Picture { pic_index, .. } = frame_state.prim_instances[prim_instance_index].kind {
373 if !store.pictures[pic_index.0].is_visible(frame_context.spatial_tree) {
374 continue;
375 }
376
377 let is_passthrough = match store.pictures[pic_index.0].raster_config {
378 Some(..) => false,
379 None => true,
380 };
381
382 if !is_passthrough {
383 let clip_root = store
384 .pictures[pic_index.0]
385 .clip_root
386 .unwrap_or_else(|| {
387 let leaf_id = frame_state.prim_instances[prim_instance_index].clip_leaf_id;
390 frame_state.clip_tree.get_leaf(leaf_id).node_id
391 }
392 );
393
394 frame_state.clip_tree.push_clip_root_node(clip_root);
395 }
396
397 update_prim_visibility(
398 pic_index,
399 Some(surface_index),
400 world_culling_rect,
401 store,
402 false,
403 frame_context,
404 frame_state,
405 tile_cache,
406 );
407
408 if is_passthrough {
409 frame_state.scratch.primitive.frame.draws[prim_instance_index].state = DrawState::PassThrough;
411
412 continue;
413 } else {
414 frame_state.clip_tree.pop_clip_root();
415 }
416 }
417
418 let prim_instance = &mut frame_state.prim_instances[prim_instance_index];
419
420 let local_coverage_rect = frame_state.data_stores.get_local_prim_coverage_rect(
421 prim_instance,
422 frame_state.scratch.primitive.frame.draws[prim_instance_index].snapped_local_rect,
423 &store.pictures,
424 frame_state.surfaces,
425 );
426
427 frame_state.clip_store.set_active_clips(
428 cluster.spatial_node_index,
429 map_local_to_picture.ref_spatial_node_index,
430 visibility_spatial_node_index,
431 prim_instance.clip_leaf_id,
432 &frame_context.spatial_tree,
433 &frame_state.data_stores.clip,
434 frame_state.clip_tree,
435 );
436
437 let clip_chain = frame_state
438 .clip_store
439 .build_clip_chain_instance(
440 local_coverage_rect,
441 &map_local_to_picture,
442 &map_surface_to_vis,
443 &frame_context.spatial_tree,
444 &mut frame_state.frame_gpu_data.f32,
445 frame_state.resource_cache,
446 &surface_culling_rect,
447 &mut frame_state.data_stores.clip,
448 frame_state.rg_builder,
449 true,
450 );
451
452 frame_state.scratch.primitive.frame.draws[prim_instance_index].clip_chain = match clip_chain {
453 Some(clip_chain) => clip_chain,
454 None => {
455 continue;
456 }
457 };
458
459 {
460 let prim_surface_index = frame_state.surface_stack.last().unwrap().1;
461 let prim_clip_chain = &frame_state.scratch.primitive.frame.draws[prim_instance_index].clip_chain;
462
463 let surface = &mut frame_state.surfaces[prim_surface_index.0];
465 surface.clipped_local_rect = surface.clipped_local_rect.union(&prim_clip_chain.pic_coverage_rect);
466 }
467
468 let new_state = match tile_cache {
469 Some(tile_cache) => {
470 tile_cache.update_prim_dependencies(
471 PrimitiveInstanceIndex(prim_instance_index as u32),
472 prim_instance,
473 cluster.spatial_node_index,
474 local_coverage_rect,
478 frame_context,
479 frame_state.data_stores,
480 frame_state.clip_store,
481 &store.pictures,
482 frame_state.resource_cache,
483 &frame_state.surface_stack,
484 &mut frame_state.composite_state,
485 &mut frame_state.frame_gpu_data.f32,
486 &mut frame_state.scratch.primitive,
487 is_root_tile_cache,
488 frame_state.surfaces,
489 frame_state.profile,
490 )
491 }
492 None => {
493 DrawState::Visible {
494 vis_flags: PrimitiveVisibilityFlags::empty(),
495 sub_slice_index: SubSliceIndex::DEFAULT,
496 }
497 }
498 };
499 frame_state.scratch.primitive.frame.draws[prim_instance_index].state = new_state;
500 }
501 }
502
503 if let Some(snapshot) = &pic.snapshot {
504 if snapshot.detached {
505 let prim_surface_index = frame_state.surface_stack.last().unwrap().1;
509 let surface = &mut frame_state.surfaces[prim_surface_index.0];
510 let clip = snapshot.area.round_out().cast_unit();
511 surface.clipped_local_rect = surface.clipped_local_rect.intersection_unchecked(&clip);
512 }
513 }
514
515 if pop_surface {
516 frame_state.pop_surface();
517 }
518
519 if let Some(ref rc) = pic.raster_config {
520 if let Some(tile_cache) = tile_cache {
521 match rc.composite_mode {
522 PictureCompositeMode::TileCache { .. } => {}
523 _ => {
524 tile_cache.pop_surface();
526 }
527 }
528 }
529 }
530}
531
532pub fn compute_conservative_visible_rect(
533 clip_chain: &ClipChainInstance,
534 culling_rect: VisRect,
535 visibility_node_index: SpatialNodeIndex,
536 prim_spatial_node_index: SpatialNodeIndex,
537 spatial_tree: &SpatialTree,
538) -> LayoutRect {
539 let map_pic_to_vis: SpaceMapper<PicturePixel, VisPixel> = SpaceMapper::new_with_target(
541 visibility_node_index,
542 clip_chain.pic_spatial_node_index,
543 culling_rect,
544 spatial_tree,
545 );
546
547 let map_local_to_pic: SpaceMapper<LayoutPixel, PicturePixel> = SpaceMapper::new_with_target(
549 clip_chain.pic_spatial_node_index,
550 prim_spatial_node_index,
551 PictureRect::max_rect(),
552 spatial_tree,
553 );
554
555 let pic_culling_rect = match map_pic_to_vis.unmap(&culling_rect) {
558 Some(rect) => rect,
559 None => return clip_chain.local_clip_rect,
560 };
561
562 let pic_culling_rect = match pic_culling_rect.intersection(&clip_chain.pic_coverage_rect) {
567 Some(rect) => rect,
568 None => return LayoutRect::zero(),
569 };
570
571 match map_local_to_pic.unmap(&pic_culling_rect) {
574 Some(rect) => rect,
575 None => clip_chain.local_clip_rect,
576 }
577}