diff --git a/api/cpp/cbindgen.rs b/api/cpp/cbindgen.rs index c08cf37f8..8e5ec8701 100644 --- a/api/cpp/cbindgen.rs +++ b/api/cpp/cbindgen.rs @@ -897,7 +897,7 @@ fn gen_platform( .with_after_include( r" namespace slint::platform { struct Rgb565Pixel; } -namespace slint::cbindgen_private { struct WindowProperties; using slint::platform::Rgb565Pixel; } +namespace slint::cbindgen_private { struct WindowProperties; using slint::platform::Rgb565Pixel; using slint::cbindgen_private::types::TexturePixelFormat; } ", ) .generate() diff --git a/api/cpp/include/slint-platform.h b/api/cpp/include/slint-platform.h index 37fa46aa1..4615241cd 100644 --- a/api/cpp/include/slint-platform.h +++ b/api/cpp/include/slint-platform.h @@ -539,6 +539,27 @@ struct Rgb565Pixel }; # ifdef SLINT_FEATURE_EXPERIMENTAL + +using cbindgen_private::types::TexturePixelFormat; + +/// This structure describes the properties of a texture for blending with +/// TargetPixelBuffer::draw_texture(). +struct Texture +{ + /// A reference to the pixel bytes of the texture. These bytes are in the format specified by + /// `pixel_format`. + std::span bytes; + /// The pixel format of the texture. + TexturePixelFormat pixel_format; + uint16_t pixel_stride; + uint16_t width; + uint16_t height; + uint16_t delta_x; + uint16_t delta_y; + uint16_t source_offset_x; + uint16_t source_offset_y; +}; + template struct TargetPixelBuffer { @@ -550,10 +571,8 @@ struct TargetPixelBuffer virtual bool fill_rectangle(int16_t x, int16_t y, int16_t width, int16_t height, const RgbaColor &premultiplied_color) = 0; virtual bool draw_texture(int16_t x, int16_t y, int16_t width, int16_t height, int16_t span_y, - const uint8_t *src, uint16_t src_stride, int16_t src_width, - int16_t src_height, uint8_t src_pixel_format, uint16_t src_dx, - uint16_t src_dy, uint16_t src_off_x, uint16_t src_off_y, - uint32_t colorize, uint8_t alpha, uint8_t rotation) = 0; + const Texture &texture, uint32_t colorize, uint8_t alpha, + uint8_t rotation) = 0; }; # endif @@ -727,15 +746,23 @@ public: }, .draw_texture = [](void *self, int16_t x, int16_t y, int16_t width, int16_t height, - int16_t span_y, const uint8_t *src, uint16_t src_stride, int16_t src_width, - int16_t src_height, uint8_t src_pixel_format, uint16_t src_dx, - uint16_t src_dy, uint16_t src_off_x, uint16_t src_off_y, uint32_t colorize, - uint8_t alpha, uint8_t rotation) { + int16_t span_y, const cbindgen_private::CppInternalTexture *internal_texture, + uint32_t colorize, uint8_t alpha, uint8_t rotation) { auto *buffer = reinterpret_cast *>(self); - return buffer->draw_texture(x, y, width, height, span_y, src, src_stride, - src_width, src_height, src_pixel_format, src_dx, - src_dy, src_off_x, src_off_y, colorize, alpha, - rotation); + Texture texture { + .bytes = std::span { internal_texture->bytes, + internal_texture->bytes_len }, + .pixel_format = internal_texture->pixel_format, + .pixel_stride = internal_texture->pixel_stride, + .width = internal_texture->width, + .height = internal_texture->height, + .delta_x = internal_texture->delta_x, + .delta_y = internal_texture->delta_y, + .source_offset_x = internal_texture->source_offset_x, + .source_offset_y = internal_texture->source_offset_y, + }; + return buffer->draw_texture(x, y, width, height, span_y, texture, colorize, + alpha, rotation); } }; auto r = @@ -769,15 +796,23 @@ public: }, .draw_texture = [](void *self, int16_t x, int16_t y, int16_t width, int16_t height, - int16_t span_y, const uint8_t *src, uint16_t src_stride, int16_t src_width, - int16_t src_height, uint8_t src_pixel_format, uint16_t src_dx, - uint16_t src_dy, uint16_t src_off_x, uint16_t src_off_y, uint32_t colorize, - uint8_t alpha, uint8_t rotation) { + int16_t span_y, const cbindgen_private::CppInternalTexture *internal_texture, + uint32_t colorize, uint8_t alpha, uint8_t rotation) { auto *buffer = reinterpret_cast *>(self); - return buffer->draw_texture(x, y, width, height, span_y, src, src_stride, - src_width, src_height, src_pixel_format, src_dx, - src_dy, src_off_x, src_off_y, colorize, alpha, - rotation); + Texture texture { + .bytes = std::span { internal_texture->bytes, + internal_texture->bytes_len }, + .pixel_format = internal_texture->pixel_format, + .pixel_stride = internal_texture->pixel_stride, + .width = internal_texture->width, + .height = internal_texture->height, + .delta_x = internal_texture->delta_x, + .delta_y = internal_texture->delta_y, + .source_offset_x = internal_texture->source_offset_x, + .source_offset_y = internal_texture->source_offset_y, + }; + return buffer->draw_texture(x, y, width, height, span_y, texture, colorize, + alpha, rotation); } }; auto r = cbindgen_private::slint_software_renderer_render_accel_rgb565(inner, diff --git a/api/cpp/platform.rs b/api/cpp/platform.rs index 0ca1f6261..97fa3f2f5 100644 --- a/api/cpp/platform.rs +++ b/api/cpp/platform.rs @@ -357,12 +357,26 @@ mod software_renderer { use i_slint_core::graphics::{IntRect, Rgb8Pixel}; use i_slint_core::software_renderer::{ PhysicalRegion, PremultipliedRgbaColor, RepaintBufferType, Rgb565Pixel, SoftwareRenderer, - TargetPixelBuffer, + TargetPixelBuffer, Texture, TexturePixelFormat, }; use i_slint_core::SharedVector; type CppTargetPixelBufferUserData = *mut c_void; + #[repr(C)] + pub struct CppInternalTexture { + pub bytes: *const u8, + pub bytes_len: usize, + pub pixel_format: TexturePixelFormat, + pub pixel_stride: u16, + pub width: u16, + pub height: u16, + pub delta_x: u16, + pub delta_y: u16, + pub source_offset_x: u16, + pub source_offset_y: u16, + } + #[repr(C)] pub struct CppRgb8TargetPixelBuffer { user_data: CppTargetPixelBufferUserData, @@ -391,15 +405,7 @@ mod software_renderer { i16, i16, i16, - *const u8, - u16, - i16, - i16, - u8, - u16, - u16, - u16, - u16, + &CppInternalTexture, u32, u8, u8, @@ -452,15 +458,7 @@ mod software_renderer { width: i16, height: i16, span_y: i16, - src: *const u8, - src_stride: u16, - src_width: i16, - src_height: i16, - src_pixel_format: u8, - dx: u16, - dy: u16, - off_x: u16, - off_y: u16, + texture: Texture<'_>, colorize: u32, alpha: u8, rotation: u8, @@ -473,15 +471,18 @@ mod software_renderer { width, height, span_y, - src, - src_stride, - src_width, - src_height, - src_pixel_format, - dx, - dy, - off_x, - off_y, + &CppInternalTexture { + bytes: texture.bytes.as_ptr(), + bytes_len: texture.bytes.len(), + pixel_format: texture.pixel_format, + pixel_stride: texture.pixel_stride, + width: texture.width, + height: texture.height, + delta_x: texture.delta_x, + delta_y: texture.delta_y, + source_offset_x: texture.source_offset_x, + source_offset_y: texture.source_offset_y, + }, colorize, alpha, rotation, @@ -518,15 +519,7 @@ mod software_renderer { i16, i16, i16, - *const u8, - u16, - i16, - i16, - u8, - u16, - u16, - u16, - u16, + &CppInternalTexture, u32, u8, u8, @@ -579,15 +572,7 @@ mod software_renderer { width: i16, height: i16, span_y: i16, - src: *const u8, - src_stride: u16, - src_width: i16, - src_height: i16, - src_pixel_format: u8, - dx: u16, - dy: u16, - off_x: u16, - off_y: u16, + texture: Texture<'_>, colorize: u32, alpha: u8, rotation: u8, @@ -600,15 +585,18 @@ mod software_renderer { width, height, span_y, - src, - src_stride, - src_width, - src_height, - src_pixel_format, - dx, - dy, - off_x, - off_y, + &CppInternalTexture { + bytes: texture.bytes.as_ptr(), + bytes_len: texture.bytes.len(), + pixel_format: texture.pixel_format, + pixel_stride: texture.pixel_stride, + width: texture.width, + height: texture.height, + delta_x: texture.delta_x, + delta_y: texture.delta_y, + source_offset_x: texture.source_offset_x, + source_offset_y: texture.source_offset_y, + }, colorize, alpha, rotation, diff --git a/internal/compiler/generator/rust.rs b/internal/compiler/generator/rust.rs index 663b27a46..e9ad4edb0 100644 --- a/internal/compiler/generator/rust.rs +++ b/internal/compiler/generator/rust.rs @@ -65,12 +65,12 @@ impl quote::ToTokens for crate::embedded_resources::PixelFormat { fn to_tokens(&self, tokens: &mut TokenStream) { use crate::embedded_resources::PixelFormat::*; let tks = match self { - Rgb => quote!(sp::PixelFormat::Rgb), - Rgba => quote!(sp::PixelFormat::Rgba), + Rgb => quote!(sp::TexturePixelFormat::Rgb), + Rgba => quote!(sp::TexturePixelFormat::Rgba), RgbaPremultiplied => { - quote!(sp::PixelFormat::RgbaPremultiplied) + quote!(sp::TexturePixelFormat::RgbaPremultiplied) } - AlphaMap(_) => quote!(sp::PixelFormat::AlphaMap), + AlphaMap(_) => quote!(sp::TexturePixelFormat::AlphaMap), }; tokens.extend(tks); } diff --git a/internal/core/graphics/image.rs b/internal/core/graphics/image.rs index f7ebf6294..fe4127fe5 100644 --- a/internal/core/graphics/image.rs +++ b/internal/core/graphics/image.rs @@ -224,8 +224,8 @@ impl PartialEq for SharedImageBuffer { #[repr(u8)] #[derive(Clone, PartialEq, Debug, Copy)] -/// The pixel format of a StaticTexture -pub enum PixelFormat { +/// The pixel format used for textures. +pub enum TexturePixelFormat { /// red, green, blue. 24bits. Rgb, /// Red, green, blue, alpha. 32bits. @@ -241,15 +241,15 @@ pub enum PixelFormat { SignedDistanceField, } -impl PixelFormat { +impl TexturePixelFormat { /// The number of bytes in a pixel pub fn bpp(self) -> usize { match self { - PixelFormat::Rgb => 3, - PixelFormat::Rgba => 4, - PixelFormat::RgbaPremultiplied => 4, - PixelFormat::AlphaMap => 1, - PixelFormat::SignedDistanceField => 1, + TexturePixelFormat::Rgb => 3, + TexturePixelFormat::Rgba => 4, + TexturePixelFormat::RgbaPremultiplied => 4, + TexturePixelFormat::AlphaMap => 1, + TexturePixelFormat::SignedDistanceField => 1, } } } @@ -261,7 +261,7 @@ pub struct StaticTexture { /// The position and size of the texture within the image pub rect: IntRect, /// The pixel format of this texture - pub format: PixelFormat, + pub format: TexturePixelFormat, /// The color, for the alpha map ones pub color: crate::Color, /// index in the data array @@ -435,7 +435,7 @@ impl ImageInner { let slice = &mut slice[(rect.min_y() + y) * stride..][rect.x_range()]; let source = &ts.data[t.index + y * rect.width() * t.format.bpp()..]; match t.format { - PixelFormat::Rgb => { + TexturePixelFormat::Rgb => { let mut iter = source.chunks_exact(3).map(|p| Rgba8Pixel { r: p[0], g: p[1], @@ -444,7 +444,7 @@ impl ImageInner { }); slice.fill_with(|| iter.next().unwrap()); } - PixelFormat::RgbaPremultiplied => { + TexturePixelFormat::RgbaPremultiplied => { let mut iter = source.chunks_exact(4).map(|p| Rgba8Pixel { r: p[0], g: p[1], @@ -453,7 +453,7 @@ impl ImageInner { }); slice.fill_with(|| iter.next().unwrap()); } - PixelFormat::Rgba => { + TexturePixelFormat::Rgba => { let mut iter = source.chunks_exact(4).map(|p| { let a = p[3]; Rgba8Pixel { @@ -465,7 +465,7 @@ impl ImageInner { }); slice.fill_with(|| iter.next().unwrap()); } - PixelFormat::AlphaMap => { + TexturePixelFormat::AlphaMap => { let col = t.color.to_argb_u8(); let mut iter = source.iter().map(|p| { let a = *p as u32 * col.alpha as u32; @@ -478,7 +478,7 @@ impl ImageInner { }); slice.fill_with(|| iter.next().unwrap()); } - PixelFormat::SignedDistanceField => { + TexturePixelFormat::SignedDistanceField => { todo!("converting from a signed distance field to an image") } }; diff --git a/internal/core/software_renderer.rs b/internal/core/software_renderer.rs index 9fcf4be99..722136414 100644 --- a/internal/core/software_renderer.rs +++ b/internal/core/software_renderer.rs @@ -18,9 +18,7 @@ pub use self::minimal_software_window::MinimalSoftwareWindow; use self::scene::*; use crate::api::PlatformError; use crate::graphics::rendering_metrics_collector::{RefreshMode, RenderingMetricsCollector}; -use crate::graphics::{ - BorderRadius, PixelFormat, Rgba8Pixel, SharedImageBuffer, SharedPixelBuffer, -}; +use crate::graphics::{BorderRadius, Rgba8Pixel, SharedImageBuffer, SharedPixelBuffer}; use crate::item_rendering::{ CachedRenderingData, DirtyRegion, PartialRenderingState, RenderBorderRectangle, RenderImage, RenderRectangle, @@ -368,6 +366,36 @@ fn region_line_ranges( mod private_api { use super::*; + pub use crate::graphics::TexturePixelFormat; + + /// This structure describes the properties of a texture for blending with [`TargetPixelBuffer::draw_texture`]. + #[allow(dead_code)] + #[non_exhaustive] + pub struct Texture<'a> { + /// A reference to the pixel bytes of the texture. These bytes are in the format specified by `pixel_format`. + pub bytes: &'a [u8], + /// The pixel format of the texture. + pub pixel_format: TexturePixelFormat, + /// The number of pixels per horizontal line of the texture. + pub pixel_stride: u16, + /// The width of the texture in pixels. + pub width: u16, + /// The height of the texture in pixels. + pub height: u16, + /// The delta to apply to the source x coordinate between pixels when drawing the texture. + /// This is used when scaling the texture. The delta is specified in 8:8 fixed point format. + pub delta_x: u16, + /// The delta to apply to the source y coordinate between pixels when drawing the texture. + /// This is used when scaling the texture. The delta is specified in 8:8 fixed point format. + pub delta_y: u16, + /// The offset within the texture to start reading pixels from in the x direction. The + /// offset is specified in 8:8 fixed point format. + pub source_offset_x: u16, + /// The offset within the texture to start reading pixels from in the y direction. The + /// offset is specified in 8:8 fixed point format. + pub source_offset_y: u16, + } + /// This trait represents access to a buffer of pixels the software renderer can render into, as well /// as certain operations that the renderer will try to delegate to this trait. Implement these functions /// to delegate rendering further to hardware-provided 2D acceleration units, such as DMA2D or PXP. @@ -405,15 +433,7 @@ mod private_api { _width: i16, _height: i16, _span_y: i16, - _src: *const u8, - _src_stride: u16, - _src_width: i16, - _src_height: i16, - _src_pixel_format: u8, - _src_dx: u16, - _src_dy: u16, - _src_off_x: u16, - _src_off_y: u16, + _src_texture: Texture<'_>, _colorize: u32, _alpha: u8, _rotation: u8, @@ -424,7 +444,10 @@ mod private_api { } #[cfg(feature = "experimental")] -pub use private_api::TargetPixelBuffer; +pub use private_api::{TargetPixelBuffer, Texture, TexturePixelFormat}; + +#[cfg(not(feature = "experimental"))] +use private_api::TexturePixelFormat; struct TargetPixelSlice<'a, T> { data: &'a mut [T], @@ -1261,15 +1284,17 @@ impl> RenderToBuffe rect.size.width, rect.size.height, geometry.origin.y, - texture.data.as_ptr(), - texture.pixel_stride, - texture.source_size().width, - texture.source_size().height, - texture.format as u8, - texture.extra.dx.0, - texture.extra.dy.0, - texture.extra.off_x.0, - texture.extra.off_y.0, + private_api::Texture { + bytes: texture.data, + pixel_format: texture.format, + pixel_stride: texture.pixel_stride, + width: texture.source_size().width as u16, + height: texture.source_size().height as u16, + delta_x: texture.extra.dx.0, + delta_y: texture.extra.dy.0, + source_offset_x: texture.extra.off_x.0, + source_offset_y: texture.extra.off_y.0, + }, texture.extra.colorize.as_argb_encoded(), texture.extra.alpha, texture.extra.rotation as u8, @@ -1545,7 +1570,8 @@ impl<'a, T: ProcessScene> SceneBuilder<'a, T> { let bpp = t.format.bpp(); let color = if colorize.alpha() > 0 { colorize } else { t.color }; - let alpha = if colorize.alpha() > 0 || t.format == PixelFormat::AlphaMap { + let alpha = if colorize.alpha() > 0 || t.format == TexturePixelFormat::AlphaMap + { color.alpha() as u16 * global_alpha_u16 / 255 } else { global_alpha_u16 @@ -1719,7 +1745,7 @@ impl<'a, T: ProcessScene> SceneBuilder<'a, T> { SceneTexture { data, pixel_stride, - format: PixelFormat::AlphaMap, + format: TexturePixelFormat::AlphaMap, extra: SceneTextureExtra { colorize: color, // color already is mixed with global alpha @@ -1750,7 +1776,7 @@ impl<'a, T: ProcessScene> SceneBuilder<'a, T> { SceneTexture { data, pixel_stride, - format: PixelFormat::SignedDistanceField, + format: TexturePixelFormat::SignedDistanceField, extra: SceneTextureExtra { colorize: color, // color already is mixed with global alpha diff --git a/internal/core/software_renderer/draw_functions.rs b/internal/core/software_renderer/draw_functions.rs index acb19e42c..07666f790 100644 --- a/internal/core/software_renderer/draw_functions.rs +++ b/internal/core/software_renderer/draw_functions.rs @@ -7,7 +7,7 @@ //! on the line buffer use super::{Fixed, PhysicalLength, PhysicalRect}; -use crate::graphics::{PixelFormat, Rgb8Pixel}; +use crate::graphics::{Rgb8Pixel, TexturePixelFormat}; use crate::lengths::{PointLengths, SizeLengths}; use crate::Color; use derive_more::{Add, Mul, Sub}; @@ -183,7 +183,7 @@ pub(super) fn draw_texture_line( fn fetch_blend_pixel( line_buffer: &mut [impl TargetPixel], - format: PixelFormat, + format: TexturePixelFormat, data: &[u8], alpha: u8, color: Color, @@ -191,10 +191,10 @@ pub(super) fn draw_texture_line( mut pos: impl FnMut(usize) -> (usize, u8, u8), ) { match format { - PixelFormat::Rgb => { + TexturePixelFormat::Rgb => { for pix in line_buffer { let pos = pos(3).0; - let p = &data[pos..pos + 3]; + let p: &[u8] = &data[pos..pos + 3]; if alpha == 0xff { *pix = TargetPixel::from_rgb(p[0], p[1], p[2]); } else { @@ -204,7 +204,7 @@ pub(super) fn draw_texture_line( } } } - PixelFormat::Rgba => { + TexturePixelFormat::Rgba => { if color.alpha() == 0 { for pix in line_buffer { let pos = pos(4).0; @@ -231,7 +231,7 @@ pub(super) fn draw_texture_line( } } } - PixelFormat::RgbaPremultiplied => { + TexturePixelFormat::RgbaPremultiplied => { if color.alpha() > 0 { for pix in line_buffer { let pos = pos(4).0; @@ -267,7 +267,7 @@ pub(super) fn draw_texture_line( } } } - PixelFormat::AlphaMap => { + TexturePixelFormat::AlphaMap => { for pix in line_buffer { let pos = pos(1).0; let c = PremultipliedRgbaColor::premultiply(Color::from_argb_u8( @@ -279,7 +279,7 @@ pub(super) fn draw_texture_line( pix.blend(c); } } - PixelFormat::SignedDistanceField => { + TexturePixelFormat::SignedDistanceField => { const RANGE: i32 = 6; let factor = (362 * 256 / delta.0) * RANGE; // 362 ≃ 255 * sqrt(2) for pix in line_buffer { diff --git a/internal/core/software_renderer/scene.rs b/internal/core/software_renderer/scene.rs index 68c62f741..cecde03ec 100644 --- a/internal/core/software_renderer/scene.rs +++ b/internal/core/software_renderer/scene.rs @@ -7,7 +7,7 @@ use super::{ Fixed, PhysicalBorderRadius, PhysicalLength, PhysicalPoint, PhysicalRect, PhysicalRegion, PhysicalSize, PremultipliedRgbaColor, RenderingRotation, }; -use crate::graphics::{PixelFormat, SharedImageBuffer}; +use crate::graphics::{SharedImageBuffer, TexturePixelFormat}; use crate::lengths::{PointLengths as _, SizeLengths as _}; use crate::Color; use alloc::rc::Rc; @@ -284,7 +284,7 @@ pub enum SceneCommand { pub struct SceneTexture<'a> { /// This should have a size so that the entire slice is ((height - 1) * pixel_stride + width) * bpp pub data: &'a [u8], - pub format: PixelFormat, + pub format: TexturePixelFormat, /// number of pixels between two lines in the source pub pixel_stride: u16, @@ -294,7 +294,7 @@ pub struct SceneTexture<'a> { impl SceneTexture<'_> { pub fn source_size(&self) -> PhysicalSize { let mut len = self.data.len(); - if self.format == PixelFormat::SignedDistanceField { + if self.format == TexturePixelFormat::SignedDistanceField { len -= 1; } else { len /= self.format.bpp(); @@ -355,27 +355,27 @@ impl SharedBufferCommand { SharedBufferData::SharedImage(SharedImageBuffer::RGB8(b)) => SceneTexture { data: &b.as_bytes()[start * 3..end * 3], pixel_stride: stride as u16, - format: PixelFormat::Rgb, + format: TexturePixelFormat::Rgb, extra: self.extra, }, SharedBufferData::SharedImage(SharedImageBuffer::RGBA8(b)) => SceneTexture { data: &b.as_bytes()[start * 4..end * 4], pixel_stride: stride as u16, - format: PixelFormat::Rgba, + format: TexturePixelFormat::Rgba, extra: self.extra, }, SharedBufferData::SharedImage(SharedImageBuffer::RGBA8Premultiplied(b)) => { SceneTexture { data: &b.as_bytes()[start * 4..end * 4], pixel_stride: stride as u16, - format: PixelFormat::RgbaPremultiplied, + format: TexturePixelFormat::RgbaPremultiplied, extra: self.extra, } } SharedBufferData::AlphaMap { data, width } => SceneTexture { data: &data[start..end], pixel_stride: *width, - format: PixelFormat::AlphaMap, + format: TexturePixelFormat::AlphaMap, extra: self.extra, }, }