Bug 1590284 - Construct picture cache slices for scroll roots. r=kvark

With this patch, picture cache slices are constructed each time
a new scroll root is established. This reduces rasterization
cost on pages that have large fixed position elements, and pages
that contain multiple scroll roots.

Differential Revision: https://phabricator.services.mozilla.com/D50026

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Glenn Watson 2019-10-27 19:12:08 +00:00
Родитель a05e2f5d41
Коммит 16bde5fcfd
20 изменённых файлов: 98 добавлений и 45 удалений

Просмотреть файл

@ -18,7 +18,7 @@ use crate::picture::{PictureUpdateState, SurfaceInfo, ROOT_SURFACE_INDEX, Surfac
use crate::picture::{RetainedTiles, TileCacheInstance, DirtyRegion, SurfaceRenderTasks, SubpixelMode};
use crate::prim_store::{SpaceMapper, PictureIndex, PrimitiveDebugId, PrimitiveScratchBuffer};
use crate::prim_store::{DeferredResolve, PrimitiveVisibilityMask};
use crate::profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters};
use crate::profiler::{FrameProfileCounters, TextureCacheProfileCounters, ResourceProfileCounters};
use crate::render_backend::{DataStores, FrameStamp, FrameId};
use crate::render_target::{RenderTarget, PictureCacheTarget, TextureCacheRenderTarget};
use crate::render_target::{RenderTargetContext, RenderTargetKind};
@ -443,8 +443,7 @@ impl FrameBuilder {
layer: DocumentLayer,
device_origin: DeviceIntPoint,
pan: WorldPoint,
texture_cache_profile: &mut TextureCacheProfileCounters,
gpu_cache_profile: &mut GpuCacheProfileCounters,
resource_profile: &mut ResourceProfileCounters,
scene_properties: &SceneProperties,
data_stores: &mut DataStores,
scratch: &mut PrimitiveScratchBuffer,
@ -458,7 +457,7 @@ impl FrameBuilder {
profile_counters
.total_primitives
.set(scene.prim_store.prim_count());
resource_profile.content_slices.set(scene.content_slice_count);
resource_cache.begin_frame(stamp);
gpu_cache.begin_frame(stamp);
@ -496,7 +495,7 @@ impl FrameBuilder {
&mut surfaces,
scratch,
debug_flags,
texture_cache_profile,
&mut resource_profile.texture_cache,
&mut composite_state,
);
@ -563,11 +562,11 @@ impl FrameBuilder {
}
}
let gpu_cache_frame_id = gpu_cache.end_frame(gpu_cache_profile).frame_id();
let gpu_cache_frame_id = gpu_cache.end_frame(&mut resource_profile.gpu_cache).frame_id();
render_tasks.write_task_data();
*render_task_counters = render_tasks.counters();
resource_cache.end_frame(texture_cache_profile);
resource_cache.end_frame(&mut resource_profile.texture_cache);
Frame {
content_origin: scene.output_rect.origin,

Просмотреть файл

@ -199,6 +199,10 @@ impl IntProfileCounter {
pub fn inc(&mut self) {
self.value += 1;
}
pub fn set(&mut self, value: usize) {
self.value = value;
}
}
impl ProfileCounter for IntProfileCounter {
@ -679,6 +683,7 @@ pub struct ResourceProfileCounters {
pub image_templates: ResourceProfileCounter,
pub texture_cache: TextureCacheProfileCounters,
pub gpu_cache: GpuCacheProfileCounters,
pub content_slices: IntProfileCounter,
}
#[derive(Clone)]
@ -762,6 +767,10 @@ impl BackendProfileCounters {
Some(expected::NUM_IMAGE_TEMPLATES),
Some(expected::IMAGE_TEMPLATES_MB),
),
content_slices: IntProfileCounter::new(
"Content Slices",
None,
),
texture_cache: TextureCacheProfileCounters::new(),
gpu_cache: GpuCacheProfileCounters::new(),
},
@ -1464,6 +1473,7 @@ impl Profiler {
fn draw_compact_profile(
&mut self,
backend_profile: &BackendProfileCounters,
renderer_profile: &RendererProfileCounters,
debug_renderer: &mut DebugRenderer,
) {
@ -1476,6 +1486,7 @@ impl Profiler {
&renderer_profile.vertices,
&renderer_profile.rendered_picture_cache_tiles,
&renderer_profile.texture_data_uploaded,
&backend_profile.resources.content_slices,
&self.ipc_time,
&self.backend_time,
&self.renderer_time,
@ -1507,6 +1518,7 @@ impl Profiler {
&renderer_profile.rendered_picture_cache_tiles,
&renderer_profile.total_picture_cache_tiles,
&renderer_profile.texture_data_uploaded,
&backend_profile.resources.content_slices,
],
None,
debug_renderer,
@ -1760,6 +1772,7 @@ impl Profiler {
}
ProfileStyle::Compact => {
self.draw_compact_profile(
backend_profile,
renderer_profile,
debug_renderer,
);
@ -1769,7 +1782,7 @@ impl Profiler {
backend_profile,
renderer_profile,
debug_renderer,
);
);
}
}
}

Просмотреть файл

@ -549,8 +549,7 @@ impl Document {
self.view.layer,
self.view.device_rect.origin,
pan,
&mut resource_profile.texture_cache,
&mut resource_profile.gpu_cache,
resource_profile,
&self.dynamic_properties,
&mut self.data_stores,
&mut self.scratch,

Просмотреть файл

@ -227,6 +227,7 @@ pub struct BuiltScene {
pub config: FrameBuilderConfig,
pub clip_scroll_tree: ClipScrollTree,
pub hit_testing_scene: Arc<HitTestingScene>,
pub content_slice_count: usize,
}
impl BuiltScene {
@ -240,6 +241,7 @@ impl BuiltScene {
clip_store: ClipStore::new(),
clip_scroll_tree: ClipScrollTree::new(),
hit_testing_scene: Arc::new(HitTestingScene::new(&HitTestingSceneStats::empty())),
content_slice_count: 0,
config: FrameBuilderConfig {
default_font_render_mode: FontRenderMode::Mono,
dual_source_blending_is_enabled: true,

Просмотреть файл

@ -358,6 +358,9 @@ pub struct SceneBuilder<'a> {
/// The current recursion depth of iframes encountered. Used to restrict picture
/// caching slices to only the top-level content frame.
iframe_depth: usize,
/// The number of picture cache slices that were created for content.
content_slice_count: usize,
}
impl<'a> SceneBuilder<'a> {
@ -397,6 +400,7 @@ impl<'a> SceneBuilder<'a> {
external_scroll_mapper: ScrollOffsetMapper::new(),
found_explicit_tile_cache: false,
iframe_depth: 0,
content_slice_count: 0,
};
let device_pixel_scale = view.accumulated_scale_factor_for_snapping();
@ -452,6 +456,7 @@ impl<'a> SceneBuilder<'a> {
clip_store: builder.clip_store,
root_pic_index: builder.root_pic_index,
config: builder.config,
content_slice_count: builder.content_slice_count,
}
}
@ -578,12 +583,14 @@ impl<'a> SceneBuilder<'a> {
clip_instance.clip_chain_id,
&mut prim_clips,
&self.clip_store,
&self.interners,
);
}
add_clips(
instance.clip_chain_id,
&mut prim_clips,
&self.clip_store,
&self.interners,
);
}
@ -1859,7 +1866,7 @@ impl<'a> SceneBuilder<'a> {
// are scrollbars. Once this lands, we can simplify this logic considerably
// (and add a separate picture cache slice / OS layer for scroll bars).
if parent_sc.pipeline_id != stacking_context.pipeline_id && self.iframe_depth == 1 {
stacking_context.init_picture_caching(&self.clip_scroll_tree);
self.content_slice_count = stacking_context.init_picture_caching(&self.clip_scroll_tree);
// Mark that a user supplied tile cache was specified.
self.found_explicit_tile_cache = true;
@ -3521,12 +3528,13 @@ impl FlattenedStackingContext {
fn init_picture_caching(
&mut self,
clip_scroll_tree: &ClipScrollTree,
) {
) -> usize {
struct SliceInfo {
cluster_index: usize,
scroll_roots: Vec<SpatialNodeIndex>,
scroll_root: SpatialNodeIndex,
}
let mut content_slice_count = 0;
let mut slices: Vec<SliceInfo> = Vec::new();
// Step through each cluster, and work out where the slice boundaries should be.
@ -3537,51 +3545,47 @@ impl FlattenedStackingContext {
// We want to create a slice in the following conditions:
// (1) This cluster is a scrollbar
// (2) This cluster begins a 'real' scroll root, where we don't currently have a real scroll root
// (2) This cluster begins a scroll root different from the current
// (3) No slice exists yet
let create_new_slice =
cluster.flags.contains(ClusterFlags::SCROLLBAR_CONTAINER) ||
slices.last().map(|slice| {
scroll_root != ROOT_SPATIAL_NODE_INDEX &&
slice.scroll_roots.is_empty()
scroll_root != slice.scroll_root
}).unwrap_or(true);
// Create a new slice if required
if create_new_slice {
slices.push(SliceInfo {
cluster_index,
scroll_roots: Vec::new(),
scroll_root
});
}
// If this is a 'real' scroll root, include that in the list of scroll roots
// that have been found for this slice.
if scroll_root != ROOT_SPATIAL_NODE_INDEX {
let slice = slices.last_mut().unwrap();
if !slice.scroll_roots.contains(&scroll_root) {
slice.scroll_roots.push(scroll_root);
}
}
}
// Walk the list of slices, setting appropriate flags on the clusters which are
// later used during setup_picture_caching.
for slice in slices.drain(..) {
let cluster = &mut self.prim_list.clusters[slice.cluster_index];
// Mark that this cluster creates a picture cache slice
cluster.flags.insert(ClusterFlags::CREATE_PICTURE_CACHE_PRE);
assert!(!slice.scroll_roots.contains(&ROOT_SPATIAL_NODE_INDEX));
// Only select a scroll root for this slice if there's a single 'real' scroll
// root. If there are no scroll roots (doesn't scroll) or there are multiple
// scroll roots, then cache as a fixed slice. In the case of multiple scroll
// roots, this means we'll do some extra rasterization work (but only in dirty
// regions) as parts of the slice scroll. However, it does mean that we
// reduce number of tiles / GPU memory, and keep subpixel AA. In future, we
// might decide to create extra slices in some cases where there are multiple
// scroll roots (specifically, non-overlapping sibling scroll roots might be
// useful to support).
if slice.scroll_roots.len() == 1 {
cluster.cache_scroll_root = Some(slice.scroll_roots.first().cloned().unwrap());
// If the page would create too many slices (an arbitrary definition where
// it's assumed the GPU memory + compositing overhead would be too high)
// then just create a single picture cache for the entire content. This at
// least means that we can cache small content changes efficiently when
// scrolling isn't occurring. Scrolling regions will be handled reasonably
// efficiently by the dirty rect tracking (since it's likely that if the
// page has so many slices there isn't a single major scroll region).
const MAX_CONTENT_SLICES: usize = 8;
if slices.len() > MAX_CONTENT_SLICES {
if let Some(cluster) = self.prim_list.clusters.first_mut() {
content_slice_count = 1;
cluster.flags.insert(ClusterFlags::CREATE_PICTURE_CACHE_PRE);
cluster.cache_scroll_root = None;
}
} else {
// Walk the list of slices, setting appropriate flags on the clusters which are
// later used during setup_picture_caching.
for slice in slices.drain(..) {
content_slice_count += 1;
let cluster = &mut self.prim_list.clusters[slice.cluster_index];
// Mark that this cluster creates a picture cache slice
cluster.flags.insert(ClusterFlags::CREATE_PICTURE_CACHE_PRE);
cluster.cache_scroll_root = Some(slice.scroll_root);
}
}
@ -3590,6 +3594,8 @@ impl FlattenedStackingContext {
if let Some(cluster) = self.prim_list.clusters.last_mut() {
cluster.flags.insert(ClusterFlags::CREATE_PICTURE_CACHE_POST);
}
content_slice_count
}
/// Return true if the stacking context isn't needed.
@ -3933,6 +3939,7 @@ fn add_clips(
clip_chain_id: ClipChainId,
prim_clips: &mut Vec<ClipDataHandle>,
clip_store: &ClipStore,
interners: &Interners,
) {
let mut current_clip_chain_id = clip_chain_id;
@ -3940,7 +3947,10 @@ fn add_clips(
let clip_chain_node = &clip_store
.clip_chain_nodes[current_clip_chain_id.0 as usize];
prim_clips.push(clip_chain_node.handle);
let clip_kind = interners.clip[clip_chain_node.handle];
if let ClipNodeKind::Rectangle = clip_kind {
prim_clips.push(clip_chain_node.handle);
}
current_clip_chain_id = clip_chain_node.parent_clip_chain_id;
}

Просмотреть файл

@ -1,3 +1,5 @@
[background-attachment-applies-to-001.xht]
expected:
if os == "android" and not e10s: FAIL
fuzzy:
if webrender and (os == "win"): maxDifference=92;totalPixels=1900

Просмотреть файл

@ -1,3 +1,5 @@
[background-attachment-applies-to-002.xht]
expected:
if os == "android" and not e10s: FAIL
fuzzy:
if webrender and (os == "win"): maxDifference=92;totalPixels=1900

Просмотреть файл

@ -1,3 +1,5 @@
[background-attachment-applies-to-003.xht]
expected:
if os == "android" and not e10s: FAIL
fuzzy:
if webrender and (os == "win"): maxDifference=92;totalPixels=1900

Просмотреть файл

@ -1,3 +1,5 @@
[background-attachment-applies-to-004.xht]
expected:
if os == "android" and not e10s: FAIL
fuzzy:
if webrender and (os == "win"): maxDifference=92;totalPixels=1900

Просмотреть файл

@ -1,3 +1,5 @@
[background-attachment-applies-to-005.xht]
expected:
if os == "android" and not e10s: FAIL
fuzzy:
if webrender and (os == "win"): maxDifference=92;totalPixels=1900

Просмотреть файл

@ -1,3 +1,5 @@
[background-attachment-applies-to-006.xht]
expected:
if os == "android" and not e10s: FAIL
fuzzy:
if webrender and (os == "win"): maxDifference=92;totalPixels=1900

Просмотреть файл

@ -1,3 +1,5 @@
[background-attachment-applies-to-007.xht]
expected:
if os == "android" and not e10s: FAIL
fuzzy:
if webrender and (os == "win"): maxDifference=92;totalPixels=1900

Просмотреть файл

@ -1,3 +1,5 @@
[background-attachment-applies-to-009.xht]
expected:
if os == "android" and not e10s: FAIL
fuzzy:
if webrender and (os == "win"): maxDifference=92;totalPixels=1900

Просмотреть файл

@ -1,3 +1,5 @@
[background-attachment-applies-to-012.xht]
expected:
if os == "android" and not e10s: FAIL
fuzzy:
if webrender and (os == "win"): maxDifference=92;totalPixels=1900

Просмотреть файл

@ -1,3 +1,5 @@
[background-attachment-applies-to-013.xht]
expected:
if os == "android" and not e10s: FAIL
fuzzy:
if webrender and (os == "win"): maxDifference=92;totalPixels=1900

Просмотреть файл

@ -1,3 +1,5 @@
[background-attachment-applies-to-014.xht]
expected:
if os == "android" and not e10s: FAIL
fuzzy:
if webrender and (os == "win"): maxDifference=92;totalPixels=1900

Просмотреть файл

@ -1,3 +1,5 @@
[background-attachment-applies-to-015.xht]
expected:
if os == "android" and not e10s: FAIL
fuzzy:
if webrender and (os == "win"): maxDifference=92;totalPixels=1900

Просмотреть файл

@ -5,3 +5,5 @@
if not webrender and (os == "win") and (version == "10.0.17134"): FAIL
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: PASS
fuzzy:
if webrender and (os == "win"): maxDifference=92;totalPixels=2206

Просмотреть файл

@ -2,3 +2,5 @@
expected:
if (os == "android") and not e10s: FAIL
if (os == "android") and e10s: PASS
fuzzy:
if webrender and (os == "win"): maxDifference=92;totalPixels=3796

Просмотреть файл

@ -3,3 +3,5 @@
if os == "android": Bug 1563766
expected:
if (os == "android") and not e10s: FAIL
fuzzy:
if webrender and (os == "win"): maxDifference=92;totalPixels=1787