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}