Commit bd8f45e4 authored by Glenn Watson's avatar Glenn Watson
Browse files

Bug 1742031 - Pt 1 - Reduce per-primitive work during visibility pass r=gfx-reviewers,nical

The per-primitive visibility calculations done during frame
building are (mostly) redundant. Since picture caches are always
enabled, and since we must determine what tile(s) a primitive is on
for dependency updates, that gives us all the information we need
for visibility (by determining at the _tile_ level which tiles are
dirty and/or visible).

This patch is a small step towards that, moving the main picture
cache update out of the update_prim_visibility functions. Follow
up patches will remove most of the per-primitive work done during
this pass.

Differential Revision: https://phabricator.services.mozilla.com/D131580
parent 9caeaefc
Loading
Loading
Loading
Loading
+63 −26
Original line number Diff line number Diff line
@@ -409,6 +409,15 @@ impl FrameBuilder {
                root_spatial_node_index,
            };

            for pic_index in scene.tile_cache_pictures.iter().rev() {
                let pic = &mut scene.prim_store.pictures[pic_index.0];

                match pic.raster_config {
                    Some(RasterConfig { surface_index, composite_mode: PictureCompositeMode::TileCache { slice_id }, .. }) => {
                        let tile_cache = tile_caches
                            .get_mut(&slice_id)
                            .expect("bug: non-existent tile cache");

                        let mut visibility_state = FrameVisibilityState {
                            clip_chain_stack: scratch.frame.clip_chain_stack.take(),
                            surface_stack: scratch.frame.surface_stack.take(),
@@ -416,27 +425,55 @@ impl FrameBuilder {
                            gpu_cache,
                            clip_store: &mut scene.clip_store,
                            scratch,
                tile_cache: None,
                            data_stores,
                            composite_state,
                        };

            for pic_index in scene.tile_cache_pictures.iter().rev() {
                        // If we have a tile cache for this picture, see if any of the
                        // relative transforms have changed, which means we need to
                        // re-map the dependencies of any child primitives.
                        let world_culling_rect = tile_cache.pre_update(
                            layout_rect_as_picture_rect(&pic.estimated_local_rect),
                            surface_index,
                            &visibility_context,
                            &mut visibility_state,
                        );

                        // Push a new surface, supplying the list of clips that should be
                        // ignored, since they are handled by clipping when drawing this surface.
                        visibility_state.push_surface(
                            surface_index,
                            &tile_cache.shared_clips,
                            frame_context.spatial_tree,
                        );

                        update_primitive_visibility(
                            &mut scene.prim_store,
                            *pic_index,
                            ROOT_SURFACE_INDEX,
                    &global_screen_world_rect,
                            &world_culling_rect,
                            &visibility_context,
                            &mut visibility_state,
                    tile_caches,
                            tile_cache,
                            true,
                            &mut scene.prim_instances,
                        );
            }

                        // Build the dirty region(s) for this tile cache.
                        tile_cache.post_update(
                            &visibility_context,
                            &mut visibility_state,
                        );

                        visibility_state.pop_surface();
                        visibility_state.scratch.frame.clip_chain_stack = visibility_state.clip_chain_stack.take();
                        visibility_state.scratch.frame.surface_stack = visibility_state.surface_stack.take();
                    }
                    _ => {
                        panic!("bug: not a tile cache");
                    }
                }
            }

            profile.end_time(profiler::FRAME_VISIBILITY_TIME);
        }
+44 −83
Original line number Diff line number Diff line
@@ -19,9 +19,8 @@ use crate::clip::{ClipInstance, ClipChainInstance};
use crate::debug_colors;
use crate::frame_builder::FrameBuilderConfig;
use crate::gpu_cache::GpuCache;
use crate::internal_types::FastHashMap;
use crate::picture::{PictureCompositeMode, ClusterFlags, SurfaceInfo, TileCacheInstance};
use crate::picture::{PrimitiveList, SurfaceIndex, RasterConfig, SliceId};
use crate::picture::{PrimitiveList, SurfaceIndex, RasterConfig};
use crate::prim_store::{ClipTaskIndex, PictureIndex, PrimitiveInstanceKind};
use crate::prim_store::{PrimitiveStore, PrimitiveInstance};
use crate::render_backend::{DataStores, ScratchBuffer};
@@ -47,7 +46,6 @@ pub struct FrameVisibilityState<'a> {
    pub resource_cache: &'a mut ResourceCache,
    pub gpu_cache: &'a mut GpuCache,
    pub scratch: &'a mut ScratchBuffer,
    pub tile_cache: Option<Box<TileCacheInstance>>,
    pub data_stores: &'a mut DataStores,
    pub clip_chain_stack: ClipChainStack,
    pub composite_state: &'a mut CompositeState,
@@ -171,66 +169,42 @@ pub fn update_primitive_visibility(
    world_culling_rect: &WorldRect,
    frame_context: &FrameVisibilityContext,
    frame_state: &mut FrameVisibilityState,
    tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
    tile_cache: &mut TileCacheInstance,
    is_root_tile_cache: bool,
    prim_instances: &mut Vec<PrimitiveInstance>,
) -> Option<PictureRect> {
    profile_scope!("update_visibility");
    let (mut prim_list, surface_index, apply_local_clip_rect, world_culling_rect, is_composite) = {
    let (mut prim_list, surface_index, apply_local_clip_rect, world_culling_rect, pop_surface) = {
        let pic = &mut store.pictures[pic_index.0];
        let mut world_culling_rect = *world_culling_rect;

        let prim_list = mem::replace(&mut pic.prim_list, PrimitiveList::empty());
        let (surface_index, is_composite) = match pic.raster_config {
            Some(ref raster_config) => (raster_config.surface_index, true),
            None => (parent_surface_index, false)
        };

        match pic.raster_config {
            Some(RasterConfig { composite_mode: PictureCompositeMode::TileCache { slice_id }, .. }) => {
                let mut tile_cache = tile_caches
                    .remove(&slice_id)
                    .expect("bug: non-existent tile cache");

                // If we have a tile cache for this picture, see if any of the
                // relative transforms have changed, which means we need to
                // re-map the dependencies of any child primitives.
                world_culling_rect = tile_cache.pre_update(
                    layout_rect_as_picture_rect(&pic.estimated_local_rect),
                    surface_index,
                    frame_context,
                    frame_state,
                );

                // Push a new surface, supplying the list of clips that should be
                // ignored, since they are handled by clipping when drawing this surface.
                frame_state.push_surface(
                    surface_index,
                    &tile_cache.shared_clips,
                    frame_context.spatial_tree,
                );
                frame_state.tile_cache = Some(tile_cache);
        let (surface_index, pop_surface) = match pic.raster_config {
            Some(RasterConfig { surface_index, composite_mode: PictureCompositeMode::TileCache { .. }, .. }) => {
                (surface_index, false)
            }
            _ => {
                if is_composite {
            Some(ref raster_config) => {
                frame_state.push_surface(
                        surface_index,
                    raster_config.surface_index,
                    &[],
                    frame_context.spatial_tree,
                );

                // Let the picture cache know that we are pushing an off-screen
                // surface, so it can treat dependencies of surface atomically.
                    frame_state.tile_cache.as_mut().unwrap().push_surface(
                tile_cache.push_surface(
                    pic.estimated_local_rect,
                    pic.spatial_node_index,
                    frame_context.spatial_tree,
                );

                (raster_config.surface_index, true)
            }
            None => {
                (parent_surface_index, false)
            }
        }
        };

        (prim_list, surface_index, pic.apply_local_clip_rect, world_culling_rect, is_composite)
        (prim_list, surface_index, pic.apply_local_clip_rect, world_culling_rect, pop_surface)
    };

    let surface = &frame_context.surfaces[surface_index.0 as usize];
@@ -300,10 +274,10 @@ pub fn update_primitive_visibility(
                        store,
                        pic_index,
                        surface_index,
                        &world_culling_rect,
                        world_culling_rect,
                        frame_context,
                        frame_state,
                        tile_caches,
                        tile_cache,
                        false,
                        prim_instances,
                    );
@@ -462,10 +436,7 @@ pub fn update_primitive_visibility(
                    }
                }

                frame_state.tile_cache
                    .as_mut()
                    .unwrap()
                    .update_prim_dependencies(
                tile_cache.update_prim_dependencies(
                    prim_instance,
                    cluster.spatial_node_index,
                    prim_local_rect,
@@ -553,7 +524,7 @@ pub fn update_primitive_visibility(
    }

    // Similar to above, pop either the clip chain or root entry off the current clip stack.
    if is_composite {
    if pop_surface {
        frame_state.pop_surface();
    }

@@ -601,20 +572,10 @@ pub fn update_primitive_visibility(
        }

        match rc.composite_mode {
            PictureCompositeMode::TileCache { .. } => {
                let mut tile_cache = frame_state.tile_cache.take().unwrap();

                // Build the dirty region(s) for this tile cache.
                tile_cache.post_update(
                    frame_context,
                    frame_state,
                );

                tile_caches.insert(SliceId::new(tile_cache.slice), tile_cache);
            }
            PictureCompositeMode::TileCache { .. } => {}
            _ => {
                // Pop the off-screen surface from the picture cache stack
                frame_state.tile_cache.as_mut().unwrap().pop_surface();
                tile_cache.pop_surface();
            }
        }

@@ -635,7 +596,7 @@ pub fn update_primitive_visibility(
fn update_prim_post_visibility(
    store: &mut PrimitiveStore,
    prim_instance: &mut PrimitiveInstance,
    world_culling_rect: WorldRect,
    world_culling_rect: &WorldRect,
    map_surface_to_world: &SpaceMapper<PicturePixel, WorldPixel>,
) {
    profile_scope!("update_prim_post_visibility");
@@ -648,7 +609,7 @@ fn update_prim_post_visibility(
                raster_config.clipped_bounding_rect = map_surface_to_world
                    .map(&prim_instance.vis.clip_chain.pic_clip_rect)
                    .and_then(|rect| {
                        rect.intersection(&world_culling_rect)
                        rect.intersection(world_culling_rect)
                    })
                    .unwrap_or(WorldRect::zero());
            }