diff --git a/gfx/wr/webrender/src/composite.rs b/gfx/wr/webrender/src/composite.rs index a5d383386b61..4777135c83ab 100644 --- a/gfx/wr/webrender/src/composite.rs +++ b/gfx/wr/webrender/src/composite.rs @@ -97,6 +97,14 @@ bitflags! { } } +#[derive(Copy, Clone, Debug, PartialEq)] +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub enum TileKind { + Opaque, + Alpha, + Clear, +} /// Describes the geometry and surface of a tile to be composited #[cfg_attr(feature = "capture", derive(Serialize))] @@ -109,6 +117,27 @@ pub struct CompositeTile { pub valid_rect: DeviceRect, pub transform: Option, pub z_id: ZBufferId, + pub kind: TileKind, +} + +fn tile_kind(surface: &CompositeTileSurface, is_opaque: bool) -> TileKind { + match surface { + // Color tiles are, by definition, opaque. We might support non-opaque color + // tiles if we ever find pages that have a lot of these. + CompositeTileSurface::Color { .. } => TileKind::Opaque, + // Clear tiles have a special bucket + CompositeTileSurface::Clear => TileKind::Clear, + CompositeTileSurface::Texture { .. } + | CompositeTileSurface::ExternalSurface { .. } => { + // Texture surfaces get bucketed by opaque/alpha, for z-rejection + // on the Draw compositor mode. + if is_opaque { + TileKind::Opaque + } else { + TileKind::Alpha + } + } + } } pub enum ExternalSurfaceDependency { @@ -405,9 +434,7 @@ impl CompositeDescriptor { } pub struct CompositeStatePreallocator { - opaque_tiles: Preallocator, - alpha_tiles: Preallocator, - clear_tiles: Preallocator, + tiles: Preallocator, external_surfaces: Preallocator, occluders: Preallocator, occluders_events: Preallocator, @@ -417,9 +444,7 @@ pub struct CompositeStatePreallocator { impl CompositeStatePreallocator { pub fn record(&mut self, state: &CompositeState) { - self.opaque_tiles.record_vec(&state.opaque_tiles); - self.alpha_tiles.record_vec(&state.alpha_tiles); - self.clear_tiles.record_vec(&state.clear_tiles); + self.tiles.record_vec(&state.tiles); self.external_surfaces.record_vec(&state.external_surfaces); self.occluders.record_vec(&state.occluders.occluders); self.occluders_events.record_vec(&state.occluders.events); @@ -428,9 +453,7 @@ impl CompositeStatePreallocator { } pub fn preallocate(&self, state: &mut CompositeState) { - self.opaque_tiles.preallocate_vec(&mut state.opaque_tiles); - self.alpha_tiles.preallocate_vec(&mut state.alpha_tiles); - self.clear_tiles.preallocate_vec(&mut state.clear_tiles); + self.tiles.preallocate_vec(&mut state.tiles); self.external_surfaces.preallocate_vec(&mut state.external_surfaces); self.occluders.preallocate_vec(&mut state.occluders.occluders); self.occluders_events.preallocate_vec(&mut state.occluders.events); @@ -442,9 +465,7 @@ impl CompositeStatePreallocator { impl Default for CompositeStatePreallocator { fn default() -> Self { CompositeStatePreallocator { - opaque_tiles: Preallocator::new(40), - alpha_tiles: Preallocator::new(16), - clear_tiles: Preallocator::new(0), + tiles: Preallocator::new(56), external_surfaces: Preallocator::new(0), occluders: Preallocator::new(16), occluders_events: Preallocator::new(32), @@ -461,12 +482,10 @@ pub struct CompositeState { // TODO(gw): Consider splitting up CompositeState into separate struct types depending // on the selected compositing mode. Many of the fields in this state struct // are only applicable to either Native or Draw compositing mode. - /// List of opaque tiles to be drawn by the Draw compositor. - pub opaque_tiles: Vec, - /// List of alpha tiles to be drawn by the Draw compositor. - pub alpha_tiles: Vec, - /// List of clear tiles to be drawn by the Draw compositor. - pub clear_tiles: Vec, + /// List of tiles to be drawn by the Draw compositor. + /// Tiles are accumulated in this vector and sorted from front to back at the end of the + /// frame. + pub tiles: Vec, /// List of primitives that were promoted to be compositor surfaces. pub external_surfaces: Vec, /// Used to generate z-id values for tiles in the Draw compositor mode. @@ -500,9 +519,7 @@ impl CompositeState { dirty_rects_are_valid: bool, ) -> Self { CompositeState { - opaque_tiles: Vec::new(), - alpha_tiles: Vec::new(), - clear_tiles: Vec::new(), + tiles: Vec::new(), z_generator: ZBufferIdGenerator::new(max_depth_ids), dirty_rects_are_valid, compositor_kind, @@ -573,13 +590,13 @@ impl CompositeState { (CompositeTileSurface::Color { color: *color }, true) } TileSurface::Clear => { - (CompositeTileSurface::Clear, false) + (CompositeTileSurface::Clear, true) } TileSurface::Texture { descriptor, .. } => { let surface = descriptor.resolve(resource_cache, tile_cache.current_tile_size); ( CompositeTileSurface::Texture { surface }, - tile.is_opaque + tile.is_opaque ) } }; @@ -593,6 +610,7 @@ impl CompositeState { } let tile = CompositeTile { + kind: tile_kind(&surface, is_opaque), surface, rect: device_rect, valid_rect: tile.device_valid_rect.translate(-device_rect.origin.to_vector()), @@ -602,7 +620,7 @@ impl CompositeState { z_id: tile.z_id, }; - self.push_tile(tile, is_opaque); + self.tiles.push(tile); } // Sort the tile descriptor lists, since iterating values in the tile_cache.tiles @@ -714,8 +732,10 @@ impl CompositeState { ResolvedExternalSurfaceIndex::INVALID }; + let surface = CompositeTileSurface::ExternalSurface { external_surface_index }; let tile = CompositeTile { - surface: CompositeTileSurface::ExternalSurface { external_surface_index }, + kind: tile_kind(&surface, compositor_surface.is_opaque), + surface, rect: external_surface.surface_rect, valid_rect: external_surface.surface_rect.translate(-external_surface.surface_rect.origin.to_vector()), dirty_rect: external_surface.surface_rect.translate(-external_surface.surface_rect.origin.to_vector()), @@ -738,7 +758,7 @@ impl CompositeState { } ); - self.push_tile(tile, compositor_surface.is_opaque); + self.tiles.push(tile); } } } @@ -841,39 +861,9 @@ impl CompositeState { external_surface_index } - /// Add a tile to the appropriate array, depending on tile properties and compositor mode. - fn push_tile( - &mut self, - tile: CompositeTile, - is_opaque: bool, - ) { - match tile.surface { - CompositeTileSurface::Color { .. } => { - // Color tiles are, by definition, opaque. We might support non-opaque color - // tiles if we ever find pages that have a lot of these. - self.opaque_tiles.push(tile); - } - CompositeTileSurface::Clear => { - // Clear tiles have a special bucket - self.clear_tiles.push(tile); - } - CompositeTileSurface::Texture { .. } => { - // Texture surfaces get bucketed by opaque/alpha, for z-rejection - // on the Draw compositor mode. - if is_opaque { - self.opaque_tiles.push(tile); - } else { - self.alpha_tiles.push(tile); - } - } - CompositeTileSurface::ExternalSurface { .. } => { - if is_opaque { - self.opaque_tiles.push(tile); - } else { - self.alpha_tiles.push(tile); - } - } - } + pub fn end_frame(&mut self) { + // Sort tiles from front to back. + self.tiles.sort_by_key(|tile| -tile.z_id.0); } } diff --git a/gfx/wr/webrender/src/frame_builder.rs b/gfx/wr/webrender/src/frame_builder.rs index a23d9f5f47f2..c76170a7ca92 100644 --- a/gfx/wr/webrender/src/frame_builder.rs +++ b/gfx/wr/webrender/src/frame_builder.rs @@ -689,6 +689,8 @@ impl FrameBuilder { self.prim_headers_prealloc.record_vec(&mut prim_headers.headers_int); self.composite_state_prealloc.record(&composite_state); + composite_state.end_frame(); + Frame { device_rect: DeviceIntRect::new( device_origin, diff --git a/gfx/wr/webrender/src/rectangle_occlusion.rs b/gfx/wr/webrender/src/rectangle_occlusion.rs index b01f335bef88..a79e4ba02617 100644 --- a/gfx/wr/webrender/src/rectangle_occlusion.rs +++ b/gfx/wr/webrender/src/rectangle_occlusion.rs @@ -62,18 +62,11 @@ use euclid::point2; use smallvec::SmallVec; use api::units::*; -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum ItemSource { - Opaque(usize), - Alpha(usize), - Clear(usize), -} - /// A visible part of a rectangle after occlusion culling. #[derive(Debug, PartialEq)] pub struct Item { pub rectangle: DeviceBox2D, - pub src: ItemSource, + pub key: usize, } /// A builder that applies occlusion culling with rectangles provided in front-to-back order. @@ -95,7 +88,7 @@ impl FrontToBackBuilder { /// Add a rectangle, potentially splitting it and discarding the occluded parts if any. /// /// Returns true the rectangle is at least partially visible. - pub fn add(&mut self, rect: &DeviceBox2D, is_opaque: bool, src: ItemSource) -> bool { + pub fn add(&mut self, rect: &DeviceBox2D, is_opaque: bool, key: usize) -> bool { let mut fragments: SmallVec<[DeviceBox2D; 16]> = SmallVec::new(); fragments.push(*rect); @@ -117,7 +110,7 @@ impl FrontToBackBuilder { for rect in &fragments { list.push(Item { rectangle: *rect, - src, + key, }); } diff --git a/gfx/wr/webrender/src/renderer/mod.rs b/gfx/wr/webrender/src/renderer/mod.rs index 855a792a2712..c67cae6a4c5b 100644 --- a/gfx/wr/webrender/src/renderer/mod.rs +++ b/gfx/wr/webrender/src/renderer/mod.rs @@ -57,6 +57,7 @@ use crate::capture::{CaptureConfig, ExternalCaptureImage, PlainExternalImage}; use crate::composite::{CompositeState, CompositeTileSurface, ResolvedExternalSurface, CompositorSurfaceTransform}; use crate::composite::{CompositorKind, Compositor, NativeTileId, CompositeFeatures, CompositeSurfaceFormat, ResolvedExternalSurfaceColorData}; use crate::composite::{CompositorConfig, NativeSurfaceOperationDetails, NativeSurfaceId, NativeSurfaceOperation}; +use crate::composite::TileKind; use crate::c_str; use crate::debug_colors; use crate::device::{DepthFunction, Device, DrawTarget, ExternalTexture, GpuFrameId}; @@ -3287,13 +3288,7 @@ impl Renderer { ); for item in tiles_iter { - let tile = match item.src { - occ::ItemSource::Opaque(idx) => &composite_state.opaque_tiles[idx], - occ::ItemSource::Alpha(idx) => &composite_state.alpha_tiles[idx], - occ::ItemSource::Clear(..) => { - continue; - } - }; + let tile = &composite_state.tiles[item.key]; let clip_rect = item.rectangle.to_rect(); @@ -3502,35 +3497,13 @@ impl Renderer { } } - let cap = composite_state.opaque_tiles.len() + - composite_state.alpha_tiles.len() + - composite_state.clear_tiles.len(); + let cap = composite_state.tiles.len(); let mut occlusion = occlusion::FrontToBackBuilder::with_capacity(cap, cap); - let mut items = Vec::with_capacity(cap); - - // TODO: This will get simpler if we stop storing tiles in separate arrays. - - for (idx, tile) in composite_state.opaque_tiles.iter().enumerate() { - items.push((tile.z_id.0, occ::ItemSource::Opaque(idx))); - } - for (idx, tile) in composite_state.alpha_tiles.iter().enumerate() { - items.push((tile.z_id.0, occ::ItemSource::Alpha(idx))); - } - for (idx, tile) in composite_state.clear_tiles.iter().enumerate() { - items.push((tile.z_id.0, occ::ItemSource::Clear(idx))); - } - - items.sort_by_key(|item| -item.0); - for &(_, src) in &items { - let tile = match src { - occ::ItemSource::Opaque(idx) => &composite_state.opaque_tiles[idx], - occ::ItemSource::Alpha(idx) => &composite_state.alpha_tiles[idx], - occ::ItemSource::Clear(idx) => &composite_state.clear_tiles[idx], - }; - - let is_opaque = !matches!(src, occ::ItemSource::Alpha(..)); + for (idx, tile) in composite_state.tiles.iter().enumerate() { + // Clear tiles overwrite whatever is under them, so they are treated as opaque. + let is_opaque = tile.kind != TileKind::Alpha; // Determine a clip rect to apply to this tile, depending on what // the partial present mode is. @@ -3553,7 +3526,7 @@ impl Renderer { continue; } - occlusion.add(&rect, is_opaque, src); + occlusion.add(&rect, is_opaque, idx); } // Clear the framebuffer @@ -3578,8 +3551,9 @@ impl Renderer { // We are only interested in tiles backed with actual cached pixels so we don't // count clear tiles here. - let num_tiles = composite_state.opaque_tiles.len() - + composite_state.alpha_tiles.len(); + let num_tiles = composite_state.tiles + .iter() + .filter(|tile| tile.kind != TileKind::Clear).count(); self.profile.set(profiler::PICTURE_TILES, num_tiles); if !occlusion.opaque_items().is_empty() { @@ -4442,7 +4416,10 @@ impl Renderer { // Work out how many dirty rects WR produced, and if that's more than // what the device supports. - for tile in composite_state.opaque_tiles.iter().chain(composite_state.alpha_tiles.iter()) { + for tile in &composite_state.tiles { + if tile.kind == TileKind::Clear { + continue; + } let tile_dirty_rect = tile.dirty_rect.translate(tile.rect.origin.to_vector()); let transformed_dirty_rect = if let Some(transform) = tile.transform { transform.outer_transformed_rect(&tile_dirty_rect) @@ -4616,7 +4593,10 @@ impl Renderer { let compositor = self.compositor_config.compositor().unwrap(); // Invalidate any native surface tiles that might be updated by passes. if !frame.has_been_rendered { - for tile in frame.composite_state.opaque_tiles.iter().chain(frame.composite_state.alpha_tiles.iter()) { + for tile in &frame.composite_state.tiles { + if tile.kind == TileKind::Clear { + continue; + } if !tile.dirty_rect.is_empty() { if let CompositeTileSurface::Texture { surface: ResolvedSurfaceTexture::Native { id, .. } } = tile.surface {