From c796602aab6359a341707d7553d2def9930f147c Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Mon, 24 Feb 2025 09:45:11 +0100 Subject: [PATCH] wl_surface: track if surface is fully opaque --- src/cursor.rs | 3 +++ src/gfx_api.rs | 3 +++ src/ifs/wl_surface.rs | 20 +++++++++++++++++++- src/portal/ptr_gui.rs | 2 ++ src/rect/region.rs | 20 ++++++++++++++++++++ src/renderer.rs | 13 +++++++++---- src/renderer/renderer_base.rs | 2 ++ src/state.rs | 1 + 8 files changed, 59 insertions(+), 5 deletions(-) diff --git a/src/cursor.rs b/src/cursor.rs index 4f093f93..faae24f7 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -391,6 +391,7 @@ fn render_img(image: &InstantiatedCursorImage, renderer: &mut Renderer, x: Fixed None, AcquireSync::None, ReleaseSync::None, + false, ); } } @@ -414,6 +415,7 @@ impl Cursor for StaticCursor { None, AcquireSync::None, ReleaseSync::None, + false, ); } } @@ -455,6 +457,7 @@ impl Cursor for AnimatedCursor { None, AcquireSync::None, ReleaseSync::None, + false, ); } } diff --git a/src/gfx_api.rs b/src/gfx_api.rs index 6c7b1100..cc0522ec 100644 --- a/src/gfx_api.rs +++ b/src/gfx_api.rs @@ -192,6 +192,8 @@ pub struct CopyTexture { pub acquire_sync: AcquireSync, pub release_sync: ReleaseSync, pub alpha: Option, + #[expect(dead_code)] + pub opaque: bool, } #[derive(Clone, Debug)] @@ -371,6 +373,7 @@ impl dyn GfxFramebuffer { resv.cloned(), acquire_sync, release_sync, + false, ); let clear = self.format().has_alpha.then_some(&Color::TRANSPARENT); self.render(fb_acquire_sync, fb_release_sync, &ops, clear) diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index e63c953f..41118523 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -278,7 +278,7 @@ pub struct WlSurface { role: Cell, pending: RefCell>, input_region: CloneCell>>, - opaque_region: Cell>>, + opaque_region: CloneCell>>, buffer_points: RefCell, pub buffer_points_norm: RefCell, damage_matrix: Cell, @@ -331,6 +331,7 @@ pub struct WlSurface { clear_fifo_on_vblank: Cell, commit_timer: CloneCell>>, before_latch_listener: EventListener, + is_opaque: Cell, } impl Debug for WlSurface { @@ -668,6 +669,7 @@ impl WlSurface { clear_fifo_on_vblank: Default::default(), commit_timer: Default::default(), before_latch_listener: EventListener::new(slf.clone()), + is_opaque: Cell::new(false), } } @@ -1195,6 +1197,7 @@ impl WlSurface { } } let transform_changed = viewport_changed || scale_changed || buffer_transform_changed; + let mut buffer_abs_pos_size_changed = false; if buffer_changed || transform_changed { let mut buffer_points = self.buffer_points.borrow_mut(); let mut buffer_points_norm = self.buffer_points_norm.borrow_mut(); @@ -1288,6 +1291,7 @@ impl WlSurface { .set(buffer_abs_pos.with_size(width, height).unwrap()); max_surface_size = (width.max(old_width), height.max(old_height)); damage_full = true; + buffer_abs_pos_size_changed = true; } } let has_new_frame_requests = pending.frame_request.is_not_empty(); @@ -1304,15 +1308,25 @@ impl WlSurface { mem::swap(fbs.deref_mut(), &mut pending.presentation_feedback); fbs.is_not_empty() }; + let mut opaque_region_changed = false; { if let Some(region) = pending.input_region.take() { self.input_region.set(region); self.client.state.tree_changed(); } if let Some(region) = pending.opaque_region.take() { + opaque_region_changed = true; self.opaque_region.set(region); } } + if opaque_region_changed || buffer_abs_pos_size_changed { + let pos = self.buffer_abs_pos.get().at_point(0, 0); + let is_opaque = match self.opaque_region.get() { + None => false, + Some(o) => o.contains_rect(&pos), + }; + self.is_opaque.set(is_opaque); + } let mut tearing_changed = false; if let Some(tearing) = pending.tearing.take() { if self.tearing.replace(tearing) != tearing { @@ -1636,6 +1650,10 @@ impl WlSurface { pub fn alpha(&self) -> Option { self.alpha.get() } + + pub fn opaque(&self) -> bool { + self.is_opaque.get() + } } object_base! { diff --git a/src/portal/ptr_gui.rs b/src/portal/ptr_gui.rs index 265ef2c9..635a4fd8 100644 --- a/src/portal/ptr_gui.rs +++ b/src/portal/ptr_gui.rs @@ -225,6 +225,7 @@ impl GuiElement for Button { None, AcquireSync::None, ReleaseSync::None, + false, ); } } @@ -325,6 +326,7 @@ impl GuiElement for Label { None, AcquireSync::None, ReleaseSync::None, + false, ); } } diff --git a/src/rect/region.rs b/src/rect/region.rs index 2218a51d..21abd7df 100644 --- a/src/rect/region.rs +++ b/src/rect/region.rs @@ -175,6 +175,26 @@ where } false } + + pub fn contains_rect(&self, rect: &Rect) -> bool { + if rect.is_empty() { + return true; + } + let mut y1 = rect.y1(); + for r in self.rects() { + if r.y2() <= y1 || r.x2() <= rect.x1() { + continue; + } + if r.y1() > y1 || r.x1() > rect.x1() || r.x2() < rect.x2() { + return false; + } + y1 = r.y2(); + if y1 >= rect.y2() { + return true; + } + } + false + } } impl Deref for Region diff --git a/src/renderer.rs b/src/renderer.rs index 8a8c255d..53ad5254 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -124,6 +124,7 @@ impl Renderer<'_> { None, AcquireSync::None, ReleaseSync::None, + false, ); } if let Some(status) = &rd.status { @@ -141,6 +142,7 @@ impl Renderer<'_> { None, AcquireSync::None, ReleaseSync::None, + false, ); } } @@ -219,6 +221,7 @@ impl Renderer<'_> { None, AcquireSync::None, ReleaseSync::None, + false, ); } } @@ -264,6 +267,7 @@ impl Renderer<'_> { None, AcquireSync::None, ReleaseSync::None, + false, ); } } @@ -379,7 +383,6 @@ impl Renderer<'_> { } else { size = self.base.scale_point(size.0, size.1); } - let alpha = surface.alpha(); if let Some(children) = children.deref() { macro_rules! render { ($children:expr) => { @@ -401,10 +404,10 @@ impl Renderer<'_> { }; } render!(&children.below); - self.render_buffer(surface, &buffer, alpha, x, y, *tpoints, size, bounds); + self.render_buffer(surface, &buffer, x, y, *tpoints, size, bounds); render!(&children.above); } else { - self.render_buffer(surface, &buffer, alpha, x, y, *tpoints, size, bounds); + self.render_buffer(surface, &buffer, x, y, *tpoints, size, bounds); } } @@ -412,13 +415,13 @@ impl Renderer<'_> { &mut self, surface: &WlSurface, buffer: &Rc, - alpha: Option, x: i32, y: i32, tpoints: SampleRect, tsize: (i32, i32), bounds: Option<&Rect>, ) { + let alpha = surface.alpha(); if let Some(tex) = buffer.buffer.get_texture(surface) { self.base.render_texture( &tex, @@ -432,6 +435,7 @@ impl Renderer<'_> { Some(buffer.clone()), AcquireSync::Unnecessary, buffer.release_sync, + surface.opaque(), ); } else if let Some(color) = &buffer.buffer.color { if let Some(rect) = Rect::new_sized(x, y, tsize.0, tsize.1) { @@ -496,6 +500,7 @@ impl Renderer<'_> { None, AcquireSync::None, ReleaseSync::None, + false, ); } } diff --git a/src/renderer/renderer_base.rs b/src/renderer/renderer_base.rs index 3c291a40..b5413b87 100644 --- a/src/renderer/renderer_base.rs +++ b/src/renderer/renderer_base.rs @@ -156,6 +156,7 @@ impl RendererBase<'_> { buffer_resv: Option>, acquire_sync: AcquireSync, release_sync: ReleaseSync, + opaque: bool, ) { let mut texcoord = tpoints.unwrap_or_else(SampleRect::identity); @@ -198,6 +199,7 @@ impl RendererBase<'_> { buffer_resv, acquire_sync, release_sync, + opaque, })); } } diff --git a/src/state.rs b/src/state.rs index a69c3795..6b0b4a8a 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1046,6 +1046,7 @@ impl State { resv.cloned(), acquire_sync.clone(), release_sync, + false, ); if render_hardware_cursors { if let Some(cursor_user_group) = self.cursor_user_group_hardware_cursor.get() {