| ☠☠ backed out by 0690f68a8d99 ☠ ☠ | |
| author | Glenn Watson <gw@intuitionlibrary.com> |
| Mon, 13 Jan 2020 02:51:32 +0000 | |
| changeset 509889 | 7295ca89e880c1c930643e72ff0600cb71cebb9e |
| parent 509888 | 4882109367167555a50bdb4808efb34d73538961 |
| child 509890 | 1ba5465db9d10e8b59e736f34f098f0da6d92c33 |
| child 509891 | 944aec333e6fb7063de587612f43698bf1f1f654 |
| push id | 37008 |
| push user | dvarga@mozilla.com |
| push date | Mon, 13 Jan 2020 09:38:23 +0000 |
| treeherder | mozilla-central@7295ca89e880 [default view] [failures only] |
| perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
| reviewers | nical |
| bugs | 1608280 |
| milestone | 74.0a1 |
| first release with | nightly linux32
7295ca89e880
/
74.0a1
/
20200113093823
/
files
nightly linux64
7295ca89e880
/
74.0a1
/
20200113093823
/
files
nightly mac
7295ca89e880
/
74.0a1
/
20200113093823
/
files
nightly win32
7295ca89e880
/
74.0a1
/
20200113093823
/
files
nightly win64
7295ca89e880
/
74.0a1
/
20200113093823
/
files
|
| last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
| releases | nightly linux32
74.0a1
/
20200113093823
/
pushlog to previous
nightly linux64
74.0a1
/
20200113093823
/
pushlog to previous
nightly mac
74.0a1
/
20200113093823
/
pushlog to previous
nightly win32
74.0a1
/
20200113093823
/
pushlog to previous
nightly win64
74.0a1
/
20200113093823
/
pushlog to previous
|
| gfx/wr/webrender/src/composite.rs | file | annotate | diff | comparison | revisions | |
| gfx/wr/webrender/src/picture.rs | file | annotate | diff | comparison | revisions |
--- a/gfx/wr/webrender/src/composite.rs +++ b/gfx/wr/webrender/src/composite.rs @@ -117,16 +117,26 @@ pub enum CompositorKind { }, /// Native OS compositor. Native { /// Maximum dirty rects per compositor surface. max_update_rects: usize, }, } +impl CompositorKind { + /// Returns true if this compositor is native (uses OS compositor) + pub fn is_native(&self) -> bool { + match self { + CompositorKind::Draw { .. } => false, + CompositorKind::Native { .. } => true, + } + } +} + impl Default for CompositorKind { /// Default compositor config is full present without partial present. fn default() -> Self { CompositorKind::Draw { max_partial_present_rects: 0, } } } @@ -296,18 +306,27 @@ impl CompositeState { // This can occur when a tile is found to be occluded during frame building. continue; } visible_tile_count += 1; let device_rect = (tile.world_rect * global_device_pixel_scale).round(); let dirty_rect = (tile.world_dirty_rect * global_device_pixel_scale).round(); + let valid_rect = (tile.world_valid_rect * global_device_pixel_scale).round_out(); let surface = tile.surface.as_ref().expect("no tile surface set!"); + // When compositing in simple (draw) mode, each tile only needs to write pixels + // where (a) the valid region of the tile is and (b) the overall clip rect of + // the picture cache surface. + let clip_rect = match valid_rect.intersection(&device_clip_rect) { + Some(clip_rect) => clip_rect, + None => continue, + }; + let (surface, is_opaque) = match surface { TileSurface::Color { color } => { (CompositeTileSurface::Color { color: *color }, true) } TileSurface::Clear => { (CompositeTileSurface::Clear, false) } TileSurface::Texture { descriptor, .. } => { @@ -318,17 +337,17 @@ impl CompositeState { ) } }; let tile = CompositeTile { surface, rect: device_rect, dirty_rect, - clip_rect: device_clip_rect, + clip_rect, z_id, tile_id: tile.id, }; self.push_tile(tile, is_opaque); } if visible_tile_count > 0 {
--- a/gfx/wr/webrender/src/picture.rs +++ b/gfx/wr/webrender/src/picture.rs @@ -333,38 +333,41 @@ pub struct SpatialNodeDependency { /// The current value retrieved from the clip-scroll tree. value: TransformKey, /// True if it was changed (or is new) since the last frame build. changed: bool, } // Immutable context passed to picture cache tiles during pre_update struct TilePreUpdateContext { - /// The local rect of the overall picture cache - local_rect: PictureRect, - - /// The local clip rect (in picture space) of the entire picture cache - local_clip_rect: PictureRect, - /// Maps from picture cache coords -> world space coords. pic_to_world_mapper: SpaceMapper<PicturePixel, WorldPixel>, /// The fractional position of the picture cache, which may /// require invalidation of all tiles. fract_offset: PictureVector2D, /// The optional background color of the picture cache instance background_color: Option<ColorF>, /// The visible part of the screen in world coords. global_screen_world_rect: WorldRect, + + /// The current compositing mode. + compositor_kind: CompositorKind, } // Immutable context passed to picture cache tiles during post_update struct TilePostUpdateContext<'a> { + /// The local rect of the overall picture cache + local_rect: PictureRect, + + /// The local clip rect (in picture space) of the entire picture cache + local_clip_rect: PictureRect, + /// The calculated backdrop information for this cache instance. backdrop: BackdropInfo, /// Information about transform node differences from last frame. spatial_nodes: &'a FastHashMap<SpatialNodeIndex, SpatialNodeDependency>, /// Information about opacity bindings from the picture cache. opacity_bindings: &'a FastHashMap<PropertyBindingId, OpacityBindingInfo>, @@ -571,18 +574,20 @@ enum InvalidationReason { } /// Information about a cached tile. pub struct Tile { /// The current world rect of this tile. pub world_rect: WorldRect, /// The current local rect of this tile. pub rect: PictureRect, - /// The local rect of the tile clipped to the overall picture local rect. - clipped_rect: PictureRect, + /// The valid region of this tile (parts of the tile affected by primitives). + pub valid_rect: PictureRect, + /// The world-space valid 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, /// The content descriptor for this tile from the previous frame. pub prev_descriptor: TileDescriptor, /// Handle to the backing surface for this tile. pub surface: Option<TileSurface>, /// If true, this tile is marked valid, and the existing texture @@ -618,17 +623,18 @@ pub struct Tile { impl Tile { /// Construct a new, invalid tile. fn new( id: TileId, ) -> Self { Tile { rect: PictureRect::zero(), - clipped_rect: PictureRect::zero(), + valid_rect: PictureRect::zero(), + world_valid_rect: WorldRect::zero(), world_rect: WorldRect::zero(), surface: None, current_descriptor: TileDescriptor::new(), prev_descriptor: TileDescriptor::new(), is_valid: false, is_visible: false, fract_offset: PictureVector2D::zero(), id, @@ -734,21 +740,16 @@ impl Tile { fn pre_update( &mut self, rect: PictureRect, ctx: &TilePreUpdateContext, ) { self.rect = rect; self.invalidation_reason = None; - self.clipped_rect = self.rect - .intersection(&ctx.local_rect) - .and_then(|r| r.intersection(&ctx.local_clip_rect)) - .unwrap_or_else(PictureRect::zero); - self.world_rect = ctx.pic_to_world_mapper .map(&self.rect) .expect("bug: map local tile rect"); // Check if this tile is currently on screen. self.is_visible = self.world_rect.intersects(&ctx.global_screen_world_rect); // If the tile isn't visible, early exit, skipping the normal set up to @@ -775,29 +776,46 @@ impl Tile { // Clear any dependencies so that when we rebuild them we // can compare if the tile has the same content. mem::swap( &mut self.current_descriptor, &mut self.prev_descriptor, ); self.current_descriptor.clear(); self.root.clear(rect); + + // Reset which part of the tile contains valid primitives. If the tile + // has a background color, the entire primitive must always be drawn + // composited. Otherwise, we will update the valid region of the tile + // during `add_prim_dependency`. For now, this optimization only applies + // to Draw compositor kinds - native compositors will be implemented + // as a follow up. + let has_background_color = self.background_color.is_some(); + let is_native_compositor = ctx.compositor_kind.is_native(); + self.valid_rect = if has_background_color || is_native_compositor { + self.rect + } else { + PictureRect::zero() + }; } /// Add dependencies for a given primitive to this tile. fn add_prim_dependency( &mut self, info: &PrimitiveDependencyInfo, ) { // If this tile isn't currently visible, we don't want to update the dependencies // for this tile, as an optimization, since it won't be drawn anyway. if !self.is_visible { return; } + // Update the picture space valid region of this tile. + self.valid_rect = self.valid_rect.union(&info.prim_clip_rect); + // Include any image keys this tile depends on. self.current_descriptor.images.extend_from_slice(&info.images); // Include any opacity bindings this primitive depends on. self.current_descriptor.opacity_bindings.extend_from_slice(&info.opacity_bindings); // Include any clip nodes that this primitive depends on. self.current_descriptor.clips.extend_from_slice(&info.clips); @@ -893,17 +911,22 @@ impl Tile { } return false; } // 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. - self.is_opaque = ctx.backdrop.rect.contains_rect(&self.clipped_rect); + let clipped_rect = self.rect + .intersection(&ctx.local_rect) + .and_then(|r| r.intersection(&ctx.local_clip_rect)) + .and_then(|r| r.intersection(&self.valid_rect)) + .unwrap_or_else(PictureRect::zero); + self.is_opaque = ctx.backdrop.rect.contains_rect(&clipped_rect); // 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 // mode, we can only use dirty rects if the compositor supports partial surface updates. let (supports_dirty_rects, supports_simple_prims) = match state.composite_state.compositor_kind { CompositorKind::Draw { .. } => { (true, true) } @@ -1850,22 +1873,21 @@ impl TileCacheInstance { self.tile_bounds_p0 = TileOffset::new(x0, y0); self.tile_bounds_p1 = TileOffset::new(x1, y1); let mut world_culling_rect = WorldRect::zero(); mem::swap(&mut self.tiles, &mut self.old_tiles); let ctx = TilePreUpdateContext { - local_rect: self.local_rect, - local_clip_rect: self.local_clip_rect, pic_to_world_mapper, fract_offset: self.fract_offset, background_color: self.background_color, global_screen_world_rect: frame_context.global_screen_world_rect, + compositor_kind: frame_state.composite_state.compositor_kind, }; self.tiles.clear(); for y in y0 .. y1 { for x in x0 .. x1 { let key = TileOffset::new(x, y); let mut tile = self.old_tiles @@ -2319,16 +2341,18 @@ impl TileCacheInstance { self.spatial_nodes.insert(spatial_node_index, SpatialNodeDependency { changed, value, }); } let ctx = TilePostUpdateContext { + local_rect: self.local_rect, + local_clip_rect: self.local_clip_rect, backdrop: self.backdrop, spatial_nodes: &self.spatial_nodes, opacity_bindings: &self.opacity_bindings, current_tile_size: self.current_tile_size, }; let mut state = TilePostUpdateState { resource_cache: frame_state.resource_cache, @@ -3648,16 +3672,17 @@ impl PicturePrimitive { tile.is_visible = false; continue; } if frame_context.debug_flags.contains(DebugFlags::PICTURE_CACHING_DBG) { tile.root.draw_debug_rects( &map_pic_to_world, tile.is_opaque, + &tile.valid_rect, scratch, frame_context.global_device_pixel_scale, ); let label_offset = DeviceVector2D::new(20.0, 30.0); let tile_device_rect = tile.world_rect * frame_context.global_device_pixel_scale; if tile_device_rect.size.height >= label_offset.y { let surface = tile.surface.as_ref().expect("no tile surface set!"); @@ -3699,18 +3724,19 @@ impl PicturePrimitive { if id.is_none() { // There is no current surface allocation, so ensure the entire tile is invalidated tile.invalidate(None, InvalidationReason::NoSurface); } } } } - // Update the world dirty rect + // Update the world space dirty and valid rects tile.world_dirty_rect = map_pic_to_world.map(&tile.dirty_rect).expect("bug"); + tile.world_valid_rect = map_pic_to_world.map(&tile.valid_rect).expect("bug"); if tile.is_valid { continue; } // Ensure that this texture is allocated. if let TileSurface::Texture { ref mut descriptor, ref mut visibility_mask } = tile.surface.as_mut().unwrap() { match descriptor { @@ -3779,25 +3805,38 @@ impl PicturePrimitive { let content_origin_f = tile.world_rect.origin * device_pixel_scale; let content_origin = content_origin_f.round(); debug_assert!((content_origin_f.x - content_origin.x).abs() < 0.01); debug_assert!((content_origin_f.y - content_origin.y).abs() < 0.01); // Get a task-local scissor rect for the dirty region of this // picture cache task. - let scissor_rect = tile.world_dirty_rect.translate( - -tile.world_rect.origin.to_vector() - ); + let dirty_rect = tile.world_dirty_rect + .translate(-tile.world_rect.origin.to_vector()); + let dirty_rect = (dirty_rect * device_pixel_scale).round(); + + // The valid rect isn't guaranteed to be aligned to the device pixel + // grid. To ensure we don't skip any valid pixels, round this out, and + // then intersect it with the dirty rect (which _is_ device pixel + // aligned) below when creating the true scissor rect. + let valid_rect = tile.world_valid_rect + .translate(-tile.world_rect.origin.to_vector()); + let valid_rect = (valid_rect * device_pixel_scale).round_out(); + // The world rect is guaranteed to be device pixel aligned, by the tile // sizing code in tile::pre_update. However, there might be some // small floating point accuracy issues (these were observed on ARM // CPUs). Round the rect here before casting to integer device pixels // to ensure the scissor rect is correct. - let scissor_rect = (scissor_rect * device_pixel_scale).round(); + let scissor_rect = dirty_rect + .intersection(&valid_rect) + .unwrap_or(DeviceRect::zero()) + .round(); + let surface = descriptor.resolve( frame_state.resource_cache, tile_cache.current_tile_size, ); let task = RenderTask::new_picture( RenderTaskLocation::PictureCache { size: tile_cache.current_tile_size, @@ -4876,45 +4915,50 @@ impl TileNode { } } /// Draw debug information about this tile node fn draw_debug_rects( &self, pic_to_world_mapper: &SpaceMapper<PicturePixel, WorldPixel>, is_opaque: bool, + valid_rect: &PictureRect, scratch: &mut PrimitiveScratchBuffer, global_device_pixel_scale: DevicePixelScale, ) { match self.kind { TileNodeKind::Leaf { dirty_tracker, .. } => { let color = if (dirty_tracker & 1) != 0 { debug_colors::RED } else if is_opaque { debug_colors::GREEN } else { debug_colors::YELLOW }; - let world_rect = pic_to_world_mapper.map(&self.rect).unwrap(); - let device_rect = world_rect * global_device_pixel_scale; - - let outer_color = color.scale_alpha(0.3); - let inner_color = outer_color.scale_alpha(0.5); - scratch.push_debug_rect( - device_rect.inflate(-3.0, -3.0), - outer_color, - inner_color - ); + let local_rect = self.rect.intersection(valid_rect); + if let Some(local_rect) = local_rect { + let world_rect = pic_to_world_mapper.map(&local_rect).unwrap(); + let device_rect = world_rect * global_device_pixel_scale; + + let outer_color = color.scale_alpha(0.3); + let inner_color = outer_color.scale_alpha(0.5); + scratch.push_debug_rect( + device_rect.inflate(-3.0, -3.0), + outer_color, + inner_color + ); + } } TileNodeKind::Node { ref children, .. } => { for child in children.iter() { child.draw_debug_rects( pic_to_world_mapper, is_opaque, + valid_rect, scratch, global_device_pixel_scale, ); } } } }