use api::{ColorF, YuvRangedColorSpace, YuvFormat, ImageRendering, ExternalImageId, ImageBufferKind};
use api::units::*;
use api::ColorDepth;
use crate::image_source::resolve_image;
use euclid::{Box2D, Transform3D};
use crate::gpu_cache::GpuCache;
use crate::gpu_types::{ZBufferId, ZBufferIdGenerator};
use crate::internal_types::TextureSource;
use crate::picture::{ImageDependency, ResolvedSurfaceTexture, TileCacheInstance, TileId, TileSurface};
use crate::prim_store::DeferredResolve;
use crate::resource_cache::{ImageRequest, ResourceCache};
use crate::util::{Preallocator, ScaleOffset};
use crate::tile_cache::PictureCacheDebugInfo;
use std::{ops, u64, os::raw::c_void};
#[derive(Debug, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum NativeSurfaceOperationDetails {
CreateSurface {
id: NativeSurfaceId,
virtual_offset: DeviceIntPoint,
tile_size: DeviceIntSize,
is_opaque: bool,
},
CreateExternalSurface {
id: NativeSurfaceId,
is_opaque: bool,
},
DestroySurface {
id: NativeSurfaceId,
},
CreateTile {
id: NativeTileId,
},
DestroyTile {
id: NativeTileId,
},
AttachExternalImage {
id: NativeSurfaceId,
external_image: ExternalImageId,
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct NativeSurfaceOperation {
pub details: NativeSurfaceOperationDetails,
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Clone)]
pub enum CompositeTileSurface {
Texture {
surface: ResolvedSurfaceTexture,
},
Color {
color: ColorF,
},
Clear,
ExternalSurface {
external_surface_index: ResolvedExternalSurfaceIndex,
},
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum CompositeSurfaceFormat {
Rgba,
Yuv,
}
bitflags! {
pub struct CompositeFeatures: u8 {
const NO_UV_CLAMP = 1 << 0;
const NO_COLOR_MODULATION = 1 << 1;
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum TileKind {
Opaque,
Alpha,
Clear,
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Debug, Copy, Clone)]
pub struct CompositorTransformIndex(usize);
impl CompositorTransformIndex {
pub const INVALID: CompositorTransformIndex = CompositorTransformIndex(!0);
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Clone)]
pub struct CompositeTile {
pub surface: CompositeTileSurface,
pub local_rect: PictureRect,
pub local_valid_rect: PictureRect,
pub local_dirty_rect: PictureRect,
pub device_clip_rect: DeviceRect,
pub z_id: ZBufferId,
pub kind: TileKind,
pub transform_index: CompositorTransformIndex,
}
pub fn tile_kind(surface: &CompositeTileSurface, is_opaque: bool) -> TileKind {
match surface {
CompositeTileSurface::Color { .. } => TileKind::Opaque,
CompositeTileSurface::Clear => TileKind::Clear,
CompositeTileSurface::Texture { .. }
| CompositeTileSurface::ExternalSurface { .. } => {
if is_opaque {
TileKind::Opaque
} else {
TileKind::Alpha
}
}
}
}
pub enum ExternalSurfaceDependency {
Yuv {
image_dependencies: [ImageDependency; 3],
color_space: YuvRangedColorSpace,
format: YuvFormat,
channel_bit_depth: u32,
},
Rgb {
image_dependency: ImageDependency,
},
}
pub struct ExternalSurfaceDescriptor {
pub local_surface_size: LayoutSize,
pub local_rect: PictureRect,
pub local_clip_rect: PictureRect,
pub clip_rect: DeviceRect,
pub transform_index: CompositorTransformIndex,
pub image_rendering: ImageRendering,
pub z_id: ZBufferId,
pub dependency: ExternalSurfaceDependency,
pub native_surface_id: Option<NativeSurfaceId>,
pub update_params: Option<DeviceIntSize>,
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Debug, Copy, Clone)]
pub struct ExternalPlaneDescriptor {
pub texture: TextureSource,
pub uv_rect: TexelRect,
}
impl ExternalPlaneDescriptor {
fn invalid() -> Self {
ExternalPlaneDescriptor {
texture: TextureSource::Invalid,
uv_rect: TexelRect::invalid(),
}
}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct ResolvedExternalSurfaceIndex(pub usize);
impl ResolvedExternalSurfaceIndex {
pub const INVALID: ResolvedExternalSurfaceIndex = ResolvedExternalSurfaceIndex(usize::MAX);
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum ResolvedExternalSurfaceColorData {
Yuv {
image_dependencies: [ImageDependency; 3],
planes: [ExternalPlaneDescriptor; 3],
color_space: YuvRangedColorSpace,
format: YuvFormat,
channel_bit_depth: u32,
},
Rgb {
image_dependency: ImageDependency,
plane: ExternalPlaneDescriptor,
},
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct ResolvedExternalSurface {
pub color_data: ResolvedExternalSurfaceColorData,
pub image_buffer_kind: ImageBufferKind,
pub update_params: Option<(NativeSurfaceId, DeviceIntSize)>,
}
pub enum CompositorConfig {
Draw {
max_partial_present_rects: usize,
draw_previous_partial_present_regions: bool,
partial_present: Option<Box<dyn PartialPresentCompositor>>,
},
Native {
compositor: Box<dyn Compositor>,
}
}
impl CompositorConfig {
pub fn compositor(&mut self) -> Option<&mut Box<dyn Compositor>> {
match self {
CompositorConfig::Native { ref mut compositor, .. } => {
Some(compositor)
}
CompositorConfig::Draw { .. } => {
None
}
}
}
pub fn partial_present(&mut self) -> Option<&mut Box<dyn PartialPresentCompositor>> {
match self {
CompositorConfig::Native { .. } => {
None
}
CompositorConfig::Draw { ref mut partial_present, .. } => {
partial_present.as_mut()
}
}
}
}
impl Default for CompositorConfig {
fn default() -> Self {
CompositorConfig::Draw {
max_partial_present_rects: 0,
draw_previous_partial_present_regions: false,
partial_present: None,
}
}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum CompositorKind {
Draw {
max_partial_present_rects: usize,
draw_previous_partial_present_regions: bool,
},
Native {
capabilities: CompositorCapabilities,
},
}
impl Default for CompositorKind {
fn default() -> Self {
CompositorKind::Draw {
max_partial_present_rects: 0,
draw_previous_partial_present_regions: false,
}
}
}
impl CompositorKind {
pub fn get_virtual_surface_size(&self) -> i32 {
match self {
CompositorKind::Draw { .. } => 0,
CompositorKind::Native { capabilities, .. } => capabilities.virtual_surface_size,
}
}
pub fn should_redraw_on_invalidation(&self) -> bool {
match self {
CompositorKind::Draw { max_partial_present_rects, .. } => {
*max_partial_present_rects > 0
}
CompositorKind::Native { capabilities, .. } => capabilities.redraw_on_invalidation,
}
}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(PartialEq, Clone)]
pub enum TileSurfaceKind {
Texture,
Color {
color: ColorF,
},
Clear,
}
impl From<&TileSurface> for TileSurfaceKind {
fn from(surface: &TileSurface) -> Self {
match surface {
TileSurface::Texture { .. } => TileSurfaceKind::Texture,
TileSurface::Color { color } => TileSurfaceKind::Color { color: *color },
TileSurface::Clear => TileSurfaceKind::Clear,
}
}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(PartialEq, Clone)]
pub struct CompositeTileDescriptor {
pub tile_id: TileId,
pub surface_kind: TileSurfaceKind,
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(PartialEq, Clone)]
pub struct CompositeSurfaceDescriptor {
pub surface_id: Option<NativeSurfaceId>,
pub clip_rect: DeviceRect,
pub transform: CompositorSurfaceTransform,
pub image_dependencies: [ImageDependency; 3],
pub image_rendering: ImageRendering,
pub tile_descriptors: Vec<CompositeTileDescriptor>,
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(PartialEq, Clone)]
pub struct CompositeDescriptor {
pub surfaces: Vec<CompositeSurfaceDescriptor>,
}
impl CompositeDescriptor {
pub fn empty() -> Self {
CompositeDescriptor {
surfaces: Vec::new(),
}
}
}
pub struct CompositeStatePreallocator {
tiles: Preallocator,
external_surfaces: Preallocator,
occluders: Preallocator,
occluders_events: Preallocator,
occluders_active: Preallocator,
descriptor_surfaces: Preallocator,
}
impl CompositeStatePreallocator {
pub fn record(&mut self, state: &CompositeState) {
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);
self.occluders_active.record_vec(&state.occluders.active);
self.descriptor_surfaces.record_vec(&state.descriptor.surfaces);
}
pub fn preallocate(&self, state: &mut CompositeState) {
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);
self.occluders_active.preallocate_vec(&mut state.occluders.active);
self.descriptor_surfaces.preallocate_vec(&mut state.descriptor.surfaces);
}
}
impl Default for CompositeStatePreallocator {
fn default() -> Self {
CompositeStatePreallocator {
tiles: Preallocator::new(56),
external_surfaces: Preallocator::new(0),
occluders: Preallocator::new(16),
occluders_events: Preallocator::new(32),
occluders_active: Preallocator::new(16),
descriptor_surfaces: Preallocator::new(8),
}
}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct CompositorTransform {
local_to_surface: ScaleOffset,
surface_to_device: ScaleOffset,
local_to_device: ScaleOffset,
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct CompositeState {
pub tiles: Vec<CompositeTile>,
pub external_surfaces: Vec<ResolvedExternalSurface>,
pub z_generator: ZBufferIdGenerator,
pub dirty_rects_are_valid: bool,
pub compositor_kind: CompositorKind,
pub occluders: Occluders,
pub descriptor: CompositeDescriptor,
pub picture_cache_debug: PictureCacheDebugInfo,
pub transforms: Vec<CompositorTransform>,
low_quality_pinch_zoom: bool,
}
impl CompositeState {
pub fn new(
compositor_kind: CompositorKind,
max_depth_ids: i32,
dirty_rects_are_valid: bool,
low_quality_pinch_zoom: bool,
) -> Self {
CompositeState {
tiles: Vec::new(),
z_generator: ZBufferIdGenerator::new(max_depth_ids),
dirty_rects_are_valid,
compositor_kind,
occluders: Occluders::new(),
descriptor: CompositeDescriptor::empty(),
external_surfaces: Vec::new(),
picture_cache_debug: PictureCacheDebugInfo::new(),
transforms: Vec::new(),
low_quality_pinch_zoom,
}
}
pub fn register_transform(
&mut self,
local_to_surface: ScaleOffset,
surface_to_device: ScaleOffset,
) -> CompositorTransformIndex {
let index = CompositorTransformIndex(self.transforms.len());
let local_to_device = local_to_surface.accumulate(&surface_to_device);
self.transforms.push(CompositorTransform {
local_to_surface,
surface_to_device,
local_to_device,
});
index
}
pub fn get_device_rect(
&self,
local_rect: &PictureRect,
transform_index: CompositorTransformIndex,
) -> DeviceRect {
let transform = &self.transforms[transform_index.0];
transform.local_to_device.map_rect(&local_rect).round()
}
pub fn get_surface_rect<T>(
&self,
local_sub_rect: &Box2D<f32, T>,
local_bounds: &Box2D<f32, T>,
transform_index: CompositorTransformIndex,
) -> DeviceRect {
let transform = &self.transforms[transform_index.0];
let surface_bounds = transform.local_to_surface.map_rect(&local_bounds);
let surface_rect = transform.local_to_surface.map_rect(&local_sub_rect);
surface_rect
.translate(-surface_bounds.min.to_vector())
.round_out()
.intersection(&surface_bounds.size().round().into())
.unwrap_or_else(DeviceRect::zero)
}
pub fn get_device_transform(
&self,
transform_index: CompositorTransformIndex,
) -> ScaleOffset {
let transform = &self.transforms[transform_index.0];
transform.local_to_device
}
pub fn get_compositor_transform(
&self,
transform_index: CompositorTransformIndex,
) -> ScaleOffset {
let transform = &self.transforms[transform_index.0];
transform.surface_to_device
}
pub fn register_occluder(
&mut self,
z_id: ZBufferId,
rect: WorldRect,
) {
let world_rect = rect.round().to_i32();
self.occluders.push(world_rect, z_id);
}
pub fn push_surface(
&mut self,
tile_cache: &TileCacheInstance,
device_clip_rect: DeviceRect,
resource_cache: &ResourceCache,
gpu_cache: &mut GpuCache,
deferred_resolves: &mut Vec<DeferredResolve>,
) {
let slice_transform = self.get_compositor_transform(tile_cache.transform_index).to_transform();
let image_rendering = if self.low_quality_pinch_zoom {
ImageRendering::Auto
} else {
ImageRendering::CrispEdges
};
for sub_slice in &tile_cache.sub_slices {
let mut surface_device_rect = DeviceRect::zero();
for tile in sub_slice.tiles.values() {
if !tile.is_visible {
continue;
}
surface_device_rect = surface_device_rect.union(&tile.device_valid_rect);
}
self.tiles.extend_from_slice(&sub_slice.composite_tiles);
let surface_clip_rect = device_clip_rect
.intersection(&surface_device_rect)
.unwrap_or(DeviceRect::zero());
if !sub_slice.opaque_tile_descriptors.is_empty() {
self.descriptor.surfaces.push(
CompositeSurfaceDescriptor {
surface_id: sub_slice.native_surface.as_ref().map(|s| s.opaque),
clip_rect: surface_clip_rect,
transform: slice_transform,
image_dependencies: [ImageDependency::INVALID; 3],
image_rendering,
tile_descriptors: sub_slice.opaque_tile_descriptors.clone(),
}
);
}
if !sub_slice.alpha_tile_descriptors.is_empty() {
self.descriptor.surfaces.push(
CompositeSurfaceDescriptor {
surface_id: sub_slice.native_surface.as_ref().map(|s| s.alpha),
clip_rect: surface_clip_rect,
transform: slice_transform,
image_dependencies: [ImageDependency::INVALID; 3],
image_rendering,
tile_descriptors: sub_slice.alpha_tile_descriptors.clone(),
}
);
}
for compositor_surface in &sub_slice.compositor_surfaces {
let external_surface = &compositor_surface.descriptor;
let clip_rect = external_surface
.clip_rect
.intersection(&device_clip_rect)
.unwrap_or_else(DeviceRect::zero);
let required_plane_count =
match external_surface.dependency {
ExternalSurfaceDependency::Yuv { format, .. } => {
format.get_plane_num()
},
ExternalSurfaceDependency::Rgb { .. } => {
1
}
};
let mut image_dependencies = [ImageDependency::INVALID; 3];
for i in 0 .. required_plane_count {
let dependency = match external_surface.dependency {
ExternalSurfaceDependency::Yuv { image_dependencies, .. } => {
image_dependencies[i]
},
ExternalSurfaceDependency::Rgb { image_dependency, .. } => {
image_dependency
}
};
image_dependencies[i] = dependency;
}
let needs_external_surface_update = match self.compositor_kind {
CompositorKind::Draw { .. } => true,
_ => external_surface.update_params.is_some(),
};
let external_surface_index = if needs_external_surface_update {
let external_surface_index = self.compute_external_surface_dependencies(
&external_surface,
&image_dependencies,
required_plane_count,
resource_cache,
gpu_cache,
deferred_resolves,
);
if external_surface_index == ResolvedExternalSurfaceIndex::INVALID {
continue;
}
external_surface_index
} else {
ResolvedExternalSurfaceIndex::INVALID
};
let surface = CompositeTileSurface::ExternalSurface { external_surface_index };
let local_rect = external_surface.local_surface_size.cast_unit().into();
let tile = CompositeTile {
kind: tile_kind(&surface, compositor_surface.is_opaque),
surface,
local_rect,
local_valid_rect: local_rect,
local_dirty_rect: local_rect,
device_clip_rect: clip_rect,
z_id: external_surface.z_id,
transform_index: external_surface.transform_index,
};
self.descriptor.surfaces.push(
CompositeSurfaceDescriptor {
surface_id: external_surface.native_surface_id,
clip_rect,
transform: self.get_compositor_transform(external_surface.transform_index).to_transform(),
image_dependencies: image_dependencies,
image_rendering: external_surface.image_rendering,
tile_descriptors: Vec::new(),
}
);
self.tiles.push(tile);
}
}
}
fn compute_external_surface_dependencies(
&mut self,
external_surface: &ExternalSurfaceDescriptor,
image_dependencies: &[ImageDependency; 3],
required_plane_count: usize,
resource_cache: &ResourceCache,
gpu_cache: &mut GpuCache,
deferred_resolves: &mut Vec<DeferredResolve>,
) -> ResolvedExternalSurfaceIndex {
let mut planes = [
ExternalPlaneDescriptor::invalid(),
ExternalPlaneDescriptor::invalid(),
ExternalPlaneDescriptor::invalid(),
];
let mut valid_plane_count = 0;
for i in 0 .. required_plane_count {
let request = ImageRequest {
key: image_dependencies[i].key,
rendering: external_surface.image_rendering,
tile: None,
};
let cache_item = resolve_image(
request,
resource_cache,
gpu_cache,
deferred_resolves,
);
if cache_item.texture_id != TextureSource::Invalid {
valid_plane_count += 1;
let plane = &mut planes[i];
*plane = ExternalPlaneDescriptor {
texture: cache_item.texture_id,
uv_rect: cache_item.uv_rect.into(),
};
}
}
if valid_plane_count < required_plane_count {
warn!("Warnings: skip a YUV/RGB compositor surface, found {}/{} valid images",
valid_plane_count,
required_plane_count,
);
return ResolvedExternalSurfaceIndex::INVALID;
}
let external_surface_index = ResolvedExternalSurfaceIndex(self.external_surfaces.len());
let update_params = external_surface.update_params.map(|surface_size| {
(
external_surface.native_surface_id.expect("bug: no native surface!"),
surface_size
)
});
match external_surface.dependency {
ExternalSurfaceDependency::Yuv{ color_space, format, channel_bit_depth, .. } => {
let image_buffer_kind = planes[0].texture.image_buffer_kind();
self.external_surfaces.push(ResolvedExternalSurface {
color_data: ResolvedExternalSurfaceColorData::Yuv {
image_dependencies: *image_dependencies,
planes,
color_space,
format,
channel_bit_depth,
},
image_buffer_kind,
update_params,
});
},
ExternalSurfaceDependency::Rgb { .. } => {
let image_buffer_kind = planes[0].texture.image_buffer_kind();
self.external_surfaces.push(ResolvedExternalSurface {
color_data: ResolvedExternalSurfaceColorData::Rgb {
image_dependency: image_dependencies[0],
plane: planes[0],
},
image_buffer_kind,
update_params,
});
},
}
external_surface_index
}
pub fn end_frame(&mut self) {
self.tiles.sort_by_key(|tile| tile.z_id.0);
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct NativeSurfaceId(pub u64);
impl NativeSurfaceId {
pub const DEBUG_OVERLAY: NativeSurfaceId = NativeSurfaceId(u64::MAX);
}
#[repr(C)]
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct NativeTileId {
pub surface_id: NativeSurfaceId,
pub x: i32,
pub y: i32,
}
impl NativeTileId {
pub const DEBUG_OVERLAY: NativeTileId = NativeTileId {
surface_id: NativeSurfaceId::DEBUG_OVERLAY,
x: 0,
y: 0,
};
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct NativeSurfaceInfo {
pub origin: DeviceIntPoint,
pub fbo_id: u32,
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct CompositorCapabilities {
pub virtual_surface_size: i32,
pub redraw_on_invalidation: bool,
pub max_update_rects: usize,
}
impl Default for CompositorCapabilities {
fn default() -> Self {
CompositorCapabilities {
virtual_surface_size: 0,
redraw_on_invalidation: false,
max_update_rects: 1,
}
}
}
pub type CompositorSurfaceTransform = Transform3D<f32, DevicePixel, DevicePixel>;
pub trait Compositor {
fn create_surface(
&mut self,
id: NativeSurfaceId,
virtual_offset: DeviceIntPoint,
tile_size: DeviceIntSize,
is_opaque: bool,
);
fn create_external_surface(
&mut self,
id: NativeSurfaceId,
is_opaque: bool,
);
fn destroy_surface(
&mut self,
id: NativeSurfaceId,
);
fn create_tile(
&mut self,
id: NativeTileId,
);
fn destroy_tile(
&mut self,
id: NativeTileId,
);
fn attach_external_image(
&mut self,
id: NativeSurfaceId,
external_image: ExternalImageId
);
fn invalidate_tile(
&mut self,
_id: NativeTileId,
_valid_rect: DeviceIntRect
) {}
fn bind(
&mut self,
id: NativeTileId,
dirty_rect: DeviceIntRect,
valid_rect: DeviceIntRect,
) -> NativeSurfaceInfo;
fn unbind(
&mut self,
);
fn begin_frame(&mut self);
fn add_surface(
&mut self,
id: NativeSurfaceId,
transform: CompositorSurfaceTransform,
clip_rect: DeviceIntRect,
image_rendering: ImageRendering,
);
fn start_compositing(
&mut self,
_clear_color: ColorF,
_dirty_rects: &[DeviceIntRect],
_opaque_rects: &[DeviceIntRect],
) {}
fn end_frame(&mut self);
fn enable_native_compositor(&mut self, enable: bool);
fn deinit(&mut self);
fn get_capabilities(&self) -> CompositorCapabilities;
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct MappedTileInfo {
pub data: *mut c_void,
pub stride: i32,
}
#[repr(C)]
pub struct SWGLCompositeSurfaceInfo {
pub yuv_planes: u32,
pub textures: [u32; 3],
pub color_space: YuvRangedColorSpace,
pub color_depth: ColorDepth,
pub size: DeviceIntSize,
}
pub trait MappableCompositor: Compositor {
fn map_tile(
&mut self,
id: NativeTileId,
dirty_rect: DeviceIntRect,
valid_rect: DeviceIntRect,
) -> Option<MappedTileInfo>;
fn unmap_tile(&mut self);
fn lock_composite_surface(
&mut self,
ctx: *mut c_void,
external_image_id: ExternalImageId,
composite_info: *mut SWGLCompositeSurfaceInfo,
) -> bool;
fn unlock_composite_surface(&mut self, ctx: *mut c_void, external_image_id: ExternalImageId);
}
pub trait PartialPresentCompositor {
fn set_buffer_damage_region(&mut self, rects: &[DeviceIntRect]);
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
struct Occluder {
z_id: ZBufferId,
world_rect: WorldIntRect,
}
#[derive(Debug)]
enum OcclusionEventKind {
Begin,
End,
}
#[derive(Debug)]
struct OcclusionEvent {
y: i32,
x_range: ops::Range<i32>,
kind: OcclusionEventKind,
}
impl OcclusionEvent {
fn new(y: i32, kind: OcclusionEventKind, x0: i32, x1: i32) -> Self {
OcclusionEvent {
y,
x_range: ops::Range {
start: x0,
end: x1,
},
kind,
}
}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct Occluders {
occluders: Vec<Occluder>,
#[cfg_attr(feature = "serde", serde(skip))]
events: Vec<OcclusionEvent>,
#[cfg_attr(feature = "serde", serde(skip))]
active: Vec<ops::Range<i32>>,
}
impl Occluders {
fn new() -> Self {
Occluders {
occluders: Vec::new(),
events: Vec::new(),
active: Vec::new(),
}
}
fn push(&mut self, world_rect: WorldIntRect, z_id: ZBufferId) {
self.occluders.push(Occluder { world_rect, z_id });
}
pub fn is_tile_occluded(
&mut self,
z_id: ZBufferId,
world_rect: WorldRect,
) -> bool {
let world_rect = world_rect.round().to_i32();
let ref_area = world_rect.area();
let cover_area = self.area(z_id, &world_rect);
debug_assert!(cover_area <= ref_area);
ref_area == cover_area
}
fn area(
&mut self,
z_id: ZBufferId,
clip_rect: &WorldIntRect,
) -> i32 {
self.events.clear();
self.active.clear();
let mut area = 0;
for occluder in &self.occluders {
if occluder.z_id.0 < z_id.0 {
if let Some(rect) = occluder.world_rect.intersection(clip_rect) {
let x0 = rect.min.x;
let x1 = x0 + rect.width();
self.events.push(OcclusionEvent::new(rect.min.y, OcclusionEventKind::Begin, x0, x1));
self.events.push(OcclusionEvent::new(rect.min.y + rect.height(), OcclusionEventKind::End, x0, x1));
}
}
}
if self.events.is_empty() {
return 0;
}
self.events.sort_by_key(|e| e.y);
let mut cur_y = self.events[0].y;
for event in &self.events {
let dy = event.y - cur_y;
if dy != 0 && !self.active.is_empty() {
assert!(dy > 0);
self.active.sort_by_key(|i| i.start);
let mut query = 0;
let mut cur = self.active[0].start;
for interval in &self.active {
cur = interval.start.max(cur);
query += (interval.end - cur).max(0);
cur = cur.max(interval.end);
}
area += query * dy;
}
match event.kind {
OcclusionEventKind::Begin => {
self.active.push(event.x_range.clone());
}
OcclusionEventKind::End => {
let index = self.active.iter().position(|i| *i == event.x_range).unwrap();
self.active.remove(index);
}
}
cur_y = event.y;
}
area
}
}