mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-04 10:50:00 +00:00
Expose the individual rectangle in the dirty region
This commit is contained in:
parent
f45bab6a3f
commit
5955d19706
7 changed files with 117 additions and 29 deletions
|
@ -216,6 +216,8 @@ fn default_config() -> cbindgen::Config {
|
|||
.iter()
|
||||
.cloned()
|
||||
.collect();
|
||||
config.structure.associated_constants_in_body = true;
|
||||
config.constant.allow_constexpr = true;
|
||||
config
|
||||
}
|
||||
|
||||
|
@ -295,6 +297,7 @@ fn gen_corelib(
|
|||
"Rect",
|
||||
"SortOrder",
|
||||
"BitmapFont",
|
||||
"PhysicalRegion",
|
||||
]
|
||||
.iter()
|
||||
.chain(items.iter())
|
||||
|
|
|
@ -225,10 +225,9 @@ void EspPlatform::run_event_loop()
|
|||
if (buffer1) {
|
||||
auto region = m_window->m_renderer.render(buffer1.value(),
|
||||
rotated ? size.height : size.width);
|
||||
auto o = region.bounding_box_origin();
|
||||
auto s = region.bounding_box_size();
|
||||
if (s.width > 0 && s.height > 0) {
|
||||
if (buffer2) {
|
||||
if (buffer2) {
|
||||
auto s = region.bounding_box_size();
|
||||
if (s.width > 0 && s.height > 0) {
|
||||
#if SOC_LCD_RGB_SUPPORTED && ESP_IDF_VERSION_MAJOR >= 5
|
||||
xSemaphoreGive(sem_gui_ready);
|
||||
xSemaphoreTake(sem_vsync_end, portMAX_DELAY);
|
||||
|
@ -241,7 +240,9 @@ void EspPlatform::run_event_loop()
|
|||
buffer1->data());
|
||||
|
||||
std::swap(buffer1, buffer2);
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
for (auto [o, s] : region.rectangles()) {
|
||||
for (int y = o.y; y < o.y + s.height; y++) {
|
||||
for (int x = o.x; x < o.x + s.width; x++) {
|
||||
// Swap endianess to big endian
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
#include <ranges>
|
||||
|
||||
struct xcb_connection_t;
|
||||
struct wl_surface;
|
||||
|
@ -564,18 +565,68 @@ public:
|
|||
/// Returns the size of the bounding box of this region.
|
||||
PhysicalSize bounding_box_size() const
|
||||
{
|
||||
return PhysicalSize({ uint32_t(inner.width), uint32_t(inner.height) });
|
||||
if (inner.count == 0) {
|
||||
return PhysicalSize();
|
||||
}
|
||||
auto origin = bounding_box_origin();
|
||||
PhysicalSize size({ .width = uint32_t(inner.rectangles[0].max.x - origin.x),
|
||||
.height = uint32_t(inner.rectangles[0].max.y - origin.y) });
|
||||
for (size_t i = 1; i < inner.count; ++i) {
|
||||
size.width = std::max(size.width, uint32_t(inner.rectangles[i].max.x - origin.x));
|
||||
size.height = std::max(size.height, uint32_t(inner.rectangles[i].max.y - origin.y));
|
||||
}
|
||||
return size;
|
||||
}
|
||||
/// Returns the origin of the bounding box of this region.
|
||||
PhysicalPosition bounding_box_origin() const
|
||||
{
|
||||
return PhysicalPosition({ inner.x, inner.y });
|
||||
if (inner.count == 0) {
|
||||
return PhysicalPosition();
|
||||
}
|
||||
PhysicalPosition origin(
|
||||
{ .x = inner.rectangles[0].min.x, .y = inner.rectangles[0].min.y });
|
||||
for (size_t i = 1; i < inner.count; ++i) {
|
||||
origin.x = std::min<int>(origin.x, inner.rectangles[i].min.x);
|
||||
origin.y = std::min<int>(origin.y, inner.rectangles[i].min.y);
|
||||
}
|
||||
return origin;
|
||||
}
|
||||
|
||||
/// Returns a view on all the rectangles in this region.
|
||||
/// The returned type is a C++ view over PhysicalRegion::Rect structs.
|
||||
///
|
||||
/// It can be used like so:
|
||||
/// ```cpp
|
||||
/// for (auto [origin, size] : region.rectangles()) {
|
||||
/// // Do something with the rect
|
||||
/// }
|
||||
/// ```
|
||||
auto rectangles() const
|
||||
{
|
||||
return std::views::counted(inner.rectangles, inner.count)
|
||||
| std::views::transform([](const auto &box) {
|
||||
return Rect {
|
||||
.origin = PhysicalPosition({ .x = box.min.x, .y = box.min.y }),
|
||||
.size = PhysicalSize({ .width = uint32_t(box.max.x - box.min.x),
|
||||
.height = uint32_t(box.max.y - box.min.y) })
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/// A Rectangle defined with an origin and a size.
|
||||
/// The PhysicalRegion::rectangles() function returns a view over them
|
||||
struct Rect
|
||||
{
|
||||
/// The origin of the rectangle.
|
||||
PhysicalPosition origin;
|
||||
/// The size of the rectangle.
|
||||
PhysicalSize size;
|
||||
};
|
||||
|
||||
private:
|
||||
cbindgen_private::types::IntRect inner;
|
||||
cbindgen_private::PhysicalRegion inner;
|
||||
friend class SoftwareRenderer;
|
||||
PhysicalRegion(cbindgen_private::types::IntRect inner) : inner(inner) { }
|
||||
PhysicalRegion(cbindgen_private::PhysicalRegion inner) : inner(std::move(inner)) { }
|
||||
};
|
||||
|
||||
/// This enum describes which parts of the buffer passed to the SoftwareRenderer may be
|
||||
|
|
|
@ -32,13 +32,13 @@ using Size2D = Size<T>;
|
|||
struct LogicalSize : public Size<float>
|
||||
{
|
||||
/// Explicitly convert a Size<float> to a LogicalSize
|
||||
explicit LogicalSize(const Size<float> s) : Size<float>(s) {};
|
||||
explicit constexpr LogicalSize(const Size<float> s = { 0, 0 }) : Size<float>(s) { }
|
||||
};
|
||||
/// A size given in physical pixels.
|
||||
struct PhysicalSize : public Size<uint32_t>
|
||||
{
|
||||
/// Explicitly convert a Size<uint32_t> to a LogicalSize
|
||||
explicit PhysicalSize(const Size<uint32_t> s) : Size<uint32_t>(s) {};
|
||||
explicit constexpr PhysicalSize(const Size<uint32_t> s = { 0, 0 }) : Size<uint32_t>(s) { }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -355,8 +355,10 @@ pub unsafe extern "C" fn slint_platform_task_run(event: PlatformTaskOpaque) {
|
|||
mod software_renderer {
|
||||
use super::*;
|
||||
type SoftwareRendererOpaque = *const c_void;
|
||||
use i_slint_core::graphics::{IntRect, Rgb8Pixel};
|
||||
use i_slint_core::software_renderer::{RepaintBufferType, Rgb565Pixel, SoftwareRenderer};
|
||||
use i_slint_core::graphics::Rgb8Pixel;
|
||||
use i_slint_core::software_renderer::{
|
||||
PhysicalRegion, RepaintBufferType, Rgb565Pixel, SoftwareRenderer,
|
||||
};
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn slint_software_renderer_new(
|
||||
|
@ -383,12 +385,10 @@ mod software_renderer {
|
|||
buffer: *mut Rgb8Pixel,
|
||||
buffer_len: usize,
|
||||
pixel_stride: usize,
|
||||
) -> IntRect {
|
||||
) -> PhysicalRegion {
|
||||
let buffer = core::slice::from_raw_parts_mut(buffer, buffer_len);
|
||||
let renderer = &*(r as *const SoftwareRenderer);
|
||||
let r = renderer.render(buffer, pixel_stride);
|
||||
let (orig, size) = (r.bounding_box_origin(), r.bounding_box_size());
|
||||
i_slint_core::graphics::euclid::rect(orig.x, orig.y, size.width as i32, size.height as i32)
|
||||
renderer.render(buffer, pixel_stride)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -397,12 +397,10 @@ mod software_renderer {
|
|||
buffer: *mut u16,
|
||||
buffer_len: usize,
|
||||
pixel_stride: usize,
|
||||
) -> IntRect {
|
||||
) -> PhysicalRegion {
|
||||
let buffer = core::slice::from_raw_parts_mut(buffer as *mut Rgb565Pixel, buffer_len);
|
||||
let renderer = &*(r as *const SoftwareRenderer);
|
||||
let r = renderer.render(buffer, pixel_stride);
|
||||
let (orig, size) = (r.bounding_box_origin(), r.bounding_box_size());
|
||||
i_slint_core::graphics::euclid::rect(orig.x, orig.y, size.width as i32, size.height as i32)
|
||||
renderer.render(buffer, pixel_stride)
|
||||
}
|
||||
|
||||
#[cfg(feature = "experimental")]
|
||||
|
@ -418,7 +416,9 @@ mod software_renderer {
|
|||
*const core::ffi::c_void,
|
||||
),
|
||||
user_data: *mut core::ffi::c_void,
|
||||
) -> IntRect {
|
||||
) -> PhysicalRegion {
|
||||
use i_slint_core::software_renderer::PhysicalRegion;
|
||||
|
||||
struct Rgb565Processor {
|
||||
process_line_fn: extern "C" fn(
|
||||
*mut core::ffi::c_void,
|
||||
|
@ -482,9 +482,7 @@ mod software_renderer {
|
|||
|
||||
let processor = Rgb565Processor { process_line_fn, user_data };
|
||||
|
||||
let r = renderer.render_by_line(processor);
|
||||
let (orig, size) = (r.bounding_box_origin(), r.bounding_box_size());
|
||||
i_slint_core::graphics::euclid::rect(orig.x, orig.y, size.width as i32, size.height as i32)
|
||||
renderer.render_by_line(processor)
|
||||
}
|
||||
|
||||
#[cfg(feature = "experimental")]
|
||||
|
|
|
@ -198,6 +198,15 @@ pub mod ffi {
|
|||
y: f32,
|
||||
}
|
||||
|
||||
/// Expand Box2D so that cbindgen can see it.
|
||||
#[cfg(cbindgen)]
|
||||
#[repr(C)]
|
||||
struct Box2D<T, U> {
|
||||
min: euclid::Point2D<T>,
|
||||
max: euclid::Point2D<T>,
|
||||
_unit: std::marker::PhantomData<U>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use super::path::ffi::*;
|
||||
|
||||
|
|
|
@ -207,17 +207,28 @@ pub trait LineBufferProvider {
|
|||
);
|
||||
}
|
||||
|
||||
#[cfg(not(cbindgen))]
|
||||
const PHYSICAL_REGION_MAX_SIZE: usize = DirtyRegion::MAX_COUNT;
|
||||
// cbindgen can't understand associated const correctly, so hardcode the value
|
||||
#[cfg(cbindgen)]
|
||||
pub const PHYSICAL_REGION_MAX_SIZE: usize = 3;
|
||||
const _: () = {
|
||||
assert!(PHYSICAL_REGION_MAX_SIZE == 3);
|
||||
assert!(DirtyRegion::MAX_COUNT == 3);
|
||||
};
|
||||
|
||||
/// Represents a rectangular region on the screen, used for partial rendering.
|
||||
///
|
||||
/// The region may be composed of multiple sub-regions.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
#[repr(C)]
|
||||
pub struct PhysicalRegion {
|
||||
rectangles: [euclid::Box2D<i16, PhysicalPx>; DirtyRegion::MAX_COUNT],
|
||||
rectangles: [euclid::Box2D<i16, PhysicalPx>; PHYSICAL_REGION_MAX_SIZE],
|
||||
count: usize,
|
||||
}
|
||||
|
||||
impl PhysicalRegion {
|
||||
fn iter(&self) -> impl Iterator<Item = euclid::Box2D<i16, PhysicalPx>> + '_ {
|
||||
fn iter_box(&self) -> impl Iterator<Item = euclid::Box2D<i16, PhysicalPx>> + '_ {
|
||||
(0..self.count).map(|x| self.rectangles[x])
|
||||
}
|
||||
|
||||
|
@ -242,6 +253,20 @@ impl PhysicalRegion {
|
|||
let bb = self.bounding_rect();
|
||||
crate::api::PhysicalPosition { x: bb.origin.x as _, y: bb.origin.y as _ }
|
||||
}
|
||||
|
||||
/// Returns an iterator over the rectangles in this region.
|
||||
/// Each rectangle is represented by its position and its size.
|
||||
pub fn iter(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (crate::api::PhysicalPosition, crate::api::PhysicalSize)> + '_ {
|
||||
self.iter_box().map(|r| {
|
||||
let r = r.to_rect();
|
||||
(
|
||||
crate::api::PhysicalPosition { x: r.origin.x as _, y: r.origin.y as _ },
|
||||
crate::api::PhysicalSize { width: r.width() as _, height: r.height() as _ },
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes what are the x ranges that intersects the region for specified y line.
|
||||
|
@ -256,7 +281,7 @@ fn region_line_ranges(
|
|||
) -> Option<i16> {
|
||||
line_ranges.clear();
|
||||
let mut next_validity = None::<i16>;
|
||||
for geom in region.iter() {
|
||||
for geom in region.iter_box() {
|
||||
if geom.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
@ -921,7 +946,8 @@ impl Scene {
|
|||
vectors: SceneVectors,
|
||||
dirty_region: PhysicalRegion,
|
||||
) -> Self {
|
||||
let current_line = dirty_region.iter().map(|x| x.min.y_length()).min().unwrap_or_default();
|
||||
let current_line =
|
||||
dirty_region.iter_box().map(|x| x.min.y_length()).min().unwrap_or_default();
|
||||
items.retain(|i| i.pos.y_length() + i.size.height_length() > current_line);
|
||||
items.sort_unstable_by(compare_scene_item);
|
||||
let current_items_index = items.partition_point(|i| i.pos.y_length() <= current_line);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue