mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-02 06:41:14 +00:00
Qt style: Use an QImage that is backed by a SharedArray
This way we have one copy less of the data
This commit is contained in:
parent
f6edfb5e8e
commit
b60567d7f2
4 changed files with 91 additions and 19 deletions
|
@ -231,7 +231,7 @@ pub enum Resource {
|
|||
EmbeddedData(super::slice::Slice<'static, u8>),
|
||||
/// Raw ARGB
|
||||
#[allow(missing_docs)]
|
||||
EmbeddedRgbaImage { width: u32, height: u32, data: super::sharedarray::SharedArray<u8> },
|
||||
EmbeddedRgbaImage { width: u32, height: u32, data: super::sharedarray::SharedArray<u32> },
|
||||
}
|
||||
|
||||
impl Default for Resource {
|
||||
|
|
|
@ -159,6 +159,9 @@ impl<T: Clone> SharedArray<T> {
|
|||
size += 1;
|
||||
self.inner.as_mut().header.size = size;
|
||||
}
|
||||
if size == new_capacity {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,6 +182,45 @@ impl<T: Clone> SharedArray<T> {
|
|||
self.inner.as_mut().header.size += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Resize the array to the given size.
|
||||
/// If the array was smaller new elements will be initialized with the value.
|
||||
/// If the array was bigger, extra elements will be discared
|
||||
///
|
||||
/// ```
|
||||
/// use sixtyfps_corelib::SharedArray;
|
||||
/// let mut shared_array = SharedArray::<u32>::from_slice(&[1, 2, 3]);
|
||||
/// shared_array.resize(5, 8);
|
||||
/// assert_eq!(shared_array.as_slice(), &[1, 2, 3, 8, 8]);
|
||||
/// shared_array.resize(2, 0);
|
||||
/// assert_eq!(shared_array.as_slice(), &[1, 2]);
|
||||
/// ```
|
||||
pub fn resize(&mut self, new_len: usize, value: T) {
|
||||
if self.len() == new_len {
|
||||
return;
|
||||
}
|
||||
self.detach(new_len);
|
||||
// Safety: detach ensured that the array is not shared.
|
||||
let mut inner = unsafe { self.inner.as_mut() };
|
||||
|
||||
if inner.header.size >= new_len {
|
||||
while inner.header.size > new_len {
|
||||
inner.header.size -= 1;
|
||||
// Safety: The array was of size inner.header.size, so there should be an element there
|
||||
unsafe {
|
||||
drop(core::ptr::read(inner.data.as_mut_ptr().add(inner.header.size)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while inner.header.size < new_len {
|
||||
// Safety: The array must have a capacity of at least new_len because of the detach call earlier
|
||||
unsafe {
|
||||
core::ptr::write(inner.data.as_mut_ptr().add(inner.header.size), value.clone());
|
||||
}
|
||||
inner.header.size += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for SharedArray<T> {
|
||||
|
|
|
@ -494,10 +494,10 @@ impl RenderingPrimitivesBuilder for GLRenderingPrimitivesBuilder {
|
|||
)]
|
||||
}
|
||||
Resource::EmbeddedRgbaImage { width, height, data } => {
|
||||
// Safety: a slice of u32 can be transmuted to a slice of u8
|
||||
let slice = unsafe { data.as_slice().align_to().1 };
|
||||
let image = image::ImageBuffer::<image::Rgba<u8>, &[u8]>::from_raw(
|
||||
*width,
|
||||
*height,
|
||||
data.as_slice(),
|
||||
*width, *height, slice,
|
||||
)
|
||||
.unwrap();
|
||||
smallvec![GLRenderingPrimitivesBuilder::create_image(
|
||||
|
|
|
@ -42,10 +42,38 @@ macro_rules! get_size {
|
|||
|
||||
fn to_resource(image: qttypes::QImage) -> Resource {
|
||||
let size = image.size();
|
||||
// Safety: an slice of u8 can be converted to an slice of u32
|
||||
let data = unsafe { image.data().align_to::<u32>().1 };
|
||||
Resource::EmbeddedRgbaImage {
|
||||
width: size.width,
|
||||
height: size.height,
|
||||
data: SharedArray::from(image.data()),
|
||||
data: SharedArray::from_slice(data),
|
||||
}
|
||||
}
|
||||
|
||||
struct QImageWrapArray {
|
||||
/// The image reference the array, so the array must outlive the image without being detached or accessed
|
||||
img: qttypes::QImage,
|
||||
array: SharedArray<u32>,
|
||||
}
|
||||
|
||||
impl QImageWrapArray {
|
||||
pub fn new(size: qttypes::QSize, dpr: f32) -> Self {
|
||||
let mut array = SharedArray::default();
|
||||
array.resize((size.width * size.height) as usize, 0u32);
|
||||
let array_ptr = array.as_slice_mut().as_mut_ptr();
|
||||
let img = cpp!(unsafe [size as "QSize", array_ptr as "uchar*", dpr as "float"] -> qttypes::QImage as "QImage" {
|
||||
QImage img(array_ptr, size.width(), size.height(), size.width() * 4, QImage::Format_ARGB32_Premultiplied);
|
||||
img.setDevicePixelRatio(dpr);
|
||||
return img;
|
||||
});
|
||||
QImageWrapArray { img, array }
|
||||
}
|
||||
|
||||
pub fn to_resource(self) -> Resource {
|
||||
let size = self.img.size();
|
||||
drop(self.img);
|
||||
Resource::EmbeddedRgbaImage { width: size.width, height: size.height, data: self.array }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1140,6 +1168,9 @@ impl Item for NativeScrollView {
|
|||
) -> HighLevelRenderingPrimitive {
|
||||
let size: qttypes::QSize = get_size!(self);
|
||||
let dpr = window.scale_factor();
|
||||
|
||||
let mut imgarray = QImageWrapArray::new(size, dpr);
|
||||
|
||||
let data = Self::FIELD_OFFSETS.data.apply_pin(self).get();
|
||||
let left = Self::FIELD_OFFSETS.native_padding_left.apply_pin(self).get();
|
||||
let right = Self::FIELD_OFFSETS.native_padding_right.apply_pin(self).get();
|
||||
|
@ -1151,30 +1182,29 @@ impl Item for NativeScrollView {
|
|||
width: ((right - left) / dpr) as _,
|
||||
height: ((bottom - top) / dpr) as _,
|
||||
};
|
||||
let mut img = cpp!(unsafe [dpr as "float",size as "QSize", corner_rect as "QRectF"] -> qttypes::QImage as "QImage" {
|
||||
let img: &mut qttypes::QImage = &mut imgarray.img;
|
||||
cpp!(unsafe [img as "QImage*", corner_rect as "QRectF"] {
|
||||
ensure_initialized();
|
||||
auto [img, rect] = offline_style_rendering_image(size, dpr);
|
||||
QStyleOptionFrame frameOption;
|
||||
frameOption.frameShape = QFrame::StyledPanel;
|
||||
frameOption.lineWidth = 1;
|
||||
frameOption.midLineWidth = 0;
|
||||
frameOption.rect = corner_rect.toAlignedRect();
|
||||
QPainter p(&img);
|
||||
QPainter p(img);
|
||||
qApp->style()->drawPrimitive(QStyle::PE_PanelScrollAreaCorner, &frameOption, &p, global_widget());
|
||||
frameOption.rect = QRect(QPoint(), corner_rect.toAlignedRect().topLeft());
|
||||
qApp->style()->drawControl(QStyle::CE_ShapedFrame, &frameOption, &p, global_widget());
|
||||
return img;
|
||||
});
|
||||
|
||||
let mut draw_scrollbar = |horizontal: bool,
|
||||
rect: qttypes::QRectF,
|
||||
value: i32,
|
||||
page_size: i32,
|
||||
max: i32,
|
||||
active_controls: u32,
|
||||
pressed: bool| {
|
||||
let draw_scrollbar = |horizontal: bool,
|
||||
rect: qttypes::QRectF,
|
||||
value: i32,
|
||||
page_size: i32,
|
||||
max: i32,
|
||||
active_controls: u32,
|
||||
pressed: bool| {
|
||||
cpp!(unsafe [
|
||||
mut img as "QImage",
|
||||
img as "QImage*",
|
||||
value as "int",
|
||||
page_size as "int",
|
||||
max as "int",
|
||||
|
@ -1184,7 +1214,7 @@ impl Item for NativeScrollView {
|
|||
dpr as "float",
|
||||
horizontal as "bool"
|
||||
] {
|
||||
QPainter p(&img);
|
||||
QPainter p(img);
|
||||
auto r = rect.toAlignedRect();
|
||||
p.translate(r.topLeft()); // There is bugs in the styles if the scrollbar is not in (0,0)
|
||||
QStyleOptionSlider option;
|
||||
|
@ -1232,7 +1262,7 @@ impl Item for NativeScrollView {
|
|||
data.pressed == 1,
|
||||
);
|
||||
|
||||
return HighLevelRenderingPrimitive::Image { source: to_resource(img) };
|
||||
return HighLevelRenderingPrimitive::Image { source: imgarray.to_resource() };
|
||||
}
|
||||
|
||||
fn rendering_variables(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue