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 let surface_local_rect = frame_state.surfaces[raster_config.surface_index.0]
173 .unclipped_local_rect
174 .cast_unit();
175
176 if let Some(tile_cache) = tile_cache {
179 tile_cache.push_surface(
180 surface_local_rect,
181 pic.spatial_node_index,
182 frame_context.spatial_tree,
183 );
184 }
185
186 (raster_config.surface_index, true)
187 }
188 None => {
189 (parent_surface_index.expect("bug: pass-through with no parent"), false)
190 }
191 };
192
193 let surface = &frame_state.surfaces[surface_index.0 as usize];
194 let surface_culling_rect = surface.culling_rect;
195
196 let device_pixel_scale = surface.device_pixel_scale;
197 let mut map_local_to_picture = surface.map_local_to_picture.clone();
198
199 let map_surface_to_vis = SpaceMapper::new_with_target(
200 frame_context.root_spatial_node_index,
202 surface.surface_spatial_node_index,
203 surface.culling_rect,
204 frame_context.spatial_tree,
205 );
206 let visibility_spatial_node_index = surface.visibility_spatial_node_index;
207
208 for cluster in &pic.prim_list.clusters {
209 profile_scope!("cluster");
210
211 for prim_instance in &mut frame_state.prim_instances[cluster.prim_range()] {
224 prim_instance.reset();
225 }
226
227 if !cluster.flags.contains(ClusterFlags::IS_VISIBLE) {
229 continue;
230 }
231
232 map_local_to_picture.set_target_spatial_node(
233 cluster.spatial_node_index,
234 frame_context.spatial_tree,
235 );
236
237 for prim_instance_index in cluster.prim_range() {
238 if let PrimitiveInstanceKind::Picture { pic_index, .. } = frame_state.prim_instances[prim_instance_index].kind {
239 if !store.pictures[pic_index.0].is_visible(frame_context.spatial_tree) {
240 continue;
241 }
242
243 let is_passthrough = match store.pictures[pic_index.0].raster_config {
244 Some(..) => false,
245 None => true,
246 };
247
248 if !is_passthrough {
249 let clip_root = store
250 .pictures[pic_index.0]
251 .clip_root
252 .unwrap_or_else(|| {
253 let leaf_id = frame_state.prim_instances[prim_instance_index].clip_leaf_id;
256 frame_state.clip_tree.get_leaf(leaf_id).node_id
257 }
258 );
259
260 frame_state.clip_tree.push_clip_root_node(clip_root);
261 }
262
263 update_prim_visibility(
264 pic_index,
265 Some(surface_index),
266 world_culling_rect,
267 store,
268 false,
269 frame_context,
270 frame_state,
271 tile_cache,
272 );
273
274 if is_passthrough {
275 frame_state.prim_instances[prim_instance_index].vis.state = VisibilityState::PassThrough;
277
278 continue;
279 } else {
280 frame_state.clip_tree.pop_clip_root();
281 }
282 }
283
284 let prim_instance = &mut frame_state.prim_instances[prim_instance_index];
285
286 let local_coverage_rect = frame_state.data_stores.get_local_prim_coverage_rect(
287 prim_instance,
288 &store.pictures,
289 frame_state.surfaces,
290 );
291
292 frame_state.clip_store.set_active_clips(
293 cluster.spatial_node_index,
294 map_local_to_picture.ref_spatial_node_index,
295 visibility_spatial_node_index,
296 prim_instance.clip_leaf_id,
297 &frame_context.spatial_tree,
298 &frame_state.data_stores.clip,
299 frame_state.clip_tree,
300 );
301
302 let clip_chain = frame_state
303 .clip_store
304 .build_clip_chain_instance(
305 local_coverage_rect,
306 &map_local_to_picture,
307 &map_surface_to_vis,
308 &frame_context.spatial_tree,
309 frame_state.gpu_cache,
310 frame_state.resource_cache,
311 device_pixel_scale,
312 &surface_culling_rect,
313 &mut frame_state.data_stores.clip,
314 frame_state.rg_builder,
315 true,
316 );
317
318 prim_instance.vis.clip_chain = match clip_chain {
319 Some(clip_chain) => clip_chain,
320 None => {
321 continue;
322 }
323 };
324
325 {
326 let prim_surface_index = frame_state.surface_stack.last().unwrap().1;
327 let prim_clip_chain = &prim_instance.vis.clip_chain;
328
329 let surface = &mut frame_state.surfaces[prim_surface_index.0];
331 surface.clipped_local_rect = surface.clipped_local_rect.union(&prim_clip_chain.pic_coverage_rect);
332 }
333
334 prim_instance.vis.state = match tile_cache {
335 Some(tile_cache) => {
336 tile_cache.update_prim_dependencies(
337 prim_instance,
338 cluster.spatial_node_index,
339 local_coverage_rect,
343 frame_context,
344 frame_state.data_stores,
345 frame_state.clip_store,
346 &store.pictures,
347 frame_state.resource_cache,
348 &store.color_bindings,
349 &frame_state.surface_stack,
350 &mut frame_state.composite_state,
351 &mut frame_state.gpu_cache,
352 &mut frame_state.scratch.primitive,
353 is_root_tile_cache,
354 frame_state.surfaces,
355 frame_state.profile,
356 )
357 }
358 None => {
359 VisibilityState::Visible {
360 vis_flags: PrimitiveVisibilityFlags::empty(),
361 sub_slice_index: SubSliceIndex::DEFAULT,
362 }
363 }
364 };
365 }
366 }
367
368 if pop_surface {
369 frame_state.pop_surface();
370 }
371
372 if let Some(ref rc) = pic.raster_config {
373 if let Some(tile_cache) = tile_cache {
374 match rc.composite_mode {
375 PictureCompositeMode::TileCache { .. } => {}
376 _ => {
377 tile_cache.pop_surface();
379 }
380 }
381 }
382 }
383}
384
385pub fn compute_conservative_visible_rect(
386 clip_chain: &ClipChainInstance,
387 culling_rect: VisRect,
388 visibility_node_index: SpatialNodeIndex,
389 prim_spatial_node_index: SpatialNodeIndex,
390 spatial_tree: &SpatialTree,
391) -> LayoutRect {
392 let map_pic_to_vis: SpaceMapper<PicturePixel, VisPixel> = SpaceMapper::new_with_target(
394 visibility_node_index,
395 clip_chain.pic_spatial_node_index,
396 culling_rect,
397 spatial_tree,
398 );
399
400 let map_local_to_pic: SpaceMapper<LayoutPixel, PicturePixel> = SpaceMapper::new_with_target(
402 clip_chain.pic_spatial_node_index,
403 prim_spatial_node_index,
404 PictureRect::max_rect(),
405 spatial_tree,
406 );
407
408 let pic_culling_rect = match map_pic_to_vis.unmap(&culling_rect) {
411 Some(rect) => rect,
412 None => return clip_chain.local_clip_rect,
413 };
414
415 let pic_culling_rect = match pic_culling_rect.intersection(&clip_chain.pic_coverage_rect) {
420 Some(rect) => rect,
421 None => return LayoutRect::zero(),
422 };
423
424 match map_local_to_pic.unmap(&pic_culling_rect) {
427 Some(rect) => rect,
428 None => clip_chain.local_clip_rect,
429 }
430}