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}