Skip to main content

i_slint_renderer_software/
target_pixel_buffer.rs

1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4use super::*;
5
6use i_slint_core::graphics::IntSize;
7pub use i_slint_core::graphics::TexturePixelFormat;
8
9/// The pixel data of a for the source of a [`Texture`].
10#[derive(Clone)]
11#[non_exhaustive]
12pub struct TextureData<'a> {
13    /// A reference to the pixel bytes of the texture. These bytes are in the format specified by `pixel_format`.
14    pub data: &'a [u8],
15    /// The pixel format of the texture.
16    pub pixel_format: TexturePixelFormat,
17    /// The number of bytes between two lines in the data
18    pub byte_stride: usize,
19    /// The width of the texture in pixels.
20    pub width: u32,
21    /// The height of the texture in pixels.
22    pub height: u32,
23}
24
25impl<'a> TextureData<'a> {
26    pub fn new(
27        data: &'a [u8],
28        pixel_format: TexturePixelFormat,
29        byte_stride: usize,
30        size: IntSize,
31    ) -> Self {
32        let (width, height) = (size.width, size.height);
33        Self { data, pixel_format, byte_stride, width, height }
34    }
35}
36
37pub(super) enum TextureDataContainer {
38    Static(TextureData<'static>),
39    Shared { buffer: super::scene::SharedBufferData, source_rect: PhysicalRect },
40}
41
42#[derive(Debug, Clone)]
43pub struct TilingInfo {
44    /// Offset, in destination pixel of the left border of the tile.
45    pub offset_x: i32,
46    /// Offset, in destination pixel, of the top border of the tile.
47    pub offset_y: i32,
48
49    /// Scale factor in the x direction, this is the same as source's width / destination's width of the tile
50    pub scale_x: f32,
51    /// Scale factor in the y direction, this is the same as source's height / destination's height of the tile
52    pub scale_y: f32,
53
54    /// Gap in destination pixel between two tiles on the horizontal source axis.
55    pub gap_x: u32,
56    /// Gap in destination pixel between two tiles on the vertical source axis.
57    pub gap_y: u32,
58}
59
60/// This structure describes the properties of a texture for blending with [`TargetPixelBuffer::draw_texture`].
61#[non_exhaustive]
62pub struct DrawTextureArgs {
63    pub(super) data: TextureDataContainer,
64
65    /// When set, the source is to be considered as an alpha map (so for ARGB texture, the RGB component will be ignored).
66    /// And the given color is to be blended using the alpha value of the texture.
67    pub colorize: Option<Color>,
68
69    /// A value between 0 and 255 that specifies the alpha value of the texture.
70    /// If colorize is set, this value can be ignored as the alpha would be part of the `colorize` value.
71    /// A value of 0 would mean that the texture is fully transparent (so nothing is drawn),
72    /// and a value of 255 would mean fully opaque.
73    pub alpha: u8,
74
75    /// The x position in the destination buffer to draw the texture at
76    pub dst_x: isize,
77    /// The y position in the destination buffer to draw the texture at
78    pub dst_y: isize,
79    /// The width of the image in the destination. The image should be scaled to fit.
80    pub dst_width: usize,
81    /// The height of the image in the destination. The Image should be scaled to fit
82    pub dst_height: usize,
83
84    /// the rotation to apply to the texture
85    pub rotation: RenderingRotation,
86
87    /// If the texture is to be tiled, this contains the information about the tiling
88    pub tiling: Option<TilingInfo>,
89}
90
91impl DrawTextureArgs {
92    /// Returns the source image data for this texture
93    pub fn source(&self) -> TextureData<'_> {
94        match &self.data {
95            TextureDataContainer::Static(data) => data.clone(),
96            TextureDataContainer::Shared { buffer, source_rect } => {
97                let stride = buffer.width();
98                let core::ops::Range { start, end } = compute_range_in_buffer(&source_rect, stride);
99                let size = source_rect.size.to_untyped().cast();
100
101                match &buffer {
102                    SharedBufferData::SharedImage(SharedImageBuffer::RGB8(b)) => TextureData::new(
103                        &b.as_bytes()[start * 3..end * 3],
104                        TexturePixelFormat::Rgb,
105                        stride * 3,
106                        size,
107                    ),
108                    SharedBufferData::SharedImage(SharedImageBuffer::RGBA8(b)) => TextureData::new(
109                        &b.as_bytes()[start * 4..end * 4],
110                        TexturePixelFormat::Rgba,
111                        stride * 4,
112                        size,
113                    ),
114                    SharedBufferData::SharedImage(SharedImageBuffer::RGBA8Premultiplied(b)) => {
115                        TextureData::new(
116                            &b.as_bytes()[start * 4..end * 4],
117                            TexturePixelFormat::RgbaPremultiplied,
118                            stride * 4,
119                            size,
120                        )
121                    }
122                    SharedBufferData::AlphaMap { data, .. } => TextureData::new(
123                        &data[start..end],
124                        TexturePixelFormat::AlphaMap,
125                        stride,
126                        size,
127                    ),
128                }
129            }
130        }
131    }
132
133    pub(super) fn source_size(&self) -> PhysicalSize {
134        match &self.data {
135            TextureDataContainer::Static(data) => {
136                PhysicalSize::new(data.width as _, data.height as _)
137            }
138            TextureDataContainer::Shared { source_rect, .. } => source_rect.size,
139        }
140    }
141}
142
143/// This structure describes the properties of a rectangle for blending with [`TargetPixelBuffer::draw_rectangle`].
144///
145/// All the coordinate are in physical pixels
146#[non_exhaustive]
147#[derive(Default, Debug)]
148pub struct DrawRectangleArgs {
149    /// The x position in the destination buffer
150    pub x: f32,
151    /// The y position in the destination buffer
152    pub y: f32,
153    /// The width of the image in the destination.
154    pub width: f32,
155    /// The height of the image in the destination.
156    pub height: f32,
157
158    /// The top-left radius.
159    pub top_left_radius: f32,
160    /// The top-right radius.
161    pub top_right_radius: f32,
162    /// The bottom-right radius.
163    pub bottom_right_radius: f32,
164    /// The bottom-left radius.
165    pub bottom_left_radius: f32,
166
167    /// The width of the border.
168    pub border_width: f32,
169
170    /// The background of the rectangle
171    pub background: Brush,
172    /// The border of the rectangle
173    pub border: Brush,
174
175    /// A value between 0 and 255 that specifies the opacity.
176    /// A value of 0 would mean that the rectangle is fully transparent (so nothing is drawn),
177    /// and a value of 255 would mean fully opaque.
178    /// Note that the brush also might have an alpha value and the two values should be combined.
179    pub alpha: u8,
180    /// An extra rotation that should be applied to the gradient (and only to the gradient, it doesn't impact the border radius)
181    pub rotation: RenderingRotation,
182}
183
184impl DrawRectangleArgs {
185    pub(super) fn from_rect(geometry: euclid::Rect<f32, PhysicalPx>, background: Brush) -> Self {
186        Self {
187            x: geometry.origin.x,
188            y: geometry.origin.y,
189            width: geometry.size.width,
190            height: geometry.size.height,
191            background,
192            alpha: 255,
193            ..Default::default()
194        }
195    }
196
197    pub(super) fn geometry(&self) -> euclid::Rect<f32, PhysicalPx> {
198        euclid::rect(self.x, self.y, self.width, self.height)
199    }
200}
201
202/// This trait represents access to a buffer of pixels the software renderer can render into, as well
203/// as certain operations that the renderer will try to delegate to this trait. Implement these functions
204/// to delegate rendering further to hardware-provided 2D acceleration units, such as DMA2D or PXP.
205pub trait TargetPixelBuffer {
206    /// The pixel type the buffer represents.
207    type TargetPixel: TargetPixel;
208
209    /// Returns a slice of pixels for the given line.
210    fn line_slice(&mut self, line_number: usize) -> &mut [Self::TargetPixel];
211
212    /// Returns the number of lines the buffer has. This is typically the height in pixels.
213    fn num_lines(&self) -> usize;
214
215    /// Fill the background of the buffer with the given brush.
216    fn fill_background(&mut self, _brush: &Brush, _region: &PhysicalRegion) -> bool {
217        false
218    }
219
220    /// Draw a rectangle specified by the DrawRectangleArgs. That rectangle must be clipped to the given region
221    fn draw_rectangle(&mut self, _: &DrawRectangleArgs, _clip: &PhysicalRegion) -> bool {
222        false
223    }
224
225    /// Draw a texture into the buffer.
226    /// The texture must be clipped to the given region.
227    /// Returns true if the operation was successful; false if it could not be
228    /// implemented and instead the software renderer needs to draw the texture
229    fn draw_texture(&mut self, _: &DrawTextureArgs, _clip: &PhysicalRegion) -> bool {
230        false
231    }
232}