1use api::DebugFlags;
11use api::units::*;
12use std::usize;
13use crate::clip::ClipStore;
14use crate::composite::CompositeState;
15use crate::profiler::TransactionProfile;
16use crate::spatial_tree::{SpatialTree, SpatialNodeIndex};
17use crate::clip::{ClipChainInstance, ClipTree};
18use crate::frame_builder::FrameBuilderConfig;
19use crate::gpu_cache::GpuCache;
20use crate::picture::{PictureCompositeMode, ClusterFlags, SurfaceInfo, TileCacheInstance};
21use crate::picture::{SurfaceIndex, RasterConfig, SubSliceIndex};
22use crate::prim_store::{ClipTaskIndex, PictureIndex, PrimitiveInstanceKind};
23use crate::prim_store::{PrimitiveStore, PrimitiveInstance};
24use crate::render_backend::{DataStores, ScratchBuffer};
25use crate::render_task_graph::RenderTaskGraphBuilder;
26use crate::resource_cache::ResourceCache;
27use crate::scene::SceneProperties;
28use crate::space::SpaceMapper;
29use crate::util::MaxRect;
30
31pub struct FrameVisibilityContext<'a> {
32 pub spatial_tree: &'a SpatialTree,
33 pub global_screen_world_rect: WorldRect,
34 pub global_device_pixel_scale: DevicePixelScale,
35 pub debug_flags: DebugFlags,
36 pub scene_properties: &'a SceneProperties,
37 pub config: FrameBuilderConfig,
38 pub root_spatial_node_index: SpatialNodeIndex,
39}
40
41pub struct FrameVisibilityState<'a> {
42 pub clip_store: &'a mut ClipStore,
43 pub resource_cache: &'a mut ResourceCache,
44 pub gpu_cache: &'a mut GpuCache,
45 pub data_stores: &'a mut DataStores,
46 pub clip_tree: &'a mut ClipTree,
47 pub composite_state: &'a mut CompositeState,
48 pub rg_builder: &'a mut RenderTaskGraphBuilder,
49 pub prim_instances: &'a mut [PrimitiveInstance],
50 pub surfaces: &'a mut [SurfaceInfo],
51 pub surface_stack: Vec<(PictureIndex, SurfaceIndex)>,
54 pub profile: &'a mut TransactionProfile,
55 pub scratch: &'a mut ScratchBuffer,
56 pub visited_pictures: &'a mut[bool],
57}
58
59impl<'a> FrameVisibilityState<'a> {
60 pub fn push_surface(
61 &mut self,
62 pic_index: PictureIndex,
63 surface_index: SurfaceIndex,
64 ) {
65 self.surface_stack.push((pic_index, surface_index));
66 }
67
68 pub fn pop_surface(&mut self) {
69 self.surface_stack.pop().unwrap();
70 }
71}
72
73bitflags! {
74 #[cfg_attr(feature = "capture", derive(Serialize))]
80 #[derive(Debug, Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
81 pub struct PrimitiveVisibilityFlags: u8 {
82 const IS_BACKDROP = 1;
85 }
86}
87
88#[derive(Debug)]
90#[cfg_attr(feature = "capture", derive(Serialize))]
91pub enum VisibilityState {
92 Unset,
94 Culled,
96 PassThrough,
99 Visible {
101 vis_flags: PrimitiveVisibilityFlags,
104
105 sub_slice_index: SubSliceIndex,
107 },
108}
109
110#[derive(Debug)]
113#[cfg_attr(feature = "capture", derive(Serialize))]
114pub struct PrimitiveVisibility {
115 pub clip_chain: ClipChainInstance,
117
118 pub state: VisibilityState,
122
123 pub clip_task_index: ClipTaskIndex,
129}
130
131impl PrimitiveVisibility {
132 pub fn new() -> Self {
133 PrimitiveVisibility {
134 state: VisibilityState::Unset,
135 clip_chain: ClipChainInstance::empty(),
136 clip_task_index: ClipTaskIndex::INVALID,
137 }
138 }
139
140 pub fn reset(&mut self) {
141 self.state = VisibilityState::Culled;
142 self.clip_task_index = ClipTaskIndex::INVALID;
143 }
144}
145
146pub fn update_prim_visibility(
147 pic_index: PictureIndex,
148 parent_surface_index: Option<SurfaceIndex>,
149 world_culling_rect: &WorldRect,
150 store: &PrimitiveStore,
151 is_root_tile_cache: bool,
152 frame_context: &FrameVisibilityContext,
153 frame_state: &mut FrameVisibilityState,
154 tile_cache: &mut Option<&mut TileCacheInstance>,
155 ) {
156 if frame_state.visited_pictures[pic_index.0] {
157 return;
158 }
159 frame_state.visited_pictures[pic_index.0] = true;
160 let pic = &store.pictures[pic_index.0];
161
162 let (surface_index, pop_surface) = match pic.raster_config {
163 Some(RasterConfig { surface_index, composite_mode: PictureCompositeMode::TileCache { .. }, .. }) => {
164 (surface_index, false)
165 }
166 Some(ref raster_config) => {
167 frame_state.push_surface(
168 pic_index,
169 raster_config.surface_index,
170 );
171
172 if let Some(parent_surface_index) = parent_surface_index {
173 let parent_culling_rect = frame_state
174 .surfaces[parent_surface_index.0]
175 .culling_rect;
176
177 let surface = &mut frame_state
178 .surfaces[raster_config.surface_index.0 as usize];
179
180 surface.update_culling_rect(
181 parent_culling_rect,
182 &raster_config.composite_mode,
183 frame_context,
184 );
185 }
186
187 let surface_local_rect = frame_state.surfaces[raster_config.surface_index.0]
188 .unclipped_local_rect
189 .cast_unit();
190
191 if let Some(tile_cache) = tile_cache {
194 tile_cache.push_surface(
195 surface_local_rect,
196 pic.spatial_node_index,
197 frame_context.spatial_tree,
198 );
199 }
200
201 (raster_config.surface_index, true)
202 }
203 None => {
204 (parent_surface_index.expect("bug: pass-through with no parent"), false)
205 }
206 };
207
208 let surface = &frame_state.surfaces[surface_index.0 as usize];
209 let surface_culling_rect = surface.culling_rect;
210
211 let device_pixel_scale = surface.device_pixel_scale;
212 let mut map_local_to_picture = surface.map_local_to_picture.clone();
213
214 let map_surface_to_vis = SpaceMapper::new_with_target(
215 frame_context.root_spatial_node_index,
217 surface.surface_spatial_node_index,
218 surface.culling_rect,
219 frame_context.spatial_tree,
220 );
221 let visibility_spatial_node_index = surface.visibility_spatial_node_index;
222
223 for cluster in &pic.prim_list.clusters {
224 profile_scope!("cluster");
225
226 for prim_instance in &mut frame_state.prim_instances[cluster.prim_range()] {
239 prim_instance.reset();
240 }
241
242 if !cluster.flags.contains(ClusterFlags::IS_VISIBLE) {
244 continue;
245 }
246
247 map_local_to_picture.set_target_spatial_node(
248 cluster.spatial_node_index,
249 frame_context.spatial_tree,
250 );
251
252 for prim_instance_index in cluster.prim_range() {
253 if let PrimitiveInstanceKind::Picture { pic_index, .. } = frame_state.prim_instances[prim_instance_index].kind {
254 if !store.pictures[pic_index.0].is_visible(frame_context.spatial_tree) {
255 continue;
256 }
257
258 let is_passthrough = match store.pictures[pic_index.0].raster_config {
259 Some(..) => false,
260 None => true,
261 };
262
263 if !is_passthrough {
264 let clip_root = store
265 .pictures[pic_index.0]
266 .clip_root
267 .unwrap_or_else(|| {
268 let leaf_id = frame_state.prim_instances[prim_instance_index].clip_leaf_id;
271 frame_state.clip_tree.get_leaf(leaf_id).node_id
272 }
273 );
274
275 frame_state.clip_tree.push_clip_root_node(clip_root);
276 }
277
278 update_prim_visibility(
279 pic_index,
280 Some(surface_index),
281 world_culling_rect,
282 store,
283 false,
284 frame_context,
285 frame_state,
286 tile_cache,
287 );
288
289 if is_passthrough {
290 frame_state.prim_instances[prim_instance_index].vis.state = VisibilityState::PassThrough;
292
293 continue;
294 } else {
295 frame_state.clip_tree.pop_clip_root();
296 }
297 }
298
299 let prim_instance = &mut frame_state.prim_instances[prim_instance_index];
300
301 let local_coverage_rect = frame_state.data_stores.get_local_prim_coverage_rect(
302 prim_instance,
303 &store.pictures,
304 frame_state.surfaces,
305 );
306
307 frame_state.clip_store.set_active_clips(
308 cluster.spatial_node_index,
309 map_local_to_picture.ref_spatial_node_index,
310 visibility_spatial_node_index,
311 prim_instance.clip_leaf_id,
312 &frame_context.spatial_tree,
313 &frame_state.data_stores.clip,
314 frame_state.clip_tree,
315 );
316
317 let clip_chain = frame_state
318 .clip_store
319 .build_clip_chain_instance(
320 local_coverage_rect,
321 &map_local_to_picture,
322 &map_surface_to_vis,
323 &frame_context.spatial_tree,
324 frame_state.gpu_cache,
325 frame_state.resource_cache,
326 device_pixel_scale,
327 &surface_culling_rect,
328 &mut frame_state.data_stores.clip,
329 frame_state.rg_builder,
330 true,
331 );
332
333 prim_instance.vis.clip_chain = match clip_chain {
334 Some(clip_chain) => clip_chain,
335 None => {
336 continue;
337 }
338 };
339
340 {
341 let prim_surface_index = frame_state.surface_stack.last().unwrap().1;
342 let prim_clip_chain = &prim_instance.vis.clip_chain;
343
344 let surface = &mut frame_state.surfaces[prim_surface_index.0];
346 surface.clipped_local_rect = surface.clipped_local_rect.union(&prim_clip_chain.pic_coverage_rect);
347 }
348
349 prim_instance.vis.state = match tile_cache {
350 Some(tile_cache) => {
351 tile_cache.update_prim_dependencies(
352 prim_instance,
353 cluster.spatial_node_index,
354 local_coverage_rect,
358 frame_context,
359 frame_state.data_stores,
360 frame_state.clip_store,
361 &store.pictures,
362 frame_state.resource_cache,
363 &store.color_bindings,
364 &frame_state.surface_stack,
365 &mut frame_state.composite_state,
366 &mut frame_state.gpu_cache,
367 &mut frame_state.scratch.primitive,
368 is_root_tile_cache,
369 frame_state.surfaces,
370 frame_state.profile,
371 )
372 }
373 None => {
374 VisibilityState::Visible {
375 vis_flags: PrimitiveVisibilityFlags::empty(),
376 sub_slice_index: SubSliceIndex::DEFAULT,
377 }
378 }
379 };
380 }
381 }
382
383 if let Some(snapshot) = &pic.snapshot {
384 if snapshot.detached {
385 let prim_surface_index = frame_state.surface_stack.last().unwrap().1;
389 let surface = &mut frame_state.surfaces[prim_surface_index.0];
390 let clip = snapshot.area.round_out().cast_unit();
391 surface.clipped_local_rect = surface.clipped_local_rect.intersection_unchecked(&clip);
392 }
393 }
394
395 if pop_surface {
396 frame_state.pop_surface();
397 }
398
399 if let Some(ref rc) = pic.raster_config {
400 if let Some(tile_cache) = tile_cache {
401 match rc.composite_mode {
402 PictureCompositeMode::TileCache { .. } => {}
403 _ => {
404 tile_cache.pop_surface();
406 }
407 }
408 }
409 }
410}
411
412pub fn compute_conservative_visible_rect(
413 clip_chain: &ClipChainInstance,
414 culling_rect: VisRect,
415 visibility_node_index: SpatialNodeIndex,
416 prim_spatial_node_index: SpatialNodeIndex,
417 spatial_tree: &SpatialTree,
418) -> LayoutRect {
419 let map_pic_to_vis: SpaceMapper<PicturePixel, VisPixel> = SpaceMapper::new_with_target(
421 visibility_node_index,
422 clip_chain.pic_spatial_node_index,
423 culling_rect,
424 spatial_tree,
425 );
426
427 let map_local_to_pic: SpaceMapper<LayoutPixel, PicturePixel> = SpaceMapper::new_with_target(
429 clip_chain.pic_spatial_node_index,
430 prim_spatial_node_index,
431 PictureRect::max_rect(),
432 spatial_tree,
433 );
434
435 let pic_culling_rect = match map_pic_to_vis.unmap(&culling_rect) {
438 Some(rect) => rect,
439 None => return clip_chain.local_clip_rect,
440 };
441
442 let pic_culling_rect = match pic_culling_rect.intersection(&clip_chain.pic_coverage_rect) {
447 Some(rect) => rect,
448 None => return LayoutRect::zero(),
449 };
450
451 match map_local_to_pic.unmap(&pic_culling_rect) {
454 Some(rect) => rect,
455 None => clip_chain.local_clip_rect,
456 }
457}