From 446779ab83c5082067473ea7518076457812e873 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Mon, 24 Feb 2025 10:31:00 +0100 Subject: [PATCH] wl_surface: check if partially-opaque surface is opaque within render bounds --- src/ifs/wl_surface.rs | 4 ++++ src/rect/region.rs | 5 +++++ src/renderer.rs | 25 ++++++++++++++++++++++++- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index 41118523..8f7b4cf2 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -1654,6 +1654,10 @@ impl WlSurface { pub fn opaque(&self) -> bool { self.is_opaque.get() } + + pub fn opaque_region(&self) -> Option> { + self.opaque_region.get() + } } object_base! { diff --git a/src/rect/region.rs b/src/rect/region.rs index 21abd7df..0814cb17 100644 --- a/src/rect/region.rs +++ b/src/rect/region.rs @@ -177,11 +177,16 @@ where } pub fn contains_rect(&self, rect: &Rect) -> bool { + self.contains_rect2(rect, |r| *r) + } + + pub fn contains_rect2(&self, rect: &Rect, map: impl Fn(&Rect) -> Rect) -> bool { if rect.is_empty() { return true; } let mut y1 = rect.y1(); for r in self.rects() { + let r = map(r); if r.y2() <= y1 || r.x2() <= rect.x1() { continue; } diff --git a/src/renderer.rs b/src/renderer.rs index 53ad5254..fa8a0458 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -423,6 +423,10 @@ impl Renderer<'_> { ) { let alpha = surface.alpha(); if let Some(tex) = buffer.buffer.get_texture(surface) { + let mut opaque = surface.opaque(); + if !opaque && tex.format().has_alpha { + opaque = self.bounds_are_opaque(x, y, bounds, surface); + } self.base.render_texture( &tex, alpha, @@ -435,7 +439,7 @@ impl Renderer<'_> { Some(buffer.clone()), AcquireSync::Unnecessary, buffer.release_sync, - surface.opaque(), + opaque, ); } else if let Some(color) = &buffer.buffer.color { if let Some(rect) = Rect::new_sized(x, y, tsize.0, tsize.1) { @@ -519,4 +523,23 @@ impl Renderer<'_> { let (dx, dy) = surface.surface.extents.get().position(); self.render_surface(&surface.surface, x - dx, y - dy, None); } + + fn bounds_are_opaque( + &self, + x: i32, + y: i32, + bounds: Option<&Rect>, + surface: &WlSurface, + ) -> bool { + let Some(bounds) = bounds else { + return false; + }; + let Some(region) = surface.opaque_region() else { + return false; + }; + let surface_size = surface.buffer_abs_pos.get().at_point(0, 0); + let surface_size = self.base.scale_rect(surface_size); + let bounds = bounds.move_(-x, -y).intersect(surface_size); + region.contains_rect2(&bounds, |r| self.base.scale_rect(*r)) + } }