mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-31 15:47:26 +00:00
swrenderer: Support multiple rectangles for the dirty regions
This allow to be much faster in the case two small area of the screen changes.
This commit is contained in:
parent
79a188516a
commit
f45bab6a3f
6 changed files with 594 additions and 249 deletions
|
@ -8,18 +8,20 @@
|
|||
|
||||
use super::{PhysicalLength, PhysicalRect};
|
||||
use crate::graphics::{PixelFormat, Rgb8Pixel};
|
||||
use crate::lengths::{PointLengths, RectLengths, SizeLengths};
|
||||
use crate::lengths::{PointLengths, SizeLengths};
|
||||
use crate::software_renderer::fixed::Fixed;
|
||||
use crate::Color;
|
||||
use derive_more::{Add, Mul, Sub};
|
||||
use integer_sqrt::IntegerSquareRoot;
|
||||
|
||||
/// Draw one line of the texture in the line buffer
|
||||
///
|
||||
pub(super) fn draw_texture_line(
|
||||
span: &PhysicalRect,
|
||||
line: PhysicalLength,
|
||||
texture: &super::SceneTexture,
|
||||
line_buffer: &mut [impl TargetPixel],
|
||||
extra_clip: i16,
|
||||
) {
|
||||
let super::SceneTexture {
|
||||
data,
|
||||
|
@ -27,19 +29,16 @@ pub(super) fn draw_texture_line(
|
|||
pixel_stride,
|
||||
extra: super::SceneTextureExtra { colorize, alpha, rotation, dx, dy, off_x, off_y },
|
||||
} = *texture;
|
||||
let span_size = span.size.cast::<usize>();
|
||||
|
||||
let source_size = texture.source_size().cast::<i32>();
|
||||
let len = line_buffer.len();
|
||||
let y = line - span.origin.y_length();
|
||||
let y = if rotation.mirror_width() { span.size.height - y.get() - 1 } else { y.get() } as i32;
|
||||
|
||||
let line_buffer = &mut line_buffer[span.origin.x as usize..];
|
||||
|
||||
let y = (line - span.origin.y_length()).cast::<usize>();
|
||||
let y = if rotation.mirror_width() { span_size.height - y.get() - 1 } else { y.get() } as i32;
|
||||
|
||||
let off_x = Fixed::<i32, 8>::from_fixed(off_x);
|
||||
let off_y = Fixed::<i32, 8>::from_fixed(off_y);
|
||||
let dx = Fixed::<i32, 8>::from_fixed(dx);
|
||||
let dy = Fixed::<i32, 8>::from_fixed(dy);
|
||||
let off_x = Fixed::<i32, 8>::from_fixed(off_x) + dx * extra_clip as i32;
|
||||
|
||||
if !rotation.is_transpose() {
|
||||
let mut delta = dx;
|
||||
|
@ -58,8 +57,7 @@ pub(super) fn draw_texture_line(
|
|||
// the accumulated error in image pixels
|
||||
let mut acc_err;
|
||||
if rotation.mirror_height() {
|
||||
let o = (off_x + (delta * (span_size.width as i32 - 1)))
|
||||
% Fixed::from_integer(source_size.width);
|
||||
let o = (off_x + (delta * (len as i32 - 1))) % Fixed::from_integer(source_size.width);
|
||||
pos = init + o;
|
||||
init += Fixed::from_integer(source_size.width);
|
||||
end = (o / delta) as usize + 1;
|
||||
|
@ -76,9 +74,9 @@ pub(super) fn draw_texture_line(
|
|||
end += 1;
|
||||
}
|
||||
}
|
||||
end = end.min(span_size.width);
|
||||
end = end.min(len);
|
||||
let mut begin = 0;
|
||||
while begin < span_size.width {
|
||||
while begin < len {
|
||||
fetch_blend_pixel(
|
||||
&mut line_buffer[begin..end],
|
||||
format,
|
||||
|
@ -108,7 +106,7 @@ pub(super) fn draw_texture_line(
|
|||
end += 1;
|
||||
}
|
||||
};
|
||||
end = end.min(span_size.width);
|
||||
end = end.min(len);
|
||||
}
|
||||
} else {
|
||||
let bpp = format.bpp();
|
||||
|
@ -124,8 +122,8 @@ pub(super) fn draw_texture_line(
|
|||
let mut acc_err;
|
||||
if rotation.mirror_height() {
|
||||
row_init = Fixed::from_integer(source_size.height);
|
||||
row = (off_y + (row_delta * (span_size.width as i32 - 1)))
|
||||
% Fixed::from_integer(source_size.height);
|
||||
row =
|
||||
(off_y + (row_delta * (len as i32 - 1))) % Fixed::from_integer(source_size.height);
|
||||
end = (row / row_delta) as usize + 1;
|
||||
acc_err = -row_delta + row % row_delta;
|
||||
row_delta = -row_delta;
|
||||
|
@ -139,9 +137,9 @@ pub(super) fn draw_texture_line(
|
|||
end += 1;
|
||||
}
|
||||
};
|
||||
end = end.min(span_size.width);
|
||||
end = end.min(len);
|
||||
let mut begin = 0;
|
||||
while begin < span_size.width {
|
||||
while begin < len {
|
||||
fetch_blend_pixel(
|
||||
&mut line_buffer[begin..end],
|
||||
format,
|
||||
|
@ -171,7 +169,7 @@ pub(super) fn draw_texture_line(
|
|||
end += 1;
|
||||
}
|
||||
};
|
||||
end = end.min(span_size.width);
|
||||
end = end.min(len);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -283,6 +281,8 @@ pub(super) fn draw_rounded_rectangle_line(
|
|||
line: PhysicalLength,
|
||||
rr: &super::RoundedRectangle,
|
||||
line_buffer: &mut [impl TargetPixel],
|
||||
extra_left_clip: i16,
|
||||
extra_right_clip: i16,
|
||||
) {
|
||||
/// This is an integer shifted by 4 bits.
|
||||
/// Note: this is not a "fixed point" because multiplication and sqrt operation operate to
|
||||
|
@ -313,7 +313,7 @@ pub(super) fn draw_rounded_rectangle_line(
|
|||
Self(self.0 * rhs.0)
|
||||
}
|
||||
}
|
||||
let pos_x = span.origin.x as usize;
|
||||
let width = line_buffer.len();
|
||||
let y1 = (line - span.origin.y_length()) + rr.top_clip;
|
||||
let y2 = (span.origin.y_length() + span.size.height_length() - line) + rr.bottom_clip
|
||||
- PhysicalLength::new(1);
|
||||
|
@ -334,7 +334,8 @@ pub(super) fn draw_rounded_rectangle_line(
|
|||
}
|
||||
};
|
||||
let rev = |x: Shifted| {
|
||||
(Shifted::new(span.size.width) + Shifted::new(rr.right_clip.get())).saturating_sub(x)
|
||||
(Shifted::new(width) + Shifted::new(rr.right_clip.get() + extra_right_clip))
|
||||
.saturating_sub(x)
|
||||
};
|
||||
let calculate_xxxx = |r: i16, y: i16| {
|
||||
let r = Shifted::new(r);
|
||||
|
@ -374,10 +375,10 @@ pub(super) fn draw_rounded_rectangle_line(
|
|||
(x1, x2, x3, x4, rev(x5), rev(x6), rev(x7), rev(x8))
|
||||
};
|
||||
anti_alias(
|
||||
x1.saturating_sub(Shifted::new(rr.left_clip.get())),
|
||||
x2.saturating_sub(Shifted::new(rr.left_clip.get())),
|
||||
x1.saturating_sub(Shifted::new(rr.left_clip.get() + extra_left_clip)),
|
||||
x2.saturating_sub(Shifted::new(rr.left_clip.get() + extra_left_clip)),
|
||||
&mut |x, cov| {
|
||||
if x >= span.size.width as usize {
|
||||
if x >= width {
|
||||
return;
|
||||
}
|
||||
let c = if border == ZERO { rr.inner_color } else { rr.border_color };
|
||||
|
@ -387,55 +388,57 @@ pub(super) fn draw_rounded_rectangle_line(
|
|||
green: (((c.green as u32) * cov as u32) / 255) as u8,
|
||||
blue: (((c.blue as u32) * cov as u32) / 255) as u8,
|
||||
};
|
||||
line_buffer[pos_x + x].blend(col);
|
||||
line_buffer[x].blend(col);
|
||||
},
|
||||
);
|
||||
if y < rr.width {
|
||||
// up or down border (x2 .. x7)
|
||||
let l = x2.ceil().saturating_sub(rr.left_clip.get() as u32).min(span.size.width as u32)
|
||||
as usize;
|
||||
let r = x7.floor().min(span.size.width as u32) as usize;
|
||||
let l = x2
|
||||
.ceil()
|
||||
.saturating_sub((rr.left_clip.get() + extra_left_clip) as u32)
|
||||
.min(width as u32) as usize;
|
||||
let r = x7.floor().min(width as u32) as usize;
|
||||
if l < r {
|
||||
TargetPixel::blend_slice(&mut line_buffer[pos_x + l..pos_x + r], rr.border_color)
|
||||
TargetPixel::blend_slice(&mut line_buffer[l..r], rr.border_color)
|
||||
}
|
||||
} else {
|
||||
if border > ZERO {
|
||||
// 3. draw the border (between x2 and x3)
|
||||
if ONE + x2 <= x3 {
|
||||
TargetPixel::blend_slice(
|
||||
&mut line_buffer[pos_x
|
||||
+ x2.ceil()
|
||||
.saturating_sub(rr.left_clip.get() as u32)
|
||||
.min(span.size.width as u32) as usize
|
||||
..pos_x
|
||||
+ x3.floor()
|
||||
.saturating_sub(rr.left_clip.get() as u32)
|
||||
.min(span.size.width as u32)
|
||||
as usize],
|
||||
&mut line_buffer[x2
|
||||
.ceil()
|
||||
.saturating_sub((rr.left_clip.get() + extra_left_clip) as u32)
|
||||
.min(width as u32) as usize
|
||||
..x3.floor()
|
||||
.saturating_sub((rr.left_clip.get() + extra_left_clip) as u32)
|
||||
.min(width as u32) as usize],
|
||||
rr.border_color,
|
||||
)
|
||||
}
|
||||
// 4. anti-aliasing for the contents (x3 .. x4)
|
||||
anti_alias(
|
||||
x3.saturating_sub(Shifted::new(rr.left_clip.get())),
|
||||
x4.saturating_sub(Shifted::new(rr.left_clip.get())),
|
||||
x3.saturating_sub(Shifted::new(rr.left_clip.get() + extra_left_clip)),
|
||||
x4.saturating_sub(Shifted::new(rr.left_clip.get() + extra_left_clip)),
|
||||
&mut |x, cov| {
|
||||
if x >= span.size.width as usize {
|
||||
if x >= width {
|
||||
return;
|
||||
}
|
||||
let col = interpolate_color(cov, rr.border_color, rr.inner_color);
|
||||
line_buffer[pos_x + x].blend(col);
|
||||
line_buffer[x].blend(col);
|
||||
},
|
||||
);
|
||||
}
|
||||
if rr.inner_color.alpha > 0 {
|
||||
// 5. inside (x4 .. x5)
|
||||
let begin =
|
||||
x4.ceil().saturating_sub(rr.left_clip.get() as u32).min(span.size.width as u32);
|
||||
let end = x5.floor().min(span.size.width as u32);
|
||||
let begin = x4
|
||||
.ceil()
|
||||
.saturating_sub((rr.left_clip.get() + extra_left_clip) as u32)
|
||||
.min(width as u32);
|
||||
let end = x5.floor().min(width as u32);
|
||||
if begin < end {
|
||||
TargetPixel::blend_slice(
|
||||
&mut line_buffer[pos_x + begin as usize..pos_x + end as usize],
|
||||
&mut line_buffer[begin as usize..end as usize],
|
||||
rr.inner_color,
|
||||
)
|
||||
}
|
||||
|
@ -443,24 +446,24 @@ pub(super) fn draw_rounded_rectangle_line(
|
|||
if border > ZERO {
|
||||
// 6. border anti-aliasing: x5..x6
|
||||
anti_alias(x5, x6, &mut |x, cov| {
|
||||
if x >= span.size.width as usize {
|
||||
if x >= width {
|
||||
return;
|
||||
}
|
||||
let col = interpolate_color(cov, rr.inner_color, rr.border_color);
|
||||
line_buffer[pos_x + x].blend(col)
|
||||
line_buffer[x].blend(col)
|
||||
});
|
||||
// 7. border x6 .. x7
|
||||
if ONE + x6 <= x7 {
|
||||
TargetPixel::blend_slice(
|
||||
&mut line_buffer[pos_x + x6.ceil().min(span.size.width as u32) as usize
|
||||
..pos_x + x7.floor().min(span.size.width as u32) as usize],
|
||||
&mut line_buffer[x6.ceil().min(width as u32) as usize
|
||||
..x7.floor().min(width as u32) as usize],
|
||||
rr.border_color,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
anti_alias(x7, x8, &mut |x, cov| {
|
||||
if x >= span.size.width as usize {
|
||||
if x >= width {
|
||||
return;
|
||||
}
|
||||
let c = if border == ZERO { rr.inner_color } else { rr.border_color };
|
||||
|
@ -470,7 +473,7 @@ pub(super) fn draw_rounded_rectangle_line(
|
|||
green: (((c.green as u32) * (255 - cov) as u32) / 255) as u8,
|
||||
blue: (((c.blue as u32) * (255 - cov) as u32) / 255) as u8,
|
||||
};
|
||||
line_buffer[pos_x + x].blend(col);
|
||||
line_buffer[x].blend(col);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -505,11 +508,9 @@ pub(super) fn draw_gradient_line(
|
|||
rect: &PhysicalRect,
|
||||
line: PhysicalLength,
|
||||
g: &super::GradientCommand,
|
||||
line_buffer: &mut [impl TargetPixel],
|
||||
mut buffer: &mut [impl TargetPixel],
|
||||
extra_left_clip: i16,
|
||||
) {
|
||||
let mut buffer = &mut line_buffer
|
||||
[rect.origin.x as usize..(rect.origin.x_length() + rect.width_length()).get() as usize];
|
||||
|
||||
let fill_col1 = g.flags & 0b010 != 0;
|
||||
let fill_col2 = g.flags & 0b100 != 0;
|
||||
let invert_slope = g.flags & 0b1 != 0;
|
||||
|
@ -539,7 +540,8 @@ pub(super) fn draw_gradient_line(
|
|||
(y * size_x * (255 - start)) / (size_y * start)
|
||||
} else {
|
||||
(size_y - y) * size_x * (255 - start) / (size_y * start)
|
||||
} + g.left_clip.get() as i32;
|
||||
} + g.left_clip.get() as i32
|
||||
+ extra_left_clip as i32;
|
||||
|
||||
let len = ((255 * size_x) / start) as usize;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue