Bug 1872892: Allow YuvImage underlays in more circumstances. r=gw

This patch makes two changes:

1) Backdrops will be considered spanning as long as they cover the
visible local clip rect. Formerly, they had to span the entire visible
local rect, which meant that undrawn areas had to also be covered.

2) Image prims will not promote until all of the promotable YuvImage
prims have been considered for promotion. This is similar to the
original implementation of underlays in Bug 1849680, where the presence
of any YuvImage prim would prevent *all* overlay promotion (which is the
only type considered for Image prims). The new behavior will allow Image
prims to be promoted as long as all the YuvImages have been processed.

Differential Revision: https://phabricator.services.mozilla.com/D211297
This commit is contained in:
Brad Werth 2024-05-30 00:20:54 +00:00
parent 88ca13466d
commit 180caf1b4a
2 changed files with 64 additions and 29 deletions

View File

@ -1634,10 +1634,14 @@ pub struct TileCacheParams {
pub shared_clip_leaf_id: Option<ClipLeafId>,
// Virtual surface sizes are always square, so this represents both the width and height
pub virtual_surface_size: i32,
// The number of compositor surfaces that are being requested for this tile cache.
// The number of Image surfaces that are being requested for this tile cache.
// This is only a suggestion - the tile cache will clamp this as a reasonable number
// and only promote a limited number of surfaces.
pub overlay_surface_count: usize,
pub image_surface_count: usize,
// The number of YuvImage surfaces that are being requested for this tile cache.
// This is only a suggestion - the tile cache will clamp this as a reasonable number
// and only promote a limited number of surfaces.
pub yuv_image_surface_count: usize,
}
/// Defines which sub-slice (effectively a z-index) a primitive exists on within
@ -1852,6 +1856,11 @@ pub struct TileCacheInstance {
pub underlays: Vec<ExternalSurfaceDescriptor>,
/// "Region" (actually a spanning rect) containing all overlay promoted surfaces
pub overlay_region: PictureRect,
/// The number YuvImage prims in this cache, provided in our TileCacheParams.
pub yuv_images_count: usize,
/// The remaining number of YuvImage prims we will see this frame. We prioritize
/// promoting these before promoting any Image prims.
pub yuv_images_remaining: usize,
}
enum SurfacePromotionResult {
@ -1863,7 +1872,7 @@ impl TileCacheInstance {
pub fn new(params: TileCacheParams) -> Self {
// Determine how many sub-slices we need. Clamp to an arbitrary limit to ensure
// we don't create a huge number of OS compositor tiles and sub-slices.
let sub_slice_count = params.overlay_surface_count.min(MAX_COMPOSITOR_SURFACES) + 1;
let sub_slice_count = (params.image_surface_count + params.yuv_image_surface_count).min(MAX_COMPOSITOR_SURFACES) + 1;
let mut sub_slices = Vec::with_capacity(sub_slice_count);
for _ in 0 .. sub_slice_count {
@ -1916,6 +1925,8 @@ impl TileCacheInstance {
backdrop_surface: None,
underlays: Vec::new(),
overlay_region: PictureRect::zero(),
yuv_images_count: params.yuv_image_surface_count,
yuv_images_remaining: 0,
}
}
@ -1956,7 +1967,7 @@ impl TileCacheInstance {
// Determine how many sub-slices we need, based on how many compositor surface prims are
// in the supplied primitive list.
let required_sub_slice_count = params.overlay_surface_count.min(MAX_COMPOSITOR_SURFACES) + 1;
let required_sub_slice_count = (params.image_surface_count + params.yuv_image_surface_count).min(MAX_COMPOSITOR_SURFACES) + 1;
if self.sub_slices.len() != required_sub_slice_count {
self.tile_rect = TileRect::zero();
@ -1997,6 +2008,9 @@ impl TileCacheInstance {
// Since the slice flags may have changed, ensure we re-evaluate the
// appropriate tile size for this cache next update.
self.frames_until_size_eval = 0;
// Update the number of YuvImage prims we have in the scene.
self.yuv_images_count = params.yuv_image_surface_count;
}
/// Destroy any manually managed resources before this picture cache is
@ -2060,6 +2074,7 @@ impl TileCacheInstance {
self.deferred_dirty_tests.clear();
self.underlays.clear();
self.overlay_region = PictureRect::zero();
self.yuv_images_remaining = self.yuv_images_count;
for sub_slice in &mut self.sub_slices {
sub_slice.reset();
@ -3151,18 +3166,23 @@ impl TileCacheInstance {
}
let mut promote_to_surface = false;
match self.can_promote_to_surface(image_key.common.flags,
prim_clip_chain,
prim_spatial_node_index,
is_root_tile_cache,
sub_slice_index,
CompositorSurfaceKind::Overlay,
pic_coverage_rect,
frame_context) {
SurfacePromotionResult::Failed => {
}
SurfacePromotionResult::Success => {
promote_to_surface = true;
// Only consider promoting Images if all of our YuvImages have been
// processed (whether they were promoted or not).
if self.yuv_images_remaining == 0 {
match self.can_promote_to_surface(image_key.common.flags,
prim_clip_chain,
prim_spatial_node_index,
is_root_tile_cache,
sub_slice_index,
CompositorSurfaceKind::Overlay,
pic_coverage_rect,
frame_context) {
SurfacePromotionResult::Failed => {
}
SurfacePromotionResult::Success => {
promote_to_surface = true;
}
}
}
@ -3211,6 +3231,15 @@ impl TileCacheInstance {
PrimitiveInstanceKind::YuvImage { data_handle, ref mut compositor_surface_kind, .. } => {
let prim_data = &data_stores.yuv_image[data_handle];
// Note if this is one of the YuvImages we were considering for
// surface promotion. We only care for primitives that were added
// to us, indicated by is_root_tile_cache. Those are the only ones
// that were added to the TileCacheParams that configured the
// current scene.
if is_root_tile_cache && prim_data.common.flags.contains(PrimitiveFlags::PREFER_COMPOSITOR_SURFACE) {
self.yuv_images_remaining -= 1;
}
let clip_on_top = prim_clip_chain.needs_mask;
let prefer_underlay = clip_on_top || !cfg!(target_os = "macos");
let promotion_attempts = if prefer_underlay {
@ -3405,10 +3434,10 @@ impl TileCacheInstance {
};
// Calculate the screen rect in local space. When we calculate backdrops, we
// care only that they cover the visible rect, and don't have any overlapping
// prims in the visible rect.
let visible_local_rect = self.local_rect.intersection(&self.screen_rect_in_pic_space).unwrap_or_default();
if pic_coverage_rect.intersects(&visible_local_rect) {
// care only that they cover the visible rect (based off the local clip), and
// don't have any overlapping prims in the visible rect.
let visible_local_clip_rect = self.local_clip_rect.intersection(&self.screen_rect_in_pic_space).unwrap_or_default();
if pic_coverage_rect.intersects(&visible_local_clip_rect) {
self.found_prims_after_backdrop = true;
}
@ -3498,7 +3527,7 @@ impl TileCacheInstance {
}
if let Some(kind) = backdrop_candidate.kind {
if backdrop_candidate.opaque_rect.contains_box(&visible_local_rect) {
if backdrop_candidate.opaque_rect.contains_box(&visible_local_clip_rect) {
self.found_prims_after_backdrop = false;
self.backdrop.kind = Some(kind);
self.backdrop.backdrop_rect = backdrop_candidate.opaque_rect;
@ -4738,9 +4767,12 @@ pub struct PrimitiveList {
/// List of primitives grouped into clusters.
pub clusters: Vec<PrimitiveCluster>,
pub child_pictures: Vec<PictureIndex>,
/// The number of preferred compositor surfaces that were found when
/// adding prims to this list, which might be rendered as overlays
pub overlay_surface_count: usize,
/// The number of Image compositor surfaces that were found when
/// adding prims to this list, which might be rendered as overlays.
pub image_surface_count: usize,
/// The number of YuvImage compositor surfaces that were found when
/// adding prims to this list, which might be rendered as overlays.
pub yuv_image_surface_count: usize,
pub needs_scissor_rect: bool,
}
@ -4753,7 +4785,8 @@ impl PrimitiveList {
PrimitiveList {
clusters: Vec::new(),
child_pictures: Vec::new(),
overlay_surface_count: 0,
image_surface_count: 0,
yuv_image_surface_count: 0,
needs_scissor_rect: false,
}
}
@ -4761,7 +4794,8 @@ impl PrimitiveList {
pub fn merge(&mut self, other: PrimitiveList) {
self.clusters.extend(other.clusters);
self.child_pictures.extend(other.child_pictures);
self.overlay_surface_count += other.overlay_surface_count;
self.image_surface_count += other.image_surface_count;
self.yuv_image_surface_count += other.yuv_image_surface_count;
self.needs_scissor_rect |= other.needs_scissor_rect;
}
@ -4794,7 +4828,7 @@ impl PrimitiveList {
// be allocating more subslices than we actually need, but it
// gives us maximum flexibility.
if prim_flags.contains(PrimitiveFlags::PREFER_COMPOSITOR_SURFACE) {
self.overlay_surface_count += 1;
self.yuv_image_surface_count += 1;
}
}
PrimitiveInstanceKind::Image { .. } => {
@ -4804,7 +4838,7 @@ impl PrimitiveList {
// it's a little bit of work, as scene building doesn't have access
// to the opacity state of an image key at this point.
if prim_flags.contains(PrimitiveFlags::PREFER_COMPOSITOR_SURFACE) {
self.overlay_surface_count += 1;
self.image_surface_count += 1;
}
}
_ => {}

View File

@ -618,7 +618,8 @@ fn create_tile_cache(
shared_clip_node_id,
shared_clip_leaf_id,
virtual_surface_size: frame_builder_config.compositor_kind.get_virtual_surface_size(),
overlay_surface_count: prim_list.overlay_surface_count,
image_surface_count: prim_list.image_surface_count,
yuv_image_surface_count: prim_list.yuv_image_surface_count,
});
let pic_index = prim_store.pictures.alloc().init(PicturePrimitive::new_image(