piet_hardware/
gpu_backend.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later OR MPL-2.0
2// This file is a part of `piet-hardware`.
3//
4// `piet-hardware` is free software: you can redistribute it and/or modify it under the
5// terms of either:
6//
7// * GNU Lesser General Public License as published by the Free Software Foundation, either
8//   version 3 of the License, or (at your option) any later version.
9// * Mozilla Public License as published by the Mozilla Foundation, version 2.
10//
11// `piet-hardware` is distributed in the hope that it will be useful, but WITHOUT ANY
12// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13// PURPOSE. See the GNU Lesser General Public License or the Mozilla Public License for more
14// details.
15//
16// You should have received a copy of the GNU Lesser General Public License and the Mozilla
17// Public License along with `piet-hardware`. If not, see <https://www.gnu.org/licenses/>.
18
19//! Defines the GPU backend for piet-hardware.
20
21use piet::kurbo::{Affine, Rect};
22use piet::InterpolationMode;
23
24use std::error::Error;
25
26/// The backend for the GPU renderer.
27pub trait GpuContext {
28    /// A "device" that can be used to render.
29    ///
30    /// This corresponds to [`Device`] in [`wgpu`] and nothing in particular in [`glow`].
31    ///
32    /// [`Device`]: wgpu::Device
33    /// [`wgpu`]: https://crates.io/crates/wgpu
34    /// [`glow`]: https://crates.io/crates/glow
35    type Device;
36
37    /// A "queue" that can be used to render.
38    ///
39    /// This corresponds to [`Queue`] in [`wgpu`] and nothing in particular in [`glow`].
40    ///
41    /// [`Queue`]: wgpu::Queue
42    /// [`wgpu`]: https://crates.io/crates/wgpu
43    /// [`glow`]: https://crates.io/crates/glow
44    type Queue;
45
46    /// The type associated with a GPU texture.
47    type Texture;
48
49    /// The type associated with a GPU vertex buffer.
50    ///
51    /// Contains vertices, indices and any layout data.
52    type VertexBuffer;
53
54    /// The error type associated with this GPU context.
55    type Error: Error + 'static;
56
57    /// Clear the screen with the given color.
58    fn clear(&mut self, device: &Self::Device, queue: &Self::Queue, color: piet::Color);
59
60    /// Flush the GPU commands.
61    fn flush(&mut self) -> Result<(), Self::Error>;
62
63    /// Create a new texture.
64    fn create_texture(
65        &mut self,
66        device: &Self::Device,
67        interpolation: InterpolationMode,
68        repeat: RepeatStrategy,
69    ) -> Result<Self::Texture, Self::Error>;
70
71    /// Write an image to a texture.
72    fn write_texture(&mut self, texture_write: TextureWrite<'_, Self>);
73
74    /// Write a sub-image to a texture.
75    fn write_subtexture(&mut self, subtexture_write: SubtextureWrite<'_, Self>);
76
77    /// Set the interpolation mode for a texture.
78    fn set_texture_interpolation(
79        &mut self,
80        device: &Self::Device,
81        texture: &Self::Texture,
82        interpolation: InterpolationMode,
83    );
84
85    /// Get the maximum texture size.
86    fn max_texture_size(&mut self, device: &Self::Device) -> (u32, u32);
87
88    /// Create a new vertex buffer.
89    fn create_vertex_buffer(
90        &mut self,
91        device: &Self::Device,
92    ) -> Result<Self::VertexBuffer, Self::Error>;
93
94    /// Write vertices to a vertex buffer.
95    ///
96    /// The indices must be valid for the vertices set; however, it is up to the GPU implementation
97    /// to actually check this.
98    fn write_vertices(
99        &mut self,
100        device: &Self::Device,
101        queue: &Self::Queue,
102        buffer: &Self::VertexBuffer,
103        vertices: &[Vertex],
104        indices: &[u32],
105    );
106
107    /// Capture an area from the screen and put it into a texture.
108    fn capture_area(&mut self, area_capture: AreaCapture<'_, Self>) -> Result<(), Self::Error>;
109
110    /// Push buffer data to the GPU.
111    ///
112    /// The backend is expected to set up a renderer that renders data in `vertex_buffer`,
113    /// using `current_texture` to fill the triangles and `mask_texture` to clip them. In addition,
114    /// the parameters `transform`, `viewport_size` and `clip` are also expected to be used.
115    fn push_buffers(&mut self, buffer_push: BufferPush<'_, Self>) -> Result<(), Self::Error>;
116}
117
118/// The data necessary to write an image into a texture.
119pub struct TextureWrite<'a, C: GpuContext + ?Sized> {
120    /// The device to render onto.
121    pub device: &'a C::Device,
122
123    /// The queue to push the operation into.
124    pub queue: &'a C::Queue,
125
126    /// The texture to write into.
127    pub texture: &'a C::Texture,
128
129    /// The size of the image.
130    pub size: (u32, u32),
131
132    /// The format of the image.
133    pub format: piet::ImageFormat,
134
135    /// The data to write.
136    ///
137    /// This is `None` if you want to write only zeroes.
138    pub data: Option<&'a [u8]>,
139}
140
141/// The data necessary to write an image into a portion of a texture.
142pub struct SubtextureWrite<'a, C: GpuContext + ?Sized> {
143    /// The device to render onto.
144    pub device: &'a C::Device,
145
146    /// The queue to push the operation into.
147    pub queue: &'a C::Queue,
148
149    /// The texture to write into.
150    pub texture: &'a C::Texture,
151
152    /// The offset to start writing at.
153    pub offset: (u32, u32),
154
155    /// The size of the image.
156    pub size: (u32, u32),
157
158    /// The format of the image.
159    pub format: piet::ImageFormat,
160
161    /// The data to write.
162    pub data: &'a [u8],
163}
164
165/// The data necessary to capture an area of the screen.
166pub struct AreaCapture<'a, C: GpuContext + ?Sized> {
167    /// The device to render onto.
168    pub device: &'a C::Device,
169
170    /// The queue to push the operation into.
171    pub queue: &'a C::Queue,
172
173    /// The texture to write into.
174    pub texture: &'a C::Texture,
175
176    /// The offset to start at.
177    pub offset: (u32, u32),
178
179    /// The size of the rectangle to capture.
180    pub size: (u32, u32),
181
182    /// The current bitmap scale.
183    pub bitmap_scale: f64,
184}
185
186/// The data necessary to push buffer data to the GPU.
187pub struct BufferPush<'a, C: GpuContext + ?Sized> {
188    /// The device to render onto.
189    pub device: &'a C::Device,
190
191    /// The queue to push the operation into.
192    pub queue: &'a C::Queue,
193
194    /// The vertex buffer to use when pushing data.
195    pub vertex_buffer: &'a C::VertexBuffer,
196
197    /// The texture to use as the background.
198    pub current_texture: &'a C::Texture,
199
200    /// The texture to use as the mask.
201    pub mask_texture: &'a C::Texture,
202
203    /// The transformation to apply to the vertices.
204    pub transform: &'a Affine,
205
206    /// The size of the viewport.
207    pub viewport_size: (u32, u32),
208
209    /// The rectangle to clip vertices to.
210    ///
211    /// This is sometimes known as the "scissor rect".
212    pub clip: Option<Rect>,
213}
214
215impl<C: GpuContext + ?Sized> GpuContext for &mut C {
216    type Device = C::Device;
217    type Queue = C::Queue;
218    type Texture = C::Texture;
219    type VertexBuffer = C::VertexBuffer;
220    type Error = C::Error;
221
222    fn capture_area(&mut self, area_capture: AreaCapture<'_, Self>) -> Result<(), Self::Error> {
223        // Convert &C to C
224        let AreaCapture {
225            device,
226            queue,
227            texture,
228            offset,
229            size,
230            bitmap_scale,
231        } = area_capture;
232
233        (**self).capture_area(AreaCapture {
234            device,
235            queue,
236            texture,
237            offset,
238            size,
239            bitmap_scale,
240        })
241    }
242
243    fn clear(&mut self, device: &Self::Device, queue: &Self::Queue, color: piet::Color) {
244        (**self).clear(device, queue, color)
245    }
246
247    fn create_texture(
248        &mut self,
249        device: &Self::Device,
250        interpolation: InterpolationMode,
251        repeat: RepeatStrategy,
252    ) -> Result<Self::Texture, Self::Error> {
253        (**self).create_texture(device, interpolation, repeat)
254    }
255
256    fn create_vertex_buffer(
257        &mut self,
258        device: &Self::Device,
259    ) -> Result<Self::VertexBuffer, Self::Error> {
260        (**self).create_vertex_buffer(device)
261    }
262
263    fn flush(&mut self) -> Result<(), Self::Error> {
264        (**self).flush()
265    }
266
267    fn max_texture_size(&mut self, device: &Self::Device) -> (u32, u32) {
268        (**self).max_texture_size(device)
269    }
270
271    fn push_buffers(&mut self, buffer_push: BufferPush<'_, Self>) -> Result<(), Self::Error> {
272        // C and &C are different types, so make sure to convert.
273        let BufferPush {
274            device,
275            queue,
276            vertex_buffer,
277            current_texture,
278            mask_texture,
279            transform,
280            viewport_size,
281            clip,
282        } = buffer_push;
283
284        (**self).push_buffers(BufferPush {
285            device,
286            queue,
287            vertex_buffer,
288            current_texture,
289            mask_texture,
290            transform,
291            viewport_size,
292            clip,
293        })
294    }
295
296    fn set_texture_interpolation(
297        &mut self,
298        device: &Self::Device,
299        texture: &Self::Texture,
300        interpolation: InterpolationMode,
301    ) {
302        (**self).set_texture_interpolation(device, texture, interpolation)
303    }
304
305    fn write_subtexture(&mut self, subtexture_write: SubtextureWrite<'_, Self>) {
306        // Convert type from &C to C
307        let SubtextureWrite {
308            device,
309            queue,
310            texture,
311            offset,
312            size,
313            format,
314            data,
315        } = subtexture_write;
316
317        (**self).write_subtexture(SubtextureWrite {
318            device,
319            queue,
320            texture,
321            offset,
322            size,
323            format,
324            data,
325        })
326    }
327
328    fn write_texture(&mut self, texture_write: TextureWrite<'_, Self>) {
329        // Convert type from &C to C
330        let TextureWrite {
331            device,
332            queue,
333            texture,
334            size,
335            format,
336            data,
337        } = texture_write;
338
339        (**self).write_texture(TextureWrite {
340            device,
341            queue,
342            texture,
343            size,
344            format,
345            data,
346        })
347    }
348
349    fn write_vertices(
350        &mut self,
351        device: &Self::Device,
352        queue: &Self::Queue,
353        buffer: &Self::VertexBuffer,
354        vertices: &[Vertex],
355        indices: &[u32],
356    ) {
357        (**self).write_vertices(device, queue, buffer, vertices, indices)
358    }
359}
360
361/// The strategy to use for repeating.
362#[derive(Debug, Copy, Clone, PartialEq)]
363#[non_exhaustive]
364pub enum RepeatStrategy {
365    /// Repeat the image.
366    Repeat,
367
368    /// Clamp to the edge of the image.
369    Clamp,
370
371    /// Don't repeat and instead use this color.
372    Color(piet::Color),
373}
374
375/// The vertex type used by the GPU renderer.
376#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Default, bytemuck::Pod, bytemuck::Zeroable)]
377#[repr(C)]
378pub struct Vertex {
379    /// The position of the vertex.
380    pub pos: [f32; 2],
381
382    /// The coordinate of the vertex in the texture.
383    pub uv: [f32; 2],
384
385    /// The color of the vertex, in four SRGB channels.
386    pub color: [u8; 4],
387}
388
389/// The type of the buffer to use.
390#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
391pub enum BufferType {
392    /// The buffer is used for vertices.
393    Vertex,
394
395    /// The buffer is used for indices.
396    Index,
397}