2020-05-19 17:15:44 +02:00
|
|
|
use crate::quad;
|
|
|
|
|
use crate::text;
|
|
|
|
|
use crate::triangle;
|
2020-05-20 20:28:35 +02:00
|
|
|
use crate::{Settings, Transformation};
|
2021-08-26 14:41:33 +07:00
|
|
|
|
2020-05-19 17:15:44 +02:00
|
|
|
use iced_graphics::backend;
|
2020-05-19 22:55:12 +02:00
|
|
|
use iced_graphics::layer::Layer;
|
2020-05-20 20:28:35 +02:00
|
|
|
use iced_graphics::{Primitive, Viewport};
|
2021-09-20 15:09:55 +07:00
|
|
|
use iced_native::{Font, Size};
|
2020-02-28 14:38:42 +01:00
|
|
|
|
2022-12-20 20:41:09 -08:00
|
|
|
#[cfg(feature = "tracing")]
|
|
|
|
|
use tracing::info_span;
|
2022-11-29 19:50:58 -08:00
|
|
|
|
2022-11-05 03:26:19 +01:00
|
|
|
#[cfg(any(feature = "image", feature = "svg"))]
|
2020-05-19 22:55:12 +02:00
|
|
|
use crate::image;
|
2020-02-28 14:38:42 +01:00
|
|
|
|
2023-02-04 11:12:15 +01:00
|
|
|
use std::borrow::Cow;
|
|
|
|
|
|
2020-05-28 01:37:59 +02:00
|
|
|
/// A [`wgpu`] graphics backend for [`iced`].
|
2019-11-22 22:14:24 +01:00
|
|
|
///
|
|
|
|
|
/// [`wgpu`]: https://github.com/gfx-rs/wgpu-rs
|
2021-12-23 09:34:37 +02:00
|
|
|
/// [`iced`]: https://github.com/iced-rs/iced
|
2023-01-31 06:29:21 +01:00
|
|
|
#[allow(missing_debug_implementations)]
|
2020-05-19 17:15:44 +02:00
|
|
|
pub struct Backend {
|
2019-10-07 03:56:16 +02:00
|
|
|
quad_pipeline: quad::Pipeline,
|
2019-11-13 03:54:36 +01:00
|
|
|
text_pipeline: text::Pipeline,
|
2020-02-28 14:38:42 +01:00
|
|
|
triangle_pipeline: triangle::Pipeline,
|
|
|
|
|
|
2022-11-05 03:26:19 +01:00
|
|
|
#[cfg(any(feature = "image", feature = "svg"))]
|
2020-02-28 14:38:42 +01:00
|
|
|
image_pipeline: image::Pipeline,
|
2020-06-19 00:08:28 +02:00
|
|
|
|
2023-02-04 07:33:33 +01:00
|
|
|
default_font: Font,
|
2023-02-04 16:41:18 +01:00
|
|
|
default_text_size: f32,
|
2019-10-05 19:22:51 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-19 17:15:44 +02:00
|
|
|
impl Backend {
|
2020-05-30 03:03:59 +02:00
|
|
|
/// Creates a new [`Backend`].
|
2021-08-01 20:38:34 +02:00
|
|
|
pub fn new(
|
|
|
|
|
device: &wgpu::Device,
|
2023-01-31 06:29:21 +01:00
|
|
|
queue: &wgpu::Queue,
|
2021-08-01 20:38:34 +02:00
|
|
|
settings: Settings,
|
|
|
|
|
format: wgpu::TextureFormat,
|
|
|
|
|
) -> Self {
|
2023-02-04 07:33:33 +01:00
|
|
|
let text_pipeline = text::Pipeline::new(device, queue, format);
|
2021-08-01 20:38:34 +02:00
|
|
|
let quad_pipeline = quad::Pipeline::new(device, format);
|
|
|
|
|
let triangle_pipeline =
|
|
|
|
|
triangle::Pipeline::new(device, format, settings.antialiasing);
|
2019-10-07 03:56:16 +02:00
|
|
|
|
2022-11-05 03:26:19 +01:00
|
|
|
#[cfg(any(feature = "image", feature = "svg"))]
|
2021-08-01 20:38:34 +02:00
|
|
|
let image_pipeline = image::Pipeline::new(device, format);
|
2020-02-28 14:38:42 +01:00
|
|
|
|
2019-10-05 19:22:51 +02:00
|
|
|
Self {
|
2019-10-07 03:56:16 +02:00
|
|
|
quad_pipeline,
|
2019-11-11 06:07:31 +01:00
|
|
|
text_pipeline,
|
2020-01-02 19:25:00 +01:00
|
|
|
triangle_pipeline,
|
2020-02-28 14:38:42 +01:00
|
|
|
|
2022-11-05 03:26:19 +01:00
|
|
|
#[cfg(any(feature = "image", feature = "svg"))]
|
2020-02-28 14:38:42 +01:00
|
|
|
image_pipeline,
|
2020-06-19 00:08:28 +02:00
|
|
|
|
2023-02-04 07:33:33 +01:00
|
|
|
default_font: settings.default_font,
|
2020-06-19 00:08:28 +02:00
|
|
|
default_text_size: settings.default_text_size,
|
2019-10-05 19:22:51 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-30 03:03:59 +02:00
|
|
|
/// Draws the provided primitives in the given `TextureView`.
|
2020-02-09 03:25:13 +01:00
|
|
|
///
|
2020-05-30 03:03:59 +02:00
|
|
|
/// The text provided as overlay will be rendered on top of the primitives.
|
2020-02-09 03:25:13 +01:00
|
|
|
/// This is useful for rendering debug information.
|
2021-10-14 16:07:22 +07:00
|
|
|
pub fn present<T: AsRef<str>>(
|
2019-10-09 05:36:49 +02:00
|
|
|
&mut self,
|
2020-04-16 09:06:05 +03:00
|
|
|
device: &wgpu::Device,
|
2023-01-31 06:29:21 +01:00
|
|
|
queue: &wgpu::Queue,
|
2020-08-27 13:03:42 +02:00
|
|
|
staging_belt: &mut wgpu::util::StagingBelt,
|
2020-02-09 03:25:13 +01:00
|
|
|
encoder: &mut wgpu::CommandEncoder,
|
2020-05-20 20:28:35 +02:00
|
|
|
frame: &wgpu::TextureView,
|
2021-10-14 16:59:19 +07:00
|
|
|
primitives: &[Primitive],
|
2020-05-20 20:28:35 +02:00
|
|
|
viewport: &Viewport,
|
2020-05-19 22:55:12 +02:00
|
|
|
overlay_text: &[T],
|
2021-10-14 16:07:22 +07:00
|
|
|
) {
|
2019-10-07 04:05:40 +02:00
|
|
|
log::debug!("Drawing");
|
2022-12-20 20:41:09 -08:00
|
|
|
#[cfg(feature = "tracing")]
|
2022-11-29 19:50:58 -08:00
|
|
|
let _ = info_span!("Wgpu::Backend", "PRESENT").entered();
|
2019-10-07 04:05:40 +02:00
|
|
|
|
2020-05-20 20:28:35 +02:00
|
|
|
let target_size = viewport.physical_size();
|
|
|
|
|
let scale_factor = viewport.scale_factor() as f32;
|
|
|
|
|
let transformation = viewport.projection();
|
2019-10-05 19:22:51 +02:00
|
|
|
|
2021-10-14 16:59:19 +07:00
|
|
|
let mut layers = Layer::generate(primitives, viewport);
|
2020-05-20 20:28:35 +02:00
|
|
|
layers.push(Layer::overlay(overlay_text, viewport));
|
2019-10-29 02:00:17 +01:00
|
|
|
|
2023-02-07 19:26:41 +01:00
|
|
|
for layer in layers {
|
2020-01-09 03:56:13 +01:00
|
|
|
self.flush(
|
2020-02-09 03:25:13 +01:00
|
|
|
device,
|
2023-01-31 06:29:21 +01:00
|
|
|
queue,
|
2020-01-09 03:56:13 +01:00
|
|
|
scale_factor,
|
|
|
|
|
transformation,
|
|
|
|
|
&layer,
|
2020-08-27 13:03:42 +02:00
|
|
|
staging_belt,
|
2020-02-09 03:25:13 +01:00
|
|
|
encoder,
|
2022-07-04 01:17:29 +02:00
|
|
|
frame,
|
2022-11-03 04:35:16 +01:00
|
|
|
target_size,
|
2020-01-09 03:56:13 +01:00
|
|
|
);
|
2019-10-29 02:00:17 +01:00
|
|
|
}
|
2019-10-23 01:21:23 +02:00
|
|
|
|
2023-02-06 22:21:27 +01:00
|
|
|
self.quad_pipeline.end_frame();
|
2023-02-01 03:24:14 +01:00
|
|
|
self.text_pipeline.end_frame();
|
|
|
|
|
|
2022-11-05 03:26:19 +01:00
|
|
|
#[cfg(any(feature = "image", feature = "svg"))]
|
2023-02-07 22:53:08 +01:00
|
|
|
self.image_pipeline.end_frame(device, queue, encoder);
|
2019-10-09 05:36:49 +02:00
|
|
|
}
|
2019-10-11 22:15:39 +02:00
|
|
|
|
2019-10-25 03:47:34 +02:00
|
|
|
fn flush(
|
|
|
|
|
&mut self,
|
2020-04-16 09:06:05 +03:00
|
|
|
device: &wgpu::Device,
|
2023-01-31 06:29:21 +01:00
|
|
|
queue: &wgpu::Queue,
|
2020-01-09 03:56:13 +01:00
|
|
|
scale_factor: f32,
|
2019-10-25 03:47:34 +02:00
|
|
|
transformation: Transformation,
|
2019-11-22 22:14:24 +01:00
|
|
|
layer: &Layer<'_>,
|
2020-08-27 13:03:42 +02:00
|
|
|
staging_belt: &mut wgpu::util::StagingBelt,
|
2019-10-25 03:47:34 +02:00
|
|
|
encoder: &mut wgpu::CommandEncoder,
|
|
|
|
|
target: &wgpu::TextureView,
|
2022-09-29 10:52:58 -07:00
|
|
|
target_size: Size<u32>,
|
2019-10-25 03:47:34 +02:00
|
|
|
) {
|
2020-06-02 04:38:55 +02:00
|
|
|
let bounds = (layer.bounds * scale_factor).snap();
|
2019-10-25 03:47:34 +02:00
|
|
|
|
2021-10-25 16:24:26 +07:00
|
|
|
if bounds.width < 1 || bounds.height < 1 {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-26 17:09:03 +02:00
|
|
|
if !layer.quads.is_empty() {
|
2023-02-06 22:21:27 +01:00
|
|
|
self.quad_pipeline.prepare(
|
2020-04-26 17:09:03 +02:00
|
|
|
device,
|
2023-02-06 22:21:27 +01:00
|
|
|
queue,
|
2020-04-26 17:09:03 +02:00
|
|
|
&layer.quads,
|
|
|
|
|
transformation,
|
|
|
|
|
scale_factor,
|
|
|
|
|
);
|
2023-02-06 22:21:27 +01:00
|
|
|
|
|
|
|
|
let mut render_pass =
|
|
|
|
|
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
|
|
|
|
label: Some("iced_wgpu::quad render pass"),
|
|
|
|
|
color_attachments: &[Some(
|
|
|
|
|
wgpu::RenderPassColorAttachment {
|
|
|
|
|
view: target,
|
|
|
|
|
resolve_target: None,
|
|
|
|
|
ops: wgpu::Operations {
|
|
|
|
|
load: wgpu::LoadOp::Load,
|
|
|
|
|
store: true,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
)],
|
|
|
|
|
depth_stencil_attachment: None,
|
|
|
|
|
});
|
|
|
|
|
|
2023-02-07 19:26:41 +01:00
|
|
|
self.quad_pipeline.render(bounds, &mut render_pass);
|
2020-04-26 17:09:03 +02:00
|
|
|
}
|
|
|
|
|
|
2022-10-04 18:24:46 -07:00
|
|
|
if !layer.meshes.is_empty() {
|
2020-03-07 23:45:54 +01:00
|
|
|
let scaled = transformation
|
|
|
|
|
* Transformation::scale(scale_factor, scale_factor);
|
2020-01-02 19:25:00 +01:00
|
|
|
|
|
|
|
|
self.triangle_pipeline.draw(
|
2020-02-09 03:25:13 +01:00
|
|
|
device,
|
2020-08-27 13:03:42 +02:00
|
|
|
staging_belt,
|
2020-01-02 19:25:00 +01:00
|
|
|
encoder,
|
|
|
|
|
target,
|
2022-09-29 10:52:58 -07:00
|
|
|
target_size,
|
2020-03-07 23:45:54 +01:00
|
|
|
scaled,
|
2020-04-28 04:41:09 +02:00
|
|
|
scale_factor,
|
2020-01-02 19:25:00 +01:00
|
|
|
&layer.meshes,
|
|
|
|
|
);
|
2019-10-29 01:21:28 +01:00
|
|
|
}
|
2019-10-25 03:47:34 +02:00
|
|
|
|
2022-11-05 03:26:19 +01:00
|
|
|
#[cfg(any(feature = "image", feature = "svg"))]
|
2020-02-28 14:38:42 +01:00
|
|
|
{
|
2020-03-29 15:04:11 +02:00
|
|
|
if !layer.images.is_empty() {
|
2020-03-07 23:45:54 +01:00
|
|
|
let scaled = transformation
|
|
|
|
|
* Transformation::scale(scale_factor, scale_factor);
|
2020-02-28 14:38:42 +01:00
|
|
|
|
2023-02-07 22:53:08 +01:00
|
|
|
self.image_pipeline.prepare(
|
2020-02-28 14:38:42 +01:00
|
|
|
device,
|
2023-02-07 22:53:08 +01:00
|
|
|
queue,
|
2020-02-28 14:38:42 +01:00
|
|
|
encoder,
|
|
|
|
|
&layer.images,
|
2020-03-07 23:45:54 +01:00
|
|
|
scaled,
|
2020-02-28 14:38:42 +01:00
|
|
|
scale_factor,
|
2019-11-05 05:26:20 +01:00
|
|
|
);
|
2023-02-07 22:53:08 +01:00
|
|
|
|
|
|
|
|
let mut render_pass =
|
|
|
|
|
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
|
|
|
|
label: Some("iced_wgpu::image render pass"),
|
|
|
|
|
color_attachments: &[Some(
|
|
|
|
|
wgpu::RenderPassColorAttachment {
|
|
|
|
|
view: target,
|
|
|
|
|
resolve_target: None,
|
|
|
|
|
ops: wgpu::Operations {
|
|
|
|
|
load: wgpu::LoadOp::Load,
|
|
|
|
|
store: true,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
)],
|
|
|
|
|
depth_stencil_attachment: None,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
self.image_pipeline.render(bounds, &mut render_pass);
|
2020-02-28 14:38:42 +01:00
|
|
|
}
|
2019-12-06 16:47:40 +01:00
|
|
|
}
|
|
|
|
|
|
2020-03-28 15:25:55 -07:00
|
|
|
if !layer.text.is_empty() {
|
2023-01-31 06:29:21 +01:00
|
|
|
self.text_pipeline.prepare(
|
|
|
|
|
device,
|
|
|
|
|
queue,
|
|
|
|
|
&layer.text,
|
2023-02-01 03:24:14 +01:00
|
|
|
layer.bounds,
|
2023-01-31 06:29:21 +01:00
|
|
|
scale_factor,
|
|
|
|
|
target_size,
|
|
|
|
|
);
|
2019-10-27 03:11:54 +01:00
|
|
|
|
2023-01-31 06:29:21 +01:00
|
|
|
self.text_pipeline.render(encoder, target);
|
2019-10-27 03:11:54 +01:00
|
|
|
}
|
2019-10-05 19:22:51 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-19 17:15:44 +02:00
|
|
|
impl iced_graphics::Backend for Backend {
|
|
|
|
|
fn trim_measurements(&mut self) {
|
|
|
|
|
self.text_pipeline.trim_measurement_cache()
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-11 06:07:31 +01:00
|
|
|
|
2020-05-19 17:15:44 +02:00
|
|
|
impl backend::Text for Backend {
|
2023-02-04 07:33:33 +01:00
|
|
|
const ICON_FONT: Font = Font::Name("Iced-Icons");
|
2023-02-04 11:35:12 +01:00
|
|
|
const CHECKMARK_ICON: char = '\u{f00c}';
|
|
|
|
|
const ARROW_DOWN_ICON: char = '\u{e800}';
|
2023-02-04 07:33:33 +01:00
|
|
|
|
|
|
|
|
fn default_font(&self) -> Font {
|
|
|
|
|
self.default_font
|
|
|
|
|
}
|
2020-05-19 17:15:44 +02:00
|
|
|
|
2023-02-04 16:41:18 +01:00
|
|
|
fn default_size(&self) -> f32 {
|
2020-06-19 00:08:28 +02:00
|
|
|
self.default_text_size
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-19 17:15:44 +02:00
|
|
|
fn measure(
|
|
|
|
|
&self,
|
|
|
|
|
contents: &str,
|
|
|
|
|
size: f32,
|
|
|
|
|
font: Font,
|
|
|
|
|
bounds: Size,
|
|
|
|
|
) -> (f32, f32) {
|
|
|
|
|
self.text_pipeline.measure(contents, size, font, bounds)
|
|
|
|
|
}
|
2021-08-21 10:31:26 -07:00
|
|
|
|
|
|
|
|
fn hit_test(
|
|
|
|
|
&self,
|
|
|
|
|
contents: &str,
|
|
|
|
|
size: f32,
|
|
|
|
|
font: Font,
|
|
|
|
|
bounds: Size,
|
|
|
|
|
point: iced_native::Point,
|
|
|
|
|
nearest_only: bool,
|
2021-09-15 14:49:13 +07:00
|
|
|
) -> Option<text::Hit> {
|
2021-08-21 10:31:26 -07:00
|
|
|
self.text_pipeline.hit_test(
|
|
|
|
|
contents,
|
|
|
|
|
size,
|
|
|
|
|
font,
|
|
|
|
|
bounds,
|
|
|
|
|
point,
|
|
|
|
|
nearest_only,
|
|
|
|
|
)
|
|
|
|
|
}
|
2023-02-04 11:12:15 +01:00
|
|
|
|
|
|
|
|
fn load_font(&mut self, font: Cow<'static, [u8]>) {
|
|
|
|
|
self.text_pipeline.load_font(font);
|
|
|
|
|
}
|
2019-10-05 19:22:51 +02:00
|
|
|
}
|
|
|
|
|
|
2022-11-05 03:26:19 +01:00
|
|
|
#[cfg(feature = "image")]
|
2020-05-19 17:15:44 +02:00
|
|
|
impl backend::Image for Backend {
|
2022-11-05 03:13:04 +01:00
|
|
|
fn dimensions(&self, handle: &iced_native::image::Handle) -> Size<u32> {
|
2020-05-19 17:15:44 +02:00
|
|
|
self.image_pipeline.dimensions(handle)
|
2019-10-13 18:22:26 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-19 17:15:44 +02:00
|
|
|
#[cfg(feature = "svg")]
|
|
|
|
|
impl backend::Svg for Backend {
|
|
|
|
|
fn viewport_dimensions(
|
|
|
|
|
&self,
|
2021-10-31 16:24:31 +07:00
|
|
|
handle: &iced_native::svg::Handle,
|
2022-11-05 03:13:04 +01:00
|
|
|
) -> Size<u32> {
|
2020-05-19 17:15:44 +02:00
|
|
|
self.image_pipeline.viewport_dimensions(handle)
|
2019-10-05 19:22:51 +02:00
|
|
|
}
|
|
|
|
|
}
|