tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

composite.rs (73840B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 use api::{BorderRadius, ColorF, ExternalImageId, ImageBufferKind, ImageKey, ImageRendering, YuvFormat, YuvRangedColorSpace};
      6 use api::units::*;
      7 use api::ColorDepth;
      8 use crate::image_source::resolve_image;
      9 use crate::picture::ResolvedSurfaceTexture;
     10 use crate::renderer::GpuBufferBuilderF;
     11 use euclid::Box2D;
     12 use crate::gpu_types::{ZBufferId, ZBufferIdGenerator};
     13 use crate::internal_types::{FrameAllocator, FrameMemory, FrameVec, TextureSource};
     14 use crate::invalidation::compare::ImageDependency;
     15 use crate::tile_cache::{TileCacheInstance, TileSurface};
     16 use crate::tile_cache::TileId;
     17 use crate::prim_store::DeferredResolve;
     18 use crate::resource_cache::{ImageRequest, ResourceCache};
     19 use crate::segment::EdgeAaSegmentMask;
     20 use crate::util::{extract_inner_rect_safe, Preallocator, ScaleOffset};
     21 use crate::tile_cache::PictureCacheDebugInfo;
     22 use crate::device::Device;
     23 use crate::space::SpaceMapper;
     24 use std::{ops, u64, os::raw::c_void, hash};
     25 use std::num::NonZeroUsize;
     26 
     27 /*
     28 Types and definitions related to compositing picture cache tiles
     29 and/or OS compositor integration.
     30 */
     31 
     32 /// Which method is being used to draw a requested compositor surface
     33 #[cfg_attr(feature = "capture", derive(Serialize))]
     34 #[cfg_attr(feature = "replay", derive(Deserialize))]
     35 #[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq)]
     36 pub enum CompositorSurfaceKind {
     37    /// Don't create a native compositor surface, blit it as a regular primitive
     38    Blit,
     39    /// Create a native surface, draw it under content (must be opaque)
     40    Underlay,
     41    /// Create a native surface, draw it between sub-slices (supports transparent)
     42    Overlay,
     43 }
     44 
     45 impl CompositorSurfaceKind {
     46    pub fn is_composited(&self) -> bool {
     47        match *self {
     48            CompositorSurfaceKind::Blit => false,
     49            CompositorSurfaceKind::Underlay | CompositorSurfaceKind::Overlay => true,
     50        }
     51    }
     52 }
     53 
     54 /// Describes details of an operation to apply to a native surface
     55 #[derive(Debug, Clone)]
     56 #[cfg_attr(feature = "capture", derive(Serialize))]
     57 #[cfg_attr(feature = "replay", derive(Deserialize))]
     58 pub enum NativeSurfaceOperationDetails {
     59    CreateSurface {
     60        id: NativeSurfaceId,
     61        virtual_offset: DeviceIntPoint,
     62        tile_size: DeviceIntSize,
     63        is_opaque: bool,
     64    },
     65    CreateExternalSurface {
     66        id: NativeSurfaceId,
     67        is_opaque: bool,
     68    },
     69    CreateBackdropSurface {
     70        id: NativeSurfaceId,
     71        color: ColorF,
     72    },
     73    DestroySurface {
     74        id: NativeSurfaceId,
     75    },
     76    CreateTile {
     77        id: NativeTileId,
     78    },
     79    DestroyTile {
     80        id: NativeTileId,
     81    },
     82    AttachExternalImage {
     83        id: NativeSurfaceId,
     84        external_image: ExternalImageId,
     85    }
     86 }
     87 
     88 /// Describes an operation to apply to a native surface
     89 #[derive(Debug, Clone)]
     90 #[cfg_attr(feature = "capture", derive(Serialize))]
     91 #[cfg_attr(feature = "replay", derive(Deserialize))]
     92 pub struct NativeSurfaceOperation {
     93    pub details: NativeSurfaceOperationDetails,
     94 }
     95 
     96 /// Describes the source surface information for a tile to be composited. This
     97 /// is the analog of the TileSurface type, with target surface information
     98 /// resolved such that it can be used by the renderer.
     99 #[cfg_attr(feature = "capture", derive(Serialize))]
    100 #[cfg_attr(feature = "replay", derive(Deserialize))]
    101 #[derive(Clone)]
    102 pub enum CompositeTileSurface {
    103    Texture {
    104        surface: ResolvedSurfaceTexture,
    105    },
    106    Color {
    107        color: ColorF,
    108    },
    109    ExternalSurface {
    110        external_surface_index: ResolvedExternalSurfaceIndex,
    111    },
    112 }
    113 
    114 /// The surface format for a tile being composited.
    115 #[derive(Debug, Copy, Clone, PartialEq)]
    116 pub enum CompositeSurfaceFormat {
    117    Rgba,
    118    Yuv,
    119 }
    120 
    121 bitflags! {
    122    /// Optional features that can be opted-out of when compositing,
    123    /// possibly allowing a fast path to be selected.
    124    #[derive(Debug, Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
    125    pub struct CompositeFeatures: u8 {
    126        // UV coordinates do not require clamping, for example because the
    127        // entire texture is being composited.
    128        const NO_UV_CLAMP = 1 << 0;
    129        // The texture sample should not be modulated by a specified color.
    130        const NO_COLOR_MODULATION = 1 << 1;
    131        // Can skip applying clip mask.
    132        const NO_CLIP_MASK = 1 << 2;
    133    }
    134 }
    135 
    136 #[derive(Copy, Clone, Debug, PartialEq)]
    137 #[cfg_attr(feature = "capture", derive(Serialize))]
    138 #[cfg_attr(feature = "replay", derive(Deserialize))]
    139 pub enum TileKind {
    140    Opaque,
    141    Alpha,
    142 }
    143 
    144 // Index in to the compositor transforms stored in `CompositeState`
    145 #[cfg_attr(feature = "capture", derive(Serialize))]
    146 #[cfg_attr(feature = "replay", derive(Deserialize))]
    147 #[derive(Debug, Copy, Clone)]
    148 pub struct CompositorTransformIndex(usize);
    149 
    150 impl CompositorTransformIndex {
    151    pub const INVALID: CompositorTransformIndex = CompositorTransformIndex(!0);
    152 }
    153 
    154 // Index in to the compositor clips stored in `CompositeState`
    155 #[cfg_attr(feature = "capture", derive(Serialize))]
    156 #[cfg_attr(feature = "replay", derive(Deserialize))]
    157 #[derive(Debug, Copy, Clone)]
    158 pub struct CompositorClipIndex(NonZeroUsize);
    159 
    160 /// Describes the geometry and surface of a tile to be composited
    161 #[cfg_attr(feature = "capture", derive(Serialize))]
    162 #[cfg_attr(feature = "replay", derive(Deserialize))]
    163 #[derive(Clone)]
    164 pub struct CompositeTile {
    165    pub surface: CompositeTileSurface,
    166    pub local_rect: PictureRect,
    167    pub local_valid_rect: PictureRect,
    168    pub local_dirty_rect: PictureRect,
    169    pub device_clip_rect: DeviceRect,
    170    pub z_id: ZBufferId,
    171    pub kind: TileKind,
    172    pub transform_index: CompositorTransformIndex,
    173    pub clip_index: Option<CompositorClipIndex>,
    174    pub tile_id: Option<TileId>,
    175 }
    176 
    177 pub fn tile_kind(surface: &CompositeTileSurface, is_opaque: bool) -> TileKind {
    178    match surface {
    179        // Color tiles are, by definition, opaque. We might support non-opaque color
    180        // tiles if we ever find pages that have a lot of these.
    181        CompositeTileSurface::Color { .. } => TileKind::Opaque,
    182        CompositeTileSurface::Texture { .. }
    183        | CompositeTileSurface::ExternalSurface { .. } => {
    184            // Texture surfaces get bucketed by opaque/alpha, for z-rejection
    185            // on the Draw compositor mode.
    186            if is_opaque {
    187                TileKind::Opaque
    188            } else {
    189                TileKind::Alpha
    190            }
    191        }
    192    }
    193 }
    194 
    195 pub enum ExternalSurfaceDependency {
    196    Yuv {
    197        image_dependencies: [ImageDependency; 3],
    198        color_space: YuvRangedColorSpace,
    199        format: YuvFormat,
    200        channel_bit_depth: u32,
    201    },
    202    Rgb {
    203        image_dependency: ImageDependency,
    204    },
    205 }
    206 
    207 /// Describes information about drawing a primitive as a compositor surface.
    208 /// For now, we support only YUV images as compositor surfaces, but in future
    209 /// this will also support RGBA images.
    210 pub struct ExternalSurfaceDescriptor {
    211    // Normalized rectangle of this surface in local coordinate space
    212    // TODO(gw): Fix up local_rect unit kinds in ExternalSurfaceDescriptor (many flow on effects)
    213    pub local_surface_size: LayoutSize,
    214    pub local_rect: PictureRect,
    215    pub local_clip_rect: PictureRect,
    216    pub clip_rect: DeviceRect,
    217    pub transform_index: CompositorTransformIndex,
    218    pub compositor_clip_index: Option<CompositorClipIndex>,
    219    pub image_rendering: ImageRendering,
    220    pub z_id: ZBufferId,
    221    pub dependency: ExternalSurfaceDependency,
    222    /// If native compositing is enabled, the native compositor surface handle.
    223    /// Otherwise, this will be None
    224    pub native_surface_id: Option<NativeSurfaceId>,
    225    /// If the native surface needs to be updated, this will contain the size
    226    /// of the native surface as Some(size). If not dirty, this is None.
    227    pub update_params: Option<DeviceIntSize>,
    228    /// If using external compositing, a user key for the client
    229    pub external_image_id: Option<ExternalImageId>,
    230 }
    231 
    232 impl ExternalSurfaceDescriptor {
    233    /// Calculate an optional occlusion rect for a given compositor surface
    234    pub fn get_occluder_rect(
    235        &self,
    236        local_clip_rect: &PictureRect,
    237        map_pic_to_world: &SpaceMapper<PicturePixel, WorldPixel>,
    238    ) -> Option<WorldRect> {
    239        let local_surface_rect = self
    240            .local_rect
    241            .intersection(&self.local_clip_rect)
    242            .and_then(|r| {
    243                r.intersection(local_clip_rect)
    244            });
    245 
    246        local_surface_rect.map(|local_surface_rect| {
    247            map_pic_to_world
    248                .map(&local_surface_rect)
    249                .expect("bug: unable to map external surface to world space")
    250        })
    251    }
    252 }
    253 
    254 /// Information about a plane in a YUV or RGB surface.
    255 #[cfg_attr(feature = "capture", derive(Serialize))]
    256 #[cfg_attr(feature = "replay", derive(Deserialize))]
    257 #[derive(Debug, Copy, Clone)]
    258 pub struct ExternalPlaneDescriptor {
    259    pub texture: TextureSource,
    260    pub uv_rect: TexelRect,
    261 }
    262 
    263 impl ExternalPlaneDescriptor {
    264    fn invalid() -> Self {
    265        ExternalPlaneDescriptor {
    266            texture: TextureSource::Invalid,
    267            uv_rect: TexelRect::invalid(),
    268        }
    269    }
    270 }
    271 
    272 #[cfg_attr(feature = "capture", derive(Serialize))]
    273 #[cfg_attr(feature = "replay", derive(Deserialize))]
    274 #[derive(Debug, Copy, Clone, PartialEq)]
    275 pub struct ResolvedExternalSurfaceIndex(pub usize);
    276 
    277 impl ResolvedExternalSurfaceIndex {
    278    pub const INVALID: ResolvedExternalSurfaceIndex = ResolvedExternalSurfaceIndex(usize::MAX);
    279 }
    280 
    281 #[cfg_attr(feature = "capture", derive(Serialize))]
    282 #[cfg_attr(feature = "replay", derive(Deserialize))]
    283 pub enum ResolvedExternalSurfaceColorData {
    284    Yuv {
    285        // YUV specific information
    286        image_dependencies: [ImageDependency; 3],
    287        planes: [ExternalPlaneDescriptor; 3],
    288        color_space: YuvRangedColorSpace,
    289        format: YuvFormat,
    290        channel_bit_depth: u32,
    291    },
    292    Rgb {
    293        image_dependency: ImageDependency,
    294        plane: ExternalPlaneDescriptor,
    295    },
    296 }
    297 
    298 /// An ExternalSurfaceDescriptor that has had image keys
    299 /// resolved to texture handles. This contains all the
    300 /// information that the compositor step in renderer
    301 /// needs to know.
    302 #[cfg_attr(feature = "capture", derive(Serialize))]
    303 #[cfg_attr(feature = "replay", derive(Deserialize))]
    304 pub struct ResolvedExternalSurface {
    305    pub color_data: ResolvedExternalSurfaceColorData,
    306    pub image_buffer_kind: ImageBufferKind,
    307    // Update information for a native surface if it's dirty
    308    pub update_params: Option<(NativeSurfaceId, DeviceIntSize)>,
    309    /// If using external compositing, a user key for the client
    310    pub external_image_id: Option<ExternalImageId>,
    311 }
    312 
    313 /// Public interface specified in `WebRenderOptions` that configures
    314 /// how WR compositing will operate.
    315 pub enum CompositorConfig {
    316    /// Let WR draw tiles via normal batching. This requires no special OS support.
    317    Draw {
    318        /// If this is zero, a full screen present occurs at the end of the
    319        /// frame. This is the simplest and default mode. If this is non-zero,
    320        /// then the operating system supports a form of 'partial present' where
    321        /// only dirty regions of the framebuffer need to be updated.
    322        max_partial_present_rects: usize,
    323        /// If this is true, WR must draw the previous frames' dirty regions when
    324        /// doing a partial present. This is used for EGL which requires the front
    325        /// buffer to always be fully consistent.
    326        draw_previous_partial_present_regions: bool,
    327        /// A client provided interface to a compositor handling partial present.
    328        /// Required if webrender must query the backbuffer's age.
    329        partial_present: Option<Box<dyn PartialPresentCompositor>>,
    330    },
    331    Layer {
    332        /// If supplied, composite the frame using the new experimental compositing
    333        /// interface. If this is set, it overrides `compositor_config`. These will
    334        /// be unified as the interface stabilises.
    335        compositor: Box<dyn LayerCompositor>,
    336    },
    337    /// Use a native OS compositor to draw tiles. This requires clients to implement
    338    /// the Compositor trait, but can be significantly more power efficient on operating
    339    /// systems that support it.
    340    Native {
    341        /// A client provided interface to a native / OS compositor.
    342        compositor: Box<dyn Compositor>,
    343    }
    344 }
    345 
    346 impl CompositorConfig {
    347    pub fn compositor(&mut self) -> Option<&mut Box<dyn Compositor>> {
    348        match self {
    349            CompositorConfig::Native { ref mut compositor, .. } => {
    350                Some(compositor)
    351            }
    352            CompositorConfig::Draw { .. } | CompositorConfig::Layer { .. } => {
    353                None
    354            }
    355        }
    356    }
    357 
    358    pub fn partial_present(&mut self) -> Option<&mut Box<dyn PartialPresentCompositor>> {
    359        match self {
    360            CompositorConfig::Native { .. } => {
    361                None
    362            }
    363            CompositorConfig::Draw { ref mut partial_present, .. } => {
    364                partial_present.as_mut()
    365            }
    366            CompositorConfig::Layer { .. } => {
    367                None
    368            }
    369        }
    370    }
    371 
    372    pub fn layer_compositor(&mut self) -> Option<&mut Box<dyn LayerCompositor>> {
    373        match self {
    374            CompositorConfig::Native { .. } => {
    375                None
    376            }
    377            CompositorConfig::Draw { .. } => {
    378                None
    379            }
    380            CompositorConfig::Layer { ref mut compositor } => {
    381                Some(compositor)
    382            }
    383        }
    384    }
    385 }
    386 
    387 impl Default for CompositorConfig {
    388    /// Default compositor config is full present without partial present.
    389    fn default() -> Self {
    390        CompositorConfig::Draw {
    391            max_partial_present_rects: 0,
    392            draw_previous_partial_present_regions: false,
    393            partial_present: None,
    394        }
    395    }
    396 }
    397 
    398 /// This is a representation of `CompositorConfig` without the `Compositor` trait
    399 /// present. This allows it to be freely copied to other threads, such as the render
    400 /// backend where the frame builder can access it.
    401 #[cfg_attr(feature = "capture", derive(Serialize))]
    402 #[cfg_attr(feature = "replay", derive(Deserialize))]
    403 #[derive(Debug, Copy, Clone, PartialEq)]
    404 pub enum CompositorKind {
    405    /// WR handles compositing via drawing.
    406    Draw {
    407        /// Partial present support.
    408        max_partial_present_rects: usize,
    409        /// Draw previous regions when doing partial present.
    410        draw_previous_partial_present_regions: bool,
    411    },
    412    Layer {
    413 
    414    },
    415    /// Native OS compositor.
    416    Native {
    417        /// The capabilities of the underlying platform.
    418        capabilities: CompositorCapabilities,
    419    },
    420 }
    421 
    422 impl Default for CompositorKind {
    423    /// Default compositor config is full present without partial present.
    424    fn default() -> Self {
    425        CompositorKind::Draw {
    426            max_partial_present_rects: 0,
    427            draw_previous_partial_present_regions: false,
    428        }
    429    }
    430 }
    431 
    432 impl CompositorKind {
    433    pub fn get_virtual_surface_size(&self) -> i32 {
    434        match self {
    435            CompositorKind::Draw { .. } | CompositorKind::Layer {  .. }=> 0,
    436            CompositorKind::Native { capabilities, .. } => capabilities.virtual_surface_size,
    437        }
    438    }
    439 
    440    pub fn should_redraw_on_invalidation(&self) -> bool {
    441        match self {
    442            CompositorKind::Draw { max_partial_present_rects, .. } => {
    443                // When partial present is enabled, we need to force redraw.
    444                *max_partial_present_rects > 0
    445            }
    446            CompositorKind::Layer {  } => false,    // TODO(gwc): Is this correct?
    447            CompositorKind::Native { capabilities, .. } => capabilities.redraw_on_invalidation,
    448        }
    449    }
    450 }
    451 
    452 /// The backing surface kind for a tile. Same as `TileSurface`, minus
    453 /// the texture cache handles, visibility masks etc.
    454 #[cfg_attr(feature = "capture", derive(Serialize))]
    455 #[cfg_attr(feature = "replay", derive(Deserialize))]
    456 #[derive(PartialEq, Clone)]
    457 pub enum TileSurfaceKind {
    458    Texture,
    459    Color {
    460        color: ColorF,
    461    },
    462 }
    463 
    464 impl From<&TileSurface> for TileSurfaceKind {
    465    fn from(surface: &TileSurface) -> Self {
    466        match surface {
    467            TileSurface::Texture { .. } => TileSurfaceKind::Texture,
    468            TileSurface::Color { color } => TileSurfaceKind::Color { color: *color },
    469        }
    470    }
    471 }
    472 
    473 /// Describes properties that identify a tile composition uniquely.
    474 /// The backing surface for this tile.
    475 #[cfg_attr(feature = "capture", derive(Serialize))]
    476 #[cfg_attr(feature = "replay", derive(Deserialize))]
    477 #[derive(PartialEq, Clone)]
    478 pub struct CompositeTileDescriptor {
    479    pub tile_id: TileId,
    480    pub surface_kind: TileSurfaceKind,
    481 }
    482 
    483 // Whether a compositor surface / swapchain is being used
    484 // by WR to render content, or is an external swapchain for video
    485 #[cfg_attr(feature = "capture", derive(Serialize))]
    486 #[cfg_attr(feature = "replay", derive(Deserialize))]
    487 #[derive(Debug, Copy, Clone)]
    488 pub enum CompositorSurfaceUsage {
    489    Content,
    490    External {
    491        image_key: ImageKey,
    492        external_image_id: ExternalImageId,
    493        transform_index: CompositorTransformIndex,
    494    },
    495    DebugOverlay,
    496 }
    497 
    498 impl CompositorSurfaceUsage {
    499    // Returns true if usage is compatible
    500    pub fn matches(&self, other: &CompositorSurfaceUsage) -> bool {
    501        match (self, other) {
    502            // Surfaces used for content are always compatible
    503            (CompositorSurfaceUsage::Content, CompositorSurfaceUsage::Content) => true,
    504 
    505            (CompositorSurfaceUsage::Content, CompositorSurfaceUsage::External { .. }) |
    506            (CompositorSurfaceUsage::External { .. }, CompositorSurfaceUsage::Content) => false,
    507 
    508            // External surfaces are matched by image-key (which doesn't change per-frame)
    509            (CompositorSurfaceUsage::External { image_key: key1, .. }, CompositorSurfaceUsage::External { image_key: key2, .. }) => {
    510                key1 == key2
    511            }
    512 
    513            (CompositorSurfaceUsage::DebugOverlay, CompositorSurfaceUsage::DebugOverlay) => true,
    514 
    515            (CompositorSurfaceUsage::DebugOverlay, _) | (_, CompositorSurfaceUsage::DebugOverlay) => false,
    516        }
    517    }
    518 }
    519 
    520 /// Describes the properties that identify a surface composition uniquely.
    521 #[cfg_attr(feature = "capture", derive(Serialize))]
    522 #[cfg_attr(feature = "replay", derive(Deserialize))]
    523 #[derive(PartialEq, Clone)]
    524 pub struct CompositeSurfaceDescriptor {
    525    pub surface_id: Option<NativeSurfaceId>,
    526    pub clip_rect: DeviceRect,
    527    pub transform: CompositorSurfaceTransform,
    528    // A list of image keys and generations that this compositor surface
    529    // depends on. This avoids composites being skipped when the only
    530    // thing that has changed is the generation of an compositor surface
    531    // image dependency.
    532    pub image_dependencies: [ImageDependency; 3],
    533    pub image_rendering: ImageRendering,
    534    // List of the surface information for each tile added to this virtual surface
    535    pub tile_descriptors: Vec<CompositeTileDescriptor>,
    536    pub rounded_clip_rect: DeviceRect,
    537    pub rounded_clip_radii: ClipRadius,
    538 }
    539 
    540 /// Describes surface properties used to composite a frame. This
    541 /// is used to compare compositions between frames.
    542 #[cfg_attr(feature = "capture", derive(Serialize))]
    543 #[cfg_attr(feature = "replay", derive(Deserialize))]
    544 #[derive(PartialEq, Clone)]
    545 pub struct CompositeDescriptor {
    546    pub surfaces: Vec<CompositeSurfaceDescriptor>,
    547    pub external_surfaces_rect: DeviceRect,
    548 }
    549 
    550 impl CompositeDescriptor {
    551    /// Construct an empty descriptor.
    552    pub fn empty() -> Self {
    553        CompositeDescriptor {
    554            surfaces: Vec::new(),
    555            external_surfaces_rect: DeviceRect::zero(),
    556        }
    557    }
    558 }
    559 
    560 pub struct CompositeStatePreallocator {
    561    tiles: Preallocator,
    562    external_surfaces: Preallocator,
    563    occluders: Preallocator,
    564    occluders_events: Preallocator,
    565    occluders_active: Preallocator,
    566    descriptor_surfaces: Preallocator,
    567 }
    568 
    569 impl CompositeStatePreallocator {
    570    pub fn record(&mut self, state: &CompositeState) {
    571        self.tiles.record_vec(&state.tiles);
    572        self.external_surfaces.record_vec(&state.external_surfaces);
    573        self.occluders.record_vec(&state.occluders.occluders);
    574        self.occluders_events.record_vec(&state.occluders.scratch.events);
    575        self.occluders_active.record_vec(&state.occluders.scratch.active);
    576        self.descriptor_surfaces.record_vec(&state.descriptor.surfaces);
    577    }
    578 
    579    pub fn preallocate(&self, state: &mut CompositeState) {
    580        self.tiles.preallocate_framevec(&mut state.tiles);
    581        self.external_surfaces.preallocate_framevec(&mut state.external_surfaces);
    582        self.occluders.preallocate_framevec(&mut state.occluders.occluders);
    583        self.occluders_events.preallocate_framevec(&mut state.occluders.scratch.events);
    584        self.occluders_active.preallocate_framevec(&mut state.occluders.scratch.active);
    585        self.descriptor_surfaces.preallocate_vec(&mut state.descriptor.surfaces);
    586    }
    587 }
    588 
    589 impl Default for CompositeStatePreallocator {
    590    fn default() -> Self {
    591        CompositeStatePreallocator {
    592            tiles: Preallocator::new(56),
    593            external_surfaces: Preallocator::new(0),
    594            occluders: Preallocator::new(16),
    595            occluders_events: Preallocator::new(32),
    596            occluders_active: Preallocator::new(16),
    597            descriptor_surfaces: Preallocator::new(8),
    598        }
    599    }
    600 }
    601 
    602 /// A transform for either a picture cache or external compositor surface, stored
    603 /// in the `CompositeState` structure. This allows conversions from local rects
    604 /// to raster or device rects, without access to the spatial tree (e.g. during
    605 /// the render step where dirty rects are calculated). Since we know that we only
    606 /// handle scale and offset transforms for these types, we can store a single
    607 /// ScaleOffset rather than 4x4 matrix here for efficiency.
    608 #[cfg_attr(feature = "capture", derive(Serialize))]
    609 #[cfg_attr(feature = "replay", derive(Deserialize))]
    610 pub struct CompositorTransform {
    611    // Map from local rect of a composite tile to the real backing surface coords
    612    local_to_raster: ScaleOffset,
    613    // Map from surface coords to the final device space position
    614    raster_to_device: ScaleOffset,
    615    // Combined local -> surface -> device transform
    616    local_to_device: ScaleOffset,
    617 }
    618 
    619 #[cfg_attr(feature = "capture", derive(Serialize))]
    620 #[cfg_attr(feature = "replay", derive(Deserialize))]
    621 #[derive(Debug)]
    622 pub struct CompositorClip {
    623    pub rect: DeviceRect,
    624    pub radius: BorderRadius,
    625 }
    626 
    627 #[derive(PartialEq, Debug)]
    628 pub struct CompositeRoundedCorner {
    629    pub rect: LayoutRect,
    630    pub radius: LayoutSize,
    631    pub edge_flags: EdgeAaSegmentMask,
    632 }
    633 
    634 impl Eq for CompositeRoundedCorner {}
    635 
    636 impl hash::Hash for CompositeRoundedCorner {
    637    fn hash<H: hash::Hasher>(&self, state: &mut H) {
    638        self.rect.min.x.to_bits().hash(state);
    639        self.rect.min.y.to_bits().hash(state);
    640        self.rect.max.x.to_bits().hash(state);
    641        self.rect.max.y.to_bits().hash(state);
    642        self.radius.width.to_bits().hash(state);
    643        self.radius.height.to_bits().hash(state);
    644        self.edge_flags.bits().hash(state);
    645    }
    646 }
    647 
    648 /// The list of tiles to be drawn this frame
    649 #[cfg_attr(feature = "capture", derive(Serialize))]
    650 #[cfg_attr(feature = "replay", derive(Deserialize))]
    651 pub struct CompositeState {
    652    // TODO(gw): Consider splitting up CompositeState into separate struct types depending
    653    //           on the selected compositing mode. Many of the fields in this state struct
    654    //           are only applicable to either Native or Draw compositing mode.
    655    /// List of tiles to be drawn by the Draw compositor.
    656    /// Tiles are accumulated in this vector and sorted from front to back at the end of the
    657    /// frame.
    658    pub tiles: FrameVec<CompositeTile>,
    659    /// List of primitives that were promoted to be compositor surfaces.
    660    pub external_surfaces: FrameVec<ResolvedExternalSurface>,
    661    /// Used to generate z-id values for tiles in the Draw compositor mode.
    662    pub z_generator: ZBufferIdGenerator,
    663    // If false, we can't rely on the dirty rects in the CompositeTile
    664    // instances. This currently occurs during a scroll event, as a
    665    // signal to refresh the whole screen. This is only a temporary
    666    // measure until we integrate with OS compositors. In the meantime
    667    // it gives us the ability to partial present for any non-scroll
    668    // case as a simple win (e.g. video, animation etc).
    669    pub dirty_rects_are_valid: bool,
    670    /// The kind of compositor for picture cache tiles (e.g. drawn by WR, or OS compositor)
    671    pub compositor_kind: CompositorKind,
    672    /// List of registered occluders
    673    pub occluders: Occluders,
    674    /// Description of the surfaces and properties that are being composited.
    675    pub descriptor: CompositeDescriptor,
    676    /// Debugging information about the state of the pictures cached for regression testing.
    677    pub picture_cache_debug: PictureCacheDebugInfo,
    678    /// List of registered transforms used by picture cache or external surfaces
    679    pub transforms: FrameVec<CompositorTransform>,
    680    /// Whether we have low quality pinch zoom enabled
    681    low_quality_pinch_zoom: bool,
    682    /// List of registered clips used by picture cache and/or external surfaces
    683    pub clips: FrameVec<CompositorClip>,
    684 }
    685 
    686 impl CompositeState {
    687    /// Construct a new state for compositing picture tiles. This is created
    688    /// during each frame construction and passed to the renderer.
    689    pub fn new(
    690        compositor_kind: CompositorKind,
    691        max_depth_ids: i32,
    692        dirty_rects_are_valid: bool,
    693        low_quality_pinch_zoom: bool,
    694        memory: &FrameMemory,
    695    ) -> Self {
    696        // Since CompositorClipIndex is NonZeroUSize, we need to
    697        // push a dummy entry in to this array.
    698        let mut clips = memory.new_vec();
    699        clips.push(CompositorClip {
    700            rect: DeviceRect::zero(),
    701            radius: BorderRadius::zero(),
    702        });
    703 
    704        CompositeState {
    705            tiles: memory.new_vec(),
    706            z_generator: ZBufferIdGenerator::new(max_depth_ids),
    707            dirty_rects_are_valid,
    708            compositor_kind,
    709            occluders: Occluders::new(memory),
    710            descriptor: CompositeDescriptor::empty(),
    711            external_surfaces: memory.new_vec(),
    712            picture_cache_debug: PictureCacheDebugInfo::new(),
    713            transforms: memory.new_vec(),
    714            low_quality_pinch_zoom,
    715            clips,
    716        }
    717    }
    718 
    719    fn compositor_clip_params(
    720        &self,
    721        clip_index: Option<CompositorClipIndex>,
    722        default_rect: DeviceRect,
    723    ) -> (DeviceRect, ClipRadius) {
    724        match clip_index {
    725            Some(clip_index) => {
    726                let clip = self.get_compositor_clip(clip_index);
    727 
    728                (
    729                    clip.rect.cast_unit(),
    730                    ClipRadius {
    731                        top_left: clip.radius.top_left.width.round() as i32,
    732                        top_right: clip.radius.top_right.width.round() as i32,
    733                        bottom_left: clip.radius.bottom_left.width.round() as i32,
    734                        bottom_right: clip.radius.bottom_right.width.round() as i32,
    735                    }
    736                )
    737            }
    738            None => {
    739                (default_rect, ClipRadius::EMPTY)
    740            }
    741        }
    742    }
    743 
    744    /// Register use of a transform for a picture cache tile or external surface
    745    pub fn register_transform(
    746        &mut self,
    747        local_to_raster: ScaleOffset,
    748        raster_to_device: ScaleOffset,
    749    ) -> CompositorTransformIndex {
    750        let index = CompositorTransformIndex(self.transforms.len());
    751 
    752        let local_to_device = local_to_raster.then(&raster_to_device);
    753 
    754        self.transforms.push(CompositorTransform {
    755            local_to_raster,
    756            raster_to_device,
    757            local_to_device,
    758        });
    759 
    760        index
    761    }
    762 
    763    /// Register use of a clip for a picture cache tile and/or external surface
    764    pub fn register_clip(
    765        &mut self,
    766        rect: DeviceRect,
    767        radius: BorderRadius,
    768    ) -> CompositorClipIndex {
    769        let index = CompositorClipIndex(NonZeroUsize::new(self.clips.len()).expect("bug"));
    770 
    771        self.clips.push(CompositorClip {
    772            rect,
    773            radius,
    774        });
    775 
    776        index
    777    }
    778 
    779    /// Calculate the device-space rect of a local compositor surface rect
    780    pub fn get_device_rect(
    781        &self,
    782        local_rect: &PictureRect,
    783        transform_index: CompositorTransformIndex,
    784    ) -> DeviceRect {
    785        let transform = &self.transforms[transform_index.0];
    786        transform.local_to_device.map_rect(&local_rect).round()
    787    }
    788 
    789    /// Calculate the device-space rect of a local compositor surface rect, normalized
    790    /// to the origin of a given point
    791    pub fn get_surface_rect<T>(
    792        &self,
    793        local_sub_rect: &Box2D<f32, T>,
    794        local_bounds: &Box2D<f32, T>,
    795        transform_index: CompositorTransformIndex,
    796    ) -> DeviceRect {
    797        let transform = &self.transforms[transform_index.0];
    798 
    799        let surface_bounds = transform.local_to_raster.map_rect(&local_bounds);
    800        let surface_rect = transform.local_to_raster.map_rect(&local_sub_rect);
    801 
    802        surface_rect
    803            .round_out()
    804            .translate(-surface_bounds.min.to_vector())
    805            .round_out()
    806            .intersection(&surface_bounds.size().round().into())
    807            .unwrap_or_else(DeviceRect::zero)
    808    }
    809 
    810    /// Get the local -> device compositor transform
    811    pub fn get_device_transform(
    812        &self,
    813        transform_index: CompositorTransformIndex,
    814    ) -> ScaleOffset {
    815        let transform = &self.transforms[transform_index.0];
    816        transform.local_to_device
    817    }
    818 
    819    /// Get the surface -> device compositor transform
    820    pub fn get_compositor_transform(
    821        &self,
    822        transform_index: CompositorTransformIndex,
    823    ) -> ScaleOffset {
    824        let transform = &self.transforms[transform_index.0];
    825        transform.raster_to_device
    826    }
    827 
    828    /// Get the compositor clip
    829    pub fn get_compositor_clip(
    830        &self,
    831        clip_index: CompositorClipIndex,
    832    ) -> &CompositorClip {
    833        &self.clips[clip_index.0.get()]
    834    }
    835 
    836    /// Register an occluder during picture cache updates that can be
    837    /// used during frame building to occlude tiles.
    838    pub fn register_occluder(
    839        &mut self,
    840        z_id: ZBufferId,
    841        rect: WorldRect,
    842        compositor_clip: Option<CompositorClipIndex>,
    843    ) {
    844        let rect = match compositor_clip {
    845            Some(clip_index) => {
    846                let clip = self.get_compositor_clip(clip_index);
    847 
    848                let inner_rect = match extract_inner_rect_safe(
    849                    &clip.rect,
    850                    &clip.radius,
    851                ) {
    852                    Some(rect) => rect,
    853                    None => return,
    854                };
    855 
    856                match inner_rect.cast_unit().intersection(&rect) {
    857                    Some(rect) => rect,
    858                    None => return,
    859                }
    860            }
    861            None => {
    862                rect
    863            }
    864        };
    865 
    866        let world_rect = rect.round().to_i32();
    867 
    868        self.occluders.push(world_rect, z_id);
    869    }
    870 
    871    /// Push a compositor surface on to the list of tiles to be passed to the compositor
    872    fn push_compositor_surface(
    873        &mut self,
    874        external_surface: &ExternalSurfaceDescriptor,
    875        is_opaque: bool,
    876        device_clip_rect: DeviceRect,
    877        resource_cache: &ResourceCache,
    878        gpu_buffer: &mut GpuBufferBuilderF,
    879        deferred_resolves: &mut FrameVec<DeferredResolve>,
    880        clip_index: Option<CompositorClipIndex>,
    881    ) {
    882        let clip_rect = external_surface
    883            .clip_rect
    884            .intersection(&device_clip_rect)
    885            .unwrap_or_else(DeviceRect::zero);
    886 
    887        // Skip compositor surfaces with empty clip rects.
    888        if clip_rect.is_empty() {
    889            return;
    890        }
    891 
    892        let required_plane_count =
    893            match external_surface.dependency {
    894                ExternalSurfaceDependency::Yuv { format, .. } => {
    895                    format.get_plane_num()
    896                },
    897                ExternalSurfaceDependency::Rgb { .. } => {
    898                    1
    899                }
    900            };
    901 
    902        let mut image_dependencies = [ImageDependency::INVALID; 3];
    903 
    904        for i in 0 .. required_plane_count {
    905            let dependency = match external_surface.dependency {
    906                ExternalSurfaceDependency::Yuv { image_dependencies, .. } => {
    907                    image_dependencies[i]
    908                },
    909                ExternalSurfaceDependency::Rgb { image_dependency, .. } => {
    910                    image_dependency
    911                }
    912            };
    913            image_dependencies[i] = dependency;
    914        }
    915 
    916        // Get a new z_id for each compositor surface, to ensure correct ordering
    917        // when drawing with the simple (Draw) compositor, and to schedule compositing
    918        // of any required updates into the surfaces.
    919        let needs_external_surface_update = match self.compositor_kind {
    920            CompositorKind::Draw { .. } | CompositorKind::Layer { .. } => true,
    921            _ => external_surface.update_params.is_some(),
    922        };
    923        let external_surface_index = if needs_external_surface_update {
    924            let external_surface_index = self.compute_external_surface_dependencies(
    925                &external_surface,
    926                &image_dependencies,
    927                required_plane_count,
    928                resource_cache,
    929                gpu_buffer,
    930                deferred_resolves,
    931            );
    932            if external_surface_index == ResolvedExternalSurfaceIndex::INVALID {
    933                return;
    934            }
    935            external_surface_index
    936        } else {
    937            ResolvedExternalSurfaceIndex::INVALID
    938        };
    939 
    940        let surface = CompositeTileSurface::ExternalSurface { external_surface_index };
    941        let local_rect = external_surface.local_surface_size.cast_unit().into();
    942 
    943        let tile = CompositeTile {
    944            kind: tile_kind(&surface, is_opaque),
    945            surface,
    946            local_rect,
    947            local_valid_rect: local_rect,
    948            local_dirty_rect: local_rect,
    949            device_clip_rect: clip_rect,
    950            z_id: external_surface.z_id,
    951            transform_index: external_surface.transform_index,
    952            clip_index,
    953            tile_id: None,
    954        };
    955 
    956        let (rounded_clip_rect, rounded_clip_radii) = self.compositor_clip_params(
    957            clip_index,
    958            clip_rect,
    959        );
    960 
    961        // Add a surface descriptor for each compositor surface. For the Draw
    962        // compositor, this is used to avoid composites being skipped by adding
    963        // a dependency on the compositor surface external image keys / generations.
    964        self.descriptor.surfaces.push(
    965            CompositeSurfaceDescriptor {
    966                surface_id: external_surface.native_surface_id,
    967                clip_rect,
    968                transform: self.get_compositor_transform(external_surface.transform_index),
    969                image_dependencies: image_dependencies,
    970                image_rendering: external_surface.image_rendering,
    971                tile_descriptors: Vec::new(),
    972                rounded_clip_rect,
    973                rounded_clip_radii,
    974            }
    975        );
    976 
    977        let device_rect =
    978            self.get_device_rect(&local_rect, external_surface.transform_index);
    979        self.descriptor.external_surfaces_rect =
    980            self.descriptor.external_surfaces_rect.union(&device_rect);
    981 
    982        self.tiles.push(tile);
    983    }
    984 
    985    /// Add a picture cache to be composited
    986    pub fn push_surface(
    987        &mut self,
    988        tile_cache: &TileCacheInstance,
    989        device_clip_rect: DeviceRect,
    990        resource_cache: &ResourceCache,
    991        gpu_buffer: &mut GpuBufferBuilderF,
    992        deferred_resolves: &mut FrameVec<DeferredResolve>,
    993    ) {
    994        let slice_transform = self.get_compositor_transform(tile_cache.transform_index);
    995 
    996        let image_rendering = if self.low_quality_pinch_zoom {
    997            ImageRendering::Auto
    998        } else {
    999            ImageRendering::CrispEdges
   1000        };
   1001 
   1002        if let Some(backdrop_surface) = &tile_cache.backdrop_surface {
   1003            let (rounded_clip_rect, rounded_clip_radii) = self.compositor_clip_params(
   1004                tile_cache.compositor_clip,
   1005                backdrop_surface.device_rect,
   1006            );
   1007 
   1008            // Use the backdrop native surface we created and add that to the composite state.
   1009            self.descriptor.surfaces.push(
   1010                CompositeSurfaceDescriptor {
   1011                    surface_id: Some(backdrop_surface.id),
   1012                    clip_rect: backdrop_surface.device_rect,
   1013                    transform: slice_transform,
   1014                    image_dependencies: [ImageDependency::INVALID; 3],
   1015                    image_rendering,
   1016                    tile_descriptors: Vec::new(),
   1017                    rounded_clip_rect,
   1018                    rounded_clip_radii,
   1019                }
   1020            );
   1021        }
   1022 
   1023        // Add any underlay surfaces to the compositing tree
   1024        for underlay in &tile_cache.underlays {
   1025            self.push_compositor_surface(
   1026                underlay,
   1027                true,
   1028                device_clip_rect,
   1029                resource_cache,
   1030                gpu_buffer,
   1031                deferred_resolves,
   1032                tile_cache.compositor_clip,
   1033            );
   1034        }
   1035 
   1036        for sub_slice in &tile_cache.sub_slices {
   1037            let mut surface_device_rect = DeviceRect::zero();
   1038 
   1039            for tile in sub_slice.tiles.values() {
   1040                if !tile.is_visible {
   1041                    // This can occur when a tile is found to be occluded during frame building.
   1042                    continue;
   1043                }
   1044 
   1045                // Accumulate this tile into the overall surface bounds. This is used below
   1046                // to clamp the size of the supplied clip rect to a reasonable value.
   1047                // NOTE: This clip rect must include the device_valid_rect rather than
   1048                //       the tile device rect. This ensures that in the case of a picture
   1049                //       cache slice that is smaller than a single tile, the clip rect in
   1050                //       the composite descriptor will change if the position of that slice
   1051                //       is changed. Otherwise, WR may conclude that no composite is needed
   1052                //       if the tile itself was not invalidated due to changing content.
   1053                //       See bug #1675414 for more detail.
   1054                surface_device_rect = surface_device_rect.union(&tile.device_valid_rect);
   1055            }
   1056 
   1057            // Append the visible tiles from this sub-slice
   1058            self.tiles.extend_from_slice(&sub_slice.composite_tiles);
   1059 
   1060            // If the clip rect is too large, it can cause accuracy and correctness problems
   1061            // for some native compositors (specifically, CoreAnimation in this case). To
   1062            // work around that, intersect the supplied clip rect with the current bounds
   1063            // of the native surface, which ensures it is a reasonable size.
   1064            let surface_clip_rect = device_clip_rect
   1065                .intersection(&surface_device_rect)
   1066                .unwrap_or(DeviceRect::zero());
   1067 
   1068            // Only push tiles if they have valid clip rects.
   1069            if !surface_clip_rect.is_empty() {
   1070                let (rounded_clip_rect, rounded_clip_radii) = self.compositor_clip_params(
   1071                    tile_cache.compositor_clip,
   1072                    surface_clip_rect,
   1073                );
   1074 
   1075                // Add opaque surface before any compositor surfaces
   1076                if !sub_slice.opaque_tile_descriptors.is_empty() {
   1077                    self.descriptor.surfaces.push(
   1078                        CompositeSurfaceDescriptor {
   1079                            surface_id: sub_slice.native_surface.as_ref().map(|s| s.opaque),
   1080                            clip_rect: surface_clip_rect,
   1081                            transform: slice_transform,
   1082                            image_dependencies: [ImageDependency::INVALID; 3],
   1083                            image_rendering,
   1084                            tile_descriptors: sub_slice.opaque_tile_descriptors.clone(),
   1085                            rounded_clip_rect,
   1086                            rounded_clip_radii,
   1087                        }
   1088                    );
   1089                }
   1090 
   1091                // Add alpha tiles after opaque surfaces
   1092                if !sub_slice.alpha_tile_descriptors.is_empty() {
   1093                    self.descriptor.surfaces.push(
   1094                        CompositeSurfaceDescriptor {
   1095                            surface_id: sub_slice.native_surface.as_ref().map(|s| s.alpha),
   1096                            clip_rect: surface_clip_rect,
   1097                            transform: slice_transform,
   1098                            image_dependencies: [ImageDependency::INVALID; 3],
   1099                            image_rendering,
   1100                            tile_descriptors: sub_slice.alpha_tile_descriptors.clone(),
   1101                            rounded_clip_rect,
   1102                            rounded_clip_radii,
   1103                        }
   1104                    );
   1105                }
   1106            }
   1107 
   1108            // For each compositor surface that was promoted, build the
   1109            // information required for the compositor to draw it
   1110            for compositor_surface in &sub_slice.compositor_surfaces {
   1111                let compositor_clip_index = if compositor_surface.descriptor.compositor_clip_index.is_some() {
   1112                    assert!(tile_cache.compositor_clip.is_none());
   1113                    compositor_surface.descriptor.compositor_clip_index
   1114                } else {
   1115                    tile_cache.compositor_clip
   1116                };
   1117 
   1118                self.push_compositor_surface(
   1119                    &compositor_surface.descriptor,
   1120                    compositor_surface.is_opaque,
   1121                    device_clip_rect,
   1122                    resource_cache,
   1123                    gpu_buffer,
   1124                    deferred_resolves,
   1125                    compositor_clip_index,
   1126                );
   1127            }
   1128        }
   1129    }
   1130 
   1131    /// Compare this state vs. a previous frame state, and invalidate dirty rects if
   1132    /// the surface count has changed
   1133    pub fn update_dirty_rect_validity(
   1134        &mut self,
   1135        old_descriptor: &CompositeDescriptor,
   1136    ) {
   1137        // TODO(gw): Make this more robust in other cases - there are other situations where
   1138        //           the surface count may be the same but we still need to invalidate the
   1139        //           dirty rects (e.g. if the surface ordering changed, or the external
   1140        //           surface itself is animated?)
   1141 
   1142        if old_descriptor.surfaces.len() != self.descriptor.surfaces.len() {
   1143            self.dirty_rects_are_valid = false;
   1144            return;
   1145        }
   1146 
   1147        // The entire area of external surfaces are treated as dirty, however,
   1148        // if a surface has moved or shrunk that is no longer valid, as we
   1149        // additionally need to ensure the area the surface used to occupy is
   1150        // composited.
   1151        if !self
   1152            .descriptor
   1153            .external_surfaces_rect
   1154            .contains_box(&old_descriptor.external_surfaces_rect)
   1155        {
   1156            self.dirty_rects_are_valid = false;
   1157            return;
   1158        }
   1159    }
   1160 
   1161    fn compute_external_surface_dependencies(
   1162        &mut self,
   1163        external_surface: &ExternalSurfaceDescriptor,
   1164        image_dependencies: &[ImageDependency; 3],
   1165        required_plane_count: usize,
   1166        resource_cache: &ResourceCache,
   1167        gpu_buffer: &mut GpuBufferBuilderF,
   1168        deferred_resolves: &mut FrameVec<DeferredResolve>,
   1169    ) -> ResolvedExternalSurfaceIndex {
   1170        let mut planes = [
   1171            ExternalPlaneDescriptor::invalid(),
   1172            ExternalPlaneDescriptor::invalid(),
   1173            ExternalPlaneDescriptor::invalid(),
   1174        ];
   1175 
   1176        let mut valid_plane_count = 0;
   1177        for i in 0 .. required_plane_count {
   1178            let request = ImageRequest {
   1179                key: image_dependencies[i].key,
   1180                rendering: external_surface.image_rendering,
   1181                tile: None,
   1182            };
   1183 
   1184            let cache_item = resolve_image(
   1185                request,
   1186                resource_cache,
   1187                gpu_buffer,
   1188                deferred_resolves,
   1189                true,
   1190            );
   1191 
   1192            if cache_item.texture_id != TextureSource::Invalid {
   1193                valid_plane_count += 1;
   1194                let plane = &mut planes[i];
   1195                *plane = ExternalPlaneDescriptor {
   1196                    texture: cache_item.texture_id,
   1197                    uv_rect: cache_item.uv_rect.into(),
   1198                };
   1199            }
   1200        }
   1201 
   1202        // Check if there are valid images added for each YUV plane
   1203        if valid_plane_count < required_plane_count {
   1204            warn!("Warnings: skip a YUV/RGB compositor surface, found {}/{} valid images",
   1205                valid_plane_count,
   1206                required_plane_count,
   1207            );
   1208            return ResolvedExternalSurfaceIndex::INVALID;
   1209        }
   1210 
   1211        let external_surface_index = ResolvedExternalSurfaceIndex(self.external_surfaces.len());
   1212 
   1213        // If the external surface descriptor reports that the native surface
   1214        // needs to be updated, create an update params tuple for the renderer
   1215        // to use.
   1216        let update_params = external_surface.update_params.map(|surface_size| {
   1217            (
   1218                external_surface.native_surface_id.expect("bug: no native surface!"),
   1219                surface_size
   1220            )
   1221        });
   1222 
   1223        match external_surface.dependency {
   1224            ExternalSurfaceDependency::Yuv{ color_space, format, channel_bit_depth, .. } => {
   1225 
   1226                let image_buffer_kind = planes[0].texture.image_buffer_kind();
   1227 
   1228                self.external_surfaces.push(ResolvedExternalSurface {
   1229                    color_data: ResolvedExternalSurfaceColorData::Yuv {
   1230                        image_dependencies: *image_dependencies,
   1231                        planes,
   1232                        color_space,
   1233                        format,
   1234                        channel_bit_depth,
   1235                        },
   1236                    image_buffer_kind,
   1237                    update_params,
   1238                    external_image_id: external_surface.external_image_id,
   1239                });
   1240            },
   1241            ExternalSurfaceDependency::Rgb { .. } => {
   1242                let image_buffer_kind = planes[0].texture.image_buffer_kind();
   1243 
   1244                self.external_surfaces.push(ResolvedExternalSurface {
   1245                    color_data: ResolvedExternalSurfaceColorData::Rgb {
   1246                        image_dependency: image_dependencies[0],
   1247                        plane: planes[0],
   1248                    },
   1249                    image_buffer_kind,
   1250                    update_params,
   1251                    external_image_id: external_surface.external_image_id,
   1252                });
   1253            },
   1254        }
   1255        external_surface_index
   1256    }
   1257 
   1258    pub fn end_frame(&mut self) {
   1259        // Sort tiles from front to back.
   1260        self.tiles.sort_by_key(|tile| tile.z_id.0);
   1261    }
   1262 
   1263    #[cfg(feature = "debugger")]
   1264    pub fn print_to_string(&self) -> String {
   1265        use crate::print_tree::PrintTree;
   1266        use crate::print_tree::PrintTreePrinter;
   1267 
   1268        let mut buf = Vec::<u8>::new();
   1269        {
   1270            let mut pt = PrintTree::new_with_sink("composite config", &mut buf);
   1271 
   1272            pt.new_level("tiles".into());
   1273            for (i, tile) in self.tiles.iter().enumerate() {
   1274                pt.new_level(format!("tile {}", i));
   1275                pt.add_item(format!("local_rect = {:?}", tile.local_rect.to_rect()));
   1276                pt.add_item(format!("local_valid_rect = {:?}", tile.local_valid_rect.to_rect()));
   1277                pt.add_item(format!("local_dirty_rect = {:?}", tile.local_dirty_rect.to_rect()));
   1278                pt.add_item(format!("device_clip_rect = {:?}", tile.device_clip_rect.to_rect()));
   1279                pt.add_item(format!("z_id = {:?}", tile.z_id));
   1280                pt.add_item(format!("kind = {:?}", tile.kind));
   1281                pt.add_item(format!("tile_id = {:?}", tile.tile_id));
   1282                pt.add_item(format!("clip = {:?}", tile.clip_index));
   1283                pt.add_item(format!("transform = {:?}", tile.transform_index));
   1284                pt.end_level();
   1285            }
   1286            pt.end_level();
   1287 
   1288            pt.new_level("external_surfaces".into());
   1289            for (i, surface) in self.external_surfaces.iter().enumerate() {
   1290                pt.new_level(format!("surface {}", i));
   1291                pt.add_item(format!("{:?}", surface.image_buffer_kind));
   1292                pt.end_level();
   1293            }
   1294            pt.end_level();
   1295 
   1296            pt.new_level("occluders".into());
   1297            for (i, occluder) in self.occluders.occluders.iter().enumerate() {
   1298                pt.new_level(format!("occluder {}", i));
   1299                pt.add_item(format!("{:?}", occluder.z_id));
   1300                pt.add_item(format!("{:?}", occluder.world_rect.to_rect()));
   1301                pt.end_level();
   1302            }
   1303            pt.end_level();
   1304 
   1305            pt.new_level("transforms".into());
   1306            for (i, transform) in self.transforms.iter().enumerate() {
   1307                pt.new_level(format!("transform {}", i));
   1308                pt.add_item(format!("local_to_raster {:?}", transform.local_to_raster));
   1309                pt.add_item(format!("raster_to_device {:?}", transform.raster_to_device));
   1310                pt.add_item(format!("local_to_device {:?}", transform.local_to_device));
   1311                pt.end_level();
   1312            }
   1313            pt.end_level();
   1314 
   1315            pt.new_level("clips".into());
   1316            for (i, clip) in self.clips.iter().enumerate() {
   1317                pt.new_level(format!("clip {}", i));
   1318                pt.add_item(format!("{:?}", clip.rect.to_rect()));
   1319                pt.add_item(format!("{:?}", clip.radius));
   1320                pt.end_level();
   1321            }
   1322            pt.end_level();
   1323        }
   1324 
   1325        std::str::from_utf8(&buf).unwrap_or("(Tree printer emitted non-utf8)").to_string()
   1326    }
   1327 }
   1328 
   1329 /// An arbitrary identifier for a native (OS compositor) surface
   1330 #[repr(C)]
   1331 #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
   1332 #[cfg_attr(feature = "capture", derive(Serialize))]
   1333 #[cfg_attr(feature = "replay", derive(Deserialize))]
   1334 pub struct NativeSurfaceId(pub u64);
   1335 
   1336 impl NativeSurfaceId {
   1337    /// A special id for the native surface that is used for debug / profiler overlays.
   1338    pub const DEBUG_OVERLAY: NativeSurfaceId = NativeSurfaceId(u64::MAX);
   1339 }
   1340 
   1341 #[repr(C)]
   1342 #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
   1343 #[cfg_attr(feature = "capture", derive(Serialize))]
   1344 #[cfg_attr(feature = "replay", derive(Deserialize))]
   1345 pub struct NativeTileId {
   1346    pub surface_id: NativeSurfaceId,
   1347    pub x: i32,
   1348    pub y: i32,
   1349 }
   1350 
   1351 impl NativeTileId {
   1352    /// A special id for the native surface that is used for debug / profiler overlays.
   1353    pub const DEBUG_OVERLAY: NativeTileId = NativeTileId {
   1354        surface_id: NativeSurfaceId::DEBUG_OVERLAY,
   1355        x: 0,
   1356        y: 0,
   1357    };
   1358 }
   1359 
   1360 /// Information about a bound surface that the native compositor
   1361 /// returns to WR.
   1362 #[repr(C)]
   1363 #[derive(Copy, Clone)]
   1364 pub struct NativeSurfaceInfo {
   1365    /// An offset into the surface that WR should draw. Some compositing
   1366    /// implementations (notably, DirectComposition) use texture atlases
   1367    /// when the surface sizes are small. In this case, an offset can
   1368    /// be returned into the larger texture where WR should draw. This
   1369    /// can be (0, 0) if texture atlases are not used.
   1370    pub origin: DeviceIntPoint,
   1371    /// The ID of the FBO that WR should bind to, in order to draw to
   1372    /// the bound surface. On Windows (ANGLE) this will always be 0,
   1373    /// since creating a p-buffer sets the default framebuffer to
   1374    /// be the DirectComposition surface. On Mac, this will be non-zero,
   1375    /// since it identifies the IOSurface that has been bound to draw to.
   1376    // TODO(gw): This may need to be a larger / different type for WR
   1377    //           backends that are not GL.
   1378    pub fbo_id: u32,
   1379 }
   1380 
   1381 #[repr(C)]
   1382 #[derive(Debug, Copy, Clone)]
   1383 pub struct WindowProperties {
   1384    pub is_opaque: bool,
   1385    pub enable_screenshot: bool,
   1386 }
   1387 
   1388 impl Default for WindowProperties {
   1389    fn default() -> Self {
   1390        WindowProperties {
   1391            is_opaque: true,
   1392            enable_screenshot: true,
   1393        }
   1394    }
   1395 }
   1396 
   1397 #[repr(C)]
   1398 #[derive(Debug, Copy, Clone, PartialEq)]
   1399 #[cfg_attr(feature = "capture", derive(Serialize))]
   1400 #[cfg_attr(feature = "replay", derive(Deserialize))]
   1401 pub struct CompositorCapabilities {
   1402    /// The virtual surface size used by the underlying platform.
   1403    pub virtual_surface_size: i32,
   1404    /// Whether the compositor requires redrawing on invalidation.
   1405    pub redraw_on_invalidation: bool,
   1406    /// The maximum number of dirty rects that can be provided per compositor
   1407    /// surface update. If this is zero, the entire compositor surface for
   1408    /// a given tile will be drawn if it's dirty.
   1409    pub max_update_rects: usize,
   1410    /// Whether or not this compositor will create surfaces for backdrops.
   1411    pub supports_surface_for_backdrop: bool,
   1412    /// Whether external compositor surface supports negative scaling.
   1413    pub supports_external_compositor_surface_negative_scaling: bool,
   1414 }
   1415 
   1416 impl Default for CompositorCapabilities {
   1417    fn default() -> Self {
   1418        // The default set of compositor capabilities for a given platform.
   1419        // These should only be modified if a compositor diverges specifically
   1420        // from the default behavior so that compositors don't have to track
   1421        // which changes to this structure unless necessary.
   1422        CompositorCapabilities {
   1423            virtual_surface_size: 0,
   1424            redraw_on_invalidation: false,
   1425            // Assume compositors can do at least partial update of surfaces. If not,
   1426            // the native compositor should override this to be 0.
   1427            max_update_rects: 1,
   1428            supports_surface_for_backdrop: false,
   1429            supports_external_compositor_surface_negative_scaling: true,
   1430        }
   1431    }
   1432 }
   1433 
   1434 #[repr(C)]
   1435 #[derive(Copy, Clone, Debug)]
   1436 pub struct WindowVisibility {
   1437    pub is_fully_occluded: bool,
   1438 }
   1439 
   1440 impl Default for WindowVisibility {
   1441    fn default() -> Self {
   1442        WindowVisibility {
   1443            is_fully_occluded: false,
   1444        }
   1445    }
   1446 }
   1447 
   1448 /// The transform type to apply to Compositor surfaces.
   1449 // TODO: Should transform from CompositorSurfacePixel instead, but this requires a cleanup of the
   1450 // Compositor API to use CompositorSurface-space geometry instead of Device-space where necessary
   1451 // to avoid a bunch of noisy cast_unit calls and make it actually type-safe. May be difficult due
   1452 // to pervasive use of Device-space nomenclature inside WR.
   1453 // pub struct CompositorSurfacePixel;
   1454 pub type CompositorSurfaceTransform = ScaleOffset;
   1455 
   1456 #[repr(C)]
   1457 #[cfg_attr(feature = "capture", derive(Serialize))]
   1458 #[cfg_attr(feature = "replay", derive(Deserialize))]
   1459 #[derive(PartialEq, Copy, Clone, Debug)]
   1460 pub struct ClipRadius {
   1461    pub top_left: i32,
   1462    pub top_right: i32,
   1463    pub bottom_left: i32,
   1464    pub bottom_right: i32,
   1465 }
   1466 
   1467 impl ClipRadius {
   1468    pub const EMPTY: ClipRadius = ClipRadius { top_left: 0, top_right: 0, bottom_left: 0, bottom_right: 0 };
   1469 }
   1470 
   1471 /// Defines an interface to a native (OS level) compositor. If supplied
   1472 /// by the client application, then picture cache slices will be
   1473 /// composited by the OS compositor, rather than drawn via WR batches.
   1474 pub trait Compositor {
   1475    /// Create a new OS compositor surface with the given properties.
   1476    fn create_surface(
   1477        &mut self,
   1478        device: &mut Device,
   1479        id: NativeSurfaceId,
   1480        virtual_offset: DeviceIntPoint,
   1481        tile_size: DeviceIntSize,
   1482        is_opaque: bool,
   1483    );
   1484 
   1485    /// Create a new OS compositor surface that can be used with an
   1486    /// existing ExternalImageId, instead of being drawn to by WebRender.
   1487    /// Surfaces created by this can only be used with attach_external_image,
   1488    /// and not create_tile/destroy_tile/bind/unbind.
   1489    fn create_external_surface(
   1490        &mut self,
   1491        device: &mut Device,
   1492        id: NativeSurfaceId,
   1493        is_opaque: bool,
   1494    );
   1495 
   1496    /// Create a new OS backdrop surface that will display a color.
   1497    fn create_backdrop_surface(
   1498        &mut self,
   1499        device: &mut Device,
   1500        id: NativeSurfaceId,
   1501        color: ColorF,
   1502    );
   1503 
   1504    /// Destroy the surface with the specified id. WR may call this
   1505    /// at any time the surface is no longer required (including during
   1506    /// renderer deinit). It's the responsibility of the embedder
   1507    /// to ensure that the surface is only freed once the GPU is
   1508    /// no longer using the surface (if this isn't already handled
   1509    /// by the operating system).
   1510    fn destroy_surface(
   1511        &mut self,
   1512        device: &mut Device,
   1513        id: NativeSurfaceId,
   1514    );
   1515 
   1516    /// Create a new OS compositor tile with the given properties.
   1517    fn create_tile(
   1518        &mut self,
   1519        device: &mut Device,
   1520        id: NativeTileId,
   1521    );
   1522 
   1523    /// Destroy an existing compositor tile.
   1524    fn destroy_tile(
   1525        &mut self,
   1526        device: &mut Device,
   1527        id: NativeTileId,
   1528    );
   1529 
   1530    /// Attaches an ExternalImageId to an OS compositor surface created
   1531    /// by create_external_surface, and uses that as the contents of
   1532    /// the surface. It is expected that a single surface will have
   1533    /// many different images attached (like one for each video frame).
   1534    fn attach_external_image(
   1535        &mut self,
   1536        device: &mut Device,
   1537        id: NativeSurfaceId,
   1538        external_image: ExternalImageId
   1539    );
   1540 
   1541    /// Mark a tile as invalid before any surfaces are queued for
   1542    /// composition and before it is updated with bind. This is useful
   1543    /// for early composition, allowing for dependency tracking of which
   1544    /// surfaces can be composited early while others are still updating.
   1545    fn invalidate_tile(
   1546        &mut self,
   1547        _device: &mut Device,
   1548        _id: NativeTileId,
   1549        _valid_rect: DeviceIntRect
   1550    ) {}
   1551 
   1552    /// Bind this surface such that WR can issue OpenGL commands
   1553    /// that will target the surface. Returns an (x, y) offset
   1554    /// where WR should draw into the surface. This can be set
   1555    /// to (0, 0) if the OS doesn't use texture atlases. The dirty
   1556    /// rect is a local surface rect that specifies which part
   1557    /// of the surface needs to be updated. If max_update_rects
   1558    /// in CompositeConfig is 0, this will always be the size
   1559    /// of the entire surface. The returned offset is only
   1560    /// relevant to compositors that store surfaces in a texture
   1561    /// atlas (that is, WR expects that the dirty rect doesn't
   1562    /// affect the coordinates of the returned origin).
   1563    fn bind(
   1564        &mut self,
   1565        device: &mut Device,
   1566        id: NativeTileId,
   1567        dirty_rect: DeviceIntRect,
   1568        valid_rect: DeviceIntRect,
   1569    ) -> NativeSurfaceInfo;
   1570 
   1571    /// Unbind the surface. This is called by WR when it has
   1572    /// finished issuing OpenGL commands on the current surface.
   1573    fn unbind(
   1574        &mut self,
   1575        device: &mut Device,
   1576    );
   1577 
   1578    /// Begin the frame
   1579    fn begin_frame(&mut self, device: &mut Device);
   1580 
   1581    /// Add a surface to the visual tree to be composited. Visuals must
   1582    /// be added every frame, between the begin/end transaction call. The
   1583    /// z-order of the surfaces is determined by the order they are added
   1584    /// to the visual tree.
   1585    // TODO(gw): Adding visuals every frame makes the interface simple,
   1586    //           but may have performance implications on some compositors?
   1587    //           We might need to change the interface to maintain a visual
   1588    //           tree that can be mutated?
   1589    // TODO(gw): We might need to add a concept of a hierachy in future.
   1590    fn add_surface(
   1591        &mut self,
   1592        device: &mut Device,
   1593        id: NativeSurfaceId,
   1594        transform: CompositorSurfaceTransform,
   1595        clip_rect: DeviceIntRect,
   1596        image_rendering: ImageRendering,
   1597        rounded_clip_rect: DeviceIntRect,
   1598        rounded_clip_radii: ClipRadius,
   1599    );
   1600 
   1601    /// Notify the compositor that all tiles have been invalidated and all
   1602    /// native surfaces have been added, thus it is safe to start compositing
   1603    /// valid surfaces. The dirty rects array allows native compositors that
   1604    /// support partial present to skip copying unchanged areas.
   1605    /// Optionally provides a set of rectangles for the areas known to be
   1606    /// opaque, this is currently only computed if the caller is SwCompositor.
   1607    fn start_compositing(
   1608        &mut self,
   1609        _device: &mut Device,
   1610        _clear_color: ColorF,
   1611        _dirty_rects: &[DeviceIntRect],
   1612        _opaque_rects: &[DeviceIntRect],
   1613    ) {}
   1614 
   1615    /// Commit any changes in the compositor tree for this frame. WR calls
   1616    /// this once when all surface and visual updates are complete, to signal
   1617    /// that the OS composite transaction should be applied.
   1618    fn end_frame(&mut self, device: &mut Device);
   1619 
   1620    /// Enable/disable native compositor usage
   1621    fn enable_native_compositor(&mut self, device: &mut Device, enable: bool);
   1622 
   1623    /// Safely deinitialize any remaining resources owned by the compositor.
   1624    fn deinit(&mut self, device: &mut Device);
   1625 
   1626    /// Get the capabilities struct for this compositor. This is used to
   1627    /// specify what features a compositor supports, depending on the
   1628    /// underlying platform
   1629    fn get_capabilities(&self, device: &mut Device) -> CompositorCapabilities;
   1630 
   1631    fn get_window_visibility(&self, device: &mut Device) -> WindowVisibility;
   1632 }
   1633 
   1634 // Describes the configuration for an input layer that the compositor
   1635 // implemention should prepare
   1636 #[derive(Debug)]
   1637 pub struct CompositorInputLayer {
   1638    // Device space location of the layer (pre-clip)
   1639    pub offset: DeviceIntPoint,
   1640    // Device space clip-rect of the layer
   1641    pub clip_rect: DeviceIntRect,
   1642    // Whether a content or external surface
   1643    pub usage: CompositorSurfaceUsage,
   1644    // If true, layer is opaque, blend can be disabled
   1645    pub is_opaque: bool,
   1646    pub rounded_clip_rect: DeviceIntRect,
   1647    pub rounded_clip_radii: ClipRadius,
   1648 }
   1649 
   1650 // Provides the parameters about the frame to the compositor implementation.
   1651 // TODO(gw): Include information about picture cache slices and external surfaces.
   1652 #[derive(Debug)]
   1653 pub struct CompositorInputConfig<'a> {
   1654    pub enable_screenshot: bool,
   1655    pub layers: &'a [CompositorInputLayer],
   1656 }
   1657 
   1658 // Trait for implementors of swapchain based compositing.
   1659 // TODO(gw): Extend to handle external surfaces, layers, swgl, etc.
   1660 pub trait LayerCompositor {
   1661    // Prepare to composite a frame. Ensure that layers are constructed
   1662    // to match the input config
   1663    fn begin_frame(
   1664        &mut self,
   1665        input: &CompositorInputConfig,
   1666    ) -> bool;
   1667 
   1668    // Bind a layer (by index in the input config) to begin rendering
   1669    // content to it.
   1670    fn bind_layer(
   1671        &mut self,
   1672        index: usize,
   1673        dirty_rects: &[DeviceIntRect],
   1674    );
   1675 
   1676    // Complete rendering of a layer and present / swap buffers
   1677    fn present_layer(
   1678        &mut self,
   1679        index: usize,
   1680        dirty_rects: &[DeviceIntRect],
   1681    );
   1682 
   1683    fn add_surface(
   1684        &mut self,
   1685        index: usize,
   1686        transform: CompositorSurfaceTransform,
   1687        clip_rect: DeviceIntRect,
   1688        image_rendering: ImageRendering,
   1689        rounded_clip_rect: DeviceIntRect,
   1690        rounded_clip_radii: ClipRadius,
   1691    );
   1692 
   1693    // Finish compositing this frame - commit the visual tree to the OS
   1694    fn end_frame(&mut self);
   1695 
   1696    // Get current information about the window, such as opacity
   1697    fn get_window_properties(&self) -> WindowProperties;
   1698 }
   1699 
   1700 /// Information about the underlying data buffer of a mapped tile.
   1701 #[repr(C)]
   1702 #[derive(Copy, Clone)]
   1703 pub struct MappedTileInfo {
   1704    pub data: *mut c_void,
   1705    pub stride: i32,
   1706 }
   1707 
   1708 /// Descriptor for a locked surface that will be directly composited by SWGL.
   1709 #[repr(C)]
   1710 pub struct SWGLCompositeSurfaceInfo {
   1711    /// The number of YUV planes in the surface. 0 indicates non-YUV BGRA.
   1712    /// 1 is interleaved YUV. 2 is NV12. 3 is planar YUV.
   1713    pub yuv_planes: u32,
   1714    /// Textures for planes of the surface, or 0 if not applicable.
   1715    pub textures: [u32; 3],
   1716    /// Color space of surface if using a YUV format.
   1717    pub color_space: YuvRangedColorSpace,
   1718    /// Color depth of surface if using a YUV format.
   1719    pub color_depth: ColorDepth,
   1720    /// The actual source surface size before transformation.
   1721    pub size: DeviceIntSize,
   1722 }
   1723 
   1724 /// A Compositor variant that supports mapping tiles into CPU memory.
   1725 pub trait MappableCompositor: Compositor {
   1726    /// Map a tile's underlying buffer so it can be used as the backing for
   1727    /// a SWGL framebuffer. This is intended to be a replacement for 'bind'
   1728    /// in any compositors that intend to directly interoperate with SWGL
   1729    /// while supporting some form of native layers.
   1730    fn map_tile(
   1731        &mut self,
   1732        device: &mut Device,
   1733        id: NativeTileId,
   1734        dirty_rect: DeviceIntRect,
   1735        valid_rect: DeviceIntRect,
   1736    ) -> Option<MappedTileInfo>;
   1737 
   1738    /// Unmap a tile that was was previously mapped via map_tile to signal
   1739    /// that SWGL is done rendering to the buffer.
   1740    fn unmap_tile(&mut self, device: &mut Device);
   1741 
   1742    fn lock_composite_surface(
   1743        &mut self,
   1744        device: &mut Device,
   1745        ctx: *mut c_void,
   1746        external_image_id: ExternalImageId,
   1747        composite_info: *mut SWGLCompositeSurfaceInfo,
   1748    ) -> bool;
   1749    fn unlock_composite_surface(&mut self, device: &mut Device, ctx: *mut c_void, external_image_id: ExternalImageId);
   1750 }
   1751 
   1752 /// Defines an interface to a non-native (application-level) Compositor which handles
   1753 /// partial present. This is required if webrender must query the backbuffer's age.
   1754 /// TODO: Use the Compositor trait for native and non-native compositors, and integrate
   1755 /// this functionality there.
   1756 pub trait PartialPresentCompositor {
   1757    /// Allows webrender to specify the total region that will be rendered to this frame,
   1758    /// ie the frame's dirty region and some previous frames' dirty regions, if applicable
   1759    /// (calculated using the buffer age). Must be called before anything has been rendered
   1760    /// to the main framebuffer.
   1761    fn set_buffer_damage_region(&mut self, rects: &[DeviceIntRect]);
   1762 }
   1763 
   1764 /// Information about an opaque surface used to occlude tiles.
   1765 #[cfg_attr(feature = "capture", derive(Serialize))]
   1766 #[cfg_attr(feature = "replay", derive(Deserialize))]
   1767 struct Occluder {
   1768    z_id: ZBufferId,
   1769    world_rect: WorldIntRect,
   1770 }
   1771 
   1772 // Whether this event is the start or end of a rectangle
   1773 #[derive(Debug)]
   1774 enum OcclusionEventKind {
   1775    Begin,
   1776    End,
   1777 }
   1778 
   1779 // A list of events on the y-axis, with the rectangle range that it affects on the x-axis
   1780 #[derive(Debug)]
   1781 struct OcclusionEvent {
   1782    y: i32,
   1783    x_range: ops::Range<i32>,
   1784    kind: OcclusionEventKind,
   1785 }
   1786 
   1787 impl OcclusionEvent {
   1788    fn new(y: i32, kind: OcclusionEventKind, x0: i32, x1: i32) -> Self {
   1789        OcclusionEvent {
   1790            y,
   1791            x_range: ops::Range {
   1792                start: x0,
   1793                end: x1,
   1794            },
   1795            kind,
   1796        }
   1797    }
   1798 }
   1799 
   1800 /// This struct exists to provide a Default impl and allow #[serde(skip)]
   1801 /// on the two frame vectors. Unfortunately FrameVec does not have a Default
   1802 /// implementation (vectors only implement it with the global allocator).
   1803 pub struct OccludersScratchBuffers {
   1804    events: FrameVec<OcclusionEvent>,
   1805    active: FrameVec<ops::Range<i32>>,
   1806 }
   1807 
   1808 impl Default for OccludersScratchBuffers {
   1809    fn default() -> Self {
   1810        OccludersScratchBuffers {
   1811            events: FrameVec::new_in(FrameAllocator::fallback()),
   1812            active: FrameVec::new_in(FrameAllocator::fallback()),
   1813        }
   1814    }
   1815 }
   1816 
   1817 /// List of registered occluders.
   1818 ///
   1819 /// Also store a couple of vectors for reuse.
   1820 #[cfg_attr(feature = "capture", derive(Serialize))]
   1821 #[cfg_attr(feature = "replay", derive(Deserialize))]
   1822 pub struct Occluders {
   1823    occluders: FrameVec<Occluder>,
   1824 
   1825    // The two vectors in scratch are kept to avoid unnecessary reallocations in area().
   1826    #[cfg_attr(any(feature = "capture", feature = "replay"), serde(skip))]
   1827    scratch: OccludersScratchBuffers,
   1828 }
   1829 
   1830 impl Occluders {
   1831    fn new(memory: &FrameMemory) -> Self {
   1832        Occluders {
   1833            occluders: memory.new_vec(),
   1834            scratch: OccludersScratchBuffers {
   1835                events: memory.new_vec(),
   1836                active: memory.new_vec(),
   1837            }
   1838        }
   1839    }
   1840 
   1841    fn push(&mut self, world_rect: WorldIntRect, z_id: ZBufferId) {
   1842        self.occluders.push(Occluder { world_rect, z_id });
   1843    }
   1844 
   1845    /// Returns true if a tile with the specified rectangle and z_id
   1846    /// is occluded by an opaque surface in front of it.
   1847    pub fn is_tile_occluded(
   1848        &mut self,
   1849        z_id: ZBufferId,
   1850        world_rect: WorldRect,
   1851    ) -> bool {
   1852        // It's often the case that a tile is only occluded by considering multiple
   1853        // picture caches in front of it (for example, the background tiles are
   1854        // often occluded by a combination of the content slice + the scrollbar slices).
   1855 
   1856        // The basic algorithm is:
   1857        //    For every occluder:
   1858        //      If this occluder is in front of the tile we are querying:
   1859        //         Clip the occluder rectangle to the query rectangle.
   1860        //    Calculate the total non-overlapping area of those clipped occluders.
   1861        //    If the cumulative area of those occluders is the same as the area of the query tile,
   1862        //       Then the entire tile must be occluded and can be skipped during rasterization and compositing.
   1863 
   1864        // Get the reference area we will compare against.
   1865        let world_rect = world_rect.round().to_i32();
   1866        let ref_area = world_rect.area();
   1867 
   1868        // Calculate the non-overlapping area of the valid occluders.
   1869        let cover_area = self.area(z_id, &world_rect);
   1870        debug_assert!(cover_area <= ref_area);
   1871 
   1872        // Check if the tile area is completely covered
   1873        ref_area == cover_area
   1874    }
   1875 
   1876    /// Return the total area covered by a set of occluders, accounting for
   1877    /// overlapping areas between those rectangles.
   1878    fn area(
   1879        &mut self,
   1880        z_id: ZBufferId,
   1881        clip_rect: &WorldIntRect,
   1882    ) -> i32 {
   1883        // This implementation is based on the article https://leetcode.com/articles/rectangle-area-ii/.
   1884        // This is not a particularly efficient implementation (it skips building segment trees), however
   1885        // we typically use this where the length of the rectangles array is < 10, so simplicity is more important.
   1886 
   1887        self.scratch.events.clear();
   1888        self.scratch.active.clear();
   1889 
   1890        let mut area = 0;
   1891 
   1892        // Step through each rectangle and build the y-axis event list
   1893        for occluder in &self.occluders {
   1894            // Only consider occluders in front of this rect
   1895            if occluder.z_id.0 < z_id.0 {
   1896                // Clip the source rect to the rectangle we care about, since we only
   1897                // want to record area for the tile we are comparing to.
   1898                if let Some(rect) = occluder.world_rect.intersection(clip_rect) {
   1899                    let x0 = rect.min.x;
   1900                    let x1 = x0 + rect.width();
   1901                    self.scratch.events.push(OcclusionEvent::new(rect.min.y, OcclusionEventKind::Begin, x0, x1));
   1902                    self.scratch.events.push(OcclusionEvent::new(rect.min.y + rect.height(), OcclusionEventKind::End, x0, x1));
   1903                }
   1904            }
   1905        }
   1906 
   1907        // If we didn't end up with any valid events, the area must be 0
   1908        if self.scratch.events.is_empty() {
   1909            return 0;
   1910        }
   1911 
   1912        // Sort the events by y-value
   1913        self.scratch.events.sort_by_key(|e| e.y);
   1914        let mut cur_y = self.scratch.events[0].y;
   1915 
   1916        // Step through each y interval
   1917        for event in &self.scratch.events {
   1918            // This is the dimension of the y-axis we are accumulating areas for
   1919            let dy = event.y - cur_y;
   1920 
   1921            // If we have active events covering x-ranges in this y-interval, process them
   1922            if dy != 0 && !self.scratch.active.is_empty() {
   1923                assert!(dy > 0);
   1924 
   1925                // Step through the x-ranges, ordered by x0 of each event
   1926                self.scratch.active.sort_by_key(|i| i.start);
   1927                let mut query = 0;
   1928                let mut cur = self.scratch.active[0].start;
   1929 
   1930                // Accumulate the non-overlapping x-interval that contributes to area for this y-interval.
   1931                for interval in &self.scratch.active {
   1932                    cur = interval.start.max(cur);
   1933                    query += (interval.end - cur).max(0);
   1934                    cur = cur.max(interval.end);
   1935                }
   1936 
   1937                // Accumulate total area for this y-interval
   1938                area += query * dy;
   1939            }
   1940 
   1941            // Update the active events list
   1942            match event.kind {
   1943                OcclusionEventKind::Begin => {
   1944                    self.scratch.active.push(event.x_range.clone());
   1945                }
   1946                OcclusionEventKind::End => {
   1947                    let index = self.scratch.active.iter().position(|i| *i == event.x_range).unwrap();
   1948                    self.scratch.active.remove(index);
   1949                }
   1950            }
   1951 
   1952            cur_y = event.y;
   1953        }
   1954 
   1955        area
   1956    }
   1957 }