ribir_gpu/
lib.rs

1pub mod error;
2use std::ops::Range;
3
4pub use gpu_backend::Texture;
5use ribir_geom::{DevicePoint, DeviceRect, DeviceSize};
6use ribir_painter::{image::ColorFormat, Color, GradientStop, VertexBuffers};
7mod gpu_backend;
8use zerocopy::AsBytes;
9
10#[cfg(feature = "wgpu")]
11pub mod wgpu_impl;
12pub use gpu_backend::*;
13#[cfg(feature = "wgpu")]
14pub use wgpu_impl::*;
15
16/// Trait to help implement a gpu backend.
17///
18/// The call graph:
19///
20/// -- begin_frame()
21
22///   +--->-------- Draw Phase --------------------------+
23///   |                                                  |
24///   |    +->- new_texture()----+                       |   
25///   |    +-<-------<------<----+                       |
26///   |                                                  v
27///   | -> load_alpha_vertices()                         |
28///   |                                                  |
29///   | -> + draw_alpha_triangles_with_scissor()--+      |
30///   |    ^                                      v      |
31///   |    ^----<-----------<---------------------+      |
32///   |                                                  |
33///   | -> + draw_alpha_triangles()---------------+      |
34///   |    ^                                      v      |
35///   |    +----<-----------<---------------------+      |
36///   |                                                  |
37///   | -> load_textures()                               |
38///   | -> load_mask_layers()                            |
39///   |                                                  |    
40///   |        +--------------------------+              |
41///   |        |  load_color_vertices()   |              |
42///   |     +->|  draw_color_triangles()  |              |
43///   |     |  +--------------------------+              |
44///   |     |                                            |
45///   |     |  +--------------------------+              |
46///   |     |  | load_img_primitives()    |              |
47///   |     +->| load_image_vertices()    |              |
48///   |     |  | draw_img_triangles()     |              |
49///   |     |  +--------------------------+              |
50///   |     |                                            |
51///   | ->  |  +------------------------------------+    |
52///   |     |  | load_radial_gradient_primitives()  |    v
53///   |     +->| load_radial_gradient_stops()       |    |
54///   |     |  | load_radial_gradient_vertices()    |    |
55///   |     |  | draw_radial_gradient_triangles()   |    |
56///   |     |  +------------------------------------+    |
57///   |     |                                            |
58///   |     |  +------------------------------------+    |
59///   |     |  | load_linear_gradient_primitives()  |    |
60///   |     +->| load_linear_gradient_stops()       |    |
61///   |        | load_linear_gradient_vertices()    |    |
62///   |        | draw_linear_gradient_triangles()   |    |
63///   |        +------------------------------------+    |
64///   +---<----------------------------------------------+
65///
66/// -+ ->- end_frame()
67///
68/// The coordinate always start from the left-top to right-bottom. Vertices
69/// use percent as value, and others use pixel value.
70///     Vertices Axis           Device axis
71///  0  +----x----+> 1       0 +----x-----+> width
72///     |         |            |          |   
73///     y         |            y          |
74///     |         |            |          |
75///     +---------+            +----------+
76///     v                      v
77///     1                     height
78
79pub trait GPUBackendImpl {
80  type Texture: Texture;
81
82  /// A frame start, call once per frame
83  fn begin_frame(&mut self);
84
85  /// Returns the limits of the GPU backend.
86  fn limits(&self) -> &DrawPhaseLimits;
87
88  /// Create a texture.
89  fn new_texture(&mut self, size: DeviceSize, format: ColorFormat) -> Self::Texture;
90  /// Load the vertices and indices buffer that `draw_alpha_triangles` &
91  /// `draw_alpha_triangles_with_scissor` will use.
92  fn load_alpha_vertices(&mut self, buffers: &VertexBuffers<()>);
93  /// Draw triangles only alpha channel with 1.0. Caller guarantee the texture
94  /// format is `ColorFormat::Alpha8`, caller will try to batch as much as
95  /// possible, but also possibly call multi times in a frame.
96  fn draw_alpha_triangles(&mut self, indices: &Range<u32>, texture: &mut Self::Texture);
97  /// Same behavior as `draw_alpha_triangles`, but the Vertex with a offset and
98  /// gives a clip rectangle for the texture, the path should only painting in
99  /// the rectangle.
100  fn draw_alpha_triangles_with_scissor(
101    &mut self, indices: &Range<u32>, texture: &mut Self::Texture, scissor: DeviceRect,
102  );
103
104  /// load textures that will be use in this draw phase
105  fn load_textures(&mut self, textures: &[&Self::Texture]);
106  /// load the mask layers that the current draw phase will use, called at
107  /// most once per draw phase.
108  fn load_mask_layers(&mut self, layers: &[MaskLayer]);
109  /// Load the vertices and indices buffer that `draw_color_triangles` will
110  /// use.
111  fn load_color_vertices(&mut self, buffers: &VertexBuffers<ColorAttr>);
112  /// Load the vertices and indices buffer that `draw_img_triangles` will use.
113  fn load_img_primitives(&mut self, primitives: &[ImgPrimitive]);
114  /// Load the vertices and indices buffer that `draw_img_triangles` will use.
115  fn load_img_vertices(&mut self, buffers: &VertexBuffers<ImagePrimIndex>);
116
117  /// Load the primitives that `draw_radial_gradient_triangles` will use.
118  fn load_radial_gradient_primitives(&mut self, primitives: &[RadialGradientPrimitive]);
119  /// Load the gradient color stops that `draw_radial_gradient_triangles` will
120  /// use.
121  fn load_radial_gradient_stops(&mut self, stops: &[GradientStopPrimitive]);
122  /// Load the vertices and indices buffer that `draw_radial_gradient_triangles`
123  /// will use.
124  fn load_radial_gradient_vertices(&mut self, buffers: &VertexBuffers<RadialGradientPrimIndex>);
125
126  /// Load the primitives that `draw_linear_gradient_triangles` will use.
127  fn load_linear_gradient_primitives(&mut self, primitives: &[LinearGradientPrimitive]);
128  /// Load the gradient color stops that `draw_linear_gradient_triangles` will
129  /// use.
130  fn load_linear_gradient_stops(&mut self, stops: &[GradientStopPrimitive]);
131  /// Load the vertices and indices buffer that `draw_linear_gradient_triangles`
132  /// will use.
133  fn load_linear_gradient_vertices(&mut self, buffers: &VertexBuffers<LinearGradientPrimIndex>);
134  /// Draw pure color triangles in the texture. And use the clear color clear
135  /// the texture first if it's a Some-Value
136  fn draw_color_triangles(
137    &mut self, texture: &mut Self::Texture, indices: Range<u32>, clear: Option<Color>,
138  );
139  /// Draw triangles fill with image. And use the clear color clear the texture
140  /// first if it's a Some-Value
141  fn draw_img_triangles(
142    &mut self, texture: &mut Self::Texture, indices: Range<u32>, clear: Option<Color>,
143  );
144  /// Draw triangles fill with color radial gradient. And use the clear color
145  /// clear the texture first if it's a Some-Value
146  fn draw_radial_gradient_triangles(
147    &mut self, texture: &mut Self::Texture, indices: Range<u32>, clear: Option<Color>,
148  );
149
150  /// Draw triangles fill with color linear gradient. And use the clear color
151  /// clear the texture first if it's a Some-Value
152  fn draw_linear_gradient_triangles(
153    &mut self, texture: &mut Self::Texture, indices: Range<u32>, clear: Option<Color>,
154  );
155
156  fn copy_texture_from_texture(
157    &mut self, dist_tex: &mut Self::Texture, copy_to: DevicePoint, from_tex: &Self::Texture,
158    from_rect: &DeviceRect,
159  );
160  /// A frame end, call once per frame
161  fn end_frame(&mut self);
162}
163
164/// Represents the sets of limits an GPU backend can provide in a single draw
165pub struct DrawPhaseLimits {
166  /// The maximum size of the texture that the backend can create.
167  pub texture_size: DeviceSize,
168  /// The maximum number of textures that the backend can load in a single draw
169  pub max_tex_load: usize,
170  /// The maximum number of mask layers that the backend can load in a single
171  /// draw phase
172  pub max_image_primitives: usize,
173  /// The maximum number of radial gradient primitives that the backend can load
174  /// in a single draw
175  pub max_radial_gradient_primitives: usize,
176  /// The maximum number of linear gradient primitives that the backend can load
177  /// in a single draw
178  pub max_linear_gradient_primitives: usize,
179  /// The maximum number of gradient stops that the backend can load in a single
180  /// draw phase
181  pub max_gradient_stop_primitives: usize,
182  /// The maximum number of mask layers that the backend can load in a single
183  pub max_mask_layers: usize,
184}
185
186#[repr(packed)]
187#[derive(AsBytes, PartialEq, Clone, Copy)]
188pub struct ColorAttr {
189  /// brush's Rgba color
190  pub color: [u8; 4],
191  /// The index of the head mask layer.
192  pub mask_head: i32,
193}
194
195#[repr(packed)]
196#[derive(AsBytes, PartialEq, Clone, Copy, Debug)]
197pub struct ImagePrimIndex(u32);
198
199#[repr(packed)]
200#[derive(AsBytes, PartialEq, Clone, Copy, Debug)]
201pub struct RadialGradientPrimIndex(u32);
202
203#[repr(packed)]
204#[derive(AsBytes, PartialEq, Clone, Copy, Debug)]
205pub struct LinearGradientPrimIndex(u32);
206
207#[repr(packed)]
208#[derive(AsBytes, PartialEq, Clone, Copy, Debug)]
209pub struct GradientStopPrimitive {
210  pub color: u32,
211  pub offset: f32,
212}
213
214impl GradientStopPrimitive {
215  fn new(stop: &GradientStop) -> Self {
216    GradientStopPrimitive { color: stop.color.into_u32(), offset: stop.offset }
217  }
218}
219
220#[repr(packed)]
221#[derive(AsBytes, PartialEq, Clone, Copy, Debug)]
222pub struct RadialGradientPrimitive {
223  /// A 2x3 column-major matrix, transform a vertex position to the texture
224  /// position
225  pub transform: [f32; 6],
226  /// The color stop's start index
227  pub stop_start: u32,
228  /// The size of the color stop
229  pub stop_cnt: u32,
230  /// position of the start center
231  pub start_center: [f32; 2],
232  /// position of the end center
233  pub end_center: [f32; 2],
234  /// the radius of the start circle.
235  pub start_radius: f32,
236  /// the radius of the end circle.
237  pub end_radius: f32,
238  /// The index of the head mask layer.
239  pub mask_head: i32,
240  /// the spread method of the gradient. 0 for pad, 1 for reflect and 2
241  /// for repeat
242  pub spread: u32,
243}
244
245#[repr(packed)]
246#[derive(AsBytes, PartialEq, Clone, Copy, Debug)]
247pub struct LinearGradientPrimitive {
248  /// A 2x3 column-major matrix, transform a vertex position to the texture
249  /// position
250  pub transform: [f32; 6],
251  /// position of the start center
252  pub start_position: [f32; 2],
253  /// position of the end center
254  pub end_position: [f32; 2],
255  /// The color stop information, there are two parts:
256  /// - The high 16-bit index represents the start index of the color stop.
257  /// - The low 16-bit index represents the size of the color stop.
258  pub stop: u32,
259  /// A mix of two 16-bit values:
260  /// - The high 16-bit index represents the head mask layer.
261  /// - The low 16-bit represents the spread method of the gradient. 0 for pad,
262  ///   1 for reflect and 2 for repeat
263  pub mask_head_and_spread: i32,
264}
265
266#[repr(packed)]
267#[derive(AsBytes, PartialEq, Clone, Copy)]
268pub struct ImgPrimitive {
269  /// A 2x3 column-major matrix, transform a vertex position to the image
270  /// texture slice position.
271  pub transform: [f32; 6],
272  /// The origin of the image placed in texture.
273  pub img_start: [f32; 2],
274  /// The size of the image image.
275  pub img_size: [f32; 2],
276  /// This represents a mix of two 16-bit indices:
277  /// - The high 16-bit index represents the head mask layer. It is an i16.
278  /// - The low 16-bit index represents the texture. It is a u16.
279  pub mask_head_and_tex_idx: i32,
280  /// extra alpha apply to current vertex
281  pub opacity: f32,
282}
283
284/// The mask layer describes an alpha channel layer that is used in the fragment
285/// shader to sample the alpha channel and apply it to the color.
286#[derive(AsBytes, Clone)]
287#[repr(packed)]
288pub struct MaskLayer {
289  /// A 2x3 column-major matrix, transform a vertex position to its mask texture
290  /// position.
291  pub transform: [f32; 6],
292  /// The min position this layer in the texture.
293  pub min: [f32; 2],
294  /// max min position this layer in the texture.
295  pub max: [f32; 2],
296  /// The index of the texture(alpha) that contained this layer,
297  /// `load_textures` method provide all textures a draw phase need.
298  pub mask_tex_idx: u32,
299  /// The index of the previous mask layer needs to continue to be applied. The
300  /// negative value means there isn't any more mask layer that needs to be
301  /// applied.
302  pub prev_mask_idx: i32,
303}