mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-24 18:55:30 +00:00
Backed out changeset c2c9dbf826fe (bug 1581757) by dev's request
This commit is contained in:
parent
8d8222b8a9
commit
f1e99da78f
@ -2266,8 +2266,6 @@ pub struct PrimitiveCluster {
|
||||
pub prim_instances: Vec<PrimitiveInstance>,
|
||||
/// Various flags / state for this cluster.
|
||||
pub flags: ClusterFlags,
|
||||
/// An optional scroll root to use if this cluster establishes a picture cache slice.
|
||||
pub cache_scroll_root: Option<SpatialNodeIndex>,
|
||||
}
|
||||
|
||||
/// Where to insert a prim instance in a primitive list.
|
||||
@ -2288,7 +2286,6 @@ impl PrimitiveCluster {
|
||||
spatial_node_index,
|
||||
flags,
|
||||
prim_instances: Vec::new(),
|
||||
cache_scroll_root: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -2435,15 +2432,23 @@ impl PrimitiveList {
|
||||
self.clusters.is_empty()
|
||||
}
|
||||
|
||||
/// Add an existing cluster to this prim list
|
||||
pub fn add_cluster(&mut self, cluster: PrimitiveCluster) {
|
||||
self.clusters.push(cluster);
|
||||
}
|
||||
|
||||
/// Merge another primitive list into this one
|
||||
pub fn extend(&mut self, prim_list: PrimitiveList) {
|
||||
self.clusters.extend(prim_list.clusters);
|
||||
}
|
||||
|
||||
/// Return the number of clusters in this prim list
|
||||
pub fn len(&self) -> usize {
|
||||
self.clusters.len()
|
||||
}
|
||||
|
||||
/// Split this primitive list at the given cluster index
|
||||
pub fn split_off(&mut self, index: usize) -> PrimitiveList {
|
||||
let clusters = self.clusters.split_off(index);
|
||||
PrimitiveList {
|
||||
clusters
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines configuration options for a given picture primitive.
|
||||
|
@ -21,7 +21,7 @@ use crate::image::simplify_repeated_primitive;
|
||||
use crate::intern::Interner;
|
||||
use crate::internal_types::{FastHashMap, FastHashSet, LayoutPrimitiveInfo, Filter};
|
||||
use crate::picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, PictureOptions};
|
||||
use crate::picture::{BlitReason, OrderedPictureChild, PrimitiveList, TileCacheInstance, ClusterFlags};
|
||||
use crate::picture::{BlitReason, OrderedPictureChild, PrimitiveList, TileCacheInstance};
|
||||
use crate::prim_store::{PrimitiveInstance, PrimitiveSceneData};
|
||||
use crate::prim_store::{PrimitiveInstanceKind, NinePatchDescriptor, PrimitiveStore};
|
||||
use crate::prim_store::{ScrollNodeAndClipChain, PictureIndex};
|
||||
@ -238,63 +238,6 @@ impl CompositeOps {
|
||||
}
|
||||
}
|
||||
|
||||
/// Information about unpaired Push/Pop clip chain instances that need to be fixed up.
|
||||
struct ClipChainPairInfo {
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
clip_chain_id: ClipChainId,
|
||||
}
|
||||
|
||||
/// Information about a set of primitive clusters that will form a picture cache slice.
|
||||
struct Slice {
|
||||
/// The spatial node root of the picture cache. If this is None, the slice
|
||||
/// will not be cached and instead drawn directly to the parent surface. This
|
||||
/// is a temporary measure until we enable caching all slices.
|
||||
cache_scroll_root: Option<SpatialNodeIndex>,
|
||||
/// List of primitive clusters that make up this slice
|
||||
prim_list: PrimitiveList,
|
||||
/// A list of clips that are shared by all primitives in the slice. These can be
|
||||
/// filtered out and applied when the tile cache is composited rather than per-item.
|
||||
shared_clips: Option<Vec<ClipDataHandle>>,
|
||||
}
|
||||
|
||||
impl Slice {
|
||||
// Open clip chain instances at the start of a slice
|
||||
fn push_clip_instances(
|
||||
&mut self,
|
||||
stack: &[ClipChainPairInfo],
|
||||
) {
|
||||
for clip_chain_instance in stack.iter().rev() {
|
||||
self.prim_list.add_prim_to_start(
|
||||
create_clip_prim_instance(
|
||||
clip_chain_instance.clip_chain_id,
|
||||
PrimitiveInstanceKind::PushClipChain,
|
||||
),
|
||||
LayoutSize::zero(),
|
||||
clip_chain_instance.spatial_node_index,
|
||||
PrimitiveFlags::IS_BACKFACE_VISIBLE,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Close clip chain instances at the end of a slice
|
||||
fn pop_clip_instances(
|
||||
&mut self,
|
||||
stack: &[ClipChainPairInfo],
|
||||
) {
|
||||
for clip_chain_instance in stack {
|
||||
self.prim_list.add_prim(
|
||||
create_clip_prim_instance(
|
||||
clip_chain_instance.clip_chain_id,
|
||||
PrimitiveInstanceKind::PopClipChain,
|
||||
),
|
||||
LayoutSize::zero(),
|
||||
clip_chain_instance.spatial_node_index,
|
||||
PrimitiveFlags::IS_BACKFACE_VISIBLE,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A structure that converts a serialized display list into a form that WebRender
|
||||
/// can use to later build a frame. This structure produces a BuiltScene. Public
|
||||
/// members are typically those that are destructured into the BuiltScene.
|
||||
@ -472,8 +415,6 @@ impl<'a> SceneBuilder<'a> {
|
||||
rf_offset + scroll_offset
|
||||
}
|
||||
|
||||
/// Figure out the shape of the display list, and wrap various primitive clusters
|
||||
/// into tile cache primitive instances.
|
||||
fn setup_picture_caching(
|
||||
&mut self,
|
||||
main_prim_list: &mut PrimitiveList,
|
||||
@ -482,21 +423,71 @@ impl<'a> SceneBuilder<'a> {
|
||||
return;
|
||||
}
|
||||
|
||||
// If no explicit tile cache was enabled, insert a marker that will result in the
|
||||
// entire display list being cached.
|
||||
if !self.found_explicit_tile_cache {
|
||||
if let Some(cluster) = main_prim_list.clusters.first_mut() {
|
||||
cluster.flags.insert(ClusterFlags::CREATE_PICTURE_CACHE_PRE);
|
||||
cluster.cache_scroll_root = Some(ROOT_SPATIAL_NODE_INDEX);
|
||||
}
|
||||
}
|
||||
// This method is basically a hack to set up picture caching in a minimal
|
||||
// way without having to check the public API (yet). The intent is to
|
||||
// work out a good API for this and switch to using it. In the mean
|
||||
// time, this allows basic picture caching to be enabled and used for
|
||||
// ironing out remaining bugs, fixing performance issues and profiling.
|
||||
|
||||
// List of slices that have been found
|
||||
let mut slices: Vec<Slice> = Vec::new();
|
||||
// Current stack of open clip chain instances that need to be fixed up
|
||||
//
|
||||
// We know that the display list will contain something like the following:
|
||||
// [Some number of primitives attached to root scroll now]
|
||||
// [IFrame for the content]
|
||||
// [A scroll root for the content (what we're interested in)]
|
||||
// [Primitives attached to the scroll root, possibly with sub-scroll roots]
|
||||
// [Some number of trailing primitives attached to root scroll frame]
|
||||
//
|
||||
// So we want to slice that stacking context up into:
|
||||
// [root primitives]
|
||||
// [tile cache picture]
|
||||
// [primitives attached to cached scroll root]
|
||||
// [trailing root primitives]
|
||||
//
|
||||
// This step is typically very quick, because there are only
|
||||
// a small number of items in the root stacking context, since
|
||||
// most of the content is embedded in its own picture.
|
||||
//
|
||||
|
||||
// Find the first primitive which has the desired scroll root.
|
||||
let mut first_index = None;
|
||||
let mut main_scroll_root = None;
|
||||
|
||||
// If the main primitive list that we split for picture caching has
|
||||
// clip chain instances at the top level, it's possible that we will
|
||||
// create a split resulting in one list having unmatched PushClipChain
|
||||
// or PopClipChain instances. This causes panics in pop_surface(),
|
||||
// which asserts that the clip chain instances are matched.
|
||||
|
||||
// The code below is a (very inelegant) solution to that. It records
|
||||
// clip chain instances found during the initial scan for scroll roots.
|
||||
// Later, it uses this information to fix up unopened or unclosed clip
|
||||
// instances on the split primitive lists.
|
||||
|
||||
// This is far from ideal - but it fixes the crash for now. In future
|
||||
// we will be simplifying and/or removing how clip chain instances
|
||||
// and picture cache splitting works, so we can tidy this up as
|
||||
// part of those future changes.
|
||||
|
||||
let mut clip_chain_instances = Vec::new();
|
||||
let mut clip_chain_instance_stack = Vec::new();
|
||||
// Tracker for whether a new slice should be created
|
||||
let mut create_slice = true;
|
||||
|
||||
// Maintain a list of clip node handles that are shared by every primitive
|
||||
// in this list. These are often root / fixed position clips. We collect these
|
||||
// and handle them when compositing the picture cache tiles. This saves per-item
|
||||
// clip work, but more importantly, it avoids lots of invalidations due to
|
||||
// content being clipped by fixed iframe/scrollframe rects.
|
||||
|
||||
// TODO(gw): The logic to build the shared clips list is quite complicated, because:
|
||||
// (a) We want to cache result and not do a heap of extra work per primitive,
|
||||
// since stress tests like dl_mutate have 50000+ primitives. Since each
|
||||
// primitive often shares the same clip chain as the previous primitive,
|
||||
// caching the last set of prim clips is generally sufficient.
|
||||
// (b) The general logic to set up picture caching is still complicated due to
|
||||
// not caching multiple slices (e.g. scroll bars). Once we enable
|
||||
// multiple picture cache slices, this logic becomes much simpler.
|
||||
|
||||
// The clips we have found that exist on every primitive we are going to cache.
|
||||
let mut shared_clips = Vec::new();
|
||||
// The clips found the last time we traversed a set of clip chains. Stored and cleared
|
||||
// here to avoid constant allocations.
|
||||
let mut prim_clips = Vec::new();
|
||||
@ -505,44 +496,58 @@ impl<'a> SceneBuilder<'a> {
|
||||
// The last prim clip chain we build prim_clips for.
|
||||
let mut last_prim_clip_chain_id = ClipChainId::NONE;
|
||||
|
||||
// Walk the supplied top level of clusters, slicing into slices as appropriate
|
||||
for cluster in main_prim_list.clusters.drain(..) {
|
||||
// Check if this cluster requires a new slice
|
||||
create_slice |= cluster.flags.contains(ClusterFlags::CREATE_PICTURE_CACHE_PRE);
|
||||
/// Records the indices in the list of a push/pop clip chain instance pair.
|
||||
#[derive(Debug)]
|
||||
struct ClipChainPairInfo {
|
||||
push_index: usize,
|
||||
pop_index: usize,
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
clip_chain_id: ClipChainId,
|
||||
}
|
||||
|
||||
if create_slice {
|
||||
// When creating a slice, close off any open clip chains on prev slice.
|
||||
if let Some(prev_slice) = slices.last_mut() {
|
||||
prev_slice.pop_clip_instances(&clip_chain_instance_stack);
|
||||
}
|
||||
// Helper fn to collect clip handles from a given clip chain.
|
||||
fn add_clips(
|
||||
clip_chain_id: ClipChainId,
|
||||
prim_clips: &mut Vec<ClipDataHandle>,
|
||||
clip_store: &ClipStore,
|
||||
) {
|
||||
let mut current_clip_chain_id = clip_chain_id;
|
||||
|
||||
let mut slice = Slice {
|
||||
cache_scroll_root: cluster.cache_scroll_root,
|
||||
prim_list: PrimitiveList::empty(),
|
||||
shared_clips: None,
|
||||
};
|
||||
while current_clip_chain_id != ClipChainId::NONE {
|
||||
let clip_chain_node = &clip_store
|
||||
.clip_chain_nodes[current_clip_chain_id.0 as usize];
|
||||
|
||||
// Open up clip chains on the stack on the new slice
|
||||
slice.push_clip_instances(&clip_chain_instance_stack);
|
||||
slices.push(slice);
|
||||
create_slice = false;
|
||||
prim_clips.push(clip_chain_node.handle);
|
||||
|
||||
current_clip_chain_id = clip_chain_node.parent_clip_chain_id;
|
||||
}
|
||||
}
|
||||
|
||||
for (cluster_index, cluster) in main_prim_list.clusters.iter().enumerate() {
|
||||
let scroll_root = self.clip_scroll_tree.find_scroll_root(
|
||||
cluster.spatial_node_index,
|
||||
);
|
||||
|
||||
// Step through each prim instance, in order to collect shared clips for the slice.
|
||||
for instance in &cluster.prim_instances {
|
||||
// If a Push/Pop clip chain, record that in the clip stack stack.
|
||||
// If we encounter a push/pop clip, record where they occurred in the
|
||||
// primitive list for later processing.
|
||||
match instance.kind {
|
||||
PrimitiveInstanceKind::PushClipChain => {
|
||||
clip_chain_instance_stack.push(ClipChainPairInfo {
|
||||
clip_chain_instance_stack.push(clip_chain_instances.len());
|
||||
clip_chain_instances.push(ClipChainPairInfo {
|
||||
push_index: cluster_index,
|
||||
pop_index: usize::MAX,
|
||||
spatial_node_index: cluster.spatial_node_index,
|
||||
clip_chain_id: instance.clip_chain_id,
|
||||
});
|
||||
// Invalidate the prim_clips cache - a clip chain was removed.
|
||||
// Invalidate the prim_clips cache - there is a new clip chain.
|
||||
update_shared_clips = true;
|
||||
continue;
|
||||
}
|
||||
PrimitiveInstanceKind::PopClipChain => {
|
||||
let clip_chain_instance = clip_chain_instance_stack.pop().unwrap();
|
||||
let index = clip_chain_instance_stack.pop().unwrap();
|
||||
let clip_chain_instance = &mut clip_chain_instances[index];
|
||||
debug_assert_eq!(clip_chain_instance.pop_index, usize::MAX);
|
||||
debug_assert_eq!(
|
||||
clip_chain_instance.clip_chain_id,
|
||||
instance.clip_chain_id,
|
||||
@ -551,6 +556,7 @@ impl<'a> SceneBuilder<'a> {
|
||||
clip_chain_instance.spatial_node_index,
|
||||
cluster.spatial_node_index,
|
||||
);
|
||||
clip_chain_instance.pop_index = cluster_index;
|
||||
// Invalidate the prim_clips cache - a clip chain was removed.
|
||||
update_shared_clips = true;
|
||||
continue;
|
||||
@ -562,93 +568,141 @@ impl<'a> SceneBuilder<'a> {
|
||||
update_shared_clips |= last_prim_clip_chain_id != instance.clip_chain_id;
|
||||
last_prim_clip_chain_id = instance.clip_chain_id;
|
||||
|
||||
// TODO(gw): This is a hack for wrench, to not share clips for implicit
|
||||
// picture caches. It's needed until we properly exclude
|
||||
// shared clips that are not simple.
|
||||
if update_shared_clips && self.found_explicit_tile_cache {
|
||||
if update_shared_clips {
|
||||
prim_clips.clear();
|
||||
// Update the list of clips that apply to this primitive instance
|
||||
for clip_instance in &clip_chain_instance_stack {
|
||||
// Collect any clips from the clip chain stack that will affect this prim.
|
||||
for clip_instance_index in &clip_chain_instance_stack {
|
||||
let clip_instance = &clip_chain_instances[*clip_instance_index];
|
||||
add_clips(
|
||||
clip_instance.clip_chain_id,
|
||||
&mut prim_clips,
|
||||
&self.clip_store,
|
||||
);
|
||||
}
|
||||
// Collect any clips from the primitive's specific clip chain.
|
||||
add_clips(
|
||||
instance.clip_chain_id,
|
||||
&mut prim_clips,
|
||||
&self.clip_store,
|
||||
);
|
||||
|
||||
// We want to only retain clips that are shared across all primitives.
|
||||
// TODO(gw): We could consider using a HashSet here, but:
|
||||
// (a) The sizes of these arrays are typically very small (<< 10).
|
||||
// (b) We would have to impl Ord/Eq on interner handles, which we
|
||||
// otherwise don't need / want.
|
||||
shared_clips.retain(|h1: &ClipDataHandle| {
|
||||
let uid = h1.uid();
|
||||
prim_clips.iter().any(|h2| {
|
||||
uid == h2.uid()
|
||||
})
|
||||
});
|
||||
|
||||
update_shared_clips = false;
|
||||
}
|
||||
|
||||
// If there are no shared clips set for this slice, the shared clips are just
|
||||
// the current clips set. Otherwise, the shared clips are those that are
|
||||
// in both the current shared list and the clips list for this primitive.
|
||||
match slices.last_mut().unwrap().shared_clips {
|
||||
Some(ref mut shared_clips) => {
|
||||
if update_shared_clips {
|
||||
shared_clips.retain(|h1: &ClipDataHandle| {
|
||||
let uid = h1.uid();
|
||||
prim_clips.iter().any(|h2| {
|
||||
uid == h2.uid()
|
||||
})
|
||||
});
|
||||
if scroll_root != ROOT_SPATIAL_NODE_INDEX {
|
||||
// If we find multiple scroll roots in this page, then skip
|
||||
// picture caching for now. In future, we can handle picture
|
||||
// caching on these sites by creating a tile cache per
|
||||
// scroll root, or (more likely) selecting the common parent
|
||||
// scroll root between the detected scroll roots.
|
||||
match main_scroll_root {
|
||||
Some(main_scroll_root) => {
|
||||
if main_scroll_root != scroll_root {
|
||||
return;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
main_scroll_root = Some(scroll_root);
|
||||
}
|
||||
}
|
||||
ref mut shared_clips @ None => {
|
||||
*shared_clips = Some(prim_clips.clone());
|
||||
|
||||
if first_index.is_none() {
|
||||
// The first time we identify a prim that will be cached, set the prim_clips
|
||||
// array to this, such that the retain() logic above works.
|
||||
shared_clips = prim_clips.clone();
|
||||
first_index = Some(cluster_index);
|
||||
}
|
||||
}
|
||||
|
||||
update_shared_clips = false;
|
||||
}
|
||||
|
||||
// If this cluster creates a slice after, then note that for next cluster
|
||||
create_slice |= cluster.flags.contains(ClusterFlags::CREATE_PICTURE_CACHE_POST);
|
||||
|
||||
// Finally, add this cluster to the current slice
|
||||
slices.last_mut().unwrap().prim_list.add_cluster(cluster);
|
||||
}
|
||||
|
||||
// Close off any open clip chains on prev slice.
|
||||
if let Some(prev_slice) = slices.last_mut() {
|
||||
prev_slice.pop_clip_instances(&clip_chain_instance_stack);
|
||||
}
|
||||
|
||||
// Step through the slices, creating picture cache wrapper instances.
|
||||
for (slice_index, slice) in slices.drain(..).enumerate() {
|
||||
match slice.cache_scroll_root {
|
||||
Some(scroll_root) => {
|
||||
let background_color = if slice_index == 0 {
|
||||
self.config.background_color
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let instance = create_tile_cache(
|
||||
slice_index,
|
||||
scroll_root,
|
||||
slice.prim_list,
|
||||
background_color,
|
||||
slice.shared_clips.unwrap_or(Vec::new()),
|
||||
&mut self.interners,
|
||||
&mut self.prim_store,
|
||||
&mut self.clip_store,
|
||||
);
|
||||
|
||||
main_prim_list.add_prim(
|
||||
instance,
|
||||
LayoutSize::zero(),
|
||||
scroll_root,
|
||||
PrimitiveFlags::IS_BACKFACE_VISIBLE,
|
||||
);
|
||||
}
|
||||
None => {
|
||||
main_prim_list.extend(slice.prim_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let main_scroll_root = match main_scroll_root {
|
||||
Some(main_scroll_root) => main_scroll_root,
|
||||
None => ROOT_SPATIAL_NODE_INDEX,
|
||||
};
|
||||
|
||||
// Get the list of existing primitives in the main stacking context.
|
||||
let mut old_prim_list = mem::replace(main_prim_list, PrimitiveList::empty());
|
||||
|
||||
// In the simple case, there are no preceding or trailing primitives,
|
||||
// because everything is anchored to the root scroll node. Handle
|
||||
// this case specially to avoid underflow error in the Some(..)
|
||||
// path below.
|
||||
|
||||
let mut preceding_prims;
|
||||
let mut remaining_prims;
|
||||
|
||||
match first_index {
|
||||
Some(first_index) => {
|
||||
// Split off the preceding primtives.
|
||||
remaining_prims = old_prim_list.split_off(first_index);
|
||||
preceding_prims = old_prim_list;
|
||||
}
|
||||
None => {
|
||||
preceding_prims = PrimitiveList::empty();
|
||||
remaining_prims = old_prim_list;
|
||||
}
|
||||
}
|
||||
|
||||
let mid_index = preceding_prims.len();
|
||||
|
||||
// Step through each clip chain pair, and see if it crosses a slice boundary.
|
||||
for clip_chain_instance in clip_chain_instances {
|
||||
if clip_chain_instance.push_index < mid_index && clip_chain_instance.pop_index >= mid_index {
|
||||
preceding_prims.add_prim(
|
||||
create_clip_prim_instance(
|
||||
clip_chain_instance.clip_chain_id,
|
||||
PrimitiveInstanceKind::PopClipChain,
|
||||
),
|
||||
LayoutSize::zero(),
|
||||
clip_chain_instance.spatial_node_index,
|
||||
PrimitiveFlags::IS_BACKFACE_VISIBLE,
|
||||
);
|
||||
|
||||
remaining_prims.add_prim_to_start(
|
||||
create_clip_prim_instance(
|
||||
clip_chain_instance.clip_chain_id,
|
||||
PrimitiveInstanceKind::PushClipChain,
|
||||
),
|
||||
LayoutSize::zero(),
|
||||
clip_chain_instance.spatial_node_index,
|
||||
PrimitiveFlags::IS_BACKFACE_VISIBLE,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let instance = create_tile_cache(
|
||||
0,
|
||||
main_scroll_root,
|
||||
remaining_prims,
|
||||
self.config.background_color,
|
||||
shared_clips,
|
||||
&mut self.interners,
|
||||
&mut self.prim_store,
|
||||
&mut self.clip_store,
|
||||
);
|
||||
|
||||
// This contains the tile caching picture, with preceding and
|
||||
// trailing primitives outside the main scroll root.
|
||||
main_prim_list.extend(preceding_prims);
|
||||
main_prim_list.add_prim(
|
||||
instance,
|
||||
LayoutSize::zero(),
|
||||
main_scroll_root,
|
||||
PrimitiveFlags::IS_BACKFACE_VISIBLE,
|
||||
);
|
||||
}
|
||||
|
||||
fn build_items(
|
||||
@ -1678,6 +1732,9 @@ impl<'a> SceneBuilder<'a> {
|
||||
None
|
||||
};
|
||||
|
||||
// Mark if a user supplied tile cache was specified.
|
||||
self.found_explicit_tile_cache |= create_tile_cache;
|
||||
|
||||
if is_pipeline_root && create_tile_cache && self.config.enable_picture_caching {
|
||||
// we don't expect any nested tile-cache-enabled stacking contexts
|
||||
debug_assert!(!self.sc_stack.iter().any(|sc| sc.create_tile_cache));
|
||||
@ -1816,55 +1873,39 @@ impl<'a> SceneBuilder<'a> {
|
||||
let parent_is_empty = match self.sc_stack.last_mut() {
|
||||
Some(parent_sc) => {
|
||||
if stacking_context.is_redundant(parent_sc) {
|
||||
if !stacking_context.prim_list.is_empty() {
|
||||
if stacking_context.clip_chain_id != ClipChainId::NONE {
|
||||
let prim = create_clip_prim_instance(
|
||||
stacking_context.clip_chain_id,
|
||||
PrimitiveInstanceKind::PushClipChain,
|
||||
);
|
||||
stacking_context.prim_list.add_prim_to_start(
|
||||
prim,
|
||||
LayoutSize::zero(),
|
||||
stacking_context.spatial_node_index,
|
||||
PrimitiveFlags::IS_BACKFACE_VISIBLE,
|
||||
);
|
||||
if stacking_context.clip_chain_id != ClipChainId::NONE {
|
||||
let prim = create_clip_prim_instance(
|
||||
stacking_context.clip_chain_id,
|
||||
PrimitiveInstanceKind::PushClipChain,
|
||||
);
|
||||
parent_sc.prim_list.add_prim(
|
||||
prim,
|
||||
LayoutSize::zero(),
|
||||
stacking_context.spatial_node_index,
|
||||
PrimitiveFlags::IS_BACKFACE_VISIBLE,
|
||||
);
|
||||
}
|
||||
|
||||
let prim = create_clip_prim_instance(
|
||||
stacking_context.clip_chain_id,
|
||||
PrimitiveInstanceKind::PopClipChain,
|
||||
);
|
||||
stacking_context.prim_list.add_prim(
|
||||
prim,
|
||||
LayoutSize::zero(),
|
||||
stacking_context.spatial_node_index,
|
||||
PrimitiveFlags::IS_BACKFACE_VISIBLE,
|
||||
);
|
||||
}
|
||||
// If the parent context primitives list is empty, it's faster
|
||||
// to assign the storage of the popped context instead of paying
|
||||
// the copying cost for extend.
|
||||
if parent_sc.prim_list.is_empty() {
|
||||
parent_sc.prim_list = stacking_context.prim_list;
|
||||
} else {
|
||||
parent_sc.prim_list.extend(stacking_context.prim_list);
|
||||
}
|
||||
|
||||
// If popping a redundant stacking context that is from a different pipeline,
|
||||
// we want to insert flags where the picture cache slices should be created
|
||||
// for this iframe. For now, we want to match existing behavior, that is:
|
||||
// - Only cache content that is within the main scroll root, and:
|
||||
// - Skip caching fixed position content before / after the scroll root.
|
||||
// This means that we don't add scrollbars, which cause lots of extra
|
||||
// invalidations. There is ongoing work to add tags to primitives that
|
||||
// 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 {
|
||||
stacking_context.init_picture_caching(&self.clip_scroll_tree);
|
||||
|
||||
// Mark that a user supplied tile cache was specified.
|
||||
self.found_explicit_tile_cache = true;
|
||||
}
|
||||
|
||||
// If the parent context primitives list is empty, it's faster
|
||||
// to assign the storage of the popped context instead of paying
|
||||
// the copying cost for extend.
|
||||
if parent_sc.prim_list.is_empty() {
|
||||
parent_sc.prim_list = stacking_context.prim_list;
|
||||
} else {
|
||||
parent_sc.prim_list.extend(stacking_context.prim_list);
|
||||
}
|
||||
if stacking_context.clip_chain_id != ClipChainId::NONE {
|
||||
let prim = create_clip_prim_instance(
|
||||
stacking_context.clip_chain_id,
|
||||
PrimitiveInstanceKind::PopClipChain,
|
||||
);
|
||||
parent_sc.prim_list.add_prim(
|
||||
prim,
|
||||
LayoutSize::zero(),
|
||||
stacking_context.spatial_node_index,
|
||||
PrimitiveFlags::IS_BACKFACE_VISIBLE,
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
@ -1874,7 +1915,7 @@ impl<'a> SceneBuilder<'a> {
|
||||
None => true,
|
||||
};
|
||||
|
||||
if self.sc_stack.is_empty() {
|
||||
if stacking_context.create_tile_cache {
|
||||
self.setup_picture_caching(
|
||||
&mut stacking_context.prim_list,
|
||||
);
|
||||
@ -1907,6 +1948,35 @@ impl<'a> SceneBuilder<'a> {
|
||||
),
|
||||
};
|
||||
|
||||
// If no user supplied tile cache was specified, and picture caching is enabled,
|
||||
// create an implicit tile cache for the whole frame builder.
|
||||
// TODO(gw): This is only needed temporarily - once we support multiple slices
|
||||
// correctly, this will be handled by setup_picture_caching.
|
||||
if self.sc_stack.is_empty() &&
|
||||
!self.found_explicit_tile_cache &&
|
||||
self.config.enable_picture_caching {
|
||||
|
||||
let instance = create_tile_cache(
|
||||
0,
|
||||
ROOT_SPATIAL_NODE_INDEX,
|
||||
stacking_context.prim_list,
|
||||
self.config.background_color,
|
||||
Vec::new(),
|
||||
&mut self.interners,
|
||||
&mut self.prim_store,
|
||||
&mut self.clip_store,
|
||||
);
|
||||
|
||||
let mut prim_list = PrimitiveList::empty();
|
||||
prim_list.add_prim(
|
||||
instance,
|
||||
LayoutSize::zero(),
|
||||
ROOT_SPATIAL_NODE_INDEX,
|
||||
PrimitiveFlags::IS_BACKFACE_VISIBLE,
|
||||
);
|
||||
stacking_context.prim_list = prim_list;
|
||||
}
|
||||
|
||||
// Add picture for this actual stacking context contents to render into.
|
||||
let leaf_pic_index = PictureIndex(self.prim_store.pictures
|
||||
.alloc()
|
||||
@ -3509,61 +3579,6 @@ impl FlattenedStackingContext {
|
||||
self.transform_style == TransformStyle::Preserve3D && self.composite_ops.is_empty()
|
||||
}
|
||||
|
||||
/// Set up appropriate cluster flags for picture caching on this stacking context.
|
||||
fn init_picture_caching(
|
||||
&mut self,
|
||||
clip_scroll_tree: &ClipScrollTree,
|
||||
) {
|
||||
let mut selected_cluster_and_scroll_root = None;
|
||||
|
||||
// There's probably a tidier way to express the logic below, but we will be
|
||||
// removing this shortly anyway, as we create slices for more than just the
|
||||
// main scroll root.
|
||||
for (cluster_index, cluster) in self.prim_list.clusters.iter().enumerate() {
|
||||
let scroll_root = clip_scroll_tree.find_scroll_root(
|
||||
cluster.spatial_node_index,
|
||||
);
|
||||
if scroll_root != ROOT_SPATIAL_NODE_INDEX {
|
||||
match selected_cluster_and_scroll_root {
|
||||
Some((_, selected_scroll_root)) => {
|
||||
if selected_scroll_root != scroll_root {
|
||||
// Found multiple scroll roots - bail out and just cache fixed position
|
||||
selected_cluster_and_scroll_root = None;
|
||||
break;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
selected_cluster_and_scroll_root = Some((cluster_index, scroll_root));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Either set up a fixed root cache, or a scrolling one if there was only
|
||||
// a single scroll root found (the common case).
|
||||
match selected_cluster_and_scroll_root {
|
||||
Some((cluster_index, scroll_root)) => {
|
||||
let cluster = &mut self.prim_list.clusters[cluster_index];
|
||||
cluster.flags.insert(ClusterFlags::CREATE_PICTURE_CACHE_PRE);
|
||||
cluster.cache_scroll_root = Some(scroll_root);
|
||||
}
|
||||
None => {
|
||||
if let Some(cluster) = self.prim_list.clusters.first_mut() {
|
||||
cluster.flags.insert(ClusterFlags::CREATE_PICTURE_CACHE_PRE);
|
||||
cluster.cache_scroll_root = Some(ROOT_SPATIAL_NODE_INDEX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For now, always end the cache slice at the end of the stacking context.
|
||||
// This preserves existing behavior, but breaks in some cases on platforms
|
||||
// that use overlay scroll bars. We can fix this as a follow up once this
|
||||
// patch lands.
|
||||
if let Some(cluster) = self.prim_list.clusters.last_mut() {
|
||||
cluster.flags.insert(ClusterFlags::CREATE_PICTURE_CACHE_POST);
|
||||
}
|
||||
}
|
||||
|
||||
/// Return true if the stacking context isn't needed.
|
||||
pub fn is_redundant(
|
||||
&self,
|
||||
@ -3606,6 +3621,11 @@ impl FlattenedStackingContext {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If this stacking context gets picture caching, we need it.
|
||||
if self.create_tile_cache {
|
||||
return false;
|
||||
}
|
||||
|
||||
// It is redundant!
|
||||
true
|
||||
}
|
||||
@ -3894,21 +3914,3 @@ fn create_tile_cache(
|
||||
parent_clip_chain_id,
|
||||
)
|
||||
}
|
||||
|
||||
// Helper fn to collect clip handles from a given clip chain.
|
||||
fn add_clips(
|
||||
clip_chain_id: ClipChainId,
|
||||
prim_clips: &mut Vec<ClipDataHandle>,
|
||||
clip_store: &ClipStore,
|
||||
) {
|
||||
let mut current_clip_chain_id = clip_chain_id;
|
||||
|
||||
while current_clip_chain_id != ClipChainId::NONE {
|
||||
let clip_chain_node = &clip_store
|
||||
.clip_chain_nodes[current_clip_chain_id.0 as usize];
|
||||
|
||||
prim_clips.push(clip_chain_node.handle);
|
||||
|
||||
current_clip_chain_id = clip_chain_node.parent_clip_chain_id;
|
||||
}
|
||||
}
|
||||
|
@ -83,8 +83,8 @@ fuzzy-if(Android&&!webrender,3-3,4-4) fuzzy-if(Android&&webrender,13-13,4-4) fuz
|
||||
# checkerboarding to occur
|
||||
default-preferences pref(layers.low-precision-buffer,false)
|
||||
skip-if(!asyncPan) == checkerboard-1.html checkerboard-1-ref.html
|
||||
skip-if(!asyncPan) == checkerboard-2.html checkerboard-2-ref.html
|
||||
skip-if(!asyncPan) == checkerboard-3.html checkerboard-3-ref.html
|
||||
skip-if(!asyncPan) fails-if(geckoview&&webrender) == checkerboard-2.html checkerboard-2-ref.html
|
||||
skip-if(!asyncPan) fails-if(geckoview&&webrender) == checkerboard-3.html checkerboard-3-ref.html
|
||||
default-preferences
|
||||
|
||||
skip-if(!Android) pref(apz.allow_zooming,true) fails-if(geckoview&&webrender) == position-fixed-async-zoom-1.html position-fixed-async-zoom-1-ref.html
|
||||
|
Loading…
Reference in New Issue
Block a user