Expose the individual rectangle in the dirty region

This commit is contained in:
Olivier Goffart 2024-04-26 13:32:30 +02:00
parent f45bab6a3f
commit 5955d19706
7 changed files with 117 additions and 29 deletions

View file

@ -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())

View file

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

View file

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

View file

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

View file

@ -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")]