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 6 - Support an opaque/alpha native surface per sli…

…ce. r=Bert

Previously, a native compositor surface was considered to be
completely opaque, or completely translucent. This is due to
a limitation in how alpha is handled in the DirectComposition
API level.

With this patch, each picture cache slice maintains both an
opaque and translucent native surface handle. Tiles are assigned
to one of those surfaces based on their current opacity.

This is a performance optimization in some cases, since:
 - Even if part of a cache is translucent, opaque tiles can
   still participate in occlusion at the compositor level.
 - If a tile is changing from opaque to translucent, it now
   invalidates only that tile, rather than the entire surface.

The primary benefit of this patch is that it allows compositor
surfaces to be drawn sliced in between the opaque surface and
any overlay / alpha tiles.

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

[ghsync] From https://hg.mozilla.org/mozilla-central/rev/6814870342efc284b2edec7c9aeb45240cb0fe09
  • Loading branch information
gw3583 authored and moz-gfx committed Mar 2, 2020
commit 6cffb1b466740013f103ba89732f3edb4d6bc754
@@ -236,7 +236,6 @@ struct Occluder {
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(PartialEq, Clone)]
pub struct CompositeSurfaceDescriptor {
pub slice: usize,
pub surface_id: Option<NativeSurfaceId>,
pub offset: DevicePoint,
pub clip_rect: DeviceRect,
@@ -385,42 +384,44 @@ impl CompositeState {
gpu_cache: &mut GpuCache,
deferred_resolves: &mut Vec<DeferredResolve>,
) {
let mut visible_tile_count = 0;
let mut visible_opaque_tile_count = 0;
let mut visible_alpha_tile_count = 0;

for tile in tile_cache.tiles.values() {
if !tile.is_visible {
// This can occur when a tile is found to be occluded during frame building.
continue;
}

visible_tile_count += 1;

let device_rect = (tile.world_tile_rect * global_device_pixel_scale).round();
let surface = tile.surface.as_ref().expect("no tile surface set!");

let (surface, is_opaque) = match surface {
let (surface, is_opaque, tile_id) = match surface {
TileSurface::Color { color } => {
(CompositeTileSurface::Color { color: *color }, true)
(CompositeTileSurface::Color { color: *color }, true, None)
}
TileSurface::Clear => {
(CompositeTileSurface::Clear, false)
(CompositeTileSurface::Clear, false, None)
}
TileSurface::Texture { descriptor, .. } => {
let surface = descriptor.resolve(resource_cache, tile_cache.current_tile_size);
let tile_id = match surface {
ResolvedSurfaceTexture::Native { id, .. } => Some(id),
ResolvedSurfaceTexture::TextureCache { .. } => None,
};
(
CompositeTileSurface::Texture { surface },
tile.is_opaque || tile_cache.is_opaque(),
tile_id,
)
}
};

let tile_id = tile_cache.native_surface_id.map(|surface_id| {
NativeTileId {
surface_id,
x: tile.tile_offset.x,
y: tile.tile_offset.y,
}
});
if is_opaque {
visible_opaque_tile_count += 1;
} else {
visible_alpha_tile_count += 1;
}

// Determine ordering of this tile, based on presence of compositor
// surfaces that intersect the tile.
@@ -525,11 +526,20 @@ impl CompositeState {
});
}

if visible_tile_count > 0 {
if visible_opaque_tile_count > 0 {
self.descriptor.surfaces.push(
CompositeSurfaceDescriptor {
surface_id: tile_cache.native_surface.as_ref().map(|s| s.opaque),
offset: tile_cache.device_position,
clip_rect: device_clip_rect,
}
);
}

if visible_alpha_tile_count > 0 {
self.descriptor.surfaces.push(
CompositeSurfaceDescriptor {
slice: tile_cache.slice,
surface_id: tile_cache.native_surface_id,
surface_id: tile_cache.native_surface.as_ref().map(|s| s.alpha),
offset: tile_cache.device_position,
clip_rect: device_clip_rect,
}
@@ -402,8 +402,9 @@ impl FrameBuilder {
// we need to manually clean up any native compositor surfaces that were
// allocated by these tiles.
for (_, mut cache_state) in visibility_state.retained_tiles.caches.drain() {
if let Some(native_surface_id) = cache_state.native_surface_id.take() {
visibility_state.resource_cache.destroy_compositor_surface(native_surface_id);
if let Some(native_surface) = cache_state.native_surface.take() {
visibility_state.resource_cache.destroy_compositor_surface(native_surface.opaque);
visibility_state.resource_cache.destroy_compositor_surface(native_surface.alpha);
}
}
}
@@ -274,9 +274,7 @@ pub struct PictureCacheState {
/// Various allocations we want to avoid re-doing.
allocations: PictureCacheRecycledAllocations,
/// Currently allocated native compositor surface for this picture cache.
pub native_surface_id: Option<NativeSurfaceId>,
/// True if the entire picture cache is opaque.
is_opaque: bool,
pub native_surface: Option<NativeSurface>,
}

pub struct PictureCacheRecycledAllocations {
@@ -1212,7 +1210,26 @@ impl Tile {
let clipped_rect = self.current_descriptor.local_valid_rect
.intersection(&ctx.local_clip_rect)
.unwrap_or_else(PictureRect::zero);
self.is_opaque = ctx.backdrop.rect.contains_rect(&clipped_rect);
let is_opaque = ctx.backdrop.rect.contains_rect(&clipped_rect);

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).
// TODO(gw): This property probably changes very rarely, so it is OK to invalidate
// everything in this case. If it turns out that this isn't true, we could
// consider other options, such as per-tile opacity (natively supported
// on CoreAnimation, and supported if backed by non-virtual surfaces in
// DirectComposition).
if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { ref mut id, .. }, .. }) = self.surface {
if let Some(id) = id.take() {
state.resource_cache.destroy_compositor_tile(id);
}
}

// Invalidate the entire tile to force a redraw.
self.invalidate(None, InvalidationReason::SurfaceOpacityChanged { became_opaque: is_opaque });
self.is_opaque = is_opaque;
}

// Check if the selected composite mode supports dirty rect updates. For Draw composite
// mode, we can always update the content with smaller dirty rects. For native composite
@@ -2038,6 +2055,24 @@ impl TileCacheLogger {
}
}

/// Represents the native surfaces created for a picture cache, if using
/// a native compositor. An opaque and alpha surface is always created,
/// but tiles are added to a surface based on current opacity. If the
/// calculated opacity of a tile changes, the tile is invalidated and
/// attached to a different native surface. This means that we don't
/// need to invalidate the entire surface if only some tiles are changing
/// opacity. It also means we can take advantage of opaque tiles on cache
/// slices where only some of the tiles are opaque. There is an assumption
/// that creating a native surface is cheap, and only when a tile is added
/// to a surface is there a significant cost. This assumption holds true
/// for the current native compositor implementations on Windows and Mac.
pub struct NativeSurface {
/// Native surface for opaque tiles
pub opaque: NativeSurfaceId,
/// Native surface for alpha tiles
pub alpha: NativeSurfaceId,
}

/// Represents a cache of tiles that make up a picture primitives.
pub struct TileCacheInstance {
/// Index of the tile cache / slice for this frame builder. It's determined
@@ -2123,15 +2158,13 @@ pub struct TileCacheInstance {
/// keep around the hash map used as compare_cache to avoid reallocating it each
/// frame.
compare_cache: FastHashMap<PrimitiveComparisonKey, PrimitiveCompareResult>,
/// The allocated compositor surface for this picture cache. May be None if
/// The allocated compositor surfaces for this picture cache. May be None if
/// not using native compositor, or if the surface was destroyed and needs
/// to be reallocated next time this surface contains valid tiles.
pub native_surface_id: Option<NativeSurfaceId>,
pub native_surface: Option<NativeSurface>,
/// The current device position of this cache. Used to set the compositor
/// offset of the surface when building the visual tree.
pub device_position: DevicePoint,
/// True if the entire picture cache surface is opaque.
is_opaque: bool,
/// The currently considered tile size override. Used to check if we should
/// re-evaluate tile size, even if the frame timer hasn't expired.
tile_size_override: Option<DeviceIntSize>,
@@ -2187,9 +2220,8 @@ impl TileCacheInstance {
frames_until_size_eval: 0,
fract_offset: PictureVector2D::zero(),
compare_cache: FastHashMap::default(),
native_surface_id: None,
native_surface: None,
device_position: DevicePoint::zero(),
is_opaque: true,
tile_size_override: None,
external_surfaces: Vec::new(),
}
@@ -2314,8 +2346,7 @@ impl TileCacheInstance {
self.opacity_bindings = prev_state.opacity_bindings;
self.color_bindings = prev_state.color_bindings;
self.current_tile_size = prev_state.current_tile_size;
self.native_surface_id = prev_state.native_surface_id;
self.is_opaque = prev_state.is_opaque;
self.native_surface = prev_state.native_surface;

fn recycle_map<K: std::cmp::Eq + std::hash::Hash, V>(
ideal_len: usize,
@@ -2377,8 +2408,9 @@ impl TileCacheInstance {
if desired_tile_size != self.current_tile_size {
// Destroy any native surfaces on the tiles that will be dropped due
// to resizing.
if let Some(native_surface_id) = self.native_surface_id.take() {
frame_state.resource_cache.destroy_compositor_surface(native_surface_id);
if let Some(native_surface) = self.native_surface.take() {
frame_state.resource_cache.destroy_compositor_surface(native_surface.opaque);
frame_state.resource_cache.destroy_compositor_surface(native_surface.alpha);
}
self.tiles.clear();
self.current_tile_size = desired_tile_size;
@@ -2572,22 +2604,25 @@ impl TileCacheInstance {
}

// If compositor mode is changed, need to drop all incompatible tiles.
match (frame_context.config.compositor_kind, self.native_surface_id) {
(CompositorKind::Draw { .. }, Some(_)) => {
frame_state.composite_state.destroy_native_tiles(
self.tiles.values_mut(),
frame_state.resource_cache,
);
match frame_context.config.compositor_kind {
CompositorKind::Draw { .. } => {
for tile in self.tiles.values_mut() {
tile.surface = None;
// Invalidate the entire tile to force a redraw.
tile.invalidate(None, InvalidationReason::CompositorKindChanged);
if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { ref mut id, .. }, .. }) = tile.surface {
if let Some(id) = id.take() {
frame_state.resource_cache.destroy_compositor_tile(id);
tile.surface = None;
// Invalidate the entire tile to force a redraw.
tile.invalidate(None, InvalidationReason::CompositorKindChanged);
}
}
}
if let Some(native_surface_id) = self.native_surface_id.take() {
frame_state.resource_cache.destroy_compositor_surface(native_surface_id);

if let Some(native_surface) = self.native_surface.take() {
frame_state.resource_cache.destroy_compositor_surface(native_surface.opaque);
frame_state.resource_cache.destroy_compositor_surface(native_surface.alpha);
}
}
(CompositorKind::Native { .. }, None) => {
CompositorKind::Native { .. } => {
// This could hit even when compositor mode is not changed,
// then we need to check if there are incompatible tiles.
for tile in self.tiles.values_mut() {
@@ -2598,7 +2633,6 @@ impl TileCacheInstance {
}
}
}
(_, _) => {}
}

world_culling_rect
@@ -3193,38 +3227,8 @@ impl TileCacheInstance {

// Step through each tile and invalidate if the dependencies have changed. Determine
// the current opacity setting and whether it's changed.
let mut tile_cache_is_opaque = true;
for tile in self.tiles.values_mut() {
if tile.post_update(&ctx, &mut state, frame_context) {
tile_cache_is_opaque &= tile.is_opaque;
}
}

// If opacity changed, the native compositor surface and all tiles get invalidated.
// (this does nothing if not using native compositor mode).
// TODO(gw): This property probably changes very rarely, so it is OK to invalidate
// everything in this case. If it turns out that this isn't true, we could
// consider other options, such as per-tile opacity (natively supported
// on CoreAnimation, and supported if backed by non-virtual surfaces in
// DirectComposition).
if self.is_opaque != tile_cache_is_opaque {
if let Some(native_surface_id) = self.native_surface_id.take() {
// Since the native surface will be destroyed, need to clear the compositor tile
// handle for all tiles. This means the tiles will be reallocated on demand
// when the tiles are added to render tasks.
for tile in self.tiles.values_mut() {
if let Some(TileSurface::Texture { descriptor: SurfaceTextureDescriptor::Native { ref mut id, .. }, .. }) = tile.surface {
*id = None;
}
// Invalidate the entire tile to force a redraw.
tile.invalidate(None, InvalidationReason::SurfaceOpacityChanged {
became_opaque: tile_cache_is_opaque });
}
// Destroy the compositor surface. It will be reallocated with the correct
// opacity flag when render tasks are generated for tiles.
frame_state.resource_cache.destroy_compositor_surface(native_surface_id);
}
self.is_opaque = tile_cache_is_opaque;
tile.post_update(&ctx, &mut state, frame_context);
}

// When under test, record a copy of the dirty region to support
@@ -4056,7 +4060,7 @@ impl PicturePrimitive {
&mut self,
retained_tiles: &mut RetainedTiles,
) {
if let Some(mut tile_cache) = self.tile_cache.take() {
if let Some(tile_cache) = self.tile_cache.take() {
if !tile_cache.tiles.is_empty() {
retained_tiles.caches.insert(
tile_cache.slice,
@@ -4067,8 +4071,7 @@ impl PicturePrimitive {
color_bindings: tile_cache.color_bindings,
root_transform: tile_cache.root_transform,
current_tile_size: tile_cache.current_tile_size,
native_surface_id: tile_cache.native_surface_id.take(),
is_opaque: tile_cache.is_opaque,
native_surface: tile_cache.native_surface,
allocations: PictureCacheRecycledAllocations {
old_opacity_bindings: tile_cache.old_opacity_bindings,
old_color_bindings: tile_cache.old_color_bindings,
@@ -4624,20 +4627,36 @@ impl PicturePrimitive {
// Allocate a native surface id if we're in native compositing mode,
// and we don't have a surface yet (due to first frame, or destruction
// due to tile size changing etc).
if tile_cache.native_surface_id.is_none() {
let surface_id = frame_state
if tile_cache.native_surface.is_none() {
let opaque = frame_state
.resource_cache
.create_compositor_surface(
tile_cache.current_tile_size,
tile_cache.is_opaque,
true,
);

tile_cache.native_surface_id = Some(surface_id);
let alpha = frame_state
.resource_cache
.create_compositor_surface(
tile_cache.current_tile_size,
false,
);

tile_cache.native_surface = Some(NativeSurface {
opaque,
alpha,
});
}

// Create the tile identifier and allocate it.
let surface_id = if tile.is_opaque {
tile_cache.native_surface.as_ref().unwrap().opaque
} else {
tile_cache.native_surface.as_ref().unwrap().alpha
};

let tile_id = NativeTileId {
surface_id: tile_cache.native_surface_id.unwrap(),
surface_id,
x: tile.tile_offset.x,
y: tile.tile_offset.y,
};
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.