mirror of
https://github.com/slint-ui/slint.git
synced 2025-11-03 05:12:55 +00:00
C++: support for RGB8 in the line by line rendering
Note: this adds a mendatory template parametter to the (experimental) `render_by_line` function. I tried to get the PixelType auto-detected from the callback but i didn't manage
This commit is contained in:
parent
48fbf887aa
commit
07803ccd6c
4 changed files with 130 additions and 100 deletions
|
|
@ -896,7 +896,8 @@ fn gen_platform(
|
|||
.with_include("slint_internal.h")
|
||||
.with_after_include(
|
||||
r"
|
||||
namespace slint::cbindgen_private { struct WindowProperties; }
|
||||
namespace slint::platform { struct Rgb565Pixel; }
|
||||
namespace slint::cbindgen_private { struct WindowProperties; using slint::platform::Rgb565Pixel; }
|
||||
",
|
||||
)
|
||||
.generate()
|
||||
|
|
|
|||
|
|
@ -271,27 +271,24 @@ void EspPlatform<PixelType>::run_event_loop()
|
|||
}
|
||||
#ifdef SLINT_FEATURE_EXPERIMENTAL
|
||||
} else {
|
||||
std::unique_ptr<slint::platform::Rgb565Pixel, void (*)(void *)> lb(
|
||||
static_cast<slint::platform::Rgb565Pixel *>(
|
||||
heap_caps_malloc((rotated ? size.height : size.width)
|
||||
* sizeof(slint::platform::Rgb565Pixel),
|
||||
MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)),
|
||||
std::unique_ptr<PixelType, void (*)(void *)> lb(
|
||||
static_cast<PixelType *>(heap_caps_malloc(
|
||||
(rotated ? size.height : size.width) * sizeof(PixelType),
|
||||
MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)),
|
||||
heap_caps_free);
|
||||
m_window->m_renderer.render_by_line([this, &lb](std::size_t line_y,
|
||||
std::size_t line_start,
|
||||
std::size_t line_end,
|
||||
auto &&render_fn) {
|
||||
std::span<slint::platform::Rgb565Pixel> view { lb.get(),
|
||||
line_end - line_start };
|
||||
render_fn(view);
|
||||
if (byte_swap) {
|
||||
// Swap endianness to big endian
|
||||
std::for_each(view.begin(), view.end(),
|
||||
[](auto &rgbpix) { byte_swap_color(&rgbpix); });
|
||||
}
|
||||
esp_lcd_panel_draw_bitmap(panel_handle, line_start, line_y, line_end,
|
||||
line_y + 1, lb.get());
|
||||
});
|
||||
m_window->m_renderer.render_by_line<PixelType>(
|
||||
[this, &lb](std::size_t line_y, std::size_t line_start,
|
||||
std::size_t line_end, auto &&render_fn) {
|
||||
std::span<PixelType> view { lb.get(), line_end - line_start };
|
||||
render_fn(view);
|
||||
if (byte_swap) {
|
||||
// Swap endianness to big endian
|
||||
std::for_each(view.begin(), view.end(),
|
||||
[](auto &rgbpix) { byte_swap_color(&rgbpix); });
|
||||
}
|
||||
esp_lcd_panel_draw_bitmap(panel_handle, line_start, line_y,
|
||||
line_end, line_y + 1, lb.get());
|
||||
});
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -708,27 +708,37 @@ public:
|
|||
/// a line buffer (as std::span) and invoke the provided fourth parameter (render_fn) with it,
|
||||
/// to fill it with pixels. After the line buffer is filled with pixels, your implementation is
|
||||
/// free to flush that line to the screen for display.
|
||||
template<typename Callback>
|
||||
///
|
||||
/// The first template parameter (PixelType) must be specified and can be either Rgb565Pixel or
|
||||
/// Rgb8Pixel.
|
||||
template<typename PixelType, typename Callback>
|
||||
requires requires(Callback callback) {
|
||||
callback(size_t(0), size_t(0), size_t(0), [&callback](std::span<Rgb565Pixel>) {});
|
||||
callback(size_t(0), size_t(0), size_t(0), [&callback](std::span<PixelType>) {});
|
||||
}
|
||||
PhysicalRegion render_by_line(Callback process_line_callback) const
|
||||
{
|
||||
auto r = cbindgen_private::slint_software_renderer_render_by_line_rgb565(
|
||||
inner,
|
||||
[](void *process_line_callback_ptr, uintptr_t line, uintptr_t line_start,
|
||||
uintptr_t line_end, void (*render_fn)(const void *, uint16_t *, std::size_t),
|
||||
const void *render_fn_data) {
|
||||
(*reinterpret_cast<Callback *>(process_line_callback_ptr))(
|
||||
std::size_t(line), std::size_t(line_start), std::size_t(line_end),
|
||||
[render_fn, render_fn_data](std::span<Rgb565Pixel> line_span) {
|
||||
render_fn(render_fn_data,
|
||||
reinterpret_cast<uint16_t *>(line_span.data()),
|
||||
line_span.size());
|
||||
});
|
||||
},
|
||||
&process_line_callback);
|
||||
return PhysicalRegion { r };
|
||||
auto process_line_fn = [](void *process_line_callback_ptr, uintptr_t line,
|
||||
uintptr_t line_start, uintptr_t line_end,
|
||||
void (*render_fn)(const void *, PixelType *, std::size_t),
|
||||
const void *render_fn_data) {
|
||||
(*reinterpret_cast<Callback *>(process_line_callback_ptr))(
|
||||
std::size_t(line), std::size_t(line_start), std::size_t(line_end),
|
||||
[render_fn, render_fn_data](std::span<PixelType> line_span) {
|
||||
render_fn(render_fn_data, line_span.data(), line_span.size());
|
||||
});
|
||||
};
|
||||
|
||||
if constexpr (std::is_same_v<PixelType, Rgb565Pixel>) {
|
||||
return PhysicalRegion { cbindgen_private::slint_software_renderer_render_by_line_rgb565(
|
||||
inner, process_line_fn, &process_line_callback) };
|
||||
} else if constexpr (std::is_same_v<PixelType, Rgb8Pixel>) {
|
||||
return PhysicalRegion { cbindgen_private::slint_software_renderer_render_by_line_rgb8(
|
||||
inner, process_line_fn, &process_line_callback) };
|
||||
} else {
|
||||
static_assert(std::is_same_v<PixelType, Rgba8Pixel>
|
||||
|| std::is_same_v<PixelType, Rgb565Pixel>,
|
||||
"Unsupported PixelType. It must be either Rgba8Pixel or Rgb565Pixel");
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
|
|
|
|||
|
|
@ -403,6 +403,70 @@ mod software_renderer {
|
|||
renderer.render(buffer, pixel_stride)
|
||||
}
|
||||
|
||||
#[cfg(feature = "experimental")]
|
||||
struct LineByLineProcessor<TargetPixel> {
|
||||
process_line_fn: extern "C" fn(
|
||||
*mut core::ffi::c_void,
|
||||
usize,
|
||||
usize,
|
||||
usize,
|
||||
extern "C" fn(*const core::ffi::c_void, *mut TargetPixel, usize),
|
||||
*const core::ffi::c_void,
|
||||
),
|
||||
user_data: *mut core::ffi::c_void,
|
||||
}
|
||||
|
||||
#[cfg(feature = "experimental")]
|
||||
impl<TargetPixel: i_slint_core::software_renderer::TargetPixel>
|
||||
i_slint_core::software_renderer::LineBufferProvider for LineByLineProcessor<TargetPixel>
|
||||
{
|
||||
type TargetPixel = TargetPixel;
|
||||
fn process_line(
|
||||
&mut self,
|
||||
line: usize,
|
||||
range: core::ops::Range<usize>,
|
||||
render_fn: impl FnOnce(&mut [TargetPixel]),
|
||||
) {
|
||||
self.cpp_process_line(line, range, render_fn);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "experimental")]
|
||||
impl<TargetPixel> LineByLineProcessor<TargetPixel> {
|
||||
fn cpp_process_line<RenderFn: FnOnce(&mut [TargetPixel])>(
|
||||
&mut self,
|
||||
line: usize,
|
||||
range: core::ops::Range<usize>,
|
||||
render_fn: RenderFn,
|
||||
) {
|
||||
let mut render_fn = Some(render_fn);
|
||||
let render_fn_ptr = &mut render_fn as *mut Option<RenderFn> as *const core::ffi::c_void;
|
||||
|
||||
extern "C" fn cpp_render_line_callback<
|
||||
TargetPixel,
|
||||
RenderFn: FnOnce(&mut [TargetPixel]),
|
||||
>(
|
||||
render_fn_ptr: *const core::ffi::c_void,
|
||||
line_start: *mut TargetPixel,
|
||||
len: usize,
|
||||
) {
|
||||
let line_slice = unsafe { core::slice::from_raw_parts_mut(line_start, len) };
|
||||
let render_fn =
|
||||
unsafe { (*(render_fn_ptr as *mut Option<RenderFn>)).take().unwrap() };
|
||||
render_fn(line_slice);
|
||||
}
|
||||
|
||||
(self.process_line_fn)(
|
||||
self.user_data,
|
||||
line,
|
||||
range.start,
|
||||
range.end,
|
||||
cpp_render_line_callback::<TargetPixel, RenderFn>,
|
||||
render_fn_ptr,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "experimental")]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn slint_software_renderer_render_by_line_rgb565(
|
||||
|
|
@ -412,74 +476,32 @@ mod software_renderer {
|
|||
usize,
|
||||
usize,
|
||||
usize,
|
||||
extern "C" fn(*const core::ffi::c_void, *mut u16, usize),
|
||||
extern "C" fn(*const core::ffi::c_void, *mut Rgb565Pixel, usize),
|
||||
*const core::ffi::c_void,
|
||||
),
|
||||
user_data: *mut core::ffi::c_void,
|
||||
) -> PhysicalRegion {
|
||||
struct Rgb565Processor {
|
||||
process_line_fn: extern "C" fn(
|
||||
*mut core::ffi::c_void,
|
||||
usize,
|
||||
usize,
|
||||
usize,
|
||||
extern "C" fn(*const core::ffi::c_void, *mut u16, usize),
|
||||
*const core::ffi::c_void,
|
||||
),
|
||||
user_data: *mut core::ffi::c_void,
|
||||
}
|
||||
|
||||
impl i_slint_core::software_renderer::LineBufferProvider for Rgb565Processor {
|
||||
type TargetPixel = Rgb565Pixel;
|
||||
fn process_line(
|
||||
&mut self,
|
||||
line: usize,
|
||||
range: core::ops::Range<usize>,
|
||||
render_fn: impl FnOnce(&mut [Rgb565Pixel]),
|
||||
) {
|
||||
self.cpp_process_line(line, range, render_fn);
|
||||
}
|
||||
}
|
||||
|
||||
impl Rgb565Processor {
|
||||
fn cpp_process_line<RenderFn: FnOnce(&mut [Rgb565Pixel])>(
|
||||
&mut self,
|
||||
line: usize,
|
||||
range: core::ops::Range<usize>,
|
||||
render_fn: RenderFn,
|
||||
) {
|
||||
let mut render_fn = Some(render_fn);
|
||||
let render_fn_ptr =
|
||||
&mut render_fn as *mut Option<RenderFn> as *const core::ffi::c_void;
|
||||
|
||||
extern "C" fn cpp_render_line_callback<RenderFn: FnOnce(&mut [Rgb565Pixel])>(
|
||||
render_fn_ptr: *const core::ffi::c_void,
|
||||
line_start: *mut u16,
|
||||
len: usize,
|
||||
) {
|
||||
let line_slice = unsafe {
|
||||
core::slice::from_raw_parts_mut(line_start as *mut Rgb565Pixel, len)
|
||||
};
|
||||
let render_fn =
|
||||
unsafe { (*(render_fn_ptr as *mut Option<RenderFn>)).take().unwrap() };
|
||||
render_fn(line_slice);
|
||||
}
|
||||
|
||||
(self.process_line_fn)(
|
||||
self.user_data,
|
||||
line,
|
||||
range.start,
|
||||
range.end,
|
||||
cpp_render_line_callback::<RenderFn>,
|
||||
render_fn_ptr,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let renderer = &*(r as *const SoftwareRenderer);
|
||||
let processor = LineByLineProcessor { process_line_fn, user_data };
|
||||
renderer.render_by_line(processor)
|
||||
}
|
||||
|
||||
let processor = Rgb565Processor { process_line_fn, user_data };
|
||||
|
||||
#[cfg(feature = "experimental")]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn slint_software_renderer_render_by_line_rgb8(
|
||||
r: SoftwareRendererOpaque,
|
||||
process_line_fn: extern "C" fn(
|
||||
*mut core::ffi::c_void,
|
||||
usize,
|
||||
usize,
|
||||
usize,
|
||||
extern "C" fn(*const core::ffi::c_void, *mut Rgb8Pixel, usize),
|
||||
*const core::ffi::c_void,
|
||||
),
|
||||
user_data: *mut core::ffi::c_void,
|
||||
) -> PhysicalRegion {
|
||||
let renderer = &*(r as *const SoftwareRenderer);
|
||||
let processor = LineByLineProcessor { process_line_fn, user_data };
|
||||
renderer.render_by_line(processor)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue