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 {
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.

View file

@ -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<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 {

View file

@ -202,7 +202,7 @@ enum RenderError {
#[derive(Default)]
struct GfxGlState {
triangles: RefCell<Vec<[f32; 2]>>,
fill_rect: VecStorage<&'static FillRect>,
fill_rect: VecStorage<FillRect>,
copy_tex: VecStorage<&'static CopyTexture>,
}
@ -233,7 +233,11 @@ fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) -> Option<SyncFile> {
}
}
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<SyncFile> {
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 => {}

View file

@ -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;

View file

@ -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);
}
}
};

View file

@ -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 {

View file

@ -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<f32>) {
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<f32>,
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,
}));
}
}

View file

@ -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>) -> [f32; 4] {
let a = alpha.unwrap_or(1.0);
[self.r * a, self.g * a, self.b * a, self.a * a]
}
#[expect(dead_code)]