Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync changes from mozilla-central gfx/wr #3872

Merged
merged 33 commits into from Mar 6, 2020
Merged
Changes from 1 commit
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
240b8ed
Bug 1510030 - Don't return the current opacity value from update_opac…
hiikezoe Feb 27, 2020
0809ea1
Bug 1510030 - Fix the comment for OpacityBinding::update(). r=gw
hiikezoe Feb 27, 2020
8aa347d
Bug 1510030 - Make prepare_prim_for_render private. r=gw
hiikezoe Feb 27, 2020
b2bc0a8
Bug 1510030 - Implement WebRender backend to run background color ani…
hiikezoe Feb 27, 2020
b0e0510
Backed out 6 changesets (bug 1510030) for webrender bustages CLOSED TREE
bogdantara Feb 27, 2020
8353c5a
Bug 1510030 - Don't return the current opacity value from update_opac…
hiikezoe Feb 27, 2020
6f45b76
Bug 1510030 - Fix the comment for OpacityBinding::update(). r=gw
hiikezoe Feb 27, 2020
d422aab
Bug 1510030 - Make prepare_prim_for_render private. r=gw
hiikezoe Feb 27, 2020
692bc61
Bug 1510030 - Implement WebRender backend to run background color ani…
hiikezoe Feb 27, 2020
1fc3512
Backed out 6 changesets (bug 1510030) for test_running_on_compositor.…
bogdantara Feb 27, 2020
13e86e2
Bug 1510030 - Don't return the current opacity value from update_opac…
hiikezoe Feb 27, 2020
ecd8232
Bug 1510030 - Fix the comment for OpacityBinding::update(). r=gw
hiikezoe Feb 27, 2020
b152ac5
Bug 1510030 - Make prepare_prim_for_render private. r=gw
hiikezoe Feb 27, 2020
7b1f4fa
Bug 1510030 - Implement WebRender backend to run background color ani…
hiikezoe Feb 27, 2020
1ee6c0f
Bug 1616995 - patch 2 - Support vertical skew for upright-vertical fo…
jfkthame Feb 29, 2020
85ccbbf
Bug 1596513: Part 1: Take scale factors into account when rendering d…
cbrewster Feb 29, 2020
142de92
Bug 1596513: Part 3: Ensure drop shadow blur radius does not exceed M…
cbrewster Feb 29, 2020
6cffb1b
Bug 1579235 - Part 6 - Support an opaque/alpha native surface per sli…
gw3583 Mar 2, 2020
54d5fe8
Bug 1579235 - Part 7 - Fix UV rect calculation for external textures.…
gw3583 Mar 2, 2020
ab7ca3e
Bug 1579235 - Part 8 - Remove overlay tiles, they can be alpha tiles …
gw3583 Mar 2, 2020
49df0ec
Bug 1619265 - Bump rust versions for github CI. r=jrmuizel
staktrace Mar 2, 2020
ad0cd12
Bug 1579235 - Part 9 - Optimize compositor surface overlays. r=Bert
gw3583 Mar 3, 2020
4d776c9
Bug 1613260 - Support per-task scale for local space rasterization r=…
bpeersmoz Mar 3, 2020
517a4b6
Bug 1619293 - Re-enable rust flags in github CI. r=jrmuizel
staktrace Mar 3, 2020
7ed1505
Bug 1613260 - Increase allowed fuzz on new tests so they pass in AppV…
staktrace Mar 4, 2020
bf01196
Bug 1618319: Segregate intern::UpdateList insertions and removals. r=gw
Mar 4, 2020
a1991bc
Bug 1579235 - Part 10 - Fix incorrect skipping of composites. r=Bert
gw3583 Mar 4, 2020
dab8afd
Bug 1619393 - Reftest improvements for fuzzy tests r=gw
bpeersmoz Mar 5, 2020
8d121d8
Bug 1616255 - Handle start and end offsets in conic-gradient WR shade…
nt1m Mar 5, 2020
256215e
Bug 1619393 - Increase fuzz by one to allow reftest to pass on AppVey…
staktrace Mar 6, 2020
5aad73f
Bug 1579235 - Part 11 - Refactor how external surfaces are composited…
gw3583 Mar 6, 2020
4236b41
Bug 1579235 - Part 12 - Support native compositor surfaces. r=Bert,so…
gw3583 Mar 6, 2020
51b4045
Bug 1618939 - Hit MOZ_CRASH(explicit panic) at gfx/wr/webrender/src/r…
bpeersmoz Mar 6, 2020
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Bug 1579235 - Part 9 - Optimize compositor surface overlays. r=Bert

This patch improves the performance of compositor surfaces in
two ways:

(1) Ignore primitives behind the first compositor surface when
    determining whether a tile needs to be moved to the overlay
    (alpha) pass. This means WR only moves a tile to the alpha
    pass when it has primitives that overlap with the compositor
    surface bounding rect, and are ordered after that compositor
    surface. In practice, this means most tiles are able to
    remain in the fast (opaque) path. Typically, a small number
    of tiles that contain overlay video controls are moved to the
    alpha pass.

(2) Register the opaque compositor surfaces as potential occluders.
    This allows tiles that are completely covered by a compositor
    surface to be removed from the compositor visual tree, which
    helps both the simple and native compositor modes.

Between them, these optimizations typically mean that when watching
video in full-screen, nothing is composited except the video surface
itself, and some small region(s) where video overlay controls are
currently active.

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

[ghsync] From https://hg.mozilla.org/mozilla-central/rev/f6dc6b38288cfcb9f5f70932830d4a3d2b3759b2
  • Loading branch information
gw3583 authored and moz-gfx committed Mar 3, 2020
commit ad0cd127e3c1d9ba8d0ded408fdca8a15be6f4dd
@@ -1227,12 +1227,10 @@ impl BatchBuilder {
.map(&prim_info.combined_local_clip_rect)
.expect("bug: unable to map clip rect");
let device_clip_rect = (world_clip_rect * ctx.global_device_pixel_scale).round();
let z_id = composite_state.z_generator.next();

composite_state.push_surface(
tile_cache,
device_clip_rect,
z_id,
ctx.global_device_pixel_scale,
ctx.resource_cache,
gpu_cache,
@@ -89,13 +89,15 @@ pub struct CompositeTile {
/// this will also support RGBA images.
pub struct ExternalSurfaceDescriptor {
pub local_rect: PictureRect,
pub world_rect: WorldRect,
pub device_rect: DeviceRect,
pub clip_rect: DeviceRect,
pub image_keys: [ImageKey; 3],
pub image_rendering: ImageRendering,
pub yuv_color_space: YuvColorSpace,
pub yuv_format: YuvFormat,
pub yuv_rescale: f32,
pub z_id: ZBufferId,
}

/// Information about a plane in a YUV surface.
@@ -215,7 +217,7 @@ impl Default for CompositorKind {
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
struct Occluder {
slice: usize,
z_id: ZBufferId,
device_rect: DeviceIntRect,
}

@@ -319,22 +321,22 @@ impl CompositeState {
/// used during frame building to occlude tiles.
pub fn register_occluder(
&mut self,
slice: usize,
z_id: ZBufferId,
rect: WorldRect,
) {
let device_rect = (rect * self.global_device_pixel_scale).round().to_i32();

self.occluders.push(Occluder {
device_rect,
slice,
z_id,
});
}

/// Returns true if a tile with the specified rectangle and slice
/// Returns true if a tile with the specified rectangle and z_id
/// is occluded by an opaque surface in front of it.
pub fn is_tile_occluded(
&self,
slice: usize,
z_id: ZBufferId,
device_rect: DeviceRect,
) -> bool {
// It's often the case that a tile is only occluded by considering multiple
@@ -354,7 +356,7 @@ impl CompositeState {
let ref_area = device_rect.size.width * device_rect.size.height;

// Calculate the non-overlapping area of the valid occluders.
let cover_area = area_of_occluders(&self.occluders, slice, &device_rect);
let cover_area = area_of_occluders(&self.occluders, z_id, &device_rect);
debug_assert!(cover_area <= ref_area);

// Check if the tile area is completely covered
@@ -366,7 +368,6 @@ impl CompositeState {
&mut self,
tile_cache: &TileCacheInstance,
device_clip_rect: DeviceRect,
z_id: ZBufferId,
global_device_pixel_scale: DevicePixelScale,
resource_cache: &ResourceCache,
gpu_cache: &mut GpuCache,
@@ -417,7 +418,7 @@ impl CompositeState {
valid_rect: tile.device_valid_rect.translate(-device_rect.origin.to_vector()),
dirty_rect: tile.device_dirty_rect.translate(-device_rect.origin.to_vector()),
clip_rect: device_clip_rect,
z_id,
z_id: tile.z_id,
tile_id,
};

@@ -479,14 +480,13 @@ impl CompositeState {
.intersection(&device_clip_rect)
.unwrap_or_else(DeviceRect::zero);

// z_id for compositor surfaces can be the same as the surface it
// exists on, because we use LessEqual depth function. We could
// in future consider disabling z-read completely for drawing
// surface overlay tiles, since it doesn't do anything useful.
// Get a new z_id for each compositor surface, to ensure correct ordering
// when drawing with the simple (Draw) compositor.

self.external_surfaces.push(ResolvedExternalSurface {
device_rect: external_surface.device_rect,
clip_rect,
z_id,
z_id: external_surface.z_id,
yuv_color_space: external_surface.yuv_color_space,
yuv_format: external_surface.yuv_format,
yuv_rescale: external_surface.yuv_rescale,
@@ -689,7 +689,7 @@ pub trait Compositor {
/// overlapping areas between those rectangles.
fn area_of_occluders(
occluders: &[Occluder],
slice: usize,
z_id: ZBufferId,
clip_rect: &DeviceIntRect,
) -> i32 {
// This implementation is based on the article https://leetcode.com/articles/rectangle-area-ii/.
@@ -730,7 +730,7 @@ fn area_of_occluders(
let mut events = Vec::with_capacity(occluders.len() * 2);
for occluder in occluders {
// Only consider occluders in front of this rect
if occluder.slice > slice {
if occluder.z_id.0 > z_id.0 {
// Clip the source rect to the rectangle we care about, since we only
// want to record area for the tile we are comparing to.
if let Some(rect) = occluder.device_rect.intersection(clip_rect) {
@@ -23,7 +23,7 @@ pub const VECS_PER_TRANSFORM: usize = 8;
#[repr(C)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct ZBufferId(i32);
pub struct ZBufferId(pub i32);

// We get 24 bits of Z value - use up 22 bits of it to give us
// 4 bits to account for GPU issues. This seems to manifest on
@@ -114,7 +114,7 @@ use crate::intern::ItemUid;
use crate::internal_types::{FastHashMap, FastHashSet, PlaneSplitter, Filter, PlaneSplitAnchor, TextureSource};
use crate::frame_builder::{FrameBuildingContext, FrameBuildingState, PictureState, PictureContext};
use crate::gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
use crate::gpu_types::UvRectKind;
use crate::gpu_types::{UvRectKind, ZBufferId};
use plane_split::{Clipper, Polygon, Splitter};
use crate::prim_store::{SpaceMapper, PrimitiveVisibilityMask, PointKey, PrimitiveTemplateKind};
use crate::prim_store::{SpaceSnapper, PictureIndex, PrimitiveInstance, PrimitiveInstanceKind};
@@ -495,6 +495,16 @@ struct TilePostUpdateContext<'a> {

/// A list of the external surfaces that are present on this slice
external_surfaces: &'a [ExternalSurfaceDescriptor],

/// Pre-allocated z-id to assign to opaque tiles during post_update. We
/// use a different z-id for opaque/alpha tiles, so that compositor
/// surfaces (such as videos) can have a z-id between these values,
/// which allows compositor surfaces to occlude opaque tiles, but not
/// alpha tiles.
z_id_opaque: ZBufferId,

/// Pre-allocated z-id to assign to alpha tiles during post_update
z_id_alpha: ZBufferId,
}

// Mutable state passed to picture cache tiles during post_update
@@ -856,6 +866,14 @@ pub struct Tile {
invalidation_reason: Option<InvalidationReason>,
/// If true, this tile has one or more compositor surfaces affecting it.
pub has_compositor_surface: bool,
/// The local space valid rect for any primitives found prior to the first compositor
/// surface that affects this tile.
bg_local_valid_rect: PictureRect,
/// The local space valid rect for any primitives found after the first compositor
/// surface that affects this tile.
fg_local_valid_rect: PictureRect,
/// z-buffer id for this tile, which is one of z_id_opaque or z_id_alpha, depending on tile opacity
pub z_id: ZBufferId,
}

impl Tile {
@@ -882,6 +900,9 @@ impl Tile {
background_color: None,
invalidation_reason: None,
has_compositor_surface: false,
bg_local_valid_rect: PictureRect::zero(),
fg_local_valid_rect: PictureRect::zero(),
z_id: ZBufferId::invalid(),
}
}

@@ -999,6 +1020,8 @@ impl Tile {
),
ctx.tile_size,
);
self.bg_local_valid_rect = PictureRect::zero();
self.fg_local_valid_rect = PictureRect::zero();
self.invalidation_reason = None;
self.has_compositor_surface = false;

@@ -1063,8 +1086,17 @@ impl Tile {
// Incorporate the bounding rect of the primitive in the local valid rect
// for this tile. This is used to minimize the size of the scissor rect
// during rasterization and the draw rect during composition of partial tiles.
self.current_descriptor.local_valid_rect =
self.current_descriptor.local_valid_rect.union(&info.prim_clip_rect);

// Once we have encountered 1+ compositor surfaces affecting this tile, include
// this bounding rect in the foreground. Otherwise, include in the background rect.
// This allows us to determine if we found any primitives that are on top of the
// compositor surface(s) for this tile. If so, we need to draw the tile with alpha
// blending as an overlay.
if self.has_compositor_surface {
self.fg_local_valid_rect = self.fg_local_valid_rect.union(&info.prim_clip_rect);
} else {
self.bg_local_valid_rect = self.bg_local_valid_rect.union(&info.prim_clip_rect);
}
}

// Include any image keys this tile depends on.
@@ -1159,6 +1191,11 @@ impl Tile {
return false;
}

// Calculate the overall valid rect for this tile, including both the foreground
// and background local valid rects.
self.current_descriptor.local_valid_rect =
self.bg_local_valid_rect.union(&self.fg_local_valid_rect);

// TODO(gw): In theory, the local tile rect should always have an
// intersection with the overall picture rect. In practice,
// due to some accuracy issues with how fract_offset (and
@@ -1216,19 +1253,29 @@ impl Tile {
let mut is_opaque = ctx.backdrop.rect.contains_rect(&clipped_rect);

if self.has_compositor_surface {
// TODO(gw): This will almost always select over blend, due to the
// background rectangle. In future, we can optimize this
// case to only check items that come _after_ the compositor
// surface z_id? A better option might be to tweak the z_id
// values so that the alpha pixels get z-rejected?
// If we found primitive(s) that are ordered _after_ the first compositor
// surface, _and_ intersect with any compositor surface, then we will need
// to draw this tile with alpha blending, as an overlay to the compositor surface.
let fg_world_valid_rect = ctx.pic_to_world_mapper
.map(&self.fg_local_valid_rect)
.expect("bug: map fg local valid rect");
let fg_device_valid_rect = fg_world_valid_rect * ctx.global_device_pixel_scale;

for surface in ctx.external_surfaces {
if surface.device_rect.intersects(&self.device_valid_rect) {
if surface.device_rect.intersects(&fg_device_valid_rect) {
is_opaque = false;
break;
}
}
}

// Set the correct z_id for this tile based on opacity
if is_opaque {
self.z_id = ctx.z_id_opaque;
} else {
self.z_id = ctx.z_id_alpha;
}

if is_opaque != self.is_opaque {
// If opacity changed, the native compositor surface and all tiles get invalidated.
// (this does nothing if not using native compositor mode).
@@ -2188,6 +2235,8 @@ pub struct TileCacheInstance {
/// List of external surfaces that have been promoted from primitives
/// in this tile cache.
pub external_surfaces: Vec<ExternalSurfaceDescriptor>,
/// z-buffer ID assigned to opaque tiles in this slice
pub z_id_opaque: ZBufferId,
}

impl TileCacheInstance {
@@ -2241,6 +2290,7 @@ impl TileCacheInstance {
device_position: DevicePoint::zero(),
tile_size_override: None,
external_surfaces: Vec::new(),
z_id_opaque: ZBufferId::invalid(),
}
}

@@ -2292,6 +2342,11 @@ impl TileCacheInstance {
self.local_rect = pic_rect;
self.local_clip_rect = PictureRect::max_rect();

// Opaque surfaces get the first z_id. Compositor surfaces then get
// allocated a z_id each. After all compositor surfaces are added,
// then we allocate a z_id for alpha tiles.
self.z_id_opaque = frame_state.composite_state.z_generator.next();

// Reset the opaque rect + subpixel mode, as they are calculated
// during the prim dependency checks.
self.backdrop = BackdropInfo::empty();
@@ -2671,7 +2726,7 @@ impl TileCacheInstance {
color_bindings: &ColorBindingStorage,
image_instances: &ImageInstanceStorage,
surface_stack: &[SurfaceIndex],
composite_state: &CompositeState,
composite_state: &mut CompositeState,
) -> bool {
// This primitive exists on the last element on the current surface stack.
let prim_surface_index = *surface_stack.last().unwrap();
@@ -2945,15 +3000,18 @@ impl TileCacheInstance {
let device_rect = (world_rect * frame_context.global_device_pixel_scale).round();
let clip_rect = (world_clip_rect * frame_context.global_device_pixel_scale).round();

// Each compositor surface allocates a unique z-id
self.external_surfaces.push(ExternalSurfaceDescriptor {
local_rect: prim_info.prim_clip_rect,
world_rect,
image_keys: prim_data.kind.yuv_key,
image_rendering: prim_data.kind.image_rendering,
device_rect,
clip_rect,
yuv_color_space: prim_data.kind.color_space,
yuv_format: prim_data.kind.format,
yuv_rescale: prim_data.kind.color_depth.rescaling_factor(),
z_id: composite_state.z_generator.next(),
});
}
} else {
@@ -3160,13 +3218,26 @@ impl TileCacheInstance {
.map(&backdrop_rect)
.expect("bug: unable to map backdrop to world space");

// Since we register the entire backdrop rect, use the opaque z-id for the
// picture cache slice.
frame_state.composite_state.register_occluder(
self.slice,
self.z_id_opaque,
world_backdrop_rect,
);
}
}

// Register any external compositor surfaces as potential occluders. This
// is especially useful when viewing video in full-screen mode, as it is
// able to occlude every background tile (avoiding allocation, rasterizion
// and compositing).
for external_surface in &self.external_surfaces {
frame_state.composite_state.register_occluder(
external_surface.z_id,
external_surface.world_rect,
);
}

// Detect if the picture cache was scrolled or scaled. In this case,
// the device space dirty rects aren't applicable (until we properly
// integrate with OS compositors that can handle scrolling slices).
@@ -3224,6 +3295,9 @@ impl TileCacheInstance {
frame_context.spatial_tree,
);

// All compositor surfaces have allocated a z_id, so reserve a z_id for alpha tiles.
let z_id_alpha = frame_state.composite_state.z_generator.next();

let ctx = TilePostUpdateContext {
pic_to_world_mapper,
global_device_pixel_scale: frame_context.global_device_pixel_scale,
@@ -3235,6 +3309,8 @@ impl TileCacheInstance {
current_tile_size: self.current_tile_size,
local_rect: self.local_rect,
external_surfaces: &self.external_surfaces,
z_id_opaque: self.z_id_opaque,
z_id_alpha,
};

let mut state = TilePostUpdateState {
@@ -4538,7 +4614,7 @@ impl PicturePrimitive {
// then mark it as not visible and skip drawing. When it's not occluded
// it will fail this test, and get rasterized by the render task setup
// code below.
if frame_state.composite_state.is_tile_occluded(tile_cache.slice, device_draw_rect) {
if frame_state.composite_state.is_tile_occluded(tile.z_id, device_draw_rect) {
// If this tile has an allocated native surface, free it, since it's completely
// occluded. We will need to re-allocate this surface if it becomes visible,
// but that's likely to be rare (e.g. when there is no content display list
@@ -2174,7 +2174,7 @@ impl PrimitiveStore {
&self.color_bindings,
&self.images,
&frame_state.surface_stack,
&frame_state.composite_state,
&mut frame_state.composite_state,
) {
prim_instance.visibility_info = PrimitiveVisibilityIndex::INVALID;
// Ensure the primitive clip is popped - perhaps we can use
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.