From 0872a1251d854dc652433970a483d542e0aacf71 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 22 Feb 2025 11:14:51 +0100 Subject: [PATCH] alpha-multiplier: perform multiplication in the renderer --- src/backends/metal/present.rs | 2 +- src/gfx_api.rs | 13 ++++++++++++- src/gfx_apis/gl.rs | 10 +++++++--- src/gfx_apis/vulkan/renderer.rs | 4 ++-- src/it/test_gfx_api.rs | 3 ++- src/renderer.rs | 11 ++++------- src/renderer/renderer_base.rs | 20 +++++++++++++++----- src/theme.rs | 5 +++-- 8 files changed, 46 insertions(+), 22 deletions(-) diff --git a/src/backends/metal/present.rs b/src/backends/metal/present.rs index d8bddce2..7bd59489 100644 --- a/src/backends/metal/present.rs +++ b/src/backends/metal/present.rs @@ -570,7 +570,7 @@ impl MetalConnector { match opt { GfxApiOpt::Sync => {} GfxApiOpt::FillRect(fr) => { - if fr.color == Color::SOLID_BLACK { + if fr.effective_color() == Color::SOLID_BLACK { // Black fills can be ignored because this is the CRTC background color. if fr.rect.is_covering() { // If fill covers the entire screen, we don't have to look further. diff --git a/src/gfx_api.rs b/src/gfx_api.rs index ca7cadac..6c7b1100 100644 --- a/src/gfx_api.rs +++ b/src/gfx_api.rs @@ -116,7 +116,7 @@ impl SampleRect { } } -#[derive(Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq)] pub struct FramebufferRect { pub x1: f32, pub x2: f32, @@ -171,6 +171,17 @@ impl FramebufferRect { pub struct FillRect { pub rect: FramebufferRect, pub color: Color, + pub alpha: Option, +} + +impl FillRect { + pub fn effective_color(&self) -> Color { + let mut color = self.color; + if let Some(alpha) = self.alpha { + color = color * alpha; + } + color + } } pub struct CopyTexture { diff --git a/src/gfx_apis/gl.rs b/src/gfx_apis/gl.rs index bbf7ce77..bb3609bf 100644 --- a/src/gfx_apis/gl.rs +++ b/src/gfx_apis/gl.rs @@ -202,7 +202,7 @@ enum RenderError { #[derive(Default)] struct GfxGlState { triangles: RefCell>, - fill_rect: VecStorage<&'static FillRect>, + fill_rect: VecStorage, copy_tex: VecStorage<&'static CopyTexture>, } @@ -233,7 +233,11 @@ fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) -> Option { } } GfxApiOpt::FillRect(f) => { - fill_rect.push(f); + fill_rect.push(FillRect { + rect: f.rect, + color: f.effective_color(), + alpha: None, + }); i += 1; } GfxApiOpt::CopyTexture(c) => { @@ -249,7 +253,7 @@ fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) -> Option { triangles.clear(); let mut color = None; while i < fill_rect.len() { - let fr = fill_rect[i]; + let fr = &fill_rect[i]; match color { None => color = Some(fr.color), Some(c) if c == fr.color => {} diff --git a/src/gfx_apis/vulkan/renderer.rs b/src/gfx_apis/vulkan/renderer.rs index 15e9a8bd..58152b76 100644 --- a/src/gfx_apis/vulkan/renderer.rs +++ b/src/gfx_apis/vulkan/renderer.rs @@ -505,7 +505,7 @@ impl VulkanRenderer { let memory = &mut *self.memory.borrow_mut(); let clear_value = clear.map(|clear| ClearValue { color: ClearColorValue { - float32: clear.to_array_srgb(), + float32: clear.to_array_srgb(None), }, }); let load_clear = memory.paint_regions.len() == 1 && { @@ -620,7 +620,7 @@ impl VulkanRenderer { GfxApiOpt::FillRect(r) => { let push = FillPushConstants { pos: r.rect.to_points(), - color: r.color.to_array_srgb(), + color: r.color.to_array_srgb(r.alpha), }; for region in &memory.paint_regions { let mut push = push; diff --git a/src/it/test_gfx_api.rs b/src/it/test_gfx_api.rs index 1cd262af..e9d9c6b8 100644 --- a/src/it/test_gfx_api.rs +++ b/src/it/test_gfx_api.rs @@ -441,11 +441,12 @@ impl GfxFramebuffer for TestGfxFb { } }; let fill_rect = |f: &FillRect, staging: &mut [Color]| { + let color = f.effective_color(); let (x1, y1, x2, y2) = fb_points(width, height, &f.rect); for y in y1..y2 { for x in x1..x2 { let dst = &mut staging[(y * width + x) as usize]; - *dst = dst.and_then(&f.color); + *dst = dst.and_then(&color); } } }; diff --git a/src/renderer.rs b/src/renderer.rs index b69d1a3b..8a8c255d 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -89,7 +89,7 @@ impl Renderer<'_> { let bar_bg = self.base.scale_rect(bar_bg); let c = theme.colors.bar_background.get(); self.base - .fill_boxes3(slice::from_ref(&bar_bg), &c, x, y, true); + .fill_boxes3(slice::from_ref(&bar_bg), &c, None, x, y, true); let rd = output.render_data.borrow_mut(); if let Some(aw) = &rd.active_workspace { let c = match aw.captured { @@ -336,7 +336,8 @@ impl Renderer<'_> { }; let color = self.state.theme.colors.highlight.get(); self.base.ops.push(GfxApiOpt::Sync); - self.base.fill_scaled_boxes(slice::from_ref(bounds), &color); + self.base + .fill_scaled_boxes(slice::from_ref(bounds), &color, None); } pub fn render_highlight(&mut self, rect: &Rect) { @@ -440,11 +441,7 @@ impl Renderer<'_> { }; if !rect.is_empty() { self.base.ops.push(GfxApiOpt::Sync); - let mut color = *color; - if let Some(alpha) = alpha { - color = color * alpha; - } - self.base.fill_scaled_boxes(&[rect], &color); + self.base.fill_scaled_boxes(&[rect], color, alpha); } } } else { diff --git a/src/renderer/renderer_base.rs b/src/renderer/renderer_base.rs index 5230e0d4..3c291a40 100644 --- a/src/renderer/renderer_base.rs +++ b/src/renderer/renderer_base.rs @@ -64,19 +64,27 @@ impl RendererBase<'_> { rect } - pub fn fill_scaled_boxes(&mut self, boxes: &[Rect], color: &Color) { - self.fill_boxes3(boxes, color, 0, 0, true); + pub fn fill_scaled_boxes(&mut self, boxes: &[Rect], color: &Color, alpha: Option) { + self.fill_boxes3(boxes, color, alpha, 0, 0, true); } pub fn fill_boxes(&mut self, boxes: &[Rect], color: &Color) { - self.fill_boxes3(boxes, color, 0, 0, false); + self.fill_boxes3(boxes, color, None, 0, 0, false); } pub fn fill_boxes2(&mut self, boxes: &[Rect], color: &Color, dx: i32, dy: i32) { - self.fill_boxes3(boxes, color, dx, dy, false); + self.fill_boxes3(boxes, color, None, dx, dy, false); } - pub fn fill_boxes3(&mut self, boxes: &[Rect], color: &Color, dx: i32, dy: i32, scaled: bool) { + pub fn fill_boxes3( + &mut self, + boxes: &[Rect], + color: &Color, + alpha: Option, + dx: i32, + dy: i32, + scaled: bool, + ) { if boxes.is_empty() || *color == Color::TRANSPARENT { return; } @@ -97,6 +105,7 @@ impl RendererBase<'_> { self.fb_height, ), color: *color, + alpha, })); } } @@ -129,6 +138,7 @@ impl RendererBase<'_> { self.fb_height, ), color: *color, + alpha: None, })); } } diff --git a/src/theme.rs b/src/theme.rs index 44a38635..d1fb8d87 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -115,8 +115,9 @@ impl Color { [to_u8(self.r), to_u8(self.g), to_u8(self.b), to_u8(self.a)] } - pub fn to_array_srgb(self) -> [f32; 4] { - [self.r, self.g, self.b, self.a] + pub fn to_array_srgb(self, alpha: Option) -> [f32; 4] { + let a = alpha.unwrap_or(1.0); + [self.r * a, self.g * a, self.b * a, self.a * a] } #[expect(dead_code)]