Bug 1584439 - Enable picture caching for scroll bars and UI content. r=nical
Once this patch lands, all content drawn by WebRender is drawn into a picture cache surface. This will incur some extra GPU memory overhead since there are extra GPU texture buffers. Much of this can be reduced by adding a couple of simple optimizations in future to detect tiles that are solid colors only. With this change, we'll now be able to provide exact dirty rects for the entire screen without any hacks, and start the work to draw into OS compositor surfaces directly. Differential Revision: https://phabricator.services.mozilla.com/D47395 --HG-- extra : moz-landing-system : lando
@ -34,7 +34,7 @@ use crate::render_task::{RenderTask, RenderTaskLocation, BlurTaskCache, ClearMod
|
||||
use crate::resource_cache::ResourceCache;
|
||||
use crate::scene::SceneProperties;
|
||||
use smallvec::SmallVec;
|
||||
use std::{mem, u8};
|
||||
use std::{mem, u8, marker};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use crate::texture_cache::TextureCacheHandle;
|
||||
use crate::util::{TransformedRectKind, MatrixHelpers, MaxRect, scale_factors, VecHelper, subtract_rect};
|
||||
@ -141,6 +141,8 @@ pub struct PictureCacheState {
|
||||
opacity_bindings: FastHashMap<PropertyBindingId, OpacityBindingInfo>,
|
||||
/// The current transform of the picture cache root spatial node
|
||||
root_transform: TransformKey,
|
||||
/// The current tile size in device pixels
|
||||
current_tile_size: DeviceIntSize,
|
||||
}
|
||||
|
||||
/// Stores a list of cached picture tiles that are retained
|
||||
@ -177,15 +179,19 @@ pub type TileOffset = Point2D<i32, TileCoordinate>;
|
||||
pub type TileSize = Size2D<i32, TileCoordinate>;
|
||||
pub type TileRect = Rect<i32, TileCoordinate>;
|
||||
|
||||
/// The size in device pixels of a cached tile. The currently chosen
|
||||
/// size is arbitrary. We should do some profiling to find the best
|
||||
/// size for real world pages.
|
||||
///
|
||||
/// Note that we use a separate, smaller size during wrench testing, so that
|
||||
/// we get tighter dirty rects and can do more meaningful invalidation
|
||||
/// tests.
|
||||
pub const TILE_SIZE_WIDTH: i32 = 2048;
|
||||
pub const TILE_SIZE_HEIGHT: i32 = 512;
|
||||
/// The size in device pixels of a normal cached tile.
|
||||
pub const TILE_SIZE_LARGE: DeviceIntSize = DeviceIntSize {
|
||||
width: 2048,
|
||||
height: 512,
|
||||
_unit: marker::PhantomData,
|
||||
};
|
||||
|
||||
/// The size in device pixels of a tile for small picture caches.
|
||||
pub const TILE_SIZE_SMALL: DeviceIntSize = DeviceIntSize {
|
||||
width: 128,
|
||||
height: 128,
|
||||
_unit: marker::PhantomData,
|
||||
};
|
||||
|
||||
/// The maximum size per axis of a surface,
|
||||
/// in WorldPixel coordinates.
|
||||
@ -286,6 +292,9 @@ struct TilePostUpdateContext<'a> {
|
||||
|
||||
/// Helper to map picture coordinates to world space
|
||||
pic_to_world_mapper: SpaceMapper<PicturePixel, WorldPixel>,
|
||||
|
||||
/// Current size in device pixels of tiles for this cache
|
||||
current_tile_size: DeviceIntSize,
|
||||
}
|
||||
|
||||
// Mutable state passed to picture cache tiles during post_update
|
||||
@ -628,10 +637,20 @@ impl Tile {
|
||||
return false;
|
||||
}
|
||||
|
||||
// For small tiles, only allow splitting once, since otherwise we
|
||||
// end up splitting into tiny dirty rects that aren't saving much
|
||||
// in the way of pixel work.
|
||||
let max_split_level = if ctx.current_tile_size == TILE_SIZE_LARGE {
|
||||
3
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
// Consider splitting / merging dirty regions
|
||||
self.root.maybe_merge_or_split(
|
||||
0,
|
||||
&self.current_descriptor.prims,
|
||||
max_split_level,
|
||||
);
|
||||
|
||||
// See if this tile is a simple color, in which case we can just draw
|
||||
@ -715,12 +734,8 @@ impl Tile {
|
||||
// Ensure that this texture is allocated.
|
||||
if let TileSurface::Texture { ref mut handle, ref mut visibility_mask } = surface {
|
||||
if !state.resource_cache.texture_cache.is_allocated(handle) {
|
||||
let tile_size = DeviceIntSize::new(
|
||||
TILE_SIZE_WIDTH,
|
||||
TILE_SIZE_HEIGHT,
|
||||
);
|
||||
state.resource_cache.texture_cache.update_picture_cache(
|
||||
tile_size,
|
||||
ctx.current_tile_size,
|
||||
handle,
|
||||
state.gpu_cache,
|
||||
);
|
||||
@ -1081,6 +1096,8 @@ pub struct TileCacheInstance {
|
||||
/// between display lists - this seems very unlikely to occur on most pages, but
|
||||
/// can be revisited if we ever notice that.
|
||||
pub slice: usize,
|
||||
/// The currently selected tile size to use for this cache
|
||||
pub current_tile_size: DeviceIntSize,
|
||||
/// The positioning node for this tile cache.
|
||||
pub spatial_node_index: SpatialNodeIndex,
|
||||
/// Hash of tiles present in this picture.
|
||||
@ -1175,6 +1192,7 @@ impl TileCacheInstance {
|
||||
root_transform: TransformKey::Local,
|
||||
shared_clips,
|
||||
shared_clip_chain,
|
||||
current_tile_size: DeviceIntSize::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1221,8 +1239,6 @@ impl TileCacheInstance {
|
||||
frame_context: &FrameVisibilityContext,
|
||||
frame_state: &mut FrameVisibilityState,
|
||||
) -> WorldRect {
|
||||
let tile_width = TILE_SIZE_WIDTH;
|
||||
let tile_height = TILE_SIZE_HEIGHT;
|
||||
self.surface_index = surface_index;
|
||||
self.local_rect = pic_rect;
|
||||
self.local_clip_rect = PictureRect::max_rect();
|
||||
@ -1292,6 +1308,26 @@ impl TileCacheInstance {
|
||||
self.root_transform = prev_state.root_transform;
|
||||
self.spatial_nodes = prev_state.spatial_nodes;
|
||||
self.opacity_bindings = prev_state.opacity_bindings;
|
||||
self.current_tile_size = prev_state.current_tile_size;
|
||||
}
|
||||
|
||||
// Work out what size tile is appropriate for this picture cache.
|
||||
let desired_tile_size = if pic_rect.size.width < 2.0 * TILE_SIZE_SMALL.width as f32 ||
|
||||
pic_rect.size.height < 2.0 * TILE_SIZE_SMALL.height as f32 {
|
||||
TILE_SIZE_SMALL
|
||||
} else {
|
||||
TILE_SIZE_LARGE
|
||||
};
|
||||
|
||||
// If the desired tile size has changed, then invalidate and drop any
|
||||
// existing tiles.
|
||||
// TODO(gw): This could in theory result in invalidating every frame if the
|
||||
// size of a picture is dynamically changing, just around the
|
||||
// threshold above. If we ever see this happening we can improve
|
||||
// the theshold logic above.
|
||||
if desired_tile_size != self.current_tile_size {
|
||||
self.tiles.clear();
|
||||
self.current_tile_size = desired_tile_size;
|
||||
}
|
||||
|
||||
// Map an arbitrary point in picture space to world space, to work out
|
||||
@ -1352,8 +1388,8 @@ impl TileCacheInstance {
|
||||
}
|
||||
|
||||
let world_tile_size = WorldSize::new(
|
||||
tile_width as f32 / frame_context.global_device_pixel_scale.0,
|
||||
tile_height as f32 / frame_context.global_device_pixel_scale.0,
|
||||
self.current_tile_size.width as f32 / frame_context.global_device_pixel_scale.0,
|
||||
self.current_tile_size.height as f32 / frame_context.global_device_pixel_scale.0,
|
||||
);
|
||||
|
||||
// We know that this is an exact rectangle, since we (for now) only support tile
|
||||
@ -1760,6 +1796,7 @@ impl TileCacheInstance {
|
||||
spatial_nodes: &self.spatial_nodes,
|
||||
opacity_bindings: &self.opacity_bindings,
|
||||
pic_to_world_mapper,
|
||||
current_tile_size: self.current_tile_size,
|
||||
};
|
||||
|
||||
let mut state = TilePostUpdateState {
|
||||
@ -2248,6 +2285,8 @@ bitflags! {
|
||||
const CREATE_PICTURE_CACHE_PRE = 16;
|
||||
/// Force creation of a picture caching slice after this cluster.
|
||||
const CREATE_PICTURE_CACHE_POST = 32;
|
||||
/// If set, this cluster represents a scroll bar container.
|
||||
const SCROLLBAR_CONTAINER = 64;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2368,6 +2407,10 @@ impl PrimitiveList {
|
||||
flags.insert(ClusterFlags::IS_BACKFACE_VISIBLE);
|
||||
}
|
||||
|
||||
if prim_flags.contains(PrimitiveFlags::IS_SCROLLBAR_CONTAINER) {
|
||||
flags.insert(ClusterFlags::SCROLLBAR_CONTAINER);
|
||||
}
|
||||
|
||||
// Insert the primitive into the first or last cluster as required
|
||||
match insert_position {
|
||||
PrimitiveListPosition::Begin => {
|
||||
@ -2628,6 +2671,7 @@ impl PicturePrimitive {
|
||||
opacity_bindings: tile_cache.opacity_bindings,
|
||||
fract_offset: tile_cache.fract_offset,
|
||||
root_transform: tile_cache.root_transform,
|
||||
current_tile_size: tile_cache.current_tile_size,
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -3034,11 +3078,6 @@ impl PicturePrimitive {
|
||||
let tile_cache = self.tile_cache.as_mut().unwrap();
|
||||
let mut first = true;
|
||||
|
||||
let tile_size = DeviceSize::new(
|
||||
TILE_SIZE_WIDTH as f32,
|
||||
TILE_SIZE_HEIGHT as f32,
|
||||
);
|
||||
|
||||
for key in &tile_cache.tiles_to_draw {
|
||||
let tile = tile_cache.tiles.get_mut(key).expect("bug: no tile found!");
|
||||
|
||||
@ -3080,9 +3119,9 @@ impl PicturePrimitive {
|
||||
RenderTaskLocation::PictureCache {
|
||||
texture: cache_item.texture_id,
|
||||
layer: cache_item.texture_layer,
|
||||
size: tile_size.to_i32(),
|
||||
size: tile_cache.current_tile_size,
|
||||
},
|
||||
tile_size,
|
||||
tile_cache.current_tile_size.to_f32(),
|
||||
pic_index,
|
||||
content_origin.to_i32(),
|
||||
UvRectKind::Rect,
|
||||
@ -4168,7 +4207,7 @@ impl TileNode {
|
||||
let world_rect = pic_to_world_mapper.map(&self.rect).unwrap();
|
||||
let device_rect = world_rect * global_device_pixel_scale;
|
||||
|
||||
let outer_color = color.scale_alpha(0.6);
|
||||
let outer_color = color.scale_alpha(0.3);
|
||||
let inner_color = outer_color.scale_alpha(0.5);
|
||||
scratch.push_debug_rect(
|
||||
device_rect.inflate(-3.0, -3.0),
|
||||
@ -4268,6 +4307,7 @@ impl TileNode {
|
||||
&self,
|
||||
level: i32,
|
||||
can_merge: bool,
|
||||
max_split_levels: i32,
|
||||
) -> Option<TileModification> {
|
||||
match self.kind {
|
||||
TileNodeKind::Leaf { dirty_tracker, frames_since_modified, .. } => {
|
||||
@ -4275,7 +4315,7 @@ impl TileNode {
|
||||
if frames_since_modified > 64 {
|
||||
let dirty_frames = dirty_tracker.count_ones();
|
||||
// If the tree isn't too deep, and has been regularly invalidating, split
|
||||
if level < 3 && dirty_frames > 32 {
|
||||
if level < max_split_levels && dirty_frames > 32 {
|
||||
Some(TileModification::Split)
|
||||
} else if can_merge && (dirty_tracker == 0 || dirty_frames == 64) && level > 0 {
|
||||
// If allowed to merge, and nothing has changed for 64 frames, merge
|
||||
@ -4298,15 +4338,16 @@ impl TileNode {
|
||||
&mut self,
|
||||
level: i32,
|
||||
curr_prims: &[PrimitiveDescriptor],
|
||||
max_split_levels: i32,
|
||||
) {
|
||||
// Determine if this tile wants to split or merge
|
||||
let tile_mod = match self.kind {
|
||||
TileNodeKind::Leaf { .. } => {
|
||||
self.get_preference(level, false)
|
||||
self.get_preference(level, false, max_split_levels)
|
||||
}
|
||||
TileNodeKind::Node { ref children, .. } => {
|
||||
// Only merge if all children want to merge
|
||||
if children.iter().all(|c| c.get_preference(level+1, true) == Some(TileModification::Merge)) {
|
||||
if children.iter().all(|c| c.get_preference(level+1, true, max_split_levels) == Some(TileModification::Merge)) {
|
||||
Some(TileModification::Merge)
|
||||
} else {
|
||||
None
|
||||
@ -4396,6 +4437,7 @@ impl TileNode {
|
||||
child.maybe_merge_or_split(
|
||||
level+1,
|
||||
curr_prims,
|
||||
max_split_levels,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ use crate::internal_types::{CacheTextureId, DebugOutput, FastHashMap, FastHashSe
|
||||
use crate::internal_types::{TextureCacheAllocationKind, TextureCacheUpdate, TextureUpdateList, TextureUpdateSource};
|
||||
use crate::internal_types::{RenderTargetInfo, SavedTargetIndex, Swizzle};
|
||||
use malloc_size_of::MallocSizeOfOps;
|
||||
use crate::picture::{RecordedDirtyRegion, TILE_SIZE_WIDTH, TILE_SIZE_HEIGHT};
|
||||
use crate::picture::{RecordedDirtyRegion, TILE_SIZE_LARGE, TILE_SIZE_SMALL};
|
||||
use crate::prim_store::DeferredResolve;
|
||||
use crate::profiler::{BackendProfileCounters, FrameProfileCounters, TimeProfileCounter,
|
||||
GpuProfileTag, RendererProfileCounters, RendererProfileTimers};
|
||||
@ -2150,7 +2150,8 @@ impl Renderer {
|
||||
}
|
||||
|
||||
let picture_tile_sizes = &[
|
||||
DeviceIntSize::new(TILE_SIZE_WIDTH, TILE_SIZE_HEIGHT),
|
||||
TILE_SIZE_LARGE,
|
||||
TILE_SIZE_SMALL,
|
||||
];
|
||||
|
||||
let texture_cache = TextureCache::new(
|
||||
|
@ -487,13 +487,11 @@ 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);
|
||||
}
|
||||
// Unconditionally insert a marker to create a picture cache slice on the
|
||||
// first cluster. This handles implicit picture caches, and also the common
|
||||
// case, by allowing the root / background primitives to be cached in a slice.
|
||||
if let Some(cluster) = main_prim_list.clusters.first_mut() {
|
||||
cluster.flags.insert(ClusterFlags::CREATE_PICTURE_CACHE_PRE);
|
||||
}
|
||||
|
||||
// List of slices that have been found
|
||||
@ -623,36 +621,35 @@ impl<'a> SceneBuilder<'a> {
|
||||
|
||||
// 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 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,
|
||||
);
|
||||
// If the cluster specifies a scroll root, use it. Otherwise,
|
||||
// just cache assuming no scrolling takes place. Even if that's
|
||||
// not true, we still get caching benefits for any changes that
|
||||
// occur while not scrolling (such as animation, video etc);
|
||||
let scroll_root = slice.cache_scroll_root.unwrap_or(ROOT_SPATIAL_NODE_INDEX);
|
||||
|
||||
main_prim_list.add_prim(
|
||||
instance,
|
||||
LayoutSize::zero(),
|
||||
scroll_root,
|
||||
PrimitiveFlags::IS_BACKFACE_VISIBLE,
|
||||
);
|
||||
}
|
||||
None => {
|
||||
main_prim_list.extend(slice.prim_list);
|
||||
}
|
||||
}
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3521,51 +3518,71 @@ impl FlattenedStackingContext {
|
||||
&mut self,
|
||||
clip_scroll_tree: &ClipScrollTree,
|
||||
) {
|
||||
let mut selected_cluster_and_scroll_root = None;
|
||||
struct SliceInfo {
|
||||
cluster_index: usize,
|
||||
scroll_roots: Vec<SpatialNodeIndex>,
|
||||
}
|
||||
|
||||
// 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.
|
||||
let mut slices: Vec<SliceInfo> = Vec::new();
|
||||
|
||||
// Step through each cluster, and work out where the slice boundaries should be.
|
||||
for (cluster_index, cluster) in self.prim_list.clusters.iter().enumerate() {
|
||||
let scroll_root = clip_scroll_tree.find_scroll_root(
|
||||
cluster.spatial_node_index,
|
||||
);
|
||||
|
||||
// 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
|
||||
// (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()
|
||||
}).unwrap_or(true);
|
||||
|
||||
// Create a new slice if required
|
||||
if create_new_slice {
|
||||
slices.push(SliceInfo {
|
||||
cluster_index,
|
||||
scroll_roots: Vec::new(),
|
||||
});
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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));
|
||||
}
|
||||
let slice = slices.last_mut().unwrap();
|
||||
if !slice.scroll_roots.contains(&scroll_root) {
|
||||
slice.scroll_roots.push(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);
|
||||
}
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
// Always end the cache at the end of the stacking context, so that we don't
|
||||
// cache anything from primitives outside this pipeline in the same slice.
|
||||
if let Some(cluster) = self.prim_list.clusters.last_mut() {
|
||||
cluster.flags.insert(ClusterFlags::CREATE_PICTURE_CACHE_POST);
|
||||
}
|
||||
@ -3613,6 +3630,11 @@ impl FlattenedStackingContext {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If this stacking context is a scrollbar, retain it so it can form a picture cache slice
|
||||
if self.prim_flags.contains(PrimitiveFlags::IS_SCROLLBAR_CONTAINER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// It is redundant!
|
||||
true
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
@ -5,7 +5,7 @@ platform(linux,mac) == border-gradient-nine-patch.yaml border-gradient-nine-patc
|
||||
platform(linux,mac) == border-radial-gradient-nine-patch.yaml border-radial-gradient-nine-patch.png
|
||||
== border-radii.yaml border-radii.png
|
||||
== border-none.yaml border-none-ref.yaml
|
||||
fuzzy(1,68) == border-overlapping-corner.yaml border-overlapping-corner-ref.yaml
|
||||
fuzzy(128,69) == border-overlapping-corner.yaml border-overlapping-corner-ref.yaml
|
||||
== border-overlapping-edge.yaml border-overlapping-edge-ref.yaml
|
||||
== border-invisible.yaml border-invisible-ref.yaml
|
||||
platform(linux,mac) == border-suite.yaml border-suite.png
|
||||
|
@ -9,7 +9,7 @@ fuzzy(8,60) == custom-clip-chains.yaml custom-clip-chains-ref.yaml
|
||||
== fixed-position-clipping.yaml fixed-position-clipping-ref.yaml
|
||||
platform(linux,mac) == segmentation-with-other-coordinate-system-clip.yaml segmentation-with-other-coordinate-system-clip.png
|
||||
== segmentation-across-rotation.yaml segmentation-across-rotation-ref.yaml
|
||||
skip_on(android,device) == color_targets(3) alpha_targets(1) stacking-context-clip.yaml stacking-context-clip-ref.yaml
|
||||
skip_on(android,device) == color_targets(4) alpha_targets(1) stacking-context-clip.yaml stacking-context-clip-ref.yaml
|
||||
== snapping.yaml snapping-ref.yaml
|
||||
fuzzy(70,2400) == clip-and-filter-with-rotation.yaml clip-and-filter-with-rotation-ref.yaml
|
||||
color_targets(1) alpha_targets(0) == clip-out-rotation.yaml blank.yaml # Unexpected color targets, see bug 1580795
|
||||
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@ -7,7 +7,7 @@ skip_on(android,emulator) == nested-mask-tiling.yaml nested-mask-ref.yaml # And
|
||||
== mask-transformed-to-empty-rect.yaml mask-transformed-to-empty-rect-ref.yaml
|
||||
platform(linux,mac) == rounded-corners.yaml rounded-corners.png
|
||||
!= mask.yaml out-of-bounds.yaml
|
||||
platform(linux,mac) fuzzy(1,17500) color_targets(3) alpha_targets(1) == mask-atomicity.yaml mask-atomicity-ref.yaml
|
||||
platform(linux,mac) fuzzy(1,17500) color_targets(6) alpha_targets(1) == mask-atomicity.yaml mask-atomicity-ref.yaml
|
||||
platform(linux,mac) fuzzy(1,17500) == mask-atomicity-tiling.yaml mask-atomicity-ref.yaml
|
||||
platform(linux,mac) == mask-perspective.yaml mask-perspective.png
|
||||
skip_on(android,emulator) == fuzzy(1,7) mask-perspective-tiling.yaml mask-perspective.yaml # Android emulator: GL error 502 at tex_sub_image_3d_pbo, fails on opt
|
||||
|
@ -1 +1 @@
|
||||
skip_on(android) == color_targets(2) alpha_targets(0) no-clip-mask.yaml no-clip-mask.png # Too wide for Android
|
||||
skip_on(android) == color_targets(4) alpha_targets(0) no-clip-mask.yaml no-clip-mask.png # Too wide for Android
|
||||
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
@ -50,9 +50,9 @@ fuzzy(0-1,0-60000) skip-if(!asyncPan) == group-opacity-surface-size-1.html group
|
||||
fuzzy-if(Android,0-1,0-197) fuzzy-if(webrender,0-1,0-1) skip-if(!asyncPan) == position-sticky-transformed.html position-sticky-transformed-ref.html
|
||||
skip-if(!asyncPan) == offscreen-prerendered-active-opacity.html offscreen-prerendered-active-opacity-ref.html
|
||||
fuzzy-if(Android,0-6,0-4) fuzzy-if(skiaContent&&!Android,0-1,0-34) fuzzy-if(webrender&>kWidget,64-64,24-24) fuzzy-if(webrender&&cocoaWidget,7-7,37-37) skip-if(!asyncPan) == offscreen-clipped-blendmode-1.html offscreen-clipped-blendmode-ref.html
|
||||
fuzzy-if(Android,0-6,0-4) fuzzy-if(webrender&>kWidget,64-64,14-14) fuzzy-if(webrender&&cocoaWidget,7-7,37-37) skip-if(!asyncPan) == offscreen-clipped-blendmode-2.html offscreen-clipped-blendmode-ref.html
|
||||
fuzzy-if(Android,0-6,0-4) fuzzy-if(webrender&>kWidget,64-64,24-24) fuzzy-if(webrender&&cocoaWidget,7-7,37-37) skip-if(!asyncPan) == offscreen-clipped-blendmode-2.html offscreen-clipped-blendmode-ref.html
|
||||
fuzzy-if(Android,0-6,0-4) skip == offscreen-clipped-blendmode-3.html offscreen-clipped-blendmode-ref.html # bug 1251588 - wrong AGR on mix-blend-mode item
|
||||
fuzzy-if(Android,0-6,0-4) fuzzy-if(webrender&>kWidget,64-64,14-14) fuzzy-if(webrender&&cocoaWidget,7-7,37-37) skip-if(!asyncPan) == offscreen-clipped-blendmode-4.html offscreen-clipped-blendmode-ref.html
|
||||
fuzzy-if(Android,0-6,0-4) fuzzy-if(webrender&>kWidget,64-64,24-24) fuzzy-if(webrender&&cocoaWidget,7-7,37-37) skip-if(!asyncPan) == offscreen-clipped-blendmode-4.html offscreen-clipped-blendmode-ref.html
|
||||
fuzzy-if(Android,0-7,0-1406) fuzzy-if(webrender&>kWidget,1-1,20-20) fuzzy-if(webrender&&cocoaWidget,1-1,19-19) skip-if(!asyncPan) == perspective-scrolling-1.html perspective-scrolling-1-ref.html
|
||||
fuzzy-if(Android,0-7,0-4) skip-if(!asyncPan) == perspective-scrolling-2.html perspective-scrolling-2-ref.html
|
||||
fuzzy-if(Android,0-19,0-4) fuzzy-if(webrender&>kWidget,24-24,14-14) fuzzy-if(webrender&&cocoaWidget,13-13,39-39) skip-if(!asyncPan) == perspective-scrolling-3.html perspective-scrolling-3-ref.html
|
||||
|
@ -51,5 +51,5 @@ fuzzy-if(Android,0-8,0-630) fuzzy-if(OSX,0-1,0-11) fuzzy-if(skiaContent,0-1,0-22
|
||||
== iframe-1.html iframe-1-ref.html
|
||||
== transformed-1.html transformed-1-ref.html
|
||||
fuzzy-if(Android,0-4,0-4) fuzzy-if(webrender&>kWidget,31-31,24-24) fuzzy-if(webrender&&cocoaWidget,8-8,37-37) skip-if(!asyncPan) == transformed-2.html transformed-2-ref.html
|
||||
skip-if(!asyncPan) fuzzy-if(Android,0-10,0-4) fuzzy-if(webrender&>kWidget,57-57,24-24) fuzzy-if(webrender&&cocoaWidget,16-16,40-40) == nested-sticky-1.html nested-sticky-1-ref.html
|
||||
skip-if(!asyncPan) fuzzy-if(Android,0-10,0-4) fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu),0-4,0-104) fuzzy-if(webrender&>kWidget,57-57,24-24) fuzzy-if(webrender&&cocoaWidget,16-16,40-40) == nested-sticky-2.html nested-sticky-2-ref.html
|
||||
skip-if(!asyncPan) fuzzy-if(Android,0-10,0-4) fuzzy-if(webrender&>kWidget,56-56,24-24) fuzzy-if(webrender&&cocoaWidget,16-16,40-40) == nested-sticky-1.html nested-sticky-1-ref.html
|
||||
skip-if(!asyncPan) fuzzy-if(Android,0-10,0-4) fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu),0-4,0-104) fuzzy-if(webrender&>kWidget,56-56,24-24) fuzzy-if(webrender&&cocoaWidget,16-16,40-40) == nested-sticky-2.html nested-sticky-2-ref.html
|
||||
|