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
This commit is contained in:
Glenn Watson 2022-02-07 22:14:47 +00:00
Родитель 4f99e4612d
Коммит 331e48d4fe
49 изменённых файлов: 990 добавлений и 1480 удалений

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

@ -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]

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 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

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 16 KiB

После

Ширина:  |  Высота:  |  Размер: 16 KiB

Двоичные данные
gfx/wr/wrench/reftests/filters/blend-clipped.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.0 KiB

После

Ширина:  |  Высота:  |  Размер: 2.4 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.3 KiB

После

Ширина:  |  Высота:  |  Размер: 3.5 KiB

Двоичные данные
gfx/wr/wrench/reftests/filters/filter-blur.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 53 KiB

После

Ширина:  |  Высота:  |  Размер: 54 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.0 KiB

После

Ширина:  |  Высота:  |  Размер: 2.9 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 32 KiB

После

Ширина:  |  Высота:  |  Размер: 46 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 12 KiB

После

Ширина:  |  Высота:  |  Размер: 12 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 10 KiB

После

Ширина:  |  Высота:  |  Размер: 11 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 77 KiB

После

Ширина:  |  Высота:  |  Размер: 77 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 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

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 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 ]

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 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