Improve performance of opacity rendering

Avoid an opacity layer also in the case where it is applied to an element with no children.
This commit is contained in:
Simon Hausmann 2022-03-25 10:25:53 +01:00 committed by Simon Hausmann
parent d6a569b8f8
commit 033cf3721e
3 changed files with 47 additions and 2 deletions

View file

@ -690,9 +690,10 @@ impl ItemRenderer for GLItemRenderer {
fn visit_opacity(&mut self, opacity_item: Pin<&Opacity>, self_rc: &ItemRc) -> RenderingResult {
let opacity = opacity_item.opacity();
if opacity != 1.0 {
if Opacity::need_layer(self_rc, opacity) {
self.render_and_blend_layer(&opacity_item.cached_rendering_data, opacity, self_rc)
} else {
self.apply_opacity(opacity);
opacity_item
.cached_rendering_data
.release(&mut self.graphics_window.graphics_cache.borrow_mut());

View file

@ -781,9 +781,10 @@ impl ItemRenderer for QtItemRenderer<'_> {
fn visit_opacity(&mut self, opacity_item: Pin<&Opacity>, self_rc: &ItemRc) -> RenderingResult {
let opacity = opacity_item.opacity();
if opacity != 1.0 {
if Opacity::need_layer(self_rc, opacity) {
self.render_and_blend_layer(&opacity_item.cached_rendering_data, opacity, self_rc)
} else {
self.apply_opacity(opacity);
opacity_item.cached_rendering_data.release(&mut self.cache.borrow_mut());
RenderingResult::ContinueRenderingChildren
}

View file

@ -205,6 +205,18 @@ impl ItemRc {
pub fn component(&self) -> vtable::VRc<ComponentVTable> {
self.component.clone()
}
/// Returns the number of child items for this item. Returns None if
/// the number is dynamically determined.
/// TODO: Remove the option when the Subtree trait exists and allows querying
pub fn children_count(&self) -> Option<u32> {
let comp_ref_pin = vtable::VRc::borrow_pin(&self.component);
let item_tree = comp_ref_pin.as_ref().get_item_tree();
match item_tree.as_slice()[self.index] {
crate::item_tree::ItemTreeNode::Item { children_count, .. } => Some(children_count),
crate::item_tree::ItemTreeNode::DynamicTree { .. } => None,
}
}
}
/// A Weak reference to an item that can be constructed from an ItemRc.
@ -837,6 +849,37 @@ impl Item for Opacity {
}
}
impl Opacity {
// This function determines the optimization opportunities for not having to render the
// children of the Opacity element into a layer:
// * The opacity item typically only one child (this is not guaranteed). If that item has
// no children, then we can skip the layer and apply the opacity directly. This is not perfect though,
// for example if the compiler inserts another synthetic element between the `Opacity` and the actual child,
// then this check will apply a layer even though it might not actually be necessary.
// * If the vale of the opacity is 1.0 then we don't need to do anything.
pub fn need_layer(self_rc: &ItemRc, opacity: f32) -> bool {
if opacity == 1.0 {
return false;
}
let component_rc = self_rc.component();
let component_ref = vtable::VRc::borrow_pin(&component_rc);
let self_index = self_rc.index();
// TODO: use first_child() once it exists
let item_tree = component_ref.as_ref().get_item_tree();
let target_item_index = match item_tree.as_slice()[self_index] {
crate::item_tree::ItemTreeNode::Item { children_count, children_index, .. }
if children_count == 1 =>
{
children_index as usize
}
_ => return true, // Dynamic tree or multiple children -> need layer
};
let target_item = ItemRc::new(component_rc.clone(), target_item_index);
// any children? Then we need a layer
target_item.children_count() != Some(0)
}
}
impl ItemConsts for Opacity {
const cached_rendering_data_offset: const_field_offset::FieldOffset<
Opacity,