Bug 1696905 - Store composite tiles in a single array. r=gfx-reviewers,bradwerth

It used to be more convenient to store them in separate arrays but with the new occlusion culling code we don't benefit from it and have to undo it to traverse tiles from front to back.
This is a cleanup patch that should not change the behavior of the code.

Differential Revision: https://phabricator.services.mozilla.com/D113989
This commit is contained in:
Nicolas Silva 2021-05-04 12:54:52 +00:00
Родитель 67286e28c2
Коммит 1f87bb2116
4 изменённых файлов: 72 добавлений и 107 удалений

Просмотреть файл

@ -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<CompositorSurfaceTransform>,
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<CompositeTile>,
/// List of alpha tiles to be drawn by the Draw compositor.
pub alpha_tiles: Vec<CompositeTile>,
/// List of clear tiles to be drawn by the Draw compositor.
pub clear_tiles: Vec<CompositeTile>,
/// 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<CompositeTile>,
/// List of primitives that were promoted to be compositor surfaces.
pub external_surfaces: Vec<ResolvedExternalSurface>,
/// 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);
}
}

Просмотреть файл

@ -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,

Просмотреть файл

@ -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,
});
}

Просмотреть файл

@ -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 {