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 #3848

Merged
merged 6 commits into from Feb 4, 2020
Prev

Bug 1608280 - Part 1 - Add a valid_rect to picture cache and composit…

…e tiles. r=mstange

This patch introduces a per-tile valid rect. In the initial implementation,
this only uses the bounds of the overall picture cache bounding rect. The
next part of this patch will make use of true per-tile valid regions, to
improve performance where there are holes in a single cache slice.

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

[ghsync] From https://hg.mozilla.org/mozilla-central/rev/42095e4b17091e46bd63d72f17145505ab1f8faf
  • Loading branch information
gw3583 authored and moz-gfx committed Feb 4, 2020
commit 74380b68db0485cb7b444b12e8eb1feac9710756
@@ -1212,15 +1212,12 @@ impl BatchBuilder {
ctx.screen_world_rect,
ctx.spatial_tree,
);
let local_tile_clip_rect = LayoutRect::from_untyped(&tile_cache.local_rect.to_untyped());
let local_tile_clip_rect = match local_tile_clip_rect.intersection(&prim_info.combined_local_clip_rect) {
Some(rect) => rect,
None => {
return;
}
};
// TODO(gw): As a follow up to the valid_rect work, see why we use
// prim_info.combined_local_clip_rect here instead of the
// local_clip_rect built in the TileCacheInstance. Perhaps
// these can be unified or are different for a good reason?
let world_clip_rect = map_local_to_world
.map(&local_tile_clip_rect)
.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();
@@ -66,6 +66,7 @@ pub struct CompositeTile {
pub rect: DeviceRect,
pub clip_rect: DeviceRect,
pub dirty_rect: DeviceRect,
pub valid_rect: DeviceRect,
pub z_id: ZBufferId,
pub tile_id: TileId,
}
@@ -303,6 +304,14 @@ impl CompositeState {
) {
let mut visible_tile_count = 0;

// TODO(gw): For now, we apply the valid rect as part of the clip rect
// during native compositing. This works for the initial
// implementation, since the valid rect is determined only
// by the bounding rect of the picture cache slice. When
// we implement proper per-tile valid rects, we will need to
// supply the valid rect directly to the compositor interface.
let mut combined_valid_rect = DeviceRect::zero();

for key in &tile_cache.tiles_to_draw {
let tile = &tile_cache.tiles[key];
if !tile.is_visible {
@@ -314,6 +323,15 @@ impl CompositeState {

let device_rect = (tile.world_tile_rect * global_device_pixel_scale).round();
let dirty_rect = (tile.world_dirty_rect * global_device_pixel_scale).round();
// The device rect is guaranteed to be aligned on a device pixel - the round
// above is just to deal with float accuracy. However, the valid rect is not
// always aligned to a device pixel. To handle this, round out to get all
// required pixels, and intersect with the tile device rect.
let valid_rect = (tile.world_valid_rect * global_device_pixel_scale)
.round_out()
.intersection(&device_rect)
.unwrap_or_else(DeviceRect::zero);
combined_valid_rect = combined_valid_rect.union(&valid_rect);
let surface = tile.surface.as_ref().expect("no tile surface set!");

let (surface, is_opaque) = match surface {
@@ -335,6 +353,7 @@ impl CompositeState {
let tile = CompositeTile {
surface,
rect: device_rect,
valid_rect,
dirty_rect,
clip_rect: device_clip_rect,
z_id,
@@ -345,14 +364,16 @@ impl CompositeState {
}

if visible_tile_count > 0 {
self.descriptor.surfaces.push(
CompositeSurfaceDescriptor {
slice: tile_cache.slice,
surface_id: tile_cache.native_surface_id,
offset: tile_cache.device_position,
clip_rect: device_clip_rect,
}
);
if let Some(clip_rect) = device_clip_rect.intersection(&combined_valid_rect) {
self.descriptor.surfaces.push(
CompositeSurfaceDescriptor {
slice: tile_cache.slice,
surface_id: tile_cache.native_surface_id,
offset: tile_cache.device_position,
clip_rect,
}
);
}
}
}

@@ -406,13 +406,13 @@ struct TilePreUpdateContext {

/// The visible part of the screen in world coords.
global_screen_world_rect: WorldRect,
}

// Immutable context passed to picture cache tiles during post_update
struct TilePostUpdateContext<'a> {
/// The local rect of the overall picture cache
local_rect: PictureRect,
}

// Immutable context passed to picture cache tiles during post_update
struct TilePostUpdateContext<'a> {
/// The local clip rect (in picture space) of the entire picture cache
local_clip_rect: PictureRect,

@@ -667,6 +667,10 @@ pub struct Tile {
/// TODO(gw): We have multiple dirty rects available due to the quadtree above. In future,
/// expose these as multiple dirty rects, which will help in some cases.
pub world_dirty_rect: WorldRect,
/// Picture space rect that contains valid pixels region of this tile.
local_valid_rect: PictureRect,
/// World space rect that contains valid pixels region of this tile.
pub world_valid_rect: WorldRect,
/// Uniquely describes the content of this tile, in a way that can be
/// (reasonably) efficiently hashed and compared.
pub current_descriptor: TileDescriptor,
@@ -707,6 +711,8 @@ impl Tile {
Tile {
local_tile_rect: PictureRect::zero(),
world_tile_rect: WorldRect::zero(),
local_valid_rect: PictureRect::zero(),
world_valid_rect: WorldRect::zero(),
local_dirty_rect: PictureRect::zero(),
world_dirty_rect: WorldRect::zero(),
surface: None,
@@ -819,12 +825,17 @@ impl Tile {
ctx: &TilePreUpdateContext,
) {
self.local_tile_rect = local_tile_rect;
self.local_valid_rect = local_tile_rect.intersection(&ctx.local_rect).unwrap();
self.invalidation_reason = None;

self.world_tile_rect = ctx.pic_to_world_mapper
.map(&self.local_tile_rect)
.expect("bug: map local tile rect");

self.world_valid_rect = ctx.pic_to_world_mapper
.map(&self.local_valid_rect)
.expect("bug: map local valid rect");

// Check if this tile is currently on screen.
self.is_visible = self.world_tile_rect.intersects(&ctx.global_screen_world_rect);

@@ -975,9 +986,8 @@ impl Tile {
// Check if this tile can be considered opaque. Opacity state must be updated only
// after all early out checks have been performed. Otherwise, we might miss updating
// the native surface next time this tile becomes visible.
let clipped_rect = self.local_tile_rect
.intersection(&ctx.local_rect)
.and_then(|r| r.intersection(&ctx.local_clip_rect))
let clipped_rect = self.local_valid_rect
.intersection(&ctx.local_clip_rect)
.unwrap_or_else(PictureRect::zero);
self.is_opaque = ctx.backdrop.rect.contains_rect(&clipped_rect);

@@ -2196,6 +2206,7 @@ impl TileCacheInstance {
mem::swap(&mut self.tiles, &mut self.old_tiles);

let ctx = TilePreUpdateContext {
local_rect: self.local_rect,
pic_to_world_mapper,
fract_offset: self.fract_offset,
background_color: self.background_color,
@@ -2719,7 +2730,6 @@ impl TileCacheInstance {
}

let ctx = TilePostUpdateContext {
local_rect: self.local_rect,
local_clip_rect: self.local_clip_rect,
backdrop: self.backdrop,
spatial_nodes: &self.spatial_nodes,
@@ -4024,19 +4034,15 @@ impl PicturePrimitive {

// Get the overall world space rect of the picture cache. Used to clip
// the tile rects below for occlusion testing to the relevant area.
let local_clip_rect = tile_cache.local_rect
.intersection(&tile_cache.local_clip_rect)
.unwrap_or_else(PictureRect::zero);

let world_clip_rect = map_pic_to_world
.map(&local_clip_rect)
.map(&tile_cache.local_clip_rect)
.expect("bug: unable to map clip rect");

for key in &tile_cache.tiles_to_draw {
let tile = tile_cache.tiles.get_mut(key).expect("bug: no tile found!");

// Get the world space rect that this tile will actually occupy on screem
let tile_draw_rect = match world_clip_rect.intersection(&tile.world_tile_rect) {
let world_draw_rect = match world_clip_rect.intersection(&tile.world_valid_rect) {
Some(rect) => rect,
None => {
tile.is_visible = false;
@@ -4048,7 +4054,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, tile_draw_rect) {
if frame_state.composite_state.is_tile_occluded(tile_cache.slice, world_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
@@ -4221,6 +4221,12 @@ impl Renderer {
None => continue,
};

// Only composite the part of the tile that contains valid pixels
let clip_rect = match clip_rect.intersection(&tile.valid_rect) {
Some(rect) => rect,
None => continue,
};

// Flush this batch if the textures aren't compatible
if !current_textures.is_compatible_with(&textures) {
self.draw_instanced_batch(
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.