Bug 1749380 - Improve how WR handles bounding rects for off-screen surfaces r=gfx-reviewers,kvark
This patch introduces a number of subtle but important changes to how we deal with off-screen surfaces. The overall goals are: - Improve rendering correctness in a number of edge cases. - Begin reducing complexity related to surfaces, scaling factors, surface size adjustments and clipping. - Improve CPU performance by removing some per-primitive work. - Simplify implementation of future SVG and CSS filters by having explicit support for picture rects + inflation regions. - Lay the groundwork for caching child picture surfaces, reduction of per-primitive work during visibility pass, simplifying picture code. Unfortunately, the nature of the changes make it impossible to split up in to small isolated patches. Details below: * Introduce `LocalRectKind` concept. This allows us to separate out the bounding rect of the surface (a group of primitives backed by a texture) from the bounding rect of the picture compositing that surface (e.g. a drop-shadow which draws the surface once at the local origin and once at a specific offset + blur-radius). This fixes a number of correctness bugs we have related to culling, clipping, invalidation regions of complex primitives such as drop-shadows and blur filters. Importantly, it makes it simpler to implement (or fix) SVG filter chains, backdrop-filter implementations. * Establish raster roots for all off-screen surfaces. Every off-screen surface uses the spatial node of the enclosing stacking context as a coordinate system root, ensuring that each off-screen surface is drawn in a 2D coordinate system, with appropriate scaling factors applied to ensure high quality rendering. The primary goal is to make it possible to correctly inflate and clip off-screen surfaces, removing some correctness issues we currently have with complex filters interacting with transforms. The initial work here doesn't reduce complexity a huge amount, but will allow us to simplify large parts of the picture/surface handling code in future, as well as simplify a number of shaders that currently must handle arbitrarily complex transform matrices. This will also allow us to simplify the implementation of features such as mix-blend-mode and backdrop-filter, which rely on readback and UV mapping from the parent surface. * Remove concepts of `estimated` and `precise` local rects for pictures. This is both a performance optimization and a code simplification. Instead, we only determine the estimated local rect during bounding rect propagation, and rely on the clipping regions from the tile dirty regions to reduce which parts of the picture we allocate if drawing to an off-screen surface. This removes some per-primitive work during the visibility pass, and also means we can rely on the final picture bounding rect from the start of the visibility pass. This also removes much of the complexity in `take_context` where we previously determined surface scale factors and device pixel ratio - instead these can be determined earlier during `propagate_bounding_rects`. * Remove some complexity in `update_prim_visibility`. This is still recursive, but follow up patches will aim to remove this recursion and integrate this pass with the picture graph (similar to how `propagate_bounding_rects` works). * Remove `PictureOptions` struct. Instead, store `inflate_if_required` with the Blur filter enum, which is the only place that uses it. * Remove `root_scaling_factor` from text runs - this is handled implicitly by the surface device-pixel scale. * Skip calling `update_clip_task` for pass-through pictures (since they have no defined local rect). * Improve scaling factors used for determining the render task cache size for complex line decorations. Differential Revision: https://phabricator.services.mozilla.com/D137569
|
@ -20,7 +20,7 @@ fails-if(useDrawSnapshot) == 1501195.html 1501195-ref.html
|
|||
== 1519754.html 1519754-ref.html
|
||||
skip-if(!asyncPan) == 1524261.html 1524261-ref.html
|
||||
fuzzy-if(!useDrawSnapshot,14-14,44-95) == 1524353.html 1524353-ref.html
|
||||
fuzzy-if(!useDrawSnapshot,2-7,17500-36908) == 1523776.html 1523776-ref.html
|
||||
== 1523776.html 1523776-ref.html
|
||||
== bug1523410-translate-scale-snap.html bug1523410-translate-scale-snap-ref.html
|
||||
== 1523080.html 1523080-ref.html
|
||||
== 1616444-same-color-different-paths.html 1616444-same-color-different-paths-ref.html
|
||||
|
|
|
@ -952,8 +952,14 @@ impl BatchBuilder {
|
|||
render_tasks,
|
||||
).unwrap();
|
||||
|
||||
let prim_rect = ctx.data_stores.get_local_prim_rect(
|
||||
child_prim_instance,
|
||||
&ctx.prim_store.pictures,
|
||||
ctx.surfaces,
|
||||
);
|
||||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: pic.precise_local_rect,
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: child_prim_info.combined_local_clip_rect,
|
||||
specific_prim_address: GpuCacheAddress::INVALID,
|
||||
transform_id: transforms
|
||||
|
@ -964,11 +970,6 @@ impl BatchBuilder {
|
|||
),
|
||||
};
|
||||
|
||||
let raster_config = pic
|
||||
.raster_config
|
||||
.as_ref()
|
||||
.expect("BUG: 3d primitive was not assigned a surface");
|
||||
|
||||
let child_pic_task_id = pic
|
||||
.primary_render_task_id
|
||||
.unwrap();
|
||||
|
@ -988,7 +989,7 @@ impl BatchBuilder {
|
|||
|
||||
let prim_header_index = prim_headers.push(&prim_header, z_id, [
|
||||
uv_rect_address.as_int(),
|
||||
if raster_config.establishes_raster_root { 1 } else { 0 },
|
||||
BrushFlags::PERSPECTIVE_INTERPOLATION.bits() as i32,
|
||||
0,
|
||||
child_clip_task_address.0 as i32,
|
||||
]);
|
||||
|
@ -1071,7 +1072,8 @@ impl BatchBuilder {
|
|||
|
||||
let prim_rect = ctx.data_stores.get_local_prim_rect(
|
||||
prim_instance,
|
||||
ctx.prim_store,
|
||||
&ctx.prim_store.pictures,
|
||||
ctx.surfaces,
|
||||
);
|
||||
|
||||
let mut batch_features = BatchFeatures::empty();
|
||||
|
@ -1539,7 +1541,7 @@ impl BatchBuilder {
|
|||
let prim_cache_address = gpu_cache.get_address(&ctx.globals.default_image_handle);
|
||||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: picture.precise_local_rect,
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
|
@ -1561,16 +1563,12 @@ impl BatchBuilder {
|
|||
Some(ref raster_config) => {
|
||||
// If the child picture was rendered in local space, we can safely
|
||||
// interpolate the UV coordinates with perspective correction.
|
||||
let brush_flags = if raster_config.establishes_raster_root {
|
||||
BrushFlags::PERSPECTIVE_INTERPOLATION
|
||||
} else {
|
||||
BrushFlags::empty()
|
||||
};
|
||||
let brush_flags = BrushFlags::PERSPECTIVE_INTERPOLATION;
|
||||
|
||||
let surface = &ctx.surfaces[raster_config.surface_index.0];
|
||||
|
||||
let mut is_opaque = prim_info.clip_task_index == ClipTaskIndex::INVALID
|
||||
&& surface.opaque_rect.contains_box(&surface.rect)
|
||||
&& surface.is_opaque
|
||||
&& transform_kind == TransformedRectKind::AxisAligned;
|
||||
|
||||
let pic_task_id = picture.primary_render_task_id.unwrap();
|
||||
|
@ -1585,7 +1583,7 @@ impl BatchBuilder {
|
|||
PictureCompositeMode::Filter(ref filter) => {
|
||||
assert!(filter.is_visible());
|
||||
match filter {
|
||||
Filter::Blur(..) => {
|
||||
Filter::Blur { .. } => {
|
||||
let (clip_task_address, clip_mask_texture_id) = ctx.get_prim_clip_task_and_texture(
|
||||
prim_info.clip_task_index,
|
||||
render_tasks,
|
||||
|
@ -1824,7 +1822,7 @@ impl BatchBuilder {
|
|||
|
||||
// These filters are handled via different paths.
|
||||
Filter::ComponentTransfer |
|
||||
Filter::Blur(..) |
|
||||
Filter::Blur { .. } |
|
||||
Filter::DropShadows(..) |
|
||||
Filter::Opacity(..) => unreachable!(),
|
||||
};
|
||||
|
@ -2111,7 +2109,7 @@ impl BatchBuilder {
|
|||
};
|
||||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: picture.precise_local_rect,
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
|
@ -3042,9 +3040,8 @@ impl BatchBuilder {
|
|||
);
|
||||
|
||||
let prim_cache_address = gpu_cache.get_address(&ctx.globals.default_image_handle);
|
||||
let backdrop_picture = &ctx.prim_store.pictures[backdrop_pic_index.0];
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: backdrop_picture.precise_local_rect,
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
transform_id,
|
||||
specific_prim_address: prim_cache_address,
|
||||
|
|
|
@ -32,7 +32,7 @@ use crate::space::SpaceMapper;
|
|||
use crate::segment::SegmentBuilder;
|
||||
use std::{f32, mem};
|
||||
use crate::util::{VecHelper, Preallocator};
|
||||
use crate::visibility::{update_primitive_visibility, FrameVisibilityState, FrameVisibilityContext};
|
||||
use crate::visibility::{update_prim_visibility, FrameVisibilityState, FrameVisibilityContext};
|
||||
use plane_split::Splitter;
|
||||
|
||||
|
||||
|
@ -125,7 +125,7 @@ impl FrameGlobalResources {
|
|||
|
||||
pub struct FrameScratchBuffer {
|
||||
dirty_region_stack: Vec<DirtyRegion>,
|
||||
surface_stack: Vec<SurfaceIndex>,
|
||||
surface_stack: Vec<(PictureIndex, SurfaceIndex)>,
|
||||
clip_chain_stack: ClipChainStack,
|
||||
}
|
||||
|
||||
|
@ -204,12 +204,13 @@ impl<'a> FrameBuildingState<'a> {
|
|||
&mut self,
|
||||
surface_index: SurfaceIndex,
|
||||
tasks: Vec<RenderTaskId>,
|
||||
raster_rect: DeviceRect,
|
||||
clipping_rect: PictureRect,
|
||||
) {
|
||||
let surface = &mut self.surfaces[surface_index.0];
|
||||
assert!(surface.render_tasks.is_none());
|
||||
surface.render_tasks = Some(SurfaceRenderTasks::Tiled(tasks));
|
||||
surface.raster_rect = Some(raster_rect);
|
||||
// TODO(gw): Include the dirty rect here, to reduce child surface sizes
|
||||
surface.clipping_rect = clipping_rect;
|
||||
}
|
||||
|
||||
/// Initialize render tasks for a simple surface, that contains only a
|
||||
|
@ -219,12 +220,12 @@ impl<'a> FrameBuildingState<'a> {
|
|||
surface_index: SurfaceIndex,
|
||||
task_id: RenderTaskId,
|
||||
parent_surface_index: SurfaceIndex,
|
||||
raster_rect: DeviceRect,
|
||||
clipping_rect: PictureRect,
|
||||
) {
|
||||
let surface = &mut self.surfaces[surface_index.0];
|
||||
assert!(surface.render_tasks.is_none());
|
||||
surface.render_tasks = Some(SurfaceRenderTasks::Simple(task_id));
|
||||
surface.raster_rect = Some(raster_rect);
|
||||
surface.clipping_rect = clipping_rect;
|
||||
|
||||
self.add_child_render_task(
|
||||
parent_surface_index,
|
||||
|
@ -241,12 +242,12 @@ impl<'a> FrameBuildingState<'a> {
|
|||
root_task_id: RenderTaskId,
|
||||
port_task_id: RenderTaskId,
|
||||
parent_surface_index: SurfaceIndex,
|
||||
raster_rect: DeviceRect,
|
||||
clipping_rect: PictureRect,
|
||||
) {
|
||||
let surface = &mut self.surfaces[surface_index.0];
|
||||
assert!(surface.render_tasks.is_none());
|
||||
surface.render_tasks = Some(SurfaceRenderTasks::Chained { root_task_id, port_task_id });
|
||||
surface.raster_rect = Some(raster_rect);
|
||||
surface.clipping_rect = clipping_rect;
|
||||
|
||||
self.add_child_render_task(
|
||||
parent_surface_index,
|
||||
|
@ -375,7 +376,6 @@ impl FrameBuilder {
|
|||
global_device_pixel_scale,
|
||||
spatial_tree,
|
||||
global_screen_world_rect,
|
||||
surfaces: &mut scene.surfaces,
|
||||
debug_flags,
|
||||
scene_properties,
|
||||
config: scene.config,
|
||||
|
@ -405,8 +405,9 @@ impl FrameBuilder {
|
|||
// 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 surface = &scene.surfaces[surface_index.0];
|
||||
let world_culling_rect = tile_cache.pre_update(
|
||||
layout_rect_as_picture_rect(&pic.estimated_local_rect),
|
||||
surface.local_rect,
|
||||
surface_index,
|
||||
&visibility_context,
|
||||
&mut visibility_state,
|
||||
|
@ -415,21 +416,23 @@ impl FrameBuilder {
|
|||
// 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(
|
||||
*pic_index,
|
||||
surface_index,
|
||||
&tile_cache.shared_clips,
|
||||
frame_context.spatial_tree,
|
||||
);
|
||||
|
||||
update_primitive_visibility(
|
||||
&mut scene.prim_store,
|
||||
update_prim_visibility(
|
||||
*pic_index,
|
||||
None,
|
||||
&world_culling_rect,
|
||||
&mut scene.prim_store,
|
||||
&mut scene.prim_instances,
|
||||
&mut scene.surfaces,
|
||||
true,
|
||||
&visibility_context,
|
||||
&mut visibility_state,
|
||||
tile_cache,
|
||||
true,
|
||||
&mut scene.prim_instances,
|
||||
);
|
||||
|
||||
// Build the dirty region(s) for this tile cache.
|
||||
|
|
|
@ -208,7 +208,11 @@ const OPACITY_EPSILON: f32 = 0.001;
|
|||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub enum Filter {
|
||||
Identity,
|
||||
Blur(f32, f32),
|
||||
Blur {
|
||||
width: f32,
|
||||
height: f32,
|
||||
should_inflate: bool,
|
||||
},
|
||||
Brightness(f32),
|
||||
Contrast(f32),
|
||||
Grayscale(f32),
|
||||
|
@ -229,7 +233,7 @@ impl Filter {
|
|||
pub fn is_visible(&self) -> bool {
|
||||
match *self {
|
||||
Filter::Identity |
|
||||
Filter::Blur(..) |
|
||||
Filter::Blur { .. } |
|
||||
Filter::Brightness(..) |
|
||||
Filter::Contrast(..) |
|
||||
Filter::Grayscale(..) |
|
||||
|
@ -254,7 +258,7 @@ impl Filter {
|
|||
pub fn is_noop(&self) -> bool {
|
||||
match *self {
|
||||
Filter::Identity => false, // this is intentional
|
||||
Filter::Blur(width, height) => width == 0.0 && height == 0.0,
|
||||
Filter::Blur { width, height, .. } => width == 0.0 && height == 0.0,
|
||||
Filter::Brightness(amount) => amount == 1.0,
|
||||
Filter::Contrast(amount) => amount == 1.0,
|
||||
Filter::Grayscale(amount) => amount == 0.0,
|
||||
|
@ -306,7 +310,7 @@ impl Filter {
|
|||
Filter::LinearToSrgb => 9,
|
||||
Filter::Flood(..) => 10,
|
||||
Filter::ComponentTransfer => 11,
|
||||
Filter::Blur(..) => 12,
|
||||
Filter::Blur { .. } => 12,
|
||||
Filter::DropShadows(..) => 13,
|
||||
Filter::Opacity(..) => 14,
|
||||
}
|
||||
|
@ -317,7 +321,7 @@ impl From<FilterOp> for Filter {
|
|||
fn from(op: FilterOp) -> Self {
|
||||
match op {
|
||||
FilterOp::Identity => Filter::Identity,
|
||||
FilterOp::Blur(w, h) => Filter::Blur(w, h),
|
||||
FilterOp::Blur(width, height) => Filter::Blur { width, height, should_inflate: true },
|
||||
FilterOp::Brightness(b) => Filter::Brightness(b),
|
||||
FilterOp::Contrast(c) => Filter::Contrast(c),
|
||||
FilterOp::Grayscale(g) => Filter::Grayscale(g),
|
||||
|
|
|
@ -106,12 +106,18 @@ impl PictureGraph {
|
|||
|
||||
let info = &mut self.pic_info[pic_index.0];
|
||||
|
||||
info.surface_index = Some(pictures[pic_index.0].assign_surface(
|
||||
match pictures[pic_index.0].assign_surface(
|
||||
frame_context,
|
||||
tile_caches,
|
||||
parent_surface_index,
|
||||
surfaces,
|
||||
));
|
||||
) {
|
||||
Some(surface_index) => {
|
||||
info.surface_index = Some(surface_index);
|
||||
}
|
||||
None => {
|
||||
info.surface_index = Some(parent_surface_index.unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,8 +64,6 @@ pub fn prepare_primitives(
|
|||
frame_context.spatial_tree,
|
||||
);
|
||||
|
||||
frame_state.surfaces[pic_context.surface_index.0].opaque_rect = PictureRect::zero();
|
||||
|
||||
for prim_instance_index in cluster.prim_range() {
|
||||
// First check for coarse visibility (if this primitive was completely off-screen)
|
||||
let prim_instance = &mut prim_instances[prim_instance_index];
|
||||
|
@ -127,14 +125,6 @@ pub fn prepare_primitives(
|
|||
prim_instances[prim_instance_index].clear_visibility();
|
||||
}
|
||||
}
|
||||
|
||||
if !cluster.opaque_rect.is_empty() {
|
||||
let surface = &mut frame_state.surfaces[pic_context.surface_index.0];
|
||||
|
||||
if let Some(cluster_opaque_rect) = surface.map_local_to_surface.map_inner_bounds(&cluster.opaque_rect) {
|
||||
surface.opaque_rect = crate::util::conservative_union_rect(&surface.opaque_rect, &cluster_opaque_rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,9 +149,14 @@ fn prepare_prim_for_render(
|
|||
// For example, scrolling may affect the location of an item in
|
||||
// local space, which may force us to render this item on a larger
|
||||
// picture target, if being composited.
|
||||
let mut is_passthrough = false;
|
||||
if let PrimitiveInstanceKind::Picture { pic_index, .. } = prim_instances[prim_instance_index].kind {
|
||||
let pic = &mut store.pictures[pic_index.0];
|
||||
|
||||
// TODO(gw): Plan to remove pictures with no composite mode, so that we don't need
|
||||
// to special case for pass through pictures.
|
||||
is_passthrough = pic.composite_mode.is_none();
|
||||
|
||||
match pic.take_context(
|
||||
pic_index,
|
||||
pic_context.surface_spatial_node_index,
|
||||
|
@ -203,32 +198,35 @@ fn prepare_prim_for_render(
|
|||
|
||||
let prim_instance = &mut prim_instances[prim_instance_index];
|
||||
|
||||
let prim_rect = data_stores.get_local_prim_rect(
|
||||
prim_instance,
|
||||
store,
|
||||
);
|
||||
if !is_passthrough {
|
||||
let prim_rect = data_stores.get_local_prim_rect(
|
||||
prim_instance,
|
||||
&store.pictures,
|
||||
frame_state.surfaces,
|
||||
);
|
||||
|
||||
if !update_clip_task(
|
||||
prim_instance,
|
||||
&prim_rect.min,
|
||||
cluster.spatial_node_index,
|
||||
pic_context.raster_spatial_node_index,
|
||||
pic_context,
|
||||
pic_state,
|
||||
frame_context,
|
||||
frame_state,
|
||||
store,
|
||||
data_stores,
|
||||
scratch,
|
||||
) {
|
||||
if prim_instance.is_chased() {
|
||||
info!("\tconsidered invisible");
|
||||
if !update_clip_task(
|
||||
prim_instance,
|
||||
&prim_rect.min,
|
||||
cluster.spatial_node_index,
|
||||
pic_context.raster_spatial_node_index,
|
||||
pic_context,
|
||||
pic_state,
|
||||
frame_context,
|
||||
frame_state,
|
||||
store,
|
||||
data_stores,
|
||||
scratch,
|
||||
) {
|
||||
if prim_instance.is_chased() {
|
||||
info!("\tconsidered invisible");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if prim_instance.is_chased() {
|
||||
info!("\tconsidered visible and ready with local pos {:?}", prim_rect.min);
|
||||
if prim_instance.is_chased() {
|
||||
info!("\tconsidered visible and ready with local pos {:?}", prim_rect.min);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
|
@ -268,7 +266,6 @@ fn prepare_interned_prim_for_render(
|
|||
let prim_spatial_node_index = cluster.spatial_node_index;
|
||||
let is_chased = prim_instance.is_chased();
|
||||
let device_pixel_scale = frame_state.surfaces[pic_context.surface_index.0].device_pixel_scale;
|
||||
let mut is_opaque = false;
|
||||
|
||||
match &mut prim_instance.kind {
|
||||
PrimitiveInstanceKind::LineDecoration { data_handle, ref mut render_task, .. } => {
|
||||
|
@ -289,9 +286,27 @@ fn prepare_interned_prim_for_render(
|
|||
// If we have a cache key, it's a wavy / dashed / dotted line. Otherwise, it's
|
||||
// a simple solid line.
|
||||
if let Some(cache_key) = line_dec_data.cache_key.as_ref() {
|
||||
// TODO(gw): Do we ever need / want to support scales for text decorations
|
||||
// based on the current transform?
|
||||
let scale_factor = Scale::new(1.0) * device_pixel_scale;
|
||||
// TODO(gw): These scale factors don't do a great job if the world transform
|
||||
// contains perspective
|
||||
let scale = frame_context
|
||||
.spatial_tree
|
||||
.get_world_transform(prim_spatial_node_index)
|
||||
.scale_factors();
|
||||
|
||||
// Scale factors are normalized to a power of 2 to reduce the number of
|
||||
// resolution changes.
|
||||
// For frames with a changing scale transform round scale factors up to
|
||||
// nearest power-of-2 boundary so that we don't keep having to redraw
|
||||
// the content as it scales up and down. Rounding up to nearest
|
||||
// power-of-2 boundary ensures we never scale up, only down --- avoiding
|
||||
// jaggies. It also ensures we never scale down by more than a factor of
|
||||
// 2, avoiding bad downscaling quality.
|
||||
let scale_width = clamp_to_scale_factor(scale.0, false);
|
||||
let scale_height = clamp_to_scale_factor(scale.1, false);
|
||||
// Pick the maximum dimension as scale
|
||||
let world_scale = LayoutToWorldScale::new(scale_width.max(scale_height));
|
||||
|
||||
let scale_factor = world_scale * device_pixel_scale;
|
||||
let mut task_size = (LayoutSize::from_au(cache_key.size) * scale_factor).ceil().to_i32();
|
||||
if task_size.width > MAX_LINE_DECORATION_RESOLUTION as i32 ||
|
||||
task_size.height > MAX_LINE_DECORATION_RESOLUTION as i32 {
|
||||
|
@ -348,12 +363,7 @@ fn prepare_interned_prim_for_render(
|
|||
.into_fast_transform();
|
||||
let prim_offset = prim_data.common.prim_rect.min.to_vector() - run.reference_frame_relative_offset;
|
||||
|
||||
let pic = &store.pictures[pic_context.pic_index.0];
|
||||
let surface = &frame_state.surfaces[pic_context.surface_index.0];
|
||||
let root_scaling_factor = match pic.raster_config {
|
||||
Some(ref raster_config) => raster_config.root_scaling_factor,
|
||||
None => 1.0
|
||||
};
|
||||
|
||||
// If subpixel AA is disabled due to the backing surface the glyphs
|
||||
// are being drawn onto, disable it (unless we are using the
|
||||
|
@ -391,7 +401,6 @@ fn prepare_interned_prim_for_render(
|
|||
&transform.to_transform().with_destination::<_>(),
|
||||
surface,
|
||||
prim_spatial_node_index,
|
||||
root_scaling_factor,
|
||||
allow_subpixel,
|
||||
frame_context.fb_config.low_quality_pinch_zoom,
|
||||
frame_state.resource_cache,
|
||||
|
@ -544,8 +553,6 @@ fn prepare_interned_prim_for_render(
|
|||
frame_context.scene_properties,
|
||||
);
|
||||
|
||||
is_opaque = prim_data.common.opacity.is_opaque;
|
||||
|
||||
write_segment(
|
||||
*segment_instance_index,
|
||||
frame_state,
|
||||
|
@ -564,7 +571,6 @@ fn prepare_interned_prim_for_render(
|
|||
let prim_data = &mut data_stores.yuv_image[*data_handle];
|
||||
let common_data = &mut prim_data.common;
|
||||
let yuv_image_data = &mut prim_data.kind;
|
||||
is_opaque = true;
|
||||
|
||||
common_data.may_need_repetition = false;
|
||||
|
||||
|
@ -602,9 +608,6 @@ fn prepare_interned_prim_for_render(
|
|||
&mut prim_instance.vis,
|
||||
);
|
||||
|
||||
// common_data.opacity.is_opaque is computed in the above update call.
|
||||
is_opaque = common_data.opacity.is_opaque;
|
||||
|
||||
write_segment(
|
||||
image_instance.segment_instance_index,
|
||||
frame_state,
|
||||
|
@ -777,12 +780,15 @@ fn prepare_interned_prim_for_render(
|
|||
if let Picture3DContext::In { root_data: None, plane_splitter_index, .. } = pic.context_3d {
|
||||
let dirty_rect = frame_state.current_dirty_region().combined;
|
||||
let splitter = &mut frame_state.plane_splitters[plane_splitter_index.0];
|
||||
let surface_index = pic.raster_config.as_ref().unwrap().surface_index;
|
||||
let surface = &frame_state.surfaces[surface_index.0];
|
||||
let local_prim_rect = surface.local_rect.cast_unit();
|
||||
|
||||
PicturePrimitive::add_split_plane(
|
||||
splitter,
|
||||
frame_context.spatial_tree,
|
||||
prim_spatial_node_index,
|
||||
pic.precise_local_rect,
|
||||
local_prim_rect,
|
||||
&prim_instance.vis.combined_local_clip_rect,
|
||||
dirty_rect,
|
||||
plane_split_anchor,
|
||||
|
@ -842,26 +848,6 @@ fn prepare_interned_prim_for_render(
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
// If the primitive is opaque, see if it can contribut to it's picture surface's opaque rect.
|
||||
|
||||
is_opaque = is_opaque && {
|
||||
let clip = prim_instance.vis.clip_task_index;
|
||||
clip == ClipTaskIndex::INVALID
|
||||
};
|
||||
|
||||
is_opaque = is_opaque && !frame_context.spatial_tree.is_relative_transform_complex(
|
||||
prim_spatial_node_index,
|
||||
pic_context.raster_spatial_node_index,
|
||||
);
|
||||
|
||||
if is_opaque {
|
||||
let prim_local_rect = data_stores.get_local_prim_rect(
|
||||
prim_instance,
|
||||
store,
|
||||
);
|
||||
cluster.opaque_rect = crate::util::conservative_union_rect(&cluster.opaque_rect, &prim_local_rect);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1424,7 +1410,8 @@ fn build_segments_if_needed(
|
|||
// in the instance and primitive template.
|
||||
let prim_local_rect = data_stores.get_local_prim_rect(
|
||||
instance,
|
||||
prim_store,
|
||||
&prim_store.pictures,
|
||||
frame_state.surfaces,
|
||||
);
|
||||
|
||||
let segment_instance_index = match instance.kind {
|
||||
|
|
|
@ -79,7 +79,7 @@ pub enum PictureCompositeKey {
|
|||
Identity,
|
||||
|
||||
// FilterOp
|
||||
Blur(Au, Au),
|
||||
Blur(Au, Au, bool),
|
||||
Brightness(Au),
|
||||
Contrast(Au),
|
||||
Grayscale(Au),
|
||||
|
@ -140,8 +140,8 @@ impl From<Option<PictureCompositeMode>> for PictureCompositeKey {
|
|||
}
|
||||
Some(PictureCompositeMode::Filter(op)) => {
|
||||
match op {
|
||||
Filter::Blur(width, height) =>
|
||||
PictureCompositeKey::Blur(Au::from_f32_px(width), Au::from_f32_px(height)),
|
||||
Filter::Blur { width, height, should_inflate } =>
|
||||
PictureCompositeKey::Blur(Au::from_f32_px(width), Au::from_f32_px(height), should_inflate),
|
||||
Filter::Brightness(value) => PictureCompositeKey::Brightness(Au::from_f32_px(value)),
|
||||
Filter::Contrast(value) => PictureCompositeKey::Contrast(Au::from_f32_px(value)),
|
||||
Filter::Grayscale(value) => PictureCompositeKey::Grayscale(Au::from_f32_px(value)),
|
||||
|
|
|
@ -246,7 +246,6 @@ impl TextRunPrimitive {
|
|||
transform: &LayoutToWorldTransform,
|
||||
mut allow_subpixel: bool,
|
||||
raster_space: RasterSpace,
|
||||
root_scaling_factor: f32,
|
||||
spatial_tree: &SpatialTree,
|
||||
) -> bool {
|
||||
// If local raster space is specified, include that in the scale
|
||||
|
@ -257,10 +256,7 @@ impl TextRunPrimitive {
|
|||
// will no longer be required.
|
||||
let raster_scale = raster_space.local_scale().unwrap_or(1.0).max(0.001);
|
||||
|
||||
// root_scaling_factor is used to scale very large pictures that establish
|
||||
// a raster root back to something sane, thus scale the device size accordingly.
|
||||
// to the shader it looks like a change in DPI which it already supports.
|
||||
let dps = surface.device_pixel_scale.0 * root_scaling_factor;
|
||||
let dps = surface.device_pixel_scale.0;
|
||||
let font_size = specified_font.size.to_f32_px();
|
||||
|
||||
// Small floating point error can accumulate in the raster * device_pixel scale.
|
||||
|
@ -442,7 +438,6 @@ impl TextRunPrimitive {
|
|||
transform: &LayoutToWorldTransform,
|
||||
surface: &SurfaceInfo,
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
root_scaling_factor: f32,
|
||||
allow_subpixel: bool,
|
||||
low_quality_pinch_zoom: bool,
|
||||
resource_cache: &mut ResourceCache,
|
||||
|
@ -464,14 +459,13 @@ impl TextRunPrimitive {
|
|||
transform,
|
||||
allow_subpixel,
|
||||
raster_space,
|
||||
root_scaling_factor,
|
||||
spatial_tree,
|
||||
);
|
||||
|
||||
if self.glyph_keys_range.is_empty() || cache_dirty {
|
||||
let subpx_dir = self.used_font.get_subpx_dir();
|
||||
|
||||
let dps = surface.device_pixel_scale.0 * root_scaling_factor;
|
||||
let dps = surface.device_pixel_scale.0;
|
||||
let transform = match raster_space {
|
||||
RasterSpace::Local(scale) => FontTransform::new(scale * dps, 0.0, 0.0, scale * dps),
|
||||
RasterSpace::Screen => self.used_font.transform.scale(dps),
|
||||
|
|
|
@ -31,12 +31,13 @@ use crate::gpu_cache::GpuCache;
|
|||
use crate::hit_test::{HitTest, HitTester, SharedHitTester};
|
||||
use crate::intern::DataStore;
|
||||
#[cfg(any(feature = "capture", feature = "replay"))]
|
||||
use crate::internal_types::DebugOutput;
|
||||
use crate::internal_types::{DebugOutput};
|
||||
use crate::internal_types::{FastHashMap, RenderedDocument, ResultMsg, FrameId, FrameStamp};
|
||||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
||||
use crate::picture::{PictureScratchBuffer, SliceId, TileCacheInstance, TileCacheParams};
|
||||
use crate::picture::{PictureScratchBuffer, SliceId, TileCacheInstance, TileCacheParams, SurfaceInfo, RasterConfig};
|
||||
use crate::picture::{PicturePrimitive};
|
||||
use crate::prim_store::{PrimitiveScratchBuffer, PrimitiveInstance};
|
||||
use crate::prim_store::{PrimitiveInstanceKind, PrimTemplateCommonData, PrimitiveStore};
|
||||
use crate::prim_store::{PrimitiveInstanceKind, PrimTemplateCommonData};
|
||||
use crate::prim_store::interned::*;
|
||||
use crate::profiler::{self, TransactionProfile};
|
||||
use crate::render_task_graph::RenderTaskGraphBuilder;
|
||||
|
@ -135,12 +136,53 @@ impl DataStores {
|
|||
pub fn get_local_prim_rect(
|
||||
&self,
|
||||
prim_instance: &PrimitiveInstance,
|
||||
prim_store: &PrimitiveStore,
|
||||
pictures: &[PicturePrimitive],
|
||||
surfaces: &[SurfaceInfo],
|
||||
) -> LayoutRect {
|
||||
match prim_instance.kind {
|
||||
PrimitiveInstanceKind::Picture { pic_index, .. } => {
|
||||
let pic = &prim_store.pictures[pic_index.0];
|
||||
pic.precise_local_rect
|
||||
let pic = &pictures[pic_index.0];
|
||||
|
||||
match pic.raster_config {
|
||||
Some(RasterConfig { surface_index, ref composite_mode, .. }) => {
|
||||
let surface = &surfaces[surface_index.0];
|
||||
|
||||
composite_mode.get_rect(surface, None)
|
||||
}
|
||||
None => {
|
||||
panic!("bug: get_local_prim_rect should not be called for pass-through pictures");
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.as_common_data(prim_instance).prim_rect
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the local coverage (space occupied) for a primitive. For most primitives,
|
||||
/// this is stored in the template. For pictures, this is stored inside the picture
|
||||
/// primitive instance itself, since this is determined during frame building.
|
||||
pub fn get_local_prim_coverage_rect(
|
||||
&self,
|
||||
prim_instance: &PrimitiveInstance,
|
||||
pictures: &[PicturePrimitive],
|
||||
surfaces: &[SurfaceInfo],
|
||||
) -> LayoutRect {
|
||||
match prim_instance.kind {
|
||||
PrimitiveInstanceKind::Picture { pic_index, .. } => {
|
||||
let pic = &pictures[pic_index.0];
|
||||
|
||||
match pic.raster_config {
|
||||
Some(RasterConfig { surface_index, ref composite_mode, .. }) => {
|
||||
let surface = &surfaces[surface_index.0];
|
||||
|
||||
composite_mode.get_coverage(surface, None)
|
||||
}
|
||||
None => {
|
||||
panic!("bug: get_local_prim_coverage_rect should not be called for pass-through pictures");
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.as_common_data(prim_instance).prim_rect
|
||||
|
|
|
@ -56,7 +56,7 @@ use crate::glyph_rasterizer::FontInstance;
|
|||
use crate::hit_test::HitTestingScene;
|
||||
use crate::intern::Interner;
|
||||
use crate::internal_types::{FastHashMap, LayoutPrimitiveInfo, Filter, PlaneSplitter, PlaneSplitterIndex, PipelineInstanceId};
|
||||
use crate::picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, PictureOptions};
|
||||
use crate::picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive};
|
||||
use crate::picture::{BlitReason, OrderedPictureChild, PrimitiveList, SurfaceInfo};
|
||||
use crate::picture_graph::PictureGraph;
|
||||
use crate::prim_store::{PrimitiveInstance, register_prim_chase_id};
|
||||
|
@ -268,7 +268,6 @@ impl PictureChainBuilder {
|
|||
self,
|
||||
composite_mode: PictureCompositeMode,
|
||||
context_3d: Picture3DContext<OrderedPictureChild>,
|
||||
options: PictureOptions,
|
||||
interners: &mut Interners,
|
||||
prim_store: &mut PrimitiveStore,
|
||||
prim_instances: &mut Vec<PrimitiveInstance>,
|
||||
|
@ -301,7 +300,6 @@ impl PictureChainBuilder {
|
|||
self.flags,
|
||||
prim_list,
|
||||
self.spatial_node_index,
|
||||
options,
|
||||
))
|
||||
);
|
||||
|
||||
|
@ -346,7 +344,6 @@ impl PictureChainBuilder {
|
|||
self.flags,
|
||||
prim_list,
|
||||
self.spatial_node_index,
|
||||
PictureOptions::default(),
|
||||
))
|
||||
);
|
||||
|
||||
|
@ -2162,7 +2159,6 @@ impl<'a> SceneBuilder<'a> {
|
|||
stacking_context.prim_flags,
|
||||
stacking_context.prim_list,
|
||||
stacking_context.spatial_node_index,
|
||||
PictureOptions::default(),
|
||||
))
|
||||
);
|
||||
|
||||
|
@ -2201,7 +2197,6 @@ impl<'a> SceneBuilder<'a> {
|
|||
stacking_context.prim_flags,
|
||||
stacking_context.prim_list,
|
||||
stacking_context.spatial_node_index,
|
||||
PictureOptions::default(),
|
||||
))
|
||||
);
|
||||
|
||||
|
@ -2300,7 +2295,6 @@ impl<'a> SceneBuilder<'a> {
|
|||
stacking_context.prim_flags,
|
||||
prim_list,
|
||||
stacking_context.spatial_node_index,
|
||||
PictureOptions::default(),
|
||||
))
|
||||
);
|
||||
|
||||
|
@ -2325,7 +2319,6 @@ impl<'a> SceneBuilder<'a> {
|
|||
stacking_context.composite_ops.filters,
|
||||
stacking_context.composite_ops.filter_primitives,
|
||||
stacking_context.composite_ops.filter_datas,
|
||||
true,
|
||||
);
|
||||
|
||||
// Same for mix-blend-mode, except we can skip if this primitive is the first in the parent
|
||||
|
@ -2351,7 +2344,6 @@ impl<'a> SceneBuilder<'a> {
|
|||
source = source.add_picture(
|
||||
composite_mode,
|
||||
Picture3DContext::Out,
|
||||
PictureOptions::default(),
|
||||
&mut self.interners,
|
||||
&mut self.prim_store,
|
||||
&mut self.prim_instances,
|
||||
|
@ -2708,7 +2700,11 @@ impl<'a> SceneBuilder<'a> {
|
|||
// Add any primitives that come after this shadow in the item
|
||||
// list to this shadow.
|
||||
let mut prim_list = PrimitiveList::empty();
|
||||
let blur_filter = Filter::Blur(std_deviation, std_deviation);
|
||||
let blur_filter = Filter::Blur {
|
||||
width: std_deviation,
|
||||
height: std_deviation,
|
||||
should_inflate: pending_shadow.should_inflate,
|
||||
};
|
||||
let blur_is_noop = blur_filter.is_noop();
|
||||
|
||||
for item in &items {
|
||||
|
@ -2778,17 +2774,10 @@ impl<'a> SceneBuilder<'a> {
|
|||
// blur radius is 0, the code in Picture::prepare_for_render will
|
||||
// detect this and mark the picture to be drawn directly into the
|
||||
// parent picture, which avoids an intermediate surface and blur.
|
||||
let blur_filter = Filter::Blur(std_deviation, std_deviation);
|
||||
assert!(!blur_filter.is_noop());
|
||||
let composite_mode = Some(PictureCompositeMode::Filter(blur_filter));
|
||||
let composite_mode_key = composite_mode.clone().into();
|
||||
|
||||
// Pass through configuration information about whether WR should
|
||||
// do the bounding rect inflation for text shadows.
|
||||
let options = PictureOptions {
|
||||
inflate_if_required: pending_shadow.should_inflate,
|
||||
};
|
||||
|
||||
// Create the primitive to draw the shadow picture into the scene.
|
||||
let shadow_pic_index = PictureIndex(self.prim_store.pictures
|
||||
.alloc()
|
||||
|
@ -2799,7 +2788,6 @@ impl<'a> SceneBuilder<'a> {
|
|||
PrimitiveFlags::IS_BACKFACE_VISIBLE,
|
||||
prim_list,
|
||||
pending_shadow.spatial_node_index,
|
||||
options,
|
||||
))
|
||||
);
|
||||
|
||||
|
@ -3495,9 +3483,6 @@ impl<'a> SceneBuilder<'a> {
|
|||
prim_flags,
|
||||
prim_list,
|
||||
backdrop_spatial_node_index,
|
||||
PictureOptions {
|
||||
inflate_if_required: false,
|
||||
},
|
||||
))
|
||||
);
|
||||
|
||||
|
@ -3520,7 +3505,6 @@ impl<'a> SceneBuilder<'a> {
|
|||
filters,
|
||||
filter_primitives,
|
||||
filter_datas,
|
||||
false,
|
||||
);
|
||||
|
||||
// Apply filters from all stacking contexts up to, but not including the backdrop root.
|
||||
|
@ -3539,7 +3523,6 @@ impl<'a> SceneBuilder<'a> {
|
|||
filters,
|
||||
filter_primitives,
|
||||
filter_datas,
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -3620,7 +3603,6 @@ impl<'a> SceneBuilder<'a> {
|
|||
mut filter_ops: Vec<Filter>,
|
||||
mut filter_primitives: Vec<FilterPrimitive>,
|
||||
filter_datas: Vec<FilterData>,
|
||||
inflate_if_required: bool,
|
||||
) -> PictureChainBuilder {
|
||||
// TODO(cbrewster): Currently CSS and SVG filters live side by side in WebRender, but unexpected results will
|
||||
// happen if they are used simulataneously. Gecko only provides either filter ops or filter primitives.
|
||||
|
@ -3672,7 +3654,6 @@ impl<'a> SceneBuilder<'a> {
|
|||
source = source.add_picture(
|
||||
composite_mode,
|
||||
Picture3DContext::Out,
|
||||
PictureOptions { inflate_if_required },
|
||||
&mut self.interners,
|
||||
&mut self.prim_store,
|
||||
&mut self.prim_instances,
|
||||
|
@ -3709,7 +3690,6 @@ impl<'a> SceneBuilder<'a> {
|
|||
source = source.add_picture(
|
||||
composite_mode,
|
||||
Picture3DContext::Out,
|
||||
PictureOptions { inflate_if_required },
|
||||
&mut self.interners,
|
||||
&mut self.prim_store,
|
||||
&mut self.prim_instances,
|
||||
|
@ -3872,7 +3852,6 @@ impl FlattenedStackingContext {
|
|||
self.prim_flags,
|
||||
mem::replace(&mut self.prim_list, PrimitiveList::empty()),
|
||||
self.spatial_node_index,
|
||||
PictureOptions::default(),
|
||||
))
|
||||
);
|
||||
|
||||
|
|
|
@ -1012,19 +1012,17 @@ impl SpatialTree {
|
|||
CoordinateSpaceMapping::Transform(transform)
|
||||
}
|
||||
|
||||
pub fn is_relative_transform_complex(
|
||||
/// Returns true if both supplied spatial nodes are in the same coordinate system
|
||||
/// (implies the relative transform produce axis-aligned rects).
|
||||
pub fn is_matching_coord_system(
|
||||
&self,
|
||||
child_index: SpatialNodeIndex,
|
||||
parent_index: SpatialNodeIndex,
|
||||
index0: SpatialNodeIndex,
|
||||
index1: SpatialNodeIndex,
|
||||
) -> bool {
|
||||
if child_index == parent_index {
|
||||
return false;
|
||||
}
|
||||
let node0 = self.get_spatial_node(index0);
|
||||
let node1 = self.get_spatial_node(index1);
|
||||
|
||||
let child = self.get_spatial_node(child_index);
|
||||
let parent = self.get_spatial_node(parent_index);
|
||||
|
||||
child.coordinate_system_id != parent.coordinate_system_id
|
||||
node0.coordinate_system_id == node1.coordinate_system_id
|
||||
}
|
||||
|
||||
fn get_world_transform_impl(
|
||||
|
|
|
@ -7,7 +7,7 @@ use api::units::*;
|
|||
use crate::clip::{ClipChainId, ClipNodeKind, ClipStore, ClipInstance};
|
||||
use crate::frame_builder::FrameBuilderConfig;
|
||||
use crate::internal_types::{FastHashMap, FastHashSet};
|
||||
use crate::picture::{PrimitiveList, PictureCompositeMode, PictureOptions, PicturePrimitive, SliceId};
|
||||
use crate::picture::{PrimitiveList, PictureCompositeMode, PicturePrimitive, SliceId};
|
||||
use crate::picture::{Picture3DContext, TileCacheParams, TileOffset};
|
||||
use crate::prim_store::{PrimitiveInstance, PrimitiveStore, PictureIndex};
|
||||
use crate::scene_building::SliceFlags;
|
||||
|
@ -629,7 +629,6 @@ fn create_tile_cache(
|
|||
PrimitiveFlags::IS_BACKFACE_VISIBLE,
|
||||
prim_list,
|
||||
scroll_root,
|
||||
PictureOptions::default(),
|
||||
));
|
||||
|
||||
PictureIndex(pic_index)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
use api::BorderRadius;
|
||||
use api::units::*;
|
||||
use euclid::{Point2D, Rect, Box2D, Size2D, Vector2D, point2};
|
||||
use euclid::{Point2D, Rect, Box2D, Size2D, Vector2D};
|
||||
use euclid::{default, Transform2D, Transform3D, Scale};
|
||||
use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps};
|
||||
use plane_split::{Clipper, Polygon};
|
||||
|
@ -1551,142 +1551,6 @@ macro_rules! c_str {
|
|||
}
|
||||
}
|
||||
|
||||
// Find a rectangle that is contained by the sum of r1 and r2.
|
||||
pub fn conservative_union_rect<U>(r1: &Box2D<f32, U>, r2: &Box2D<f32, U>) -> Box2D<f32, U> {
|
||||
// +---+---+ +--+-+--+
|
||||
// | | | | | | |
|
||||
// | | | | | | |
|
||||
// +---+---+ +--+-+--+
|
||||
if r1.min.y == r2.min.y && r1.max.y == r2.max.y {
|
||||
if r2.min.x <= r1.max.x && r2.max.x >= r1.min.x {
|
||||
let min_x = f32::min(r1.min.x, r2.min.x);
|
||||
let max_x = f32::max(r1.max.x, r2.max.x);
|
||||
|
||||
return Box2D {
|
||||
min: point2(min_x, r1.min.y),
|
||||
max: point2(max_x, r1.max.y),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// +----+ +----+
|
||||
// | | | |
|
||||
// | | +----+
|
||||
// +----+ | |
|
||||
// | | +----+
|
||||
// | | | |
|
||||
// +----+ +----+
|
||||
if r1.min.x == r2.min.x && r1.max.x == r2.max.x {
|
||||
if r2.min.y <= r1.max.y && r2.max.y >= r1.min.y {
|
||||
let min_y = f32::min(r1.min.y, r2.min.y);
|
||||
let max_y = f32::max(r1.max.y, r2.max.y);
|
||||
|
||||
return Box2D {
|
||||
min: point2(r1.min.x, min_y),
|
||||
max: point2(r1.max.x, max_y),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if r1.area() >= r2.area() { *r1 } else {*r2 }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conservative_union_rect() {
|
||||
// Adjacent, x axis
|
||||
let r = conservative_union_rect(
|
||||
&LayoutRect { min: point2(1.0, 2.0), max: point2(4.0, 6.0) },
|
||||
&LayoutRect { min: point2(4.0, 2.0), max: point2(9.0, 6.0) },
|
||||
);
|
||||
assert_eq!(r, LayoutRect { min: point2(1.0, 2.0), max: point2(9.0, 6.0) });
|
||||
|
||||
let r = conservative_union_rect(
|
||||
&LayoutRect { min: point2(4.0, 2.0), max: point2(9.0, 6.0) },
|
||||
&LayoutRect { min: point2(1.0, 2.0), max: point2(4.0, 6.0) },
|
||||
);
|
||||
assert_eq!(r, LayoutRect { min: point2(1.0, 2.0), max: point2(9.0, 6.0) });
|
||||
|
||||
// Averlapping adjacent, x axis
|
||||
let r = conservative_union_rect(
|
||||
&LayoutRect { min: point2(1.0, 2.0), max: point2(4.0, 6.0) },
|
||||
&LayoutRect { min: point2(3.0, 2.0), max: point2(8.0, 6.0) },
|
||||
);
|
||||
assert_eq!(r, LayoutRect { min: point2(1.0, 2.0), max: point2(8.0, 6.0) });
|
||||
|
||||
let r = conservative_union_rect(
|
||||
&LayoutRect { min: point2(5.0, 2.0), max: point2(8.0, 6.0) },
|
||||
&LayoutRect { min: point2(1.0, 2.0), max: point2(6.0, 6.0) },
|
||||
);
|
||||
assert_eq!(r, LayoutRect { min: point2(1.0, 2.0), max: point2(8.0, 6.0) });
|
||||
|
||||
// Adjacent but not touching, x axis
|
||||
let r = conservative_union_rect(
|
||||
&LayoutRect { min: point2(1.0, 2.0), max: point2(4.0, 6.0) },
|
||||
&LayoutRect { min: point2(6.0, 2.0), max: point2(11.0, 6.0) },
|
||||
);
|
||||
assert_eq!(r, LayoutRect { min: point2(6.0, 2.0), max: point2(11.0, 6.0) });
|
||||
|
||||
let r = conservative_union_rect(
|
||||
&LayoutRect { min: point2(1.0, 2.0), max: point2(4.0, 6.0) },
|
||||
&LayoutRect { min: point2(-6.0, 2.0), max: point2(-5.0, 6.0) },
|
||||
);
|
||||
assert_eq!(r, LayoutRect { min: point2(1.0, 2.0), max: point2(4.0, 6.0) });
|
||||
|
||||
|
||||
// Adjacent, y axis
|
||||
let r = conservative_union_rect(
|
||||
&LayoutRect { min: point2(1.0, 2.0), max: point2(4.0, 6.0) },
|
||||
&LayoutRect { min: point2(1.0, 6.0), max: point2(4.0, 10.0) },
|
||||
);
|
||||
assert_eq!(r, LayoutRect { min: point2(1.0, 2.0), max: point2(4.0, 10.0) });
|
||||
|
||||
let r = conservative_union_rect(
|
||||
&LayoutRect { min: point2(1.0, 5.0), max: point2(4.0, 9.0) },
|
||||
&LayoutRect { min: point2(1.0, 1.0), max: point2(4.0, 5.0) },
|
||||
);
|
||||
assert_eq!(r, LayoutRect { min: point2(1.0, 1.0), max: point2(4.0, 9.0) });
|
||||
|
||||
// Averlapping adjacent, y axis
|
||||
let r = conservative_union_rect(
|
||||
&LayoutRect { min: point2(1.0, 2.0), max: point2(4.0, 6.0) },
|
||||
&LayoutRect { min: point2(1.0, 3.0), max: point2(4.0, 7.0) },
|
||||
);
|
||||
assert_eq!(r, LayoutRect { min: point2(1.0, 2.0), max: point2(4.0, 7.0) });
|
||||
|
||||
let r = conservative_union_rect(
|
||||
&LayoutRect { min: point2(1.0, 4.0), max: point2(4.0, 8.0) },
|
||||
&LayoutRect { min: point2(1.0, 2.0), max: point2(4.0, 6.0) },
|
||||
);
|
||||
assert_eq!(r, LayoutRect { min: point2(1.0, 2.0), max: point2(4.0, 8.0) });
|
||||
|
||||
// Adjacent but not touching, y axis
|
||||
let r = conservative_union_rect(
|
||||
&LayoutRect { min: point2(1.0, 2.0), max: point2(4.0, 6.0) },
|
||||
&LayoutRect { min: point2(1.0, 10.0), max: point2(4.0, 15.0) },
|
||||
);
|
||||
assert_eq!(r, LayoutRect { min: point2(1.0, 10.0), max: point2(4.0, 15.0) });
|
||||
|
||||
let r = conservative_union_rect(
|
||||
&LayoutRect { min: point2(1.0, 5.0), max: point2(4.0, 9.0) },
|
||||
&LayoutRect { min: point2(1.0, 0.0), max: point2(4.0, 3.0) },
|
||||
);
|
||||
assert_eq!(r, LayoutRect { min: point2(1.0, 5.0), max: point2(4.0, 9.0) });
|
||||
|
||||
|
||||
// Contained
|
||||
let r = conservative_union_rect(
|
||||
&LayoutRect { min: point2(1.0, 2.0), max: point2(4.0, 6.0) },
|
||||
&LayoutRect { min: point2(0.0, 1.0), max: point2(10.0, 12.0) },
|
||||
);
|
||||
assert_eq!(r, LayoutRect { min: point2(0.0, 1.0), max: point2(10.0, 12.0) });
|
||||
|
||||
let r = conservative_union_rect(
|
||||
&LayoutRect { min: point2(0.0, 1.0), max: point2(10.0, 12.0) },
|
||||
&LayoutRect { min: point2(1.0, 2.0), max: point2(4.0, 6.0) },
|
||||
);
|
||||
assert_eq!(r, LayoutRect { min: point2(0.0, 1.0), max: point2(10.0, 12.0) });
|
||||
}
|
||||
|
||||
/// This is inspired by the `weak-table` crate.
|
||||
/// It holds a Vec of weak pointers that are garbage collected as the Vec
|
||||
pub struct WeakTable {
|
||||
|
|
|
@ -7,34 +7,30 @@
|
|||
//! TODO: document what this pass does!
|
||||
//!
|
||||
|
||||
use api::{ColorF, DebugFlags};
|
||||
use api::{DebugFlags};
|
||||
use api::units::*;
|
||||
use euclid::Scale;
|
||||
use std::{usize, mem};
|
||||
use std::{usize};
|
||||
use crate::batch::BatchFilter;
|
||||
use crate::clip::{ClipStore, ClipChainStack};
|
||||
use crate::composite::CompositeState;
|
||||
use crate::spatial_tree::{SpatialTree, SpatialNodeIndex};
|
||||
use crate::clip::{ClipInstance, ClipChainInstance};
|
||||
use crate::debug_colors;
|
||||
use crate::frame_builder::FrameBuilderConfig;
|
||||
use crate::gpu_cache::GpuCache;
|
||||
use crate::picture::{PictureCompositeMode, ClusterFlags, SurfaceInfo, TileCacheInstance};
|
||||
use crate::picture::{PrimitiveList, SurfaceIndex, RasterConfig};
|
||||
use crate::picture::{SurfaceIndex, RasterConfig};
|
||||
use crate::prim_store::{ClipTaskIndex, PictureIndex, PrimitiveInstanceKind};
|
||||
use crate::prim_store::{PrimitiveStore, PrimitiveInstance};
|
||||
use crate::render_backend::{DataStores, ScratchBuffer};
|
||||
use crate::resource_cache::ResourceCache;
|
||||
use crate::scene::SceneProperties;
|
||||
use crate::space::SpaceMapper;
|
||||
use crate::internal_types::Filter;
|
||||
use crate::util::{MaxRect};
|
||||
|
||||
pub struct FrameVisibilityContext<'a> {
|
||||
pub spatial_tree: &'a SpatialTree,
|
||||
pub global_screen_world_rect: WorldRect,
|
||||
pub global_device_pixel_scale: DevicePixelScale,
|
||||
pub surfaces: &'a [SurfaceInfo],
|
||||
pub debug_flags: DebugFlags,
|
||||
pub scene_properties: &'a SceneProperties,
|
||||
pub config: FrameBuilderConfig,
|
||||
|
@ -51,17 +47,18 @@ pub struct FrameVisibilityState<'a> {
|
|||
pub composite_state: &'a mut CompositeState,
|
||||
/// A stack of currently active off-screen surfaces during the
|
||||
/// visibility frame traversal.
|
||||
pub surface_stack: Vec<SurfaceIndex>,
|
||||
pub surface_stack: Vec<(PictureIndex, SurfaceIndex)>,
|
||||
}
|
||||
|
||||
impl<'a> FrameVisibilityState<'a> {
|
||||
pub fn push_surface(
|
||||
&mut self,
|
||||
pic_index: PictureIndex,
|
||||
surface_index: SurfaceIndex,
|
||||
shared_clips: &[ClipInstance],
|
||||
spatial_tree: &SpatialTree,
|
||||
) {
|
||||
self.surface_stack.push(surface_index);
|
||||
self.surface_stack.push((pic_index, surface_index));
|
||||
self.clip_chain_stack.push_surface(
|
||||
shared_clips,
|
||||
spatial_tree,
|
||||
|
@ -164,59 +161,52 @@ impl PrimitiveVisibility {
|
|||
}
|
||||
}
|
||||
|
||||
/// Update visibility pass - update each primitive visibility struct, and
|
||||
/// build the clip chain instance if appropriate.
|
||||
pub fn update_primitive_visibility(
|
||||
store: &mut PrimitiveStore,
|
||||
pub fn update_prim_visibility(
|
||||
pic_index: PictureIndex,
|
||||
parent_surface_index: Option<SurfaceIndex>,
|
||||
world_culling_rect: &WorldRect,
|
||||
store: &PrimitiveStore,
|
||||
prim_instances: &mut [PrimitiveInstance],
|
||||
surfaces: &mut [SurfaceInfo],
|
||||
is_root_tile_cache: bool,
|
||||
frame_context: &FrameVisibilityContext,
|
||||
frame_state: &mut FrameVisibilityState,
|
||||
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, pop_surface) = {
|
||||
let pic = &mut store.pictures[pic_index.0];
|
||||
) {
|
||||
let pic = &store.pictures[pic_index.0];
|
||||
|
||||
let prim_list = mem::replace(&mut pic.prim_list, PrimitiveList::empty());
|
||||
let (surface_index, pop_surface) = match pic.raster_config {
|
||||
Some(RasterConfig { surface_index, composite_mode: PictureCompositeMode::TileCache { .. }, .. }) => {
|
||||
(surface_index, false)
|
||||
}
|
||||
Some(ref raster_config) => {
|
||||
frame_state.push_surface(
|
||||
raster_config.surface_index,
|
||||
&[],
|
||||
frame_context.spatial_tree,
|
||||
);
|
||||
let (surface_index, pop_surface) = match pic.raster_config {
|
||||
Some(RasterConfig { surface_index, composite_mode: PictureCompositeMode::TileCache { .. }, .. }) => {
|
||||
(surface_index, false)
|
||||
}
|
||||
Some(ref raster_config) => {
|
||||
frame_state.push_surface(
|
||||
pic_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.
|
||||
tile_cache.push_surface(
|
||||
pic.estimated_local_rect,
|
||||
pic.spatial_node_index,
|
||||
frame_context.spatial_tree,
|
||||
);
|
||||
let surface_local_rect = surfaces[raster_config.surface_index.0].local_rect.cast_unit();
|
||||
|
||||
(raster_config.surface_index, true)
|
||||
}
|
||||
None => {
|
||||
(parent_surface_index.expect("bug: pass-through with no parent"), false)
|
||||
}
|
||||
};
|
||||
// Let the picture cache know that we are pushing an off-screen
|
||||
// surface, so it can treat dependencies of surface atomically.
|
||||
tile_cache.push_surface(
|
||||
surface_local_rect,
|
||||
pic.spatial_node_index,
|
||||
frame_context.spatial_tree,
|
||||
);
|
||||
|
||||
(prim_list, surface_index, pic.apply_local_clip_rect, world_culling_rect, pop_surface)
|
||||
(raster_config.surface_index, true)
|
||||
}
|
||||
None => {
|
||||
(parent_surface_index.expect("bug: pass-through with no parent"), false)
|
||||
}
|
||||
};
|
||||
|
||||
let surface = &frame_context.surfaces[surface_index.0 as usize];
|
||||
|
||||
let mut map_local_to_surface = surface
|
||||
.map_local_to_surface
|
||||
.clone();
|
||||
|
||||
let surface = &surfaces[surface_index.0 as usize];
|
||||
let device_pixel_scale = surface.device_pixel_scale;
|
||||
let mut map_local_to_surface = surface.map_local_to_surface.clone();
|
||||
let map_surface_to_world = SpaceMapper::new_with_target(
|
||||
frame_context.root_spatial_node_index,
|
||||
surface.surface_spatial_node_index,
|
||||
|
@ -224,9 +214,7 @@ pub fn update_primitive_visibility(
|
|||
frame_context.spatial_tree,
|
||||
);
|
||||
|
||||
let mut surface_rect = PictureRect::zero();
|
||||
|
||||
for cluster in &mut prim_list.clusters {
|
||||
for cluster in &pic.prim_list.clusters {
|
||||
profile_scope!("cluster");
|
||||
|
||||
// Each prim instance must have reset called each frame, to clear
|
||||
|
@ -256,325 +244,141 @@ pub fn update_primitive_visibility(
|
|||
);
|
||||
|
||||
for prim_instance_index in cluster.prim_range() {
|
||||
let (is_passthrough, prim_local_rect, prim_shadowed_rect) = match prim_instances[prim_instance_index].kind {
|
||||
PrimitiveInstanceKind::Picture { pic_index, .. } => {
|
||||
let (is_visible, is_passthrough) = {
|
||||
let pic = &store.pictures[pic_index.0];
|
||||
(pic.is_visible(frame_context.spatial_tree), pic.raster_config.is_none())
|
||||
};
|
||||
if let PrimitiveInstanceKind::Picture { pic_index, .. } = prim_instances[prim_instance_index].kind {
|
||||
if !store.pictures[pic_index.0].is_visible(frame_context.spatial_tree) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !is_visible {
|
||||
continue;
|
||||
}
|
||||
let is_passthrough = match store.pictures[pic_index.0].raster_config {
|
||||
Some(..) => false,
|
||||
None => true,
|
||||
};
|
||||
|
||||
if is_passthrough {
|
||||
frame_state.clip_chain_stack.push_clip(
|
||||
prim_instances[prim_instance_index].clip_set.clip_chain_id,
|
||||
frame_state.clip_store,
|
||||
);
|
||||
}
|
||||
|
||||
let pic_surface_rect = update_primitive_visibility(
|
||||
store,
|
||||
pic_index,
|
||||
Some(surface_index),
|
||||
world_culling_rect,
|
||||
frame_context,
|
||||
frame_state,
|
||||
tile_cache,
|
||||
false,
|
||||
prim_instances,
|
||||
if is_passthrough {
|
||||
frame_state.clip_chain_stack.push_clip(
|
||||
prim_instances[prim_instance_index].clip_set.clip_chain_id,
|
||||
frame_state.clip_store,
|
||||
);
|
||||
|
||||
if is_passthrough {
|
||||
frame_state.clip_chain_stack.pop_clip();
|
||||
}
|
||||
|
||||
let pic = &store.pictures[pic_index.0];
|
||||
|
||||
let mut shadow_rect = pic.precise_local_rect;
|
||||
match pic.raster_config {
|
||||
Some(ref rc) => match rc.composite_mode {
|
||||
// If we have a drop shadow filter, we also need to include the shadow in
|
||||
// our shadowed local rect for the purpose of calculating the size of the
|
||||
// picture.
|
||||
PictureCompositeMode::Filter(Filter::DropShadows(ref shadows)) => {
|
||||
for shadow in shadows {
|
||||
shadow_rect = shadow_rect.union(&pic.precise_local_rect.translate(shadow.offset));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
None => {
|
||||
// If the primitive does not have its own raster config, we need to
|
||||
// propogate the surface rect calculation to the parent.
|
||||
if let Some(ref rect) = pic_surface_rect {
|
||||
surface_rect = surface_rect.union(rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(is_passthrough, pic.precise_local_rect, shadow_rect)
|
||||
}
|
||||
_ => {
|
||||
let prim_instance = &prim_instances[prim_instance_index];
|
||||
let prim_data = &frame_state.data_stores.as_common_data(&prim_instance);
|
||||
|
||||
(false, prim_data.prim_rect, prim_data.prim_rect)
|
||||
update_prim_visibility(
|
||||
pic_index,
|
||||
Some(surface_index),
|
||||
world_culling_rect,
|
||||
store,
|
||||
prim_instances,
|
||||
surfaces,
|
||||
false,
|
||||
frame_context,
|
||||
frame_state,
|
||||
tile_cache,
|
||||
);
|
||||
|
||||
if is_passthrough {
|
||||
frame_state.clip_chain_stack.pop_clip();
|
||||
|
||||
// Pass through pictures are always considered visible in all dirty tiles.
|
||||
prim_instances[prim_instance_index].vis.state = VisibilityState::PassThrough;
|
||||
|
||||
continue;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let prim_instance = &mut prim_instances[prim_instance_index];
|
||||
|
||||
if is_passthrough {
|
||||
// Pass through pictures are always considered visible in all dirty tiles.
|
||||
prim_instance.vis.state = VisibilityState::PassThrough;
|
||||
} else {
|
||||
if prim_local_rect.width() <= 0.0 || prim_local_rect.height() <= 0.0 {
|
||||
if prim_instance.is_chased() {
|
||||
info!("\tculled for zero local rectangle");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
let local_coverage_rect = frame_state.data_stores.get_local_prim_coverage_rect(
|
||||
prim_instance,
|
||||
&store.pictures,
|
||||
surfaces,
|
||||
);
|
||||
|
||||
// Inflate the local rect for this primitive by the inflation factor of
|
||||
// the picture context and include the shadow offset. This ensures that
|
||||
// even if the primitive itstore is not visible, any effects from the
|
||||
// blur radius or shadow will be correctly taken into account.
|
||||
let inflation_factor = surface.inflation_factor;
|
||||
let local_rect = prim_shadowed_rect
|
||||
.inflate(inflation_factor, inflation_factor)
|
||||
.intersection(&prim_instance.clip_set.local_clip_rect);
|
||||
let local_rect = match local_rect {
|
||||
Some(local_rect) => local_rect,
|
||||
None => {
|
||||
if prim_instance.is_chased() {
|
||||
info!("\tculled for being out of the local clip rectangle: {:?}",
|
||||
prim_instance.clip_set.local_clip_rect);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
};
|
||||
// Include the clip chain for this primitive in the current stack.
|
||||
frame_state.clip_chain_stack.push_clip(
|
||||
prim_instance.clip_set.clip_chain_id,
|
||||
frame_state.clip_store,
|
||||
);
|
||||
|
||||
// Include the clip chain for this primitive in the current stack.
|
||||
frame_state.clip_chain_stack.push_clip(
|
||||
prim_instance.clip_set.clip_chain_id,
|
||||
frame_state.clip_store,
|
||||
);
|
||||
frame_state.clip_store.set_active_clips(
|
||||
prim_instance.clip_set.local_clip_rect,
|
||||
cluster.spatial_node_index,
|
||||
map_local_to_surface.ref_spatial_node_index,
|
||||
frame_state.clip_chain_stack.current_clips_array(),
|
||||
&frame_context.spatial_tree,
|
||||
&frame_state.data_stores.clip,
|
||||
);
|
||||
|
||||
frame_state.clip_store.set_active_clips(
|
||||
prim_instance.clip_set.local_clip_rect,
|
||||
cluster.spatial_node_index,
|
||||
map_local_to_surface.ref_spatial_node_index,
|
||||
frame_state.clip_chain_stack.current_clips_array(),
|
||||
&frame_context.spatial_tree,
|
||||
&frame_state.data_stores.clip,
|
||||
);
|
||||
|
||||
let clip_chain = frame_state
|
||||
.clip_store
|
||||
.build_clip_chain_instance(
|
||||
local_rect,
|
||||
&map_local_to_surface,
|
||||
&map_surface_to_world,
|
||||
&frame_context.spatial_tree,
|
||||
frame_state.gpu_cache,
|
||||
frame_state.resource_cache,
|
||||
surface.device_pixel_scale,
|
||||
&world_culling_rect,
|
||||
&mut frame_state.data_stores.clip,
|
||||
true,
|
||||
prim_instance.is_chased(),
|
||||
);
|
||||
|
||||
// Ensure the primitive clip is popped
|
||||
frame_state.clip_chain_stack.pop_clip();
|
||||
|
||||
prim_instance.vis.clip_chain = match clip_chain {
|
||||
Some(clip_chain) => clip_chain,
|
||||
None => {
|
||||
if prim_instance.is_chased() {
|
||||
info!("\tunable to build the clip chain, skipping");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
if prim_instance.is_chased() {
|
||||
info!("\teffective clip chain from {:?} {}",
|
||||
prim_instance.vis.clip_chain.clips_range,
|
||||
if apply_local_clip_rect { "(applied)" } else { "" },
|
||||
);
|
||||
info!("\tpicture rect {:?} @{:?}",
|
||||
prim_instance.vis.clip_chain.pic_coverage_rect,
|
||||
prim_instance.vis.clip_chain.pic_spatial_node_index,
|
||||
);
|
||||
}
|
||||
|
||||
prim_instance.vis.combined_local_clip_rect = if apply_local_clip_rect {
|
||||
prim_instance.vis.clip_chain.local_clip_rect
|
||||
} else {
|
||||
prim_instance.clip_set.local_clip_rect
|
||||
};
|
||||
|
||||
if prim_instance.vis.combined_local_clip_rect.is_empty() {
|
||||
if prim_instance.is_chased() {
|
||||
info!("\tculled for zero local clip rectangle");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Include the visible area for primitive, including any shadows, in
|
||||
// the area affected by the surface.
|
||||
match prim_instance.vis.combined_local_clip_rect.intersection(&local_rect) {
|
||||
Some(visible_rect) => {
|
||||
if let Some(rect) = map_local_to_surface.map(&visible_rect) {
|
||||
surface_rect = surface_rect.union(&rect);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if prim_instance.is_chased() {
|
||||
info!("\tculled for zero visible rectangle");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
tile_cache.update_prim_dependencies(
|
||||
prim_instance,
|
||||
cluster.spatial_node_index,
|
||||
prim_local_rect,
|
||||
frame_context,
|
||||
frame_state.data_stores,
|
||||
frame_state.clip_store,
|
||||
&store.pictures,
|
||||
frame_state.resource_cache,
|
||||
&store.color_bindings,
|
||||
&frame_state.surface_stack,
|
||||
&mut frame_state.composite_state,
|
||||
&mut frame_state.gpu_cache,
|
||||
is_root_tile_cache,
|
||||
);
|
||||
|
||||
// Skip post visibility prim update if this primitive was culled above.
|
||||
match prim_instance.vis.state {
|
||||
VisibilityState::Unset => panic!("bug: invalid state"),
|
||||
VisibilityState::Culled => continue,
|
||||
VisibilityState::Coarse { .. } | VisibilityState::Detailed { .. } | VisibilityState::PassThrough => {}
|
||||
}
|
||||
|
||||
// When the debug display is enabled, paint a colored rectangle around each
|
||||
// primitive.
|
||||
if frame_context.debug_flags.contains(::api::DebugFlags::PRIMITIVE_DBG) {
|
||||
let debug_color = match prim_instance.kind {
|
||||
PrimitiveInstanceKind::Picture { .. } => ColorF::TRANSPARENT,
|
||||
PrimitiveInstanceKind::TextRun { .. } => debug_colors::RED,
|
||||
PrimitiveInstanceKind::LineDecoration { .. } => debug_colors::PURPLE,
|
||||
PrimitiveInstanceKind::NormalBorder { .. } |
|
||||
PrimitiveInstanceKind::ImageBorder { .. } => debug_colors::ORANGE,
|
||||
PrimitiveInstanceKind::Rectangle { .. } => ColorF { r: 0.8, g: 0.8, b: 0.8, a: 0.5 },
|
||||
PrimitiveInstanceKind::YuvImage { .. } => debug_colors::BLUE,
|
||||
PrimitiveInstanceKind::Image { .. } => debug_colors::BLUE,
|
||||
PrimitiveInstanceKind::LinearGradient { .. } => debug_colors::PINK,
|
||||
PrimitiveInstanceKind::CachedLinearGradient { .. } => debug_colors::PINK,
|
||||
PrimitiveInstanceKind::RadialGradient { .. } => debug_colors::PINK,
|
||||
PrimitiveInstanceKind::ConicGradient { .. } => debug_colors::PINK,
|
||||
PrimitiveInstanceKind::Clear { .. } => debug_colors::CYAN,
|
||||
PrimitiveInstanceKind::Backdrop { .. } => debug_colors::MEDIUMAQUAMARINE,
|
||||
};
|
||||
if debug_color.a != 0.0 {
|
||||
if let Some(rect) = calculate_prim_clipped_world_rect(
|
||||
&prim_instance.vis.clip_chain.pic_coverage_rect,
|
||||
&world_culling_rect,
|
||||
&map_surface_to_world,
|
||||
) {
|
||||
let debug_rect = rect * frame_context.global_device_pixel_scale;
|
||||
frame_state.scratch.primitive.push_debug_rect(debug_rect, debug_color, debug_color.scale_alpha(0.5));
|
||||
}
|
||||
}
|
||||
} else if frame_context.debug_flags.contains(::api::DebugFlags::OBSCURE_IMAGES) {
|
||||
let is_image = matches!(
|
||||
prim_instance.kind,
|
||||
PrimitiveInstanceKind::Image { .. } | PrimitiveInstanceKind::YuvImage { .. }
|
||||
);
|
||||
if is_image {
|
||||
// We allow "small" images, since they're generally UI elements.
|
||||
if let Some(rect) = calculate_prim_clipped_world_rect(
|
||||
&prim_instance.vis.clip_chain.pic_coverage_rect,
|
||||
&world_culling_rect,
|
||||
&map_surface_to_world,
|
||||
) {
|
||||
let rect = rect * frame_context.global_device_pixel_scale;
|
||||
if rect.width() > 70.0 && rect.height() > 70.0 {
|
||||
frame_state.scratch.primitive.push_debug_rect(rect, debug_colors::PURPLE, debug_colors::PURPLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if prim_instance.is_chased() {
|
||||
info!("\tvisible with {:?}", prim_instance.vis.combined_local_clip_rect);
|
||||
}
|
||||
|
||||
// TODO(gw): This should probably be an instance method on PrimitiveInstance?
|
||||
update_prim_post_visibility(
|
||||
store,
|
||||
prim_instance,
|
||||
world_culling_rect,
|
||||
let clip_chain = frame_state
|
||||
.clip_store
|
||||
.build_clip_chain_instance(
|
||||
local_coverage_rect,
|
||||
&map_local_to_surface,
|
||||
&map_surface_to_world,
|
||||
&frame_context.spatial_tree,
|
||||
frame_state.gpu_cache,
|
||||
frame_state.resource_cache,
|
||||
device_pixel_scale,
|
||||
&world_culling_rect,
|
||||
&mut frame_state.data_stores.clip,
|
||||
true,
|
||||
prim_instance.is_chased(),
|
||||
);
|
||||
|
||||
// Ensure the primitive clip is popped
|
||||
frame_state.clip_chain_stack.pop_clip();
|
||||
|
||||
prim_instance.vis.clip_chain = match clip_chain {
|
||||
Some(clip_chain) => clip_chain,
|
||||
None => {
|
||||
if prim_instance.is_chased() {
|
||||
info!("\tunable to build the clip chain, skipping");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
if prim_instance.is_chased() {
|
||||
info!("\teffective clip chain from {:?} {}",
|
||||
prim_instance.vis.clip_chain.clips_range,
|
||||
if pic.apply_local_clip_rect { "(applied)" } else { "" },
|
||||
);
|
||||
info!("\tpicture rect {:?} @{:?}",
|
||||
prim_instance.vis.clip_chain.pic_coverage_rect,
|
||||
prim_instance.vis.clip_chain.pic_spatial_node_index,
|
||||
);
|
||||
}
|
||||
|
||||
prim_instance.vis.combined_local_clip_rect = if pic.apply_local_clip_rect {
|
||||
prim_instance.vis.clip_chain.local_clip_rect
|
||||
} else {
|
||||
prim_instance.clip_set.local_clip_rect
|
||||
};
|
||||
|
||||
tile_cache.update_prim_dependencies(
|
||||
prim_instance,
|
||||
cluster.spatial_node_index,
|
||||
// It's OK to pass the local_coverage_rect here as it's only used by primitives
|
||||
// (for compositor surfaces) that don't have inflation anyway.
|
||||
local_coverage_rect,
|
||||
frame_context,
|
||||
frame_state.data_stores,
|
||||
frame_state.clip_store,
|
||||
&store.pictures,
|
||||
frame_state.resource_cache,
|
||||
&store.color_bindings,
|
||||
&frame_state.surface_stack,
|
||||
&mut frame_state.composite_state,
|
||||
&mut frame_state.gpu_cache,
|
||||
is_root_tile_cache,
|
||||
surfaces,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Similar to above, pop either the clip chain or root entry off the current clip stack.
|
||||
if pop_surface {
|
||||
frame_state.pop_surface();
|
||||
}
|
||||
|
||||
let pic = &mut store.pictures[pic_index.0];
|
||||
pic.prim_list = prim_list;
|
||||
|
||||
// If the local rect changed (due to transforms in child primitives) then
|
||||
// invalidate the GPU cache location to re-upload the new local rect
|
||||
// and stretch size. Drop shadow filters also depend on the local rect
|
||||
// size for the extra GPU cache data handle.
|
||||
// TODO(gw): In future, if we support specifying a flag which gets the
|
||||
// stretch size from the segment rect in the shaders, we can
|
||||
// remove this invalidation here completely.
|
||||
if let Some(ref rc) = pic.raster_config {
|
||||
// Inflate the local bounding rect if required by the filter effect.
|
||||
if pic.options.inflate_if_required {
|
||||
surface_rect = rc.composite_mode.inflate_picture_rect(surface_rect, surface.scale_factors);
|
||||
}
|
||||
|
||||
// Layout space for the picture is picture space from the
|
||||
// perspective of its child primitives.
|
||||
pic.precise_local_rect = surface_rect * Scale::new(1.0);
|
||||
|
||||
// If the precise rect changed since last frame, we need to invalidate
|
||||
// any segments and gpu cache handles for drop-shadows.
|
||||
// TODO(gw): Requiring storage of the `prev_precise_local_rect` here
|
||||
// is a total hack. It's required because `prev_precise_local_rect`
|
||||
// gets written to twice (during initial vis pass and also during
|
||||
// prepare pass). The proper longer term fix for this is to make
|
||||
// use of the conservative picture rect for segmenting (which should
|
||||
// be done during scene building).
|
||||
if pic.precise_local_rect != pic.prev_precise_local_rect {
|
||||
match rc.composite_mode {
|
||||
PictureCompositeMode::Filter(Filter::DropShadows(..)) => {
|
||||
for handle in &pic.extra_gpu_data_handles {
|
||||
frame_state.gpu_cache.invalidate(handle);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
// Invalidate any segments built for this picture, since the local
|
||||
// rect has changed.
|
||||
pic.segments_are_valid = false;
|
||||
pic.prev_precise_local_rect = pic.precise_local_rect;
|
||||
}
|
||||
|
||||
match rc.composite_mode {
|
||||
PictureCompositeMode::TileCache { .. } => {}
|
||||
_ => {
|
||||
|
@ -582,50 +386,6 @@ pub fn update_primitive_visibility(
|
|||
tile_cache.pop_surface();
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
} else {
|
||||
let parent_surface = &frame_context.surfaces[parent_surface_index.expect("bug: no parent").0 as usize];
|
||||
let map_surface_to_parent_surface = SpaceMapper::new_with_target(
|
||||
parent_surface.surface_spatial_node_index,
|
||||
surface.surface_spatial_node_index,
|
||||
PictureRect::max_rect(),
|
||||
frame_context.spatial_tree,
|
||||
);
|
||||
map_surface_to_parent_surface.map(&surface_rect)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn update_prim_post_visibility(
|
||||
store: &mut PrimitiveStore,
|
||||
prim_instance: &mut PrimitiveInstance,
|
||||
world_culling_rect: &WorldRect,
|
||||
map_surface_to_world: &SpaceMapper<PicturePixel, WorldPixel>,
|
||||
) {
|
||||
profile_scope!("update_prim_post_visibility");
|
||||
match prim_instance.kind {
|
||||
PrimitiveInstanceKind::Picture { pic_index, .. } => {
|
||||
let pic = &mut store.pictures[pic_index.0];
|
||||
// If this picture has a surface, determine the clipped bounding rect for it to
|
||||
// minimize the size of the render target that is required.
|
||||
if let Some(ref mut raster_config) = pic.raster_config {
|
||||
raster_config.clipped_bounding_rect = map_surface_to_world
|
||||
.map(&prim_instance.vis.clip_chain.pic_coverage_rect)
|
||||
.and_then(|rect| {
|
||||
rect.intersection(world_culling_rect)
|
||||
})
|
||||
.unwrap_or(WorldRect::zero());
|
||||
}
|
||||
}
|
||||
PrimitiveInstanceKind::TextRun { .. } => {
|
||||
// Text runs can't request resources early here, as we don't
|
||||
// know until TileCache::post_update() whether we are drawing
|
||||
// on an opaque surface.
|
||||
// TODO(gw): We might be able to detect simple cases of this earlier,
|
||||
// during the picture traversal. But it's probably not worth it?
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -676,15 +436,3 @@ pub fn compute_conservative_visible_rect(
|
|||
None => clip_chain.local_clip_rect,
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate_prim_clipped_world_rect(
|
||||
pic_clip_rect: &PictureRect,
|
||||
world_culling_rect: &WorldRect,
|
||||
map_surface_to_world: &SpaceMapper<PicturePixel, WorldPixel>,
|
||||
) -> Option<WorldRect> {
|
||||
map_surface_to_world
|
||||
.map(&pic_clip_rect)
|
||||
.and_then(|world_rect| {
|
||||
world_rect.intersection(world_culling_rect)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
# Ensure that we correctly calculate the UV sampling rect for the backdrop
|
||||
# Similar to the mix-blend-mode-overflowing-child.html test in Gecko
|
||||
---
|
||||
root:
|
||||
items:
|
||||
- type: rect
|
||||
bounds: [0, 0, 100, 100]
|
||||
color: green
|
||||
- type: rect
|
||||
bounds: [50, 50, 100, 100]
|
||||
color: green
|
||||
- type: rect
|
||||
bounds: [50, 50, 50, 50]
|
||||
color: black
|
|
@ -0,0 +1,18 @@
|
|||
# Ensure that we correctly calculate the UV sampling rect for the backdrop
|
||||
# Similar to the mix-blend-mode-overflowing-child.html test in Gecko
|
||||
---
|
||||
root:
|
||||
items:
|
||||
- type: stacking-context
|
||||
blend-container: true
|
||||
items:
|
||||
- type: rect
|
||||
bounds: [0, 0, 100, 100]
|
||||
color: green
|
||||
- type: stacking-context
|
||||
bounds: [50, 50, 100, 100]
|
||||
mix-blend-mode: difference
|
||||
items:
|
||||
- type: rect
|
||||
bounds: [0, 0, 100, 100]
|
||||
color: green
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
root:
|
||||
items:
|
||||
- type: stacking-context
|
||||
blend-container: true
|
||||
bounds: [0, 0, 100, 100]
|
||||
items:
|
||||
- type: rect
|
||||
bounds: [0, 0, 100, 100]
|
||||
color: [255, 0, 0]
|
||||
- type: stacking-context
|
||||
bounds: [0, 0, 100, 100]
|
||||
mix-blend-mode: hue
|
||||
items:
|
||||
- type: rect
|
||||
bounds: [0, 0, 100, 100]
|
||||
color: [255, 255, 0]
|
|
@ -0,0 +1,22 @@
|
|||
# verify that the clipping_rect of a child surface (caused by the identity filter)
|
||||
# is corrected used to select the backdrop for a mix-blend child surface
|
||||
---
|
||||
root:
|
||||
items:
|
||||
- type: stacking-context
|
||||
filters: [identity]
|
||||
items:
|
||||
- type: stacking-context
|
||||
blend-container: true
|
||||
bounds: [0, 0, 100, 100]
|
||||
items:
|
||||
- type: rect
|
||||
bounds: [0, 0, 100, 100]
|
||||
color: [255, 0, 0]
|
||||
- type: stacking-context
|
||||
bounds: [0, 0, 100, 100]
|
||||
mix-blend-mode: hue
|
||||
items:
|
||||
- type: rect
|
||||
bounds: [0, 0, 100, 100]
|
||||
color: [255, 255, 0]
|
Двоичные данные
gfx/wr/wrench/reftests/blend/mix-blend-complex-transform.png
До Ширина: | Высота: | Размер: 18 KiB После Ширина: | Высота: | Размер: 33 KiB |
|
@ -25,3 +25,5 @@ fuzzy(2,420) == multi-mix-blend-mode.yaml multi-mix-blend-mode-ref.yaml
|
|||
== mix-blend-invalid-backdrop.yaml mix-blend-invalid-backdrop-ref.yaml
|
||||
platform(linux) == mix-blend-complex-transform.yaml mix-blend-complex-transform.png
|
||||
== raster-roots-1.yaml raster-roots-1-ref.yaml
|
||||
== child-surface.yaml child-surface-ref.yaml
|
||||
== blend-overflow.yaml blend-overflow-ref.yaml
|
||||
|
|
|
@ -10,7 +10,7 @@ platform(linux,mac) == segmentation-with-other-coordinate-system-clip.yaml segme
|
|||
== 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
|
||||
== snapping.yaml snapping-ref.yaml
|
||||
fuzzy(70,2400) == clip-and-filter-with-rotation.yaml clip-and-filter-with-rotation-ref.yaml
|
||||
fuzzy(160,1055) == clip-and-filter-with-rotation.yaml clip-and-filter-with-rotation-ref.yaml
|
||||
== clipped-occlusion.yaml clipped-occlusion-ref.yaml
|
||||
== clip-empty-inner-rect.yaml clip-empty-inner-rect-ref.yaml
|
||||
== iframe-nested-in-stacking-context.yaml iframe-nested-in-stacking-context-ref.yaml
|
||||
|
|
Двоичные данные
gfx/wr/wrench/reftests/filters/blend-clipped-raster-root.png
До Ширина: | Высота: | Размер: 16 KiB После Ширина: | Высота: | Размер: 16 KiB |
Двоичные данные
gfx/wr/wrench/reftests/filters/blend-clipped.png
До Ширина: | Высота: | Размер: 2.0 KiB После Ширина: | Высота: | Размер: 2.4 KiB |
Двоичные данные
gfx/wr/wrench/reftests/filters/filter-blur-scaled-xonly.png
До Ширина: | Высота: | Размер: 3.3 KiB После Ширина: | Высота: | Размер: 3.5 KiB |
Двоичные данные
gfx/wr/wrench/reftests/filters/filter-blur.png
До Ширина: | Высота: | Размер: 53 KiB После Ширина: | Высота: | Размер: 54 KiB |
Двоичные данные
gfx/wr/wrench/reftests/filters/filter-drop-shadow-clip-2.png
До Ширина: | Высота: | Размер: 3.0 KiB После Ширина: | Высота: | Размер: 2.9 KiB |
Двоичные данные
gfx/wr/wrench/reftests/filters/filter-drop-shadow-clip-3.png
До Ширина: | Высота: | Размер: 32 KiB После Ширина: | Высота: | Размер: 46 KiB |
Двоичные данные
gfx/wr/wrench/reftests/filters/filter-drop-shadow-clip.png
До Ширина: | Высота: | Размер: 12 KiB После Ширина: | Высота: | Размер: 12 KiB |
До Ширина: | Высота: | Размер: 10 KiB После Ширина: | Высота: | Размер: 11 KiB |
Двоичные данные
gfx/wr/wrench/reftests/filters/filter-drop-shadow.png
До Ширина: | Высота: | Размер: 77 KiB После Ширина: | Высота: | Размер: 77 KiB |
Двоичные данные
gfx/wr/wrench/reftests/filters/filter-large-blur-radius.png
До Ширина: | Высота: | Размер: 107 KiB После Ширина: | Высота: | Размер: 116 KiB |
|
@ -36,7 +36,7 @@ platform(linux,mac) == filter-drop-shadow-on-viewport-edge.yaml filter-drop-shad
|
|||
platform(linux,mac) == blend-clipped.yaml blend-clipped.png
|
||||
platform(linux,mac) == filter-drop-shadow-clip.yaml filter-drop-shadow-clip.png
|
||||
fuzzy(2,10) platform(linux,mac) == filter-drop-shadow-clip-2.yaml filter-drop-shadow-clip-2.png
|
||||
fuzzy(1,26) platform(linux) == filter-drop-shadow-clip-3.yaml filter-drop-shadow-clip-3.png
|
||||
fuzzy(1,58) platform(linux) == filter-drop-shadow-clip-3.yaml filter-drop-shadow-clip-3.png
|
||||
fuzzy(5,100000) == filter-drop-shadow-scaled.yaml filter-drop-shadow-scaled-ref.yaml
|
||||
== filter-segments.yaml filter-segments-ref.yaml
|
||||
== iframe-dropshadow.yaml iframe-dropshadow-ref.yaml
|
||||
|
@ -46,10 +46,10 @@ skip_on(android,device) == filter-mix-blend-mode.yaml filter-mix-blend-mode-ref.
|
|||
!= filter-blur-huge.yaml blank.yaml
|
||||
!= filter-drop-shadow-huge.yaml blank.yaml
|
||||
!= filter-drop-shadow-transform-huge.yaml blank.yaml
|
||||
fuzzy(3,79400) == filter-drop-shadow-blur-clamping.yaml filter-drop-shadow-blur-clamping-ref.yaml
|
||||
fuzzy(4,62000) == filter-drop-shadow-blur-clamping.yaml filter-drop-shadow-blur-clamping-ref.yaml
|
||||
== filter-blur-scaled.yaml filter-blur-scaled-ref.yaml
|
||||
== filter-blur-clamping.yaml filter-blur-clamping-ref.yaml
|
||||
skip_on(android,device) fuzzy(1,104) fuzzy-if(platform(swgl),4,18484) == filter-blur-scaled-xonly.yaml filter-blur-scaled-xonly.png # fails on Pixel2
|
||||
fuzzy(5,72000) == filter-blur-clamping.yaml filter-blur-clamping-ref.yaml
|
||||
skip_on(android,device) skip_on(win) fuzzy(1,104) fuzzy-if(platform(swgl),4,18484) == filter-blur-scaled-xonly.yaml filter-blur-scaled-xonly.png # fails on Pixel2
|
||||
== svg-filter-component-transfer.yaml filter-component-transfer-ref.yaml
|
||||
== svg-filter-flood.yaml svg-filter-flood-ref.yaml
|
||||
skip_on(android,device) == svg-filter-blend.yaml svg-filter-blend-ref.yaml
|
||||
|
@ -57,7 +57,7 @@ skip_on(android,device) == svg-filter-color-matrix.yaml filter-color-matrix-ref.
|
|||
platform(linux,mac) == draw_calls(8) color_targets(8) alpha_targets(0) svg-filter-blur.yaml filter-blur.png # Extra draw call is due to render task graph workaround
|
||||
platform(linux,mac) == svg-filter-drop-shadow.yaml svg-filter-drop-shadow.png
|
||||
== fuzzy(1,10000) svg-srgb-to-linear.yaml srgb-to-linear-ref.yaml
|
||||
platform(linux,mac) == fuzzy(5,35250) svg-filter-drop-shadow-rotate.yaml svg-filter-drop-shadow-rotate-ref.yaml
|
||||
platform(linux,mac) == fuzzy(6,36790) svg-filter-drop-shadow-rotate.yaml svg-filter-drop-shadow-rotate-ref.yaml
|
||||
platform(linux,mac) fuzzy(3,3550) == svg-filter-blur-transforms.yaml svg-filter-blur-transforms.png
|
||||
platform(linux,mac) == svg-filter-drop-shadow-on-viewport-edge.yaml svg-filter-drop-shadow-on-viewport-edge.png
|
||||
fuzzy(1,1) platform(linux,mac) == svg-filter-drop-shadow-perspective.yaml svg-filter-drop-shadow-perspective.png
|
||||
|
|
До Ширина: | Высота: | Размер: 11 KiB После Ширина: | Высота: | Размер: 11 KiB |
Двоичные данные
gfx/wr/wrench/reftests/text/raster-space.png
До Ширина: | Высота: | Размер: 61 KiB После Ширина: | Высота: | Размер: 61 KiB |
|
@ -81,5 +81,5 @@ fuzzy(1,15) platform(linux) force_subpixel_aa_where_possible(false) == text-fixe
|
|||
# most pixels are off by a small amount, but a few pixels on the edge vary by a lot, pushing up the fuzzy max-diff;
|
||||
# the main goal of the test is that everything is in the same place, at the same scale, clipped the same way,
|
||||
# despite 4x on-the-fly scale change.
|
||||
skip_on(android) fuzzy-range(<=3,*21700,<=20,*3500,<=119,*590) fuzzy-if(platform(swgl),108,24907) == raster_root_C_8192.yaml raster_root_C_ref.yaml
|
||||
skip_on(android) fuzzy(205,26560) == raster_root_C_8192.yaml raster_root_C_ref.yaml
|
||||
== subpx-bg-mask.yaml subpx-bg-mask-ref.yaml
|
||||
|
|
Двоичные данные
gfx/wr/wrench/reftests/text/shadow-transforms.png
До Ширина: | Высота: | Размер: 93 KiB После Ширина: | Высота: | Размер: 93 KiB |
|
@ -3,7 +3,7 @@ root:
|
|||
items:
|
||||
- type: stacking-context
|
||||
transform-style: preserve-3d
|
||||
transform: scale(-2, 44, 44727)
|
||||
transform: scale(-2, 44, 1)
|
||||
items:
|
||||
- type: rect
|
||||
bounds: [ -100, -100, 200, 101 ]
|
||||
|
|
Двоичные данные
gfx/wr/wrench/reftests/transforms/screen-space-blur.png
До Ширина: | Высота: | Размер: 226 KiB После Ширина: | Высота: | Размер: 225 KiB |
|
@ -2058,7 +2058,7 @@ pref(layout.css.supports-selector.enabled,false) != 1499386.html 1499386-ref.htm
|
|||
== 1513423-2.html 1513423-2-ref.html
|
||||
== 1513423-3.html 1513423-3-ref.html
|
||||
pref(layout.accessiblecaret.enabled,true) == 1517385.html 1517385-ref.html
|
||||
fuzzy-if(winWidget&&swgl,1-1,12-16) fuzzy-if(cocoaWidget&&swgl,1-1,32-32) fuzzy-if(useDrawSnapshot,2-2,209-209) == 1529992-1.html 1529992-1-ref.html
|
||||
fuzzy(0-5,0-2300) == 1529992-1.html 1529992-1-ref.html
|
||||
fuzzy-if(Android,9-14,44-60) fails-if(!useDrawSnapshot) == 1529992-2.html 1529992-2-ref.html
|
||||
== 1535040-1.html 1535040-1-ref.html
|
||||
== 1545360-1.xhtml 1545360-1-ref.xhtml
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
# e.g. filter: blur(3px) grayscale(0.5) invert(0.2);
|
||||
|
||||
# Some platforms render this complex filter chain a little differently, and that's ok.
|
||||
fuzzy(4-6,12000-19484) fuzzy-if(swgl,5-10,13600-20088) == long-chain.html long-chain-ref.html # Win10: Bug 1258241
|
||||
fuzzy(4-6,12000-19520) fuzzy-if(swgl,5-10,13600-20260) == long-chain.html long-chain-ref.html # Win10: Bug 1258241
|
||||
== moz-element.html moz-element-ref.html
|
||||
fuzzy-if(!useDrawSnapshot,13-15,7670-7982) fuzzy-if(!useDrawSnapshot&&swgl,11-12,14052-14056) == same-filter.html same-filter-ref.html
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
== clip-input.svg clip-input-ref.svg
|
||||
== clip-original-SourceGraphic.svg clip-original-SourceGraphic-ref.svg
|
||||
== clip-output.svg clip-output-ref.svg
|
||||
fuzzy(0-5,0-20155) == default-subregion.svg default-subregion-ref.svg
|
||||
fuzzy(0-5,0-20165) == default-subregion.svg default-subregion-ref.svg
|
||||
== different-FillPaint-filter-regions.svg different-FillPaint-filter-regions-ref.svg
|
||||
== different-StrokePaint-filter-regions.svg different-StrokePaint-filter-regions-ref.svg
|
||||
== dont-clip-previous-primitives.svg dont-clip-previous-primitives-ref.svg
|
||||
== intersecting-filter-regions.svg intersecting-filter-regions-ref.svg
|
||||
fuzzy-if(!useDrawSnapshot,9-9,5168-5536) fuzzy-if(!useDrawSnapshot&&swgl,7-7,13184-13184) == long-chain.svg simple-chain-ref.svg
|
||||
fuzzy-if(!useDrawSnapshot,9-9,5168-5536) fuzzy-if(!useDrawSnapshot&&swgl,7-7,13184-13184) == multiple-primitives-per-filter.svg simple-chain-ref.svg
|
||||
fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-173) fuzzy-if(!useDrawSnapshot||(winWidget&&isCoverageBuild),9-9,5128-5496) fuzzy-if(!useDrawSnapshot&&swgl,7-7,12836-12836) == second-filter-uses-SourceAlpha.svg second-filter-uses-SourceAlpha-ref.svg
|
||||
fuzzy-if(!useDrawSnapshot,9-9,5168-5536) fuzzy-if(!useDrawSnapshot&&swgl,7-7,13184-13184) == second-filter-uses-SourceGraphic.svg simple-chain-ref.svg
|
||||
fuzzy-if(!useDrawSnapshot,9-9,5168-5536) fuzzy-if(!useDrawSnapshot&&swgl,7-7,13170-13184) == long-chain.svg simple-chain-ref.svg
|
||||
fuzzy-if(!useDrawSnapshot,9-9,5168-5536) fuzzy-if(!useDrawSnapshot&&swgl,7-7,13170-13184) == multiple-primitives-per-filter.svg simple-chain-ref.svg
|
||||
fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-173) fuzzy-if(!useDrawSnapshot||(winWidget&&isCoverageBuild),9-9,5128-5496) fuzzy-if(!useDrawSnapshot&&swgl,7-7,12820-12830) == second-filter-uses-SourceAlpha.svg second-filter-uses-SourceAlpha-ref.svg
|
||||
fuzzy-if(!useDrawSnapshot,9-9,5168-5536) fuzzy-if(!useDrawSnapshot&&swgl,7-7,13170-13180) == second-filter-uses-SourceGraphic.svg simple-chain-ref.svg
|
||||
== simple-chain.svg simple-chain-ref.svg
|
||||
|
|
|
@ -3,7 +3,7 @@ random-if(Android) == chrome://reftest/content/text-shadow/basic-negcoord.xhtml
|
|||
!= chrome://reftest/content/text-shadow/blur.xhtml chrome://reftest/content/text-shadow/blur-notref.xhtml
|
||||
== chrome://reftest/content/text-shadow/color-inherit.xhtml chrome://reftest/content/text-shadow/color-inherit-ref.xhtml
|
||||
== chrome://reftest/content/text-shadow/multiple-noblur.xhtml chrome://reftest/content/text-shadow/multiple-noblur-ref.xhtml
|
||||
fuzzy-if(swgl&&!Android,2-2,6320-6320) random-if(useDrawSnapshot) == blur-opacity.html blur-opacity-ref.html
|
||||
fuzzy(0-2,0-6400) random-if(useDrawSnapshot) == blur-opacity.html blur-opacity-ref.html
|
||||
|
||||
fuzzy-if(cocoaWidget,0-27,0-2) fuzzy-if(winWidget,0-47,0-2) == overflow-clip.html overflow-clip-ref.html
|
||||
|
||||
|
|
|
@ -82,9 +82,9 @@ fuzzy(0-1,0-10000) == opacity-preserve3d-3.html opacity-preserve3d-3-ref.html
|
|||
fuzzy(0-1,0-10000) == opacity-preserve3d-4.html opacity-preserve3d-4-ref.html
|
||||
== opacity-preserve3d-5.html opacity-preserve3d-5-ref.html
|
||||
== snap-perspective-1.html snap-perspective-1-ref.html
|
||||
fuzzy-if(Android,0-8,0-1) == mask-layer-1.html mask-layer-ref.html
|
||||
fuzzy-if(Android,0-8,0-1) == mask-layer-2.html mask-layer-ref.html
|
||||
fuzzy(0-16,0-132) == mask-layer-3.html mask-layer-ref.html
|
||||
fuzzy(0-120,0-590) == mask-layer-1.html mask-layer-ref.html
|
||||
fuzzy(0-120,0-590) == mask-layer-2.html mask-layer-ref.html
|
||||
fuzzy(0-120,0-590) == mask-layer-3.html mask-layer-ref.html
|
||||
== split-intersect1.html split-intersect1-ref.html
|
||||
fuzzy(0-255,0-150) fails-if(useDrawSnapshot) == split-intersect2.html split-intersect2-ref.html
|
||||
fuzzy(0-255,0-100) fails-if(useDrawSnapshot) == split-non-ortho1.html split-non-ortho1-ref.html
|
||||
|
@ -94,7 +94,7 @@ fuzzy-if(winWidget&&!nativeThemePref,0-4,0-51) == transform-geometry-1.html tran
|
|||
== intermediate-1.html intermediate-1-ref.html
|
||||
== preserves3d-nested-filter-1.html preserves3d-nested-filter-1-ref.html
|
||||
!= preserve3d-scale.html about:blank
|
||||
fuzzy(0-51,0-1154) == preserve3d-scale.html preserve3d-scale-ref.html
|
||||
fuzzy(0-50,0-1460) == preserve3d-scale.html preserve3d-scale-ref.html
|
||||
fuzzy(0-1,0-5) == perspective-overflow-1.html perspective-overflow-1-ref.html
|
||||
== perspective-overflow-2.html perspective-overflow-2-ref.html
|
||||
== 1544995-1.html 1544995-1-ref.html
|
||||
|
|
|
@ -159,13 +159,13 @@ test-pref(layout.css.zoom-transform-hack.enabled,true) == zoom-hack-2.html zoom-
|
|||
== transform-anon-block-1.html transform-anon-block-1-ref.html
|
||||
test-pref(layout.animation.prerender.partial.jank,true) test-pref(layout.animation.prerender.partial,true) == partial-prerender-expansion-translate.html partial-prerender-expansion-ref.html
|
||||
test-pref(layout.animation.prerender.partial,true) == partial-prerender-translate-1.html about:blank
|
||||
test-pref(layout.animation.prerender.partial.jank,true) test-pref(layout.animation.prerender.partial,true) test-pref(layout.animation.prerender.viewport-ratio-limit,"1.125") == partial-prerender-translate-2.html partial-prerender-translate-2-ref.html
|
||||
test-pref(layout.animation.prerender.partial.jank,true) test-pref(layout.animation.prerender.partial,true) test-pref(layout.animation.prerender.viewport-ratio-limit,"1.125") fuzzy-if(Android,0-255,0-7000) == partial-prerender-translate-2.html partial-prerender-translate-2-ref.html
|
||||
fails-if(!useDrawSnapshot) test-pref(layout.animation.prerender.partial.jank,true) test-pref(layout.animation.prerender.partial,true) test-pref(layout.animation.prerender.viewport-ratio-limit,"1.125") == partial-prerender-translate-3.html partial-prerender-translate-3-ref.html # bug 1642575
|
||||
# This reftest doesn't fail on WebRender, this reftest fails only if there is a jank mechanism and the mechanism doesn't properly handle ancestor's transform values
|
||||
test-pref(layout.animation.prerender.partial.jank,true) test-pref(layout.animation.prerender.partial,true) test-pref(layout.animation.prerender.viewport-ratio-limit,"1.125") == partial-prerender-translate-4.html partial-prerender-expansion-ref.html
|
||||
# This reftest doesn't fail on WebRender, this reftest fails only if there is a jank mechanism and the mechanism does inproperly handle position:fixed scroll target
|
||||
test-pref(layout.animation.prerender.partial.jank,true) test-pref(layout.animation.prerender.partial,true) test-pref(layout.animation.prerender.viewport-ratio-limit,"1.125") == partial-prerender-translate-5.html partial-prerender-translate-5-ref.html
|
||||
random-if(useDrawSnapshot) test-pref(layout.animation.prerender.partial.jank,true) test-pref(layout.animation.prerender.partial,true) test-pref(layout.animation.prerender.viewport-ratio-limit,"1.125") == partial-prerender-translate-6.html partial-prerender-translate-6-ref.html
|
||||
random-if(useDrawSnapshot) test-pref(layout.animation.prerender.partial.jank,true) test-pref(layout.animation.prerender.partial,true) test-pref(layout.animation.prerender.viewport-ratio-limit,"1.125") fuzzy-if(Android,0-255,0-9900) == partial-prerender-translate-6.html partial-prerender-translate-6-ref.html
|
||||
test-pref(layout.animation.prerender.partial.jank,true) test-pref(layout.animation.prerender.partial,true) test-pref(layout.animation.prerender.viewport-ratio-limit,"1.125") == partial-prerender-translate-7.html partial-prerender-translate-2-ref.html
|
||||
# This reftest doesn't fail on WebRender, this reftest fails only if there is a jank mechanism and the mechanism doesn't properly clip transform in iframes.
|
||||
test-pref(layout.animation.prerender.partial.jank,true) test-pref(layout.animation.prerender.partial,true) test-pref(layout.animation.prerender.viewport-ratio-limit,"1.125") == partial-prerender-translate-8.html partial-prerender-translate-8-ref.html
|
||||
|
@ -179,6 +179,6 @@ skip test-pref(layout.animation.prerender.partial.jank,true) test-pref(layout.an
|
|||
skip-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)||Android) test-pref(layout.animation.prerender.partial,true) test-pref(layout.animation.prerender.viewport-ratio-limit,"1.125") fuzzy-if(!layersGPUAccelerated,0-75,0-2683) == partial-prerender-expansion-rotate.html partial-prerender-expansion-ref.html
|
||||
skip-if(useDrawSnapshot) test-pref(layout.animation.prerender.partial,true) test-pref(layout.animation.prerender.viewport-ratio-limit,"1.125") pref(dom.meta-viewport.enabled,true) pref(apz.allow_zooming,true) == partial-prerender-expansion-with-resolution-1.html partial-prerender-expansion-with-resolution-ref.html
|
||||
skip test-pref(layout.animation.prerender.partial,true) test-pref(layout.animation.prerender.viewport-ratio-limit,"1.125") pref(dom.meta-viewport.enabled,true) pref(apz.allow_zooming,true) == partial-prerender-expansion-with-resolution-2.html partial-prerender-expansion-with-resolution-ref.html # bug 1650039 for WebRender
|
||||
test-pref(layout.animation.prerender.partial.jank,true) test-pref(layout.animation.prerender.partial,true) test-pref(layout.animation.prerender.viewport-ratio-limit,"1.125") == partial-prerender-in-svg-1.html partial-prerender-in-svg-1-ref.html
|
||||
test-pref(layout.animation.prerender.partial.jank,true) test-pref(layout.animation.prerender.partial,true) test-pref(layout.animation.prerender.viewport-ratio-limit,"1.125") fuzzy-if(Android,0-255,0-400) == partial-prerender-in-svg-1.html partial-prerender-in-svg-1-ref.html
|
||||
test-pref(layout.animation.prerender.partial.jank,true) test-pref(layout.animation.prerender.partial,true) test-pref(layout.animation.prerender.viewport-ratio-limit,"1.125") == partial-prerender-in-svg-2.html partial-prerender-in-svg-1-ref.html # Reuse partial-prerender-in-svg-1-ref.html since the result should look same as partial-prerender-in-svg-1.html
|
||||
test-pref(layout.animation.prerender.partial.jank,true) test-pref(layout.animation.prerender.partial,true) test-pref(layout.animation.prerender.viewport-ratio-limit,"1.125") == partial-prerender-in-svg-3.html partial-prerender-in-svg-3-ref.html
|
||||
test-pref(layout.animation.prerender.partial.jank,true) test-pref(layout.animation.prerender.partial,true) test-pref(layout.animation.prerender.viewport-ratio-limit,"1.125") fuzzy-if(Android,0-255,0-2000) == partial-prerender-in-svg-3.html partial-prerender-in-svg-3-ref.html
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
[mix-blend-mode-both-parent-and-blended-with-3D-transform.html]
|
||||
fuzzy:
|
||||
maxDifference=94-95;totalPixels=340-460
|
|
@ -0,0 +1,3 @@
|
|||
[mix-blend-mode-parent-with-3D-transform.html]
|
||||
fuzzy:
|
||||
maxDifference=60-61;totalPixels=140-140
|
|
@ -1,3 +1,4 @@
|
|||
[mix-blend-mode-rotated-clip.html]
|
||||
expected:
|
||||
if swgl: PASS
|
||||
FAIL
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
[transform3d-preserve3d-001.html]
|
||||
expected:
|
||||
if os == "win": FAIL
|
||||
fuzzy:
|
||||
if os == "android": maxDifference=4;totalPixels=185
|
||||
if os == "mac": maxDifference=198;totalPixels=308
|
||||
if os == "win": maxDifference=174;totalPixels=240
|
||||
|
|