Fix window background fill

Don't blend the background but fill it when going through ProcessScene.
This commit is contained in:
Simon Hausmann 2025-02-21 11:06:36 +01:00 committed by Simon Hausmann
parent 4c1b7762bd
commit 910d45a01f
6 changed files with 91 additions and 33 deletions

View file

@ -327,6 +327,7 @@ fn gen_corelib(
"SortOrder",
"BitmapFont",
"PhysicalRegion",
"CompositionMode",
]
.iter()
.chain(items.iter())

View file

@ -540,6 +540,7 @@ struct Rgb565Pixel
# ifdef SLINT_FEATURE_EXPERIMENTAL
using cbindgen_private::CompositionMode;
using cbindgen_private::types::TexturePixelFormat;
/// This structure describes the properties of a texture for blending with
@ -587,14 +588,16 @@ struct TargetPixelBuffer
/// Fill a rectangle at the specified pixel coordinates with the given color. Return true
/// if the operation succeeded; false otherwise;
virtual bool fill_rectangle(int16_t x, int16_t y, int16_t width, int16_t height,
const RgbaColor<uint8_t> &premultiplied_color) = 0;
const RgbaColor<uint8_t> &premultiplied_color,
CompositionMode composition_mode) = 0;
/// Draw a portion of provided texture to the specified pixel coordinates.
/// Each pixel of the texture is to be blended with the given colorize color as well as the
/// alpha value.
virtual bool draw_texture(int16_t x, int16_t y, int16_t width, int16_t height,
const Texture &texture, const RgbaColor<uint8_t> &colorize,
uint8_t alpha, int screen_rotation_degrees) = 0;
uint8_t alpha, int screen_rotation_degrees,
CompositionMode composition_mode) = 0;
};
# endif
@ -761,16 +764,18 @@ public:
},
.fill_rectangle =
[](void *self, int16_t x, int16_t y, int16_t width, int16_t height, uint8_t red,
uint8_t green, uint8_t blue, uint8_t alpha) {
uint8_t green, uint8_t blue, uint8_t alpha,
CompositionMode composition_mode) {
auto *buffer = reinterpret_cast<TargetPixelBuffer<Rgb8Pixel> *>(self);
return buffer->fill_rectangle(
x, y, width, height,
Color::from_argb_uint8(alpha, red, green, blue));
Color::from_argb_uint8(alpha, red, green, blue), composition_mode);
},
.draw_texture =
[](void *self, int16_t x, int16_t y, int16_t width, int16_t height,
const cbindgen_private::CppInternalTexture *internal_texture,
uint32_t colorize, uint8_t alpha, int32_t screen_rotation_degrees) {
uint32_t colorize, uint8_t alpha, int32_t screen_rotation_degrees,
CompositionMode composition_mode) {
auto *buffer = reinterpret_cast<TargetPixelBuffer<Rgb8Pixel> *>(self);
Texture texture {
.bytes = std::span<const uint8_t> { internal_texture->bytes,
@ -786,7 +791,7 @@ public:
};
return buffer->draw_texture(x, y, width, height, texture,
Color::from_argb_encoded(colorize), alpha,
screen_rotation_degrees);
screen_rotation_degrees, composition_mode);
}
};
auto r =
@ -814,16 +819,18 @@ public:
},
.fill_rectangle =
[](void *self, int16_t x, int16_t y, int16_t width, int16_t height, uint8_t red,
uint8_t green, uint8_t blue, uint8_t alpha) {
uint8_t green, uint8_t blue, uint8_t alpha,
CompositionMode composition_mode) {
auto *buffer = reinterpret_cast<TargetPixelBuffer<Rgb565Pixel> *>(self);
return buffer->fill_rectangle(
x, y, width, height,
Color::from_argb_uint8(alpha, red, green, blue));
Color::from_argb_uint8(alpha, red, green, blue), composition_mode);
},
.draw_texture =
[](void *self, int16_t x, int16_t y, int16_t width, int16_t height,
const cbindgen_private::CppInternalTexture *internal_texture,
uint32_t colorize, uint8_t alpha, int32_t screen_rotation_degrees) {
uint32_t colorize, uint8_t alpha, int32_t screen_rotation_degrees,
CompositionMode composition_mode) {
auto *buffer = reinterpret_cast<TargetPixelBuffer<Rgb565Pixel> *>(self);
Texture texture {
.bytes = std::span<const uint8_t> { internal_texture->bytes,
@ -839,7 +846,7 @@ public:
};
return buffer->draw_texture(x, y, width, height, texture,
Color::from_argb_encoded(colorize), alpha,
screen_rotation_degrees);
screen_rotation_degrees, composition_mode);
}
};
auto r = cbindgen_private::slint_software_renderer_render_accel_rgb565(inner,

View file

@ -362,7 +362,8 @@ mod software_renderer {
#[cfg(feature = "experimental")]
use i_slint_core::software_renderer::{
PremultipliedRgbaColor, RenderingRotation, TargetPixelBuffer, Texture, TexturePixelFormat,
CompositionMode, PremultipliedRgbaColor, RenderingRotation, TargetPixelBuffer, Texture,
TexturePixelFormat,
};
#[cfg(feature = "experimental")]
@ -404,6 +405,7 @@ mod software_renderer {
u8,
u8,
u8,
CompositionMode,
) -> bool,
draw_texture: unsafe extern "C" fn(
CppTargetPixelBufferUserData,
@ -415,6 +417,7 @@ mod software_renderer {
u32,
u8,
i32,
CompositionMode,
) -> bool,
}
@ -442,6 +445,7 @@ mod software_renderer {
width: i16,
height: i16,
color: PremultipliedRgbaColor,
composition_mode: CompositionMode,
) -> bool {
unsafe {
(self.fill_rectangle)(
@ -454,6 +458,7 @@ mod software_renderer {
color.green,
color.blue,
color.alpha,
composition_mode,
)
}
}
@ -468,6 +473,7 @@ mod software_renderer {
colorize: u32,
alpha: u8,
rotation: RenderingRotation,
composition_mode: CompositionMode,
) -> bool {
unsafe {
(self.draw_texture)(
@ -491,6 +497,7 @@ mod software_renderer {
colorize,
alpha,
rotation.angle() as i32,
composition_mode,
)
}
}
@ -517,6 +524,7 @@ mod software_renderer {
u8,
u8,
u8,
CompositionMode,
) -> bool,
draw_texture: unsafe extern "C" fn(
CppTargetPixelBufferUserData,
@ -528,6 +536,7 @@ mod software_renderer {
u32,
u8,
i32,
CompositionMode,
) -> bool,
}
@ -555,6 +564,7 @@ mod software_renderer {
width: i16,
height: i16,
color: PremultipliedRgbaColor,
composition_mode: CompositionMode,
) -> bool {
unsafe {
(self.fill_rectangle)(
@ -567,6 +577,7 @@ mod software_renderer {
color.green,
color.blue,
color.alpha,
composition_mode,
)
}
}
@ -581,6 +592,7 @@ mod software_renderer {
colorize: u32,
alpha: u8,
rotation: RenderingRotation,
composition_mode: CompositionMode,
) -> bool {
unsafe {
(self.draw_texture)(
@ -604,6 +616,7 @@ mod software_renderer {
colorize,
alpha,
rotation.angle() as i32,
composition_mode,
)
}
}

View file

@ -214,6 +214,21 @@ impl From<RequestedOpenGLVersion> for RequestedGraphicsAPI {
}
}
/// This enum describes the how pixels from a source are merged with the pixels in a destination image.
/// This is a sub-set of the standard [Porter-Duff](https://en.wikipedia.org/wiki/Alpha_compositing) modes.
#[repr(u8)]
#[allow(dead_code)]
#[derive(Default, Copy, Clone, Debug)]
#[non_exhaustive]
pub enum CompositionMode {
/// Only pixels from the source target are drawn.
Source,
/// The source is placed over the destination.
#[default]
SourceOver,
// TODO: maybe add more modes (e.g. xor, plus darker, etc.)
}
/// Internal module for use by cbindgen and the C++ platform API layer.
#[cfg(feature = "ffi")]
pub mod ffi {

View file

@ -366,10 +366,10 @@ fn region_line_ranges(
mod target_pixel_buffer;
#[cfg(feature = "experimental")]
pub use target_pixel_buffer::{TargetPixelBuffer, Texture, TexturePixelFormat};
pub use target_pixel_buffer::{CompositionMode, TargetPixelBuffer, Texture, TexturePixelFormat};
#[cfg(not(feature = "experimental"))]
use target_pixel_buffer::TexturePixelFormat;
use target_pixel_buffer::{CompositionMode, TexturePixelFormat};
struct TargetPixelSlice<'a, T> {
data: &'a mut [T],
@ -592,9 +592,10 @@ impl SoftwareRenderer {
// TODO: gradient background
PremultipliedRgbaColor::blend(&mut bg, background.color().into());
renderer.actual_renderer.processor.dirty_region = dirty_region.clone();
renderer.actual_renderer.processor.process_rectangle(
renderer.actual_renderer.processor.process_rectangle_impl(
PhysicalRect::from_size(euclid::Size2D::new(size.width, size.height)),
bg,
CompositionMode::Source,
);
for (component, origin) in components {
@ -1218,6 +1219,7 @@ impl<T: TargetPixel, B: target_pixel_buffer::TargetPixelBuffer<Pixel = T>> Rende
texture.extra.colorize.as_argb_encoded(),
texture.extra.alpha,
texture.extra.rotation,
CompositionMode::default(),
) {
self.foreach_region(&geometry, |buffer, rect, extra_left_clip, extra_right_clip| {
let begin = rect.min_x();
@ -1235,6 +1237,41 @@ impl<T: TargetPixel, B: target_pixel_buffer::TargetPixelBuffer<Pixel = T>> Rende
});
}
}
fn process_rectangle_impl(
&mut self,
geometry: PhysicalRect,
color: PremultipliedRgbaColor,
composition_mode: CompositionMode,
) {
if !self.buffer.fill_rectangle(
geometry.origin.x,
geometry.origin.y,
geometry.size.width,
geometry.size.height,
color,
composition_mode,
) {
self.foreach_region(&geometry, |buffer, rect, _extra_left_clip, _extra_right_clip| {
let begin = rect.min_x();
let end = rect.max_x();
for l in rect.min_y()..rect.max_y() {
match composition_mode {
CompositionMode::Source => {
let mut fill_col = T::background();
T::blend(&mut fill_col, color);
buffer.line_slice(l as usize)[begin as usize..end as usize]
.fill(fill_col)
}
CompositionMode::SourceOver => <T as TargetPixel>::blend_slice(
&mut buffer.line_slice(l as usize)[begin as usize..end as usize],
color,
),
}
}
})
};
}
}
impl<T: TargetPixel, B: target_pixel_buffer::TargetPixelBuffer<Pixel = T>> ProcessScene
@ -1250,24 +1287,7 @@ impl<T: TargetPixel, B: target_pixel_buffer::TargetPixelBuffer<Pixel = T>> Proce
}
fn process_rectangle(&mut self, geometry: PhysicalRect, color: PremultipliedRgbaColor) {
if !self.buffer.fill_rectangle(
geometry.origin.x,
geometry.origin.y,
geometry.size.width,
geometry.size.height,
color,
) {
self.foreach_region(&geometry, |buffer, rect, _extra_left_clip, _extra_right_clip| {
let begin = rect.min_x();
let end = rect.max_x();
for l in rect.min_y()..rect.max_y() {
<T as TargetPixel>::blend_slice(
&mut buffer.line_slice(l as usize)[begin as usize..end as usize],
color,
)
}
})
};
self.process_rectangle_impl(geometry, color, CompositionMode::default());
}
fn process_rounded_rectangle(&mut self, geometry: PhysicalRect, rr: RoundedRectangle) {

View file

@ -3,7 +3,7 @@
use super::*;
pub use crate::graphics::TexturePixelFormat;
pub use crate::graphics::{CompositionMode, TexturePixelFormat};
/// This structure describes the properties of a texture for blending with [`TargetPixelBuffer::draw_texture`].
#[allow(dead_code)]
@ -56,6 +56,7 @@ pub trait TargetPixelBuffer {
_width: i16,
_height: i16,
_color: PremultipliedRgbaColor,
_composition_mode: CompositionMode,
) -> bool {
false
}
@ -73,6 +74,7 @@ pub trait TargetPixelBuffer {
_colorize: u32,
_alpha: u8,
_rotation: RenderingRotation,
_composition_mode: CompositionMode,
) -> bool {
false
}