1
0
Fork 0
forked from wry/wry

alpha-multiplier: perform multiplication in the renderer

This commit is contained in:
Julian Orth 2025-02-22 11:14:51 +01:00
parent 33718340f7
commit 0872a1251d
8 changed files with 46 additions and 22 deletions

View file

@ -570,7 +570,7 @@ impl MetalConnector {
match opt { match opt {
GfxApiOpt::Sync => {} GfxApiOpt::Sync => {}
GfxApiOpt::FillRect(fr) => { 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. // Black fills can be ignored because this is the CRTC background color.
if fr.rect.is_covering() { if fr.rect.is_covering() {
// If fill covers the entire screen, we don't have to look further. // If fill covers the entire screen, we don't have to look further.

View file

@ -116,7 +116,7 @@ impl SampleRect {
} }
} }
#[derive(Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
pub struct FramebufferRect { pub struct FramebufferRect {
pub x1: f32, pub x1: f32,
pub x2: f32, pub x2: f32,
@ -171,6 +171,17 @@ impl FramebufferRect {
pub struct FillRect { pub struct FillRect {
pub rect: FramebufferRect, pub rect: FramebufferRect,
pub color: Color, pub color: Color,
pub alpha: Option<f32>,
}
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 { pub struct CopyTexture {

View file

@ -202,7 +202,7 @@ enum RenderError {
#[derive(Default)] #[derive(Default)]
struct GfxGlState { struct GfxGlState {
triangles: RefCell<Vec<[f32; 2]>>, triangles: RefCell<Vec<[f32; 2]>>,
fill_rect: VecStorage<&'static FillRect>, fill_rect: VecStorage<FillRect>,
copy_tex: VecStorage<&'static CopyTexture>, copy_tex: VecStorage<&'static CopyTexture>,
} }
@ -233,7 +233,11 @@ fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) -> Option<SyncFile> {
} }
} }
GfxApiOpt::FillRect(f) => { GfxApiOpt::FillRect(f) => {
fill_rect.push(f); fill_rect.push(FillRect {
rect: f.rect,
color: f.effective_color(),
alpha: None,
});
i += 1; i += 1;
} }
GfxApiOpt::CopyTexture(c) => { GfxApiOpt::CopyTexture(c) => {
@ -249,7 +253,7 @@ fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) -> Option<SyncFile> {
triangles.clear(); triangles.clear();
let mut color = None; let mut color = None;
while i < fill_rect.len() { while i < fill_rect.len() {
let fr = fill_rect[i]; let fr = &fill_rect[i];
match color { match color {
None => color = Some(fr.color), None => color = Some(fr.color),
Some(c) if c == fr.color => {} Some(c) if c == fr.color => {}

View file

@ -505,7 +505,7 @@ impl VulkanRenderer {
let memory = &mut *self.memory.borrow_mut(); let memory = &mut *self.memory.borrow_mut();
let clear_value = clear.map(|clear| ClearValue { let clear_value = clear.map(|clear| ClearValue {
color: ClearColorValue { color: ClearColorValue {
float32: clear.to_array_srgb(), float32: clear.to_array_srgb(None),
}, },
}); });
let load_clear = memory.paint_regions.len() == 1 && { let load_clear = memory.paint_regions.len() == 1 && {
@ -620,7 +620,7 @@ impl VulkanRenderer {
GfxApiOpt::FillRect(r) => { GfxApiOpt::FillRect(r) => {
let push = FillPushConstants { let push = FillPushConstants {
pos: r.rect.to_points(), 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 { for region in &memory.paint_regions {
let mut push = push; let mut push = push;

View file

@ -441,11 +441,12 @@ impl GfxFramebuffer for TestGfxFb {
} }
}; };
let fill_rect = |f: &FillRect, staging: &mut [Color]| { let fill_rect = |f: &FillRect, staging: &mut [Color]| {
let color = f.effective_color();
let (x1, y1, x2, y2) = fb_points(width, height, &f.rect); let (x1, y1, x2, y2) = fb_points(width, height, &f.rect);
for y in y1..y2 { for y in y1..y2 {
for x in x1..x2 { for x in x1..x2 {
let dst = &mut staging[(y * width + x) as usize]; let dst = &mut staging[(y * width + x) as usize];
*dst = dst.and_then(&f.color); *dst = dst.and_then(&color);
} }
} }
}; };

View file

@ -89,7 +89,7 @@ impl Renderer<'_> {
let bar_bg = self.base.scale_rect(bar_bg); let bar_bg = self.base.scale_rect(bar_bg);
let c = theme.colors.bar_background.get(); let c = theme.colors.bar_background.get();
self.base 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(); let rd = output.render_data.borrow_mut();
if let Some(aw) = &rd.active_workspace { if let Some(aw) = &rd.active_workspace {
let c = match aw.captured { let c = match aw.captured {
@ -336,7 +336,8 @@ impl Renderer<'_> {
}; };
let color = self.state.theme.colors.highlight.get(); let color = self.state.theme.colors.highlight.get();
self.base.ops.push(GfxApiOpt::Sync); 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) { pub fn render_highlight(&mut self, rect: &Rect) {
@ -440,11 +441,7 @@ impl Renderer<'_> {
}; };
if !rect.is_empty() { if !rect.is_empty() {
self.base.ops.push(GfxApiOpt::Sync); self.base.ops.push(GfxApiOpt::Sync);
let mut color = *color; self.base.fill_scaled_boxes(&[rect], color, alpha);
if let Some(alpha) = alpha {
color = color * alpha;
}
self.base.fill_scaled_boxes(&[rect], &color);
} }
} }
} else { } else {

View file

@ -64,19 +64,27 @@ impl RendererBase<'_> {
rect rect
} }
pub fn fill_scaled_boxes(&mut self, boxes: &[Rect], color: &Color) { pub fn fill_scaled_boxes(&mut self, boxes: &[Rect], color: &Color, alpha: Option<f32>) {
self.fill_boxes3(boxes, color, 0, 0, true); self.fill_boxes3(boxes, color, alpha, 0, 0, true);
} }
pub fn fill_boxes(&mut self, boxes: &[Rect], color: &Color) { 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) { 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<f32>,
dx: i32,
dy: i32,
scaled: bool,
) {
if boxes.is_empty() || *color == Color::TRANSPARENT { if boxes.is_empty() || *color == Color::TRANSPARENT {
return; return;
} }
@ -97,6 +105,7 @@ impl RendererBase<'_> {
self.fb_height, self.fb_height,
), ),
color: *color, color: *color,
alpha,
})); }));
} }
} }
@ -129,6 +138,7 @@ impl RendererBase<'_> {
self.fb_height, self.fb_height,
), ),
color: *color, color: *color,
alpha: None,
})); }));
} }
} }

View file

@ -115,8 +115,9 @@ impl Color {
[to_u8(self.r), to_u8(self.g), to_u8(self.b), to_u8(self.a)] [to_u8(self.r), to_u8(self.g), to_u8(self.b), to_u8(self.a)]
} }
pub fn to_array_srgb(self) -> [f32; 4] { pub fn to_array_srgb(self, alpha: Option<f32>) -> [f32; 4] {
[self.r, self.g, self.b, self.a] let a = alpha.unwrap_or(1.0);
[self.r * a, self.g * a, self.b * a, self.a * a]
} }
#[expect(dead_code)] #[expect(dead_code)]