diff options
author | 2021-07-22 12:37:39 -0500 | |
---|---|---|
committer | 2021-07-22 12:37:39 -0500 | |
commit | e822f654e44d2d7375b7fda966bb772055f377d4 (patch) | |
tree | 8707561f1bb09c9e58cc9d9884bfb16d956f9f65 /wgpu | |
parent | 1c06920158e1a47977b2762bf8b34e56fd1a935a (diff) | |
parent | dc0b96ce407283f2ffd9add5ad339f89097555d3 (diff) | |
download | iced-e822f654e44d2d7375b7fda966bb772055f377d4.tar.gz iced-e822f654e44d2d7375b7fda966bb772055f377d4.tar.bz2 iced-e822f654e44d2d7375b7fda966bb772055f377d4.zip |
Merge branch 'master' of https://github.com/hecrj/iced into wgpu_outdatedframe
Diffstat (limited to 'wgpu')
39 files changed, 772 insertions, 639 deletions
diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 5f4699a8..9675797d 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "iced_wgpu" -version = "0.3.0" +version = "0.4.0" authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] edition = "2018" description = "A wgpu renderer for Iced" @@ -8,14 +8,26 @@ license = "MIT AND OFL-1.1" repository = "https://github.com/hecrj/iced" [features] -svg = ["resvg"] +svg = ["resvg", "usvg"] +image = ["png", "jpeg", "jpeg_rayon", "gif", "webp", "bmp"] +png = ["image_rs/png"] +jpeg = ["image_rs/jpeg"] +jpeg_rayon = ["image_rs/jpeg_rayon"] +gif = ["image_rs/gif"] +webp = ["image_rs/webp"] +pnm = ["image_rs/pnm"] +ico = ["image_rs/ico"] +bmp = ["image_rs/bmp"] +hdr = ["image_rs/hdr"] +dds = ["image_rs/dds"] +farbfeld = ["image_rs/farbfeld"] canvas = ["iced_graphics/canvas"] qr_code = ["iced_graphics/qr_code"] default_system_font = ["iced_graphics/font-source"] [dependencies] -wgpu = "0.6" -wgpu_glyph = "0.10" +wgpu = "0.9" +wgpu_glyph = "0.13" glyph_brush = "0.7" raw-window-handle = "0.3" log = "0.4" @@ -27,21 +39,26 @@ version = "1.4" features = ["derive"] [dependencies.iced_native] -version = "0.3" +version = "0.4" path = "../native" [dependencies.iced_graphics] -version = "0.1" +version = "0.2" path = "../graphics" features = ["font-fallback", "font-icons"] -[dependencies.image] +[dependencies.image_rs] version = "0.23" +package = "image" +default-features = false optional = true [dependencies.resvg] -version = "0.9" -features = ["raqote-backend"] +version = "0.12" +optional = true + +[dependencies.usvg] +version = "0.12" optional = true [package.metadata.docs.rs] diff --git a/wgpu/README.md b/wgpu/README.md index e8cb0a43..a9d95ea7 100644 --- a/wgpu/README.md +++ b/wgpu/README.md @@ -29,7 +29,7 @@ Currently, `iced_wgpu` supports the following primitives: Add `iced_wgpu` as a dependency in your `Cargo.toml`: ```toml -iced_wgpu = "0.3" +iced_wgpu = "0.4" ``` __Iced moves fast and the `master` branch can contain breaking changes!__ If diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs index fccb5ac7..783079f3 100644 --- a/wgpu/src/backend.rs +++ b/wgpu/src/backend.rs @@ -9,7 +9,7 @@ use iced_graphics::{Primitive, Viewport}; use iced_native::mouse; use iced_native::{Font, HorizontalAlignment, Size, VerticalAlignment}; -#[cfg(any(feature = "image", feature = "svg"))] +#[cfg(any(feature = "image_rs", feature = "svg"))] use crate::image; /// A [`wgpu`] graphics backend for [`iced`]. @@ -22,7 +22,7 @@ pub struct Backend { text_pipeline: text::Pipeline, triangle_pipeline: triangle::Pipeline, - #[cfg(any(feature = "image", feature = "svg"))] + #[cfg(any(feature = "image_rs", feature = "svg"))] image_pipeline: image::Pipeline, default_text_size: u16, @@ -31,8 +31,13 @@ pub struct Backend { impl Backend { /// Creates a new [`Backend`]. pub fn new(device: &wgpu::Device, settings: Settings) -> Self { - let text_pipeline = - text::Pipeline::new(device, settings.format, settings.default_font); + let text_pipeline = text::Pipeline::new( + device, + settings.format, + settings.default_font, + settings.text_multithreading, + ); + let quad_pipeline = quad::Pipeline::new(device, settings.format); let triangle_pipeline = triangle::Pipeline::new( device, @@ -40,7 +45,7 @@ impl Backend { settings.antialiasing, ); - #[cfg(any(feature = "image", feature = "svg"))] + #[cfg(any(feature = "image_rs", feature = "svg"))] let image_pipeline = image::Pipeline::new(device, settings.format); Self { @@ -48,7 +53,7 @@ impl Backend { text_pipeline, triangle_pipeline, - #[cfg(any(feature = "image", feature = "svg"))] + #[cfg(any(feature = "image_rs", feature = "svg"))] image_pipeline, default_text_size: settings.default_text_size, @@ -92,7 +97,7 @@ impl Backend { ); } - #[cfg(any(feature = "image", feature = "svg"))] + #[cfg(any(feature = "image_rs", feature = "svg"))] self.image_pipeline.trim_cache(); *mouse_interaction @@ -142,7 +147,7 @@ impl Backend { ); } - #[cfg(any(feature = "image", feature = "svg"))] + #[cfg(any(feature = "image_rs", feature = "svg"))] { if !layer.images.is_empty() { let scaled = transformation @@ -270,7 +275,7 @@ impl backend::Text for Backend { } } -#[cfg(feature = "image")] +#[cfg(feature = "image_rs")] impl backend::Image for Backend { fn dimensions(&self, handle: &iced_native::image::Handle) -> (u32, u32) { self.image_pipeline.dimensions(handle) diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs index c256ca7e..85663bf5 100644 --- a/wgpu/src/image.rs +++ b/wgpu/src/image.rs @@ -1,6 +1,6 @@ mod atlas; -#[cfg(feature = "image")] +#[cfg(feature = "image_rs")] mod raster; #[cfg(feature = "svg")] @@ -16,7 +16,7 @@ use std::mem; use bytemuck::{Pod, Zeroable}; -#[cfg(feature = "image")] +#[cfg(feature = "image_rs")] use iced_native::image; #[cfg(feature = "svg")] @@ -24,7 +24,7 @@ use iced_native::svg; #[derive(Debug)] pub struct Pipeline { - #[cfg(feature = "image")] + #[cfg(feature = "image_rs")] raster_cache: RefCell<raster::Cache>, #[cfg(feature = "svg")] vector_cache: RefCell<vector::Cache>, @@ -62,8 +62,9 @@ impl Pipeline { wgpu::BindGroupLayoutEntry { binding: 0, visibility: wgpu::ShaderStage::VERTEX, - ty: wgpu::BindingType::UniformBuffer { - dynamic: false, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, min_binding_size: wgpu::BufferSize::new( mem::size_of::<Uniforms>() as u64, ), @@ -73,7 +74,10 @@ impl Pipeline { wgpu::BindGroupLayoutEntry { binding: 1, visibility: wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Sampler { comparison: false }, + ty: wgpu::BindingType::Sampler { + comparison: false, + filtering: true, + }, count: None, }, ], @@ -94,7 +98,11 @@ impl Pipeline { wgpu::BindGroupEntry { binding: 0, resource: wgpu::BindingResource::Buffer( - uniforms_buffer.slice(..), + wgpu::BufferBinding { + buffer: &uniforms_buffer, + offset: 0, + size: None, + }, ), }, wgpu::BindGroupEntry { @@ -110,9 +118,11 @@ impl Pipeline { entries: &[wgpu::BindGroupLayoutEntry { binding: 0, visibility: wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::SampledTexture { - dimension: wgpu::TextureViewDimension::D2, - component_type: wgpu::TextureComponentType::Float, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { + filterable: true, + }, + view_dimension: wgpu::TextureViewDimension::D2Array, multisampled: false, }, count: None, @@ -126,95 +136,76 @@ impl Pipeline { bind_group_layouts: &[&constant_layout, &texture_layout], }); - let vs_module = device.create_shader_module(wgpu::include_spirv!( - "shader/image.vert.spv" - )); - - let fs_module = device.create_shader_module(wgpu::include_spirv!( - "shader/image.frag.spv" - )); + let shader = + device.create_shader_module(&wgpu::ShaderModuleDescriptor { + label: Some("iced_wgpu::image::shader"), + source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed( + include_str!("shader/image.wgsl"), + )), + flags: wgpu::ShaderFlags::all(), + }); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: Some("iced_wgpu::image pipeline"), layout: Some(&layout), - vertex_stage: wgpu::ProgrammableStageDescriptor { - module: &vs_module, - entry_point: "main", - }, - fragment_stage: Some(wgpu::ProgrammableStageDescriptor { - module: &fs_module, - entry_point: "main", - }), - rasterization_state: Some(wgpu::RasterizationStateDescriptor { - front_face: wgpu::FrontFace::Cw, - cull_mode: wgpu::CullMode::None, - ..Default::default() - }), - primitive_topology: wgpu::PrimitiveTopology::TriangleList, - color_states: &[wgpu::ColorStateDescriptor { - format, - color_blend: wgpu::BlendDescriptor { - src_factor: wgpu::BlendFactor::SrcAlpha, - dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, - operation: wgpu::BlendOperation::Add, - }, - alpha_blend: wgpu::BlendDescriptor { - src_factor: wgpu::BlendFactor::One, - dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, - operation: wgpu::BlendOperation::Add, - }, - write_mask: wgpu::ColorWrite::ALL, - }], - depth_stencil_state: None, - vertex_state: wgpu::VertexStateDescriptor { - index_format: wgpu::IndexFormat::Uint16, - vertex_buffers: &[ - wgpu::VertexBufferDescriptor { - stride: mem::size_of::<Vertex>() as u64, + vertex: wgpu::VertexState { + module: &shader, + entry_point: "vs_main", + buffers: &[ + wgpu::VertexBufferLayout { + array_stride: mem::size_of::<Vertex>() as u64, step_mode: wgpu::InputStepMode::Vertex, - attributes: &[wgpu::VertexAttributeDescriptor { + attributes: &[wgpu::VertexAttribute { shader_location: 0, - format: wgpu::VertexFormat::Float2, + format: wgpu::VertexFormat::Float32x2, offset: 0, }], }, - wgpu::VertexBufferDescriptor { - stride: mem::size_of::<Instance>() as u64, + wgpu::VertexBufferLayout { + array_stride: mem::size_of::<Instance>() as u64, step_mode: wgpu::InputStepMode::Instance, - attributes: &[ - wgpu::VertexAttributeDescriptor { - shader_location: 1, - format: wgpu::VertexFormat::Float2, - offset: 0, - }, - wgpu::VertexAttributeDescriptor { - shader_location: 2, - format: wgpu::VertexFormat::Float2, - offset: 4 * 2, - }, - wgpu::VertexAttributeDescriptor { - shader_location: 3, - format: wgpu::VertexFormat::Float2, - offset: 4 * 4, - }, - wgpu::VertexAttributeDescriptor { - shader_location: 4, - format: wgpu::VertexFormat::Float2, - offset: 4 * 6, - }, - wgpu::VertexAttributeDescriptor { - shader_location: 5, - format: wgpu::VertexFormat::Uint, - offset: 4 * 8, - }, - ], + attributes: &wgpu::vertex_attr_array!( + 1 => Float32x2, + 2 => Float32x2, + 3 => Float32x2, + 4 => Float32x2, + 5 => Sint32, + ), }, ], }, - sample_count: 1, - sample_mask: !0, - alpha_to_coverage_enabled: false, + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: "fs_main", + targets: &[wgpu::ColorTargetState { + format, + blend: Some(wgpu::BlendState { + color: wgpu::BlendComponent { + src_factor: wgpu::BlendFactor::SrcAlpha, + dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, + operation: wgpu::BlendOperation::Add, + }, + alpha: wgpu::BlendComponent { + src_factor: wgpu::BlendFactor::One, + dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, + operation: wgpu::BlendOperation::Add, + }, + }), + write_mask: wgpu::ColorWrite::ALL, + }], + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + front_face: wgpu::FrontFace::Cw, + ..Default::default() + }, + depth_stencil: None, + multisample: wgpu::MultisampleState { + count: 1, + mask: !0, + alpha_to_coverage_enabled: false, + }, }); let vertices = @@ -252,7 +243,7 @@ impl Pipeline { }); Pipeline { - #[cfg(feature = "image")] + #[cfg(feature = "image_rs")] raster_cache: RefCell::new(raster::Cache::new()), #[cfg(feature = "svg")] @@ -271,7 +262,7 @@ impl Pipeline { } } - #[cfg(feature = "image")] + #[cfg(feature = "image_rs")] pub fn dimensions(&self, handle: &image::Handle) -> (u32, u32) { let mut cache = self.raster_cache.borrow_mut(); let memory = cache.load(&handle); @@ -300,7 +291,7 @@ impl Pipeline { ) { let instances: &mut Vec<Instance> = &mut Vec::new(); - #[cfg(feature = "image")] + #[cfg(feature = "image_rs")] let mut raster_cache = self.raster_cache.borrow_mut(); #[cfg(feature = "svg")] @@ -308,7 +299,7 @@ impl Pipeline { for image in images { match &image { - #[cfg(feature = "image")] + #[cfg(feature = "image_rs")] layer::Image::Raster { handle, bounds } => { if let Some(atlas_entry) = raster_cache.upload( handle, @@ -324,7 +315,7 @@ impl Pipeline { ); } } - #[cfg(not(feature = "image"))] + #[cfg(not(feature = "image_rs"))] layer::Image::Raster { .. } => {} #[cfg(feature = "svg")] @@ -415,23 +406,25 @@ impl Pipeline { let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[ - wgpu::RenderPassColorAttachmentDescriptor { - attachment: target, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Load, - store: true, - }, + label: Some("iced_wgpu::image render pass"), + color_attachments: &[wgpu::RenderPassColorAttachment { + view: target, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, + store: true, }, - ], + }], depth_stencil_attachment: None, }); render_pass.set_pipeline(&self.pipeline); render_pass.set_bind_group(0, &self.constants, &[]); render_pass.set_bind_group(1, &self.texture, &[]); - render_pass.set_index_buffer(self.indices.slice(..)); + render_pass.set_index_buffer( + self.indices.slice(..), + wgpu::IndexFormat::Uint16, + ); render_pass.set_vertex_buffer(0, self.vertices.slice(..)); render_pass.set_vertex_buffer(1, self.instances.slice(..)); @@ -453,7 +446,7 @@ impl Pipeline { } pub fn trim_cache(&mut self) { - #[cfg(feature = "image")] + #[cfg(feature = "image_rs")] self.raster_cache.borrow_mut().trim(&mut self.texture_atlas); #[cfg(feature = "svg")] diff --git a/wgpu/src/image/atlas.rs b/wgpu/src/image/atlas.rs index 660ebe44..4855fa4a 100644 --- a/wgpu/src/image/atlas.rs +++ b/wgpu/src/image/atlas.rs @@ -4,6 +4,8 @@ mod allocation; mod allocator; mod layer; +use std::num::NonZeroU32; + pub use allocation::Allocation; pub use entry::Entry; pub use layer::Layer; @@ -24,7 +26,7 @@ impl Atlas { let extent = wgpu::Extent3d { width: SIZE, height: SIZE, - depth: 1, + depth_or_array_layers: 1, }; let texture = device.create_texture(&wgpu::TextureDescriptor { @@ -294,19 +296,19 @@ impl Atlas { let extent = wgpu::Extent3d { width, height, - depth: 1, + depth_or_array_layers: 1, }; encoder.copy_buffer_to_texture( - wgpu::BufferCopyView { + wgpu::ImageCopyBuffer { buffer, - layout: wgpu::TextureDataLayout { + layout: wgpu::ImageDataLayout { offset: offset as u64, - bytes_per_row: 4 * image_width + padding, - rows_per_image: image_height, + bytes_per_row: NonZeroU32::new(4 * image_width + padding), + rows_per_image: NonZeroU32::new(image_height), }, }, - wgpu::TextureCopyView { + wgpu::ImageCopyTexture { texture: &self.texture, mip_level: 0, origin: wgpu::Origin3d { @@ -334,7 +336,7 @@ impl Atlas { size: wgpu::Extent3d { width: SIZE, height: SIZE, - depth: self.layers.len() as u32, + depth_or_array_layers: self.layers.len() as u32, }, mip_level_count: 1, sample_count: 1, @@ -355,7 +357,7 @@ impl Atlas { } encoder.copy_texture_to_texture( - wgpu::TextureCopyView { + wgpu::ImageCopyTexture { texture: &self.texture, mip_level: 0, origin: wgpu::Origin3d { @@ -364,7 +366,7 @@ impl Atlas { z: i as u32, }, }, - wgpu::TextureCopyView { + wgpu::ImageCopyTexture { texture: &new_texture, mip_level: 0, origin: wgpu::Origin3d { @@ -376,7 +378,7 @@ impl Atlas { wgpu::Extent3d { width: SIZE, height: SIZE, - depth: 1, + depth_or_array_layers: 1, }, ); } diff --git a/wgpu/src/image/atlas/entry.rs b/wgpu/src/image/atlas/entry.rs index 0310fc54..9b3f16df 100644 --- a/wgpu/src/image/atlas/entry.rs +++ b/wgpu/src/image/atlas/entry.rs @@ -10,7 +10,7 @@ pub enum Entry { } impl Entry { - #[cfg(feature = "image")] + #[cfg(feature = "image_rs")] pub fn size(&self) -> (u32, u32) { match self { Entry::Contiguous(allocation) => allocation.size(), diff --git a/wgpu/src/image/raster.rs b/wgpu/src/image/raster.rs index 25607dab..d5c62545 100644 --- a/wgpu/src/image/raster.rs +++ b/wgpu/src/image/raster.rs @@ -4,7 +4,7 @@ use std::collections::{HashMap, HashSet}; #[derive(Debug)] pub enum Memory { - Host(::image::ImageBuffer<::image::Bgra<u8>, Vec<u8>>), + Host(::image_rs::ImageBuffer<::image_rs::Bgra<u8>, Vec<u8>>), Device(atlas::Entry), NotFound, Invalid, @@ -42,14 +42,14 @@ impl Cache { let memory = match handle.data() { image::Data::Path(path) => { - if let Ok(image) = ::image::open(path) { + if let Ok(image) = ::image_rs::open(path) { Memory::Host(image.to_bgra8()) } else { Memory::NotFound } } image::Data::Bytes(bytes) => { - if let Ok(image) = ::image::load_from_memory(&bytes) { + if let Ok(image) = ::image_rs::load_from_memory(&bytes) { Memory::Host(image.to_bgra8()) } else { Memory::Invalid @@ -60,7 +60,7 @@ impl Cache { height, pixels, } => { - if let Some(image) = ::image::ImageBuffer::from_vec( + if let Some(image) = ::image_rs::ImageBuffer::from_vec( *width, *height, pixels.to_vec(), diff --git a/wgpu/src/image/vector.rs b/wgpu/src/image/vector.rs index 95df2e99..cd511a45 100644 --- a/wgpu/src/image/vector.rs +++ b/wgpu/src/image/vector.rs @@ -1,9 +1,10 @@ -use crate::image::atlas::{self, Atlas}; use iced_native::svg; use std::collections::{HashMap, HashSet}; +use crate::image::atlas::{self, Atlas}; + pub enum Svg { - Loaded(resvg::usvg::Tree), + Loaded(usvg::Tree), NotFound, } @@ -43,17 +44,15 @@ impl Cache { return self.svgs.get(&handle.id()).unwrap(); } - let opt = resvg::Options::default(); - let svg = match handle.data() { svg::Data::Path(path) => { - match resvg::usvg::Tree::from_file(path, &opt.usvg) { + match usvg::Tree::from_file(path, &Default::default()) { Ok(tree) => Svg::Loaded(tree), Err(_) => Svg::NotFound, } } svg::Data::Bytes(bytes) => { - match resvg::usvg::Tree::from_data(&bytes, &opt.usvg) { + match usvg::Tree::from_data(&bytes, &Default::default()) { Ok(tree) => Svg::Loaded(tree), Err(_) => Svg::NotFound, } @@ -76,8 +75,8 @@ impl Cache { let id = handle.id(); let (width, height) = ( - (scale * width).round() as u32, - (scale * height).round() as u32, + (scale * width).ceil() as u32, + (scale * height).ceil() as u32, ); // TODO: Optimize! @@ -101,26 +100,29 @@ impl Cache { // We currently rerasterize the SVG when its size changes. This is slow // as heck. A GPU rasterizer like `pathfinder` may perform better. // It would be cool to be able to smooth resize the `svg` example. - let screen_size = - resvg::ScreenSize::new(width, height).unwrap(); - - let mut canvas = - resvg::raqote::DrawTarget::new(width as i32, height as i32); - - resvg::backend_raqote::render_to_canvas( + let img = resvg::render( tree, - &resvg::Options::default(), - screen_size, - &mut canvas, - ); + if width > height { + usvg::FitTo::Width(width) + } else { + usvg::FitTo::Height(height) + }, + None, + )?; + let width = img.width(); + let height = img.height(); + + let mut rgba = img.take(); + rgba.chunks_exact_mut(4).for_each(|rgba| rgba.swap(0, 2)); let allocation = texture_atlas.upload( width, height, - bytemuck::cast_slice(canvas.get_data()), + bytemuck::cast_slice(rgba.as_slice()), device, encoder, )?; + log::debug!("allocating {} {}x{}", id, width, height); let _ = self.svg_hits.insert(id); let _ = self.rasterized_hits.insert((id, width, height)); diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index a4c2ac0e..e868a655 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -49,7 +49,7 @@ pub use widget::*; pub(crate) use iced_graphics::Transformation; -#[cfg(any(feature = "image", feature = "svg"))] +#[cfg(any(feature = "image_rs", feature = "svg"))] mod image; /// A [`wgpu`] graphics renderer for [`iced`]. diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index 24d20cfa..93942fba 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -24,10 +24,11 @@ impl Pipeline { entries: &[wgpu::BindGroupLayoutEntry { binding: 0, visibility: wgpu::ShaderStage::VERTEX, - ty: wgpu::BindingType::UniformBuffer { - dynamic: false, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, min_binding_size: wgpu::BufferSize::new( - mem::size_of::<Uniforms>() as u64, + mem::size_of::<Uniforms>() as wgpu::BufferAddress, ), }, count: None, @@ -36,7 +37,7 @@ impl Pipeline { let constants_buffer = device.create_buffer(&wgpu::BufferDescriptor { label: Some("iced_wgpu::quad uniforms buffer"), - size: mem::size_of::<Uniforms>() as u64, + size: mem::size_of::<Uniforms>() as wgpu::BufferAddress, usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, mapped_at_creation: false, }); @@ -46,9 +47,7 @@ impl Pipeline { layout: &constant_layout, entries: &[wgpu::BindGroupEntry { binding: 0, - resource: wgpu::BindingResource::Buffer( - constants_buffer.slice(..), - ), + resource: constants_buffer.as_entire_binding(), }], }); @@ -59,98 +58,77 @@ impl Pipeline { bind_group_layouts: &[&constant_layout], }); - let vs_module = device - .create_shader_module(wgpu::include_spirv!("shader/quad.vert.spv")); - - let fs_module = device - .create_shader_module(wgpu::include_spirv!("shader/quad.frag.spv")); + let shader = + device.create_shader_module(&wgpu::ShaderModuleDescriptor { + label: Some("iced_wgpu::quad::shader"), + source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed( + include_str!("shader/quad.wgsl"), + )), + flags: wgpu::ShaderFlags::all(), + }); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: Some("iced_wgpu::quad pipeline"), layout: Some(&layout), - vertex_stage: wgpu::ProgrammableStageDescriptor { - module: &vs_module, - entry_point: "main", - }, - fragment_stage: Some(wgpu::ProgrammableStageDescriptor { - module: &fs_module, - entry_point: "main", - }), - rasterization_state: Some(wgpu::RasterizationStateDescriptor { - front_face: wgpu::FrontFace::Cw, - cull_mode: wgpu::CullMode::None, - ..Default::default() - }), - primitive_topology: wgpu::PrimitiveTopology::TriangleList, - color_states: &[wgpu::ColorStateDescriptor { - format, - color_blend: wgpu::BlendDescriptor { - src_factor: wgpu::BlendFactor::SrcAlpha, - dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, - operation: wgpu::BlendOperation::Add, - }, - alpha_blend: wgpu::BlendDescriptor { - src_factor: wgpu::BlendFactor::One, - dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, - operation: wgpu::BlendOperation::Add, - }, - write_mask: wgpu::ColorWrite::ALL, - }], - depth_stencil_state: None, - vertex_state: wgpu::VertexStateDescriptor { - index_format: wgpu::IndexFormat::Uint16, - vertex_buffers: &[ - wgpu::VertexBufferDescriptor { - stride: mem::size_of::<Vertex>() as u64, + vertex: wgpu::VertexState { + module: &shader, + entry_point: "vs_main", + buffers: &[ + wgpu::VertexBufferLayout { + array_stride: mem::size_of::<Vertex>() as u64, step_mode: wgpu::InputStepMode::Vertex, - attributes: &[wgpu::VertexAttributeDescriptor { + attributes: &[wgpu::VertexAttribute { shader_location: 0, - format: wgpu::VertexFormat::Float2, + format: wgpu::VertexFormat::Float32x2, offset: 0, }], }, - wgpu::VertexBufferDescriptor { - stride: mem::size_of::<layer::Quad>() as u64, + wgpu::VertexBufferLayout { + array_stride: mem::size_of::<layer::Quad>() as u64, step_mode: wgpu::InputStepMode::Instance, - attributes: &[ - wgpu::VertexAttributeDescriptor { - shader_location: 1, - format: wgpu::VertexFormat::Float2, - offset: 0, - }, - wgpu::VertexAttributeDescriptor { - shader_location: 2, - format: wgpu::VertexFormat::Float2, - offset: 4 * 2, - }, - wgpu::VertexAttributeDescriptor { - shader_location: 3, - format: wgpu::VertexFormat::Float4, - offset: 4 * (2 + 2), - }, - wgpu::VertexAttributeDescriptor { - shader_location: 4, - format: wgpu::VertexFormat::Float4, - offset: 4 * (2 + 2 + 4), - }, - wgpu::VertexAttributeDescriptor { - shader_location: 5, - format: wgpu::VertexFormat::Float, - offset: 4 * (2 + 2 + 4 + 4), - }, - wgpu::VertexAttributeDescriptor { - shader_location: 6, - format: wgpu::VertexFormat::Float, - offset: 4 * (2 + 2 + 4 + 4 + 1), - }, - ], + attributes: &wgpu::vertex_attr_array!( + 1 => Float32x2, + 2 => Float32x2, + 3 => Float32x4, + 4 => Float32x4, + 5 => Float32, + 6 => Float32, + ), }, ], }, - sample_count: 1, - sample_mask: !0, - alpha_to_coverage_enabled: false, + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: "fs_main", + targets: &[wgpu::ColorTargetState { + format, + blend: Some(wgpu::BlendState { + color: wgpu::BlendComponent { + src_factor: wgpu::BlendFactor::SrcAlpha, + dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, + operation: wgpu::BlendOperation::Add, + }, + alpha: wgpu::BlendComponent { + src_factor: wgpu::BlendFactor::One, + dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, + operation: wgpu::BlendOperation::Add, + }, + }), + write_mask: wgpu::ColorWrite::ALL, + }], + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + front_face: wgpu::FrontFace::Cw, + ..Default::default() + }, + depth_stencil: None, + multisample: wgpu::MultisampleState { + count: 1, + mask: !0, + alpha_to_coverage_enabled: false, + }, }); let vertices = @@ -232,30 +210,33 @@ impl Pipeline { { let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[ - wgpu::RenderPassColorAttachmentDescriptor { - attachment: target, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Load, - store: true, - }, + label: Some("iced_wgpu::quad render pass"), + color_attachments: &[wgpu::RenderPassColorAttachment { + view: target, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, + store: true, }, - ], + }], depth_stencil_attachment: None, }); render_pass.set_pipeline(&self.pipeline); render_pass.set_bind_group(0, &self.constants, &[]); - render_pass.set_index_buffer(self.indices.slice(..)); + render_pass.set_index_buffer( + self.indices.slice(..), + wgpu::IndexFormat::Uint16, + ); render_pass.set_vertex_buffer(0, self.vertices.slice(..)); render_pass.set_vertex_buffer(1, self.instances.slice(..)); + render_pass.set_scissor_rect( bounds.x, bounds.y, bounds.width, // TODO: Address anti-aliasing adjustments properly - bounds.height + 1, + bounds.height, ); render_pass.draw_indexed( @@ -300,6 +281,9 @@ const MAX_INSTANCES: usize = 100_000; struct Uniforms { transform: [f32; 16], scale: f32, + // Uniforms must be aligned to their largest member, + // this uses a mat4x4<f32> which aligns to 16, so align to that + _padding: [f32; 3], } impl Uniforms { @@ -307,6 +291,7 @@ impl Uniforms { Self { transform: *transformation.as_ref(), scale, + _padding: [0.0; 3], } } } @@ -316,6 +301,7 @@ impl Default for Uniforms { Self { transform: *Transformation::identity().as_ref(), scale: 1.0, + _padding: [0.0; 3], } } } diff --git a/wgpu/src/settings.rs b/wgpu/src/settings.rs index 26763e22..9a7eed34 100644 --- a/wgpu/src/settings.rs +++ b/wgpu/src/settings.rs @@ -16,6 +16,9 @@ pub struct Settings { /// [`Backend`]: crate::Backend pub present_mode: wgpu::PresentMode, + /// The internal graphics backend to use. + pub internal_backend: wgpu::BackendBit, + /// The bytes of the font that will be used by default. /// /// If `None` is provided, a default system font will be chosen. @@ -26,18 +29,67 @@ pub struct Settings { /// By default, it will be set to 20. pub default_text_size: u16, + /// If enabled, spread text workload in multiple threads when multiple cores + /// are available. + /// + /// By default, it is disabled. + pub text_multithreading: bool, + /// The antialiasing strategy that will be used for triangle primitives. + /// + /// By default, it is `None`. pub antialiasing: Option<Antialiasing>, } +impl Settings { + /// Creates new [`Settings`] using environment configuration. + /// + /// Specifically: + /// + /// - The `internal_backend` can be configured using the `WGPU_BACKEND` + /// environment variable. If the variable is not set, the primary backend + /// will be used. The following values are allowed: + /// - `vulkan` + /// - `metal` + /// - `dx12` + /// - `dx11` + /// - `gl` + /// - `webgpu` + /// - `primary` + pub fn from_env() -> Self { + Settings { + internal_backend: backend_from_env() + .unwrap_or(wgpu::BackendBit::PRIMARY), + ..Self::default() + } + } +} + impl Default for Settings { fn default() -> Settings { Settings { format: wgpu::TextureFormat::Bgra8UnormSrgb, present_mode: wgpu::PresentMode::Mailbox, + internal_backend: wgpu::BackendBit::PRIMARY, default_font: None, default_text_size: 20, + text_multithreading: false, antialiasing: None, } } } + +fn backend_from_env() -> Option<wgpu::BackendBit> { + std::env::var("WGPU_BACKEND").ok().map(|backend| { + match backend.to_lowercase().as_str() { + "vulkan" => wgpu::BackendBit::VULKAN, + "metal" => wgpu::BackendBit::METAL, + "dx12" => wgpu::BackendBit::DX12, + "dx11" => wgpu::BackendBit::DX11, + "gl" => wgpu::BackendBit::GL, + "webgpu" => wgpu::BackendBit::BROWSER_WEBGPU, + "primary" => wgpu::BackendBit::PRIMARY, + other => panic!("Unknown backend: {}", other), + } + }) +} diff --git a/wgpu/src/shader/blit.frag b/wgpu/src/shader/blit.frag deleted file mode 100644 index dfed960f..00000000 --- a/wgpu/src/shader/blit.frag +++ /dev/null @@ -1,12 +0,0 @@ -#version 450 - -layout(location = 0) in vec2 v_Uv; - -layout(set = 0, binding = 0) uniform sampler u_Sampler; -layout(set = 1, binding = 0) uniform texture2D u_Texture; - -layout(location = 0) out vec4 o_Color; - -void main() { - o_Color = texture(sampler2D(u_Texture, u_Sampler), v_Uv); -} diff --git a/wgpu/src/shader/blit.frag.spv b/wgpu/src/shader/blit.frag.spv Binary files differdeleted file mode 100644 index 2c5638b5..00000000 --- a/wgpu/src/shader/blit.frag.spv +++ /dev/null diff --git a/wgpu/src/shader/blit.vert b/wgpu/src/shader/blit.vert deleted file mode 100644 index 899cd39d..00000000 --- a/wgpu/src/shader/blit.vert +++ /dev/null @@ -1,26 +0,0 @@ -#version 450 - -layout(location = 0) out vec2 o_Uv; - -const vec2 positions[6] = vec2[6]( - vec2(-1.0, 1.0), - vec2(-1.0, -1.0), - vec2(1.0, -1.0), - vec2(-1.0, 1.0), - vec2(1.0, 1.0), - vec2(1.0, -1.0) -); - -const vec2 uvs[6] = vec2[6]( - vec2(0.0, 0.0), - vec2(0.0, 1.0), - vec2(1.0, 1.0), - vec2(0.0, 0.0), - vec2(1.0, 0.0), - vec2(1.0, 1.0) -); - -void main() { - o_Uv = uvs[gl_VertexIndex]; - gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); -} diff --git a/wgpu/src/shader/blit.vert.spv b/wgpu/src/shader/blit.vert.spv Binary files differdeleted file mode 100644 index e0b436ce..00000000 --- a/wgpu/src/shader/blit.vert.spv +++ /dev/null diff --git a/wgpu/src/shader/blit.wgsl b/wgpu/src/shader/blit.wgsl new file mode 100644 index 00000000..694f192e --- /dev/null +++ b/wgpu/src/shader/blit.wgsl @@ -0,0 +1,43 @@ +var positions: array<vec2<f32>, 6> = array<vec2<f32>, 6>( + vec2<f32>(-1.0, 1.0), + vec2<f32>(-1.0, -1.0), + vec2<f32>(1.0, -1.0), + vec2<f32>(-1.0, 1.0), + vec2<f32>(1.0, 1.0), + vec2<f32>(1.0, -1.0) +); + +var uvs: array<vec2<f32>, 6> = array<vec2<f32>, 6>( + vec2<f32>(0.0, 0.0), + vec2<f32>(0.0, 1.0), + vec2<f32>(1.0, 1.0), + vec2<f32>(0.0, 0.0), + vec2<f32>(1.0, 0.0), + vec2<f32>(1.0, 1.0) +); + +[[group(0), binding(0)]] var u_sampler: sampler; +[[group(1), binding(0)]] var u_texture: texture_2d<f32>; + +struct VertexInput { + [[builtin(vertex_index)]] vertex_index: u32; +}; + +struct VertexOutput { + [[builtin(position)]] position: vec4<f32>; + [[location(0)]] uv: vec2<f32>; +}; + +[[stage(vertex)]] +fn vs_main(input: VertexInput) -> VertexOutput { + var out: VertexOutput; + out.uv = uvs[input.vertex_index]; + out.position = vec4<f32>(positions[input.vertex_index], 0.0, 1.0); + + return out; +} + +[[stage(fragment)]] +fn fs_main(input: VertexOutput) -> [[location(0)]] vec4<f32> { + return textureSample(u_texture, u_sampler, input.uv); +} diff --git a/wgpu/src/shader/image.frag b/wgpu/src/shader/image.frag deleted file mode 100644 index 2809e9e6..00000000 --- a/wgpu/src/shader/image.frag +++ /dev/null @@ -1,12 +0,0 @@ -#version 450 - -layout(location = 0) in vec3 v_Uv; - -layout(set = 0, binding = 1) uniform sampler u_Sampler; -layout(set = 1, binding = 0) uniform texture2DArray u_Texture; - -layout(location = 0) out vec4 o_Color; - -void main() { - o_Color = texture(sampler2DArray(u_Texture, u_Sampler), v_Uv); -} diff --git a/wgpu/src/shader/image.frag.spv b/wgpu/src/shader/image.frag.spv Binary files differdeleted file mode 100644 index 65b08aa3..00000000 --- a/wgpu/src/shader/image.frag.spv +++ /dev/null diff --git a/wgpu/src/shader/image.vert b/wgpu/src/shader/image.vert deleted file mode 100644 index dab53cfe..00000000 --- a/wgpu/src/shader/image.vert +++ /dev/null @@ -1,27 +0,0 @@ -#version 450 - -layout(location = 0) in vec2 v_Pos; -layout(location = 1) in vec2 i_Pos; -layout(location = 2) in vec2 i_Scale; -layout(location = 3) in vec2 i_Atlas_Pos; -layout(location = 4) in vec2 i_Atlas_Scale; -layout(location = 5) in uint i_Layer; - -layout (set = 0, binding = 0) uniform Globals { - mat4 u_Transform; -}; - -layout(location = 0) out vec3 o_Uv; - -void main() { - o_Uv = vec3(v_Pos * i_Atlas_Scale + i_Atlas_Pos, i_Layer); - - mat4 i_Transform = mat4( - vec4(i_Scale.x, 0.0, 0.0, 0.0), - vec4(0.0, i_Scale.y, 0.0, 0.0), - vec4(0.0, 0.0, 1.0, 0.0), - vec4(i_Pos, 0.0, 1.0) - ); - - gl_Position = u_Transform * i_Transform * vec4(v_Pos, 0.0, 1.0); -} diff --git a/wgpu/src/shader/image.vert.spv b/wgpu/src/shader/image.vert.spv Binary files differdeleted file mode 100644 index 21f5db2d..00000000 --- a/wgpu/src/shader/image.vert.spv +++ /dev/null diff --git a/wgpu/src/shader/image.wgsl b/wgpu/src/shader/image.wgsl new file mode 100644 index 00000000..a63ee8f6 --- /dev/null +++ b/wgpu/src/shader/image.wgsl @@ -0,0 +1,47 @@ +[[block]] +struct Globals { + transform: mat4x4<f32>; +}; + +[[group(0), binding(0)]] var<uniform> globals: Globals; +[[group(0), binding(1)]] var u_sampler: sampler; +[[group(1), binding(0)]] var u_texture: texture_2d_array<f32>; + +struct VertexInput { + [[location(0)]] v_pos: vec2<f32>; + [[location(1)]] pos: vec2<f32>; + [[location(2)]] scale: vec2<f32>; + [[location(3)]] atlas_pos: vec2<f32>; + [[location(4)]] atlas_scale: vec2<f32>; + [[location(5)]] layer: i32; +}; + +struct VertexOutput { + [[builtin(position)]] position: vec4<f32>; + [[location(0)]] uv: vec2<f32>; + [[location(1)]] layer: f32; // this should be an i32, but naga currently reads that as requiring interpolation. +}; + +[[stage(vertex)]] +fn vs_main(input: VertexInput) -> VertexOutput { + var out: VertexOutput; + + out.uv = vec2<f32>(input.v_pos * input.atlas_scale + input.atlas_pos); + out.layer = f32(input.layer); + + var transform: mat4x4<f32> = mat4x4<f32>( + vec4<f32>(input.scale.x, 0.0, 0.0, 0.0), + vec4<f32>(0.0, input.scale.y, 0.0, 0.0), + vec4<f32>(0.0, 0.0, 1.0, 0.0), + vec4<f32>(input.pos, 0.0, 1.0) + ); + + out.position = globals.transform * transform * vec4<f32>(input.v_pos, 0.0, 1.0); + + return out; +} + +[[stage(fragment)]] +fn fs_main(input: VertexOutput) -> [[location(0)]] vec4<f32> { + return textureSample(u_texture, u_sampler, input.uv, i32(input.layer)); +} diff --git a/wgpu/src/shader/quad.frag b/wgpu/src/shader/quad.frag deleted file mode 100644 index ad1af1ad..00000000 --- a/wgpu/src/shader/quad.frag +++ /dev/null @@ -1,66 +0,0 @@ -#version 450 - -layout(location = 0) in vec4 v_Color; -layout(location = 1) in vec4 v_BorderColor; -layout(location = 2) in vec2 v_Pos; -layout(location = 3) in vec2 v_Scale; -layout(location = 4) in float v_BorderRadius; -layout(location = 5) in float v_BorderWidth; - -layout(location = 0) out vec4 o_Color; - -float distance(in vec2 frag_coord, in vec2 position, in vec2 size, float radius) -{ - // TODO: Try SDF approach: https://www.shadertoy.com/view/wd3XRN - vec2 inner_size = size - vec2(radius, radius) * 2.0; - vec2 top_left = position + vec2(radius, radius); - vec2 bottom_right = top_left + inner_size; - - vec2 top_left_distance = top_left - frag_coord; - vec2 bottom_right_distance = frag_coord - bottom_right; - - vec2 distance = vec2( - max(max(top_left_distance.x, bottom_right_distance.x), 0), - max(max(top_left_distance.y, bottom_right_distance.y), 0) - ); - - return sqrt(distance.x * distance.x + distance.y * distance.y); -} - -void main() { - vec4 mixed_color; - - // TODO: Remove branching (?) - if(v_BorderWidth > 0) { - float internal_border = max(v_BorderRadius - v_BorderWidth, 0); - - float internal_distance = distance( - gl_FragCoord.xy, - v_Pos + vec2(v_BorderWidth), - v_Scale - vec2(v_BorderWidth * 2.0), - internal_border - ); - - float border_mix = smoothstep( - max(internal_border - 0.5, 0.0), - internal_border + 0.5, - internal_distance - ); - - mixed_color = mix(v_Color, v_BorderColor, border_mix); - } else { - mixed_color = v_Color; - } - - float d = distance( - gl_FragCoord.xy, - v_Pos, - v_Scale, - v_BorderRadius - ); - - float radius_alpha = - 1.0 - smoothstep(max(v_BorderRadius - 0.5, 0), v_BorderRadius + 0.5, d); - - o_Color = vec4(mixed_color.xyz, mixed_color.w * radius_alpha); -} diff --git a/wgpu/src/shader/quad.frag.spv b/wgpu/src/shader/quad.frag.spv Binary files differdeleted file mode 100644 index 519f5f01..00000000 --- a/wgpu/src/shader/quad.frag.spv +++ /dev/null diff --git a/wgpu/src/shader/quad.vert b/wgpu/src/shader/quad.vert deleted file mode 100644 index 09a278b1..00000000 --- a/wgpu/src/shader/quad.vert +++ /dev/null @@ -1,47 +0,0 @@ -#version 450 - -layout(location = 0) in vec2 v_Pos; -layout(location = 1) in vec2 i_Pos; -layout(location = 2) in vec2 i_Scale; -layout(location = 3) in vec4 i_Color; -layout(location = 4) in vec4 i_BorderColor; -layout(location = 5) in float i_BorderRadius; -layout(location = 6) in float i_BorderWidth; - -layout (set = 0, binding = 0) uniform Globals { - mat4 u_Transform; - float u_Scale; -}; - -layout(location = 0) out vec4 o_Color; -layout(location = 1) out vec4 o_BorderColor; -layout(location = 2) out vec2 o_Pos; -layout(location = 3) out vec2 o_Scale; -layout(location = 4) out float o_BorderRadius; -layout(location = 5) out float o_BorderWidth; - -void main() { - vec2 p_Pos = i_Pos * u_Scale; - vec2 p_Scale = i_Scale * u_Scale; - - float i_BorderRadius = min( - i_BorderRadius, - min(i_Scale.x, i_Scale.y) / 2.0 - ); - - mat4 i_Transform = mat4( - vec4(p_Scale.x + 1.0, 0.0, 0.0, 0.0), - vec4(0.0, p_Scale.y + 1.0, 0.0, 0.0), - vec4(0.0, 0.0, 1.0, 0.0), - vec4(p_Pos - vec2(0.5, 0.5), 0.0, 1.0) - ); - - o_Color = i_Color; - o_BorderColor = i_BorderColor; - o_Pos = p_Pos; - o_Scale = p_Scale; - o_BorderRadius = i_BorderRadius * u_Scale; - o_BorderWidth = i_BorderWidth * u_Scale; - - gl_Position = u_Transform * i_Transform * vec4(v_Pos, 0.0, 1.0); -} diff --git a/wgpu/src/shader/quad.vert.spv b/wgpu/src/shader/quad.vert.spv Binary files differdeleted file mode 100644 index fa71ba1e..00000000 --- a/wgpu/src/shader/quad.vert.spv +++ /dev/null diff --git a/wgpu/src/shader/quad.wgsl b/wgpu/src/shader/quad.wgsl new file mode 100644 index 00000000..80d733ab --- /dev/null +++ b/wgpu/src/shader/quad.wgsl @@ -0,0 +1,122 @@ +[[block]] +struct Globals { + transform: mat4x4<f32>; + scale: f32; +}; + +[[group(0), binding(0)]] var<uniform> globals: Globals; + +struct VertexInput { + [[location(0)]] v_pos: vec2<f32>; + [[location(1)]] pos: vec2<f32>; + [[location(2)]] scale: vec2<f32>; + [[location(3)]] color: vec4<f32>; + [[location(4)]] border_color: vec4<f32>; + [[location(5)]] border_radius: f32; + [[location(6)]] border_width: f32; +}; + +struct VertexOutput { + [[builtin(position)]] position: vec4<f32>; + [[location(0)]] color: vec4<f32>; + [[location(1)]] border_color: vec4<f32>; + [[location(2)]] pos: vec2<f32>; + [[location(3)]] scale: vec2<f32>; + [[location(4)]] border_radius: f32; + [[location(5)]] border_width: f32; +}; + +[[stage(vertex)]] +fn vs_main(input: VertexInput) -> VertexOutput { + var out: VertexOutput; + + var pos: vec2<f32> = input.pos * globals.scale; + var scale: vec2<f32> = input.scale * globals.scale; + + var border_radius: f32 = min( + input.border_radius, + min(input.scale.x, input.scale.y) / 2.0 + ); + + var transform: mat4x4<f32> = mat4x4<f32>( + vec4<f32>(scale.x + 1.0, 0.0, 0.0, 0.0), + vec4<f32>(0.0, scale.y + 1.0, 0.0, 0.0), + vec4<f32>(0.0, 0.0, 1.0, 0.0), + vec4<f32>(pos - vec2<f32>(0.5, 0.5), 0.0, 1.0) + ); + + out.color = input.color; + out.border_color = input.border_color; + out.pos = pos; + out.scale = scale; + out.border_radius = border_radius * globals.scale; + out.border_width = input.border_width * globals.scale; + out.position = globals.transform * transform * vec4<f32>(input.v_pos, 0.0, 1.0); + + return out; +} + +fn distance_alg( + frag_coord: vec2<f32>, + position: vec2<f32>, + size: vec2<f32>, + radius: f32 +) -> f32 { + var inner_size: vec2<f32> = size - vec2<f32>(radius, radius) * 2.0; + var top_left: vec2<f32> = position + vec2<f32>(radius, radius); + var bottom_right: vec2<f32> = top_left + inner_size; + + var top_left_distance: vec2<f32> = top_left - frag_coord; + var bottom_right_distance: vec2<f32> = frag_coord - bottom_right; + + var dist: vec2<f32> = vec2<f32>( + max(max(top_left_distance.x, bottom_right_distance.x), 0.0), + max(max(top_left_distance.y, bottom_right_distance.y), 0.0) + ); + + return sqrt(dist.x * dist.x + dist.y * dist.y); +} + + +[[stage(fragment)]] +fn fs_main( + input: VertexOutput +) -> [[location(0)]] vec4<f32> { + var mixed_color: vec4<f32> = input.color; + + if (input.border_width > 0.0) { + var internal_border: f32 = max( + input.border_radius - input.border_width, + 0.0 + ); + + var internal_distance: f32 = distance_alg( + vec2<f32>(input.position.x, input.position.y), + input.pos + vec2<f32>(input.border_width, input.border_width), + input.scale - vec2<f32>(input.border_width * 2.0, input.border_width * 2.0), + internal_border + ); + + var border_mix: f32 = smoothStep( + max(internal_border - 0.5, 0.0), + internal_border + 0.5, + internal_distance + ); + + mixed_color = mix(input.color, input.border_color, vec4<f32>(border_mix, border_mix, border_mix, border_mix)); + } + + var dist: f32 = distance_alg( + vec2<f32>(input.position.x, input.position.y), + input.pos, + input.scale, + input.border_radius + ); + + var radius_alpha: f32 = 1.0 - smoothStep( + max(input.border_radius - 0.5, 0.0), + input.border_radius + 0.5, + dist); + + return vec4<f32>(mixed_color.x, mixed_color.y, mixed_color.z, mixed_color.w * radius_alpha); +} diff --git a/wgpu/src/shader/triangle.frag b/wgpu/src/shader/triangle.frag deleted file mode 100644 index e39c45e7..00000000 --- a/wgpu/src/shader/triangle.frag +++ /dev/null @@ -1,8 +0,0 @@ -#version 450 - -layout(location = 0) in vec4 i_Color; -layout(location = 0) out vec4 o_Color; - -void main() { - o_Color = i_Color; -} diff --git a/wgpu/src/shader/triangle.frag.spv b/wgpu/src/shader/triangle.frag.spv Binary files differdeleted file mode 100644 index 11201872..00000000 --- a/wgpu/src/shader/triangle.frag.spv +++ /dev/null diff --git a/wgpu/src/shader/triangle.vert b/wgpu/src/shader/triangle.vert deleted file mode 100644 index 1f2c009b..00000000 --- a/wgpu/src/shader/triangle.vert +++ /dev/null @@ -1,15 +0,0 @@ -#version 450 - -layout(location = 0) in vec2 i_Position; -layout(location = 1) in vec4 i_Color; - -layout(location = 0) out vec4 o_Color; - -layout (set = 0, binding = 0) uniform Globals { - mat4 u_Transform; -}; - -void main() { - gl_Position = u_Transform * vec4(i_Position, 0.0, 1.0); - o_Color = i_Color; -} diff --git a/wgpu/src/shader/triangle.vert.spv b/wgpu/src/shader/triangle.vert.spv Binary files differdeleted file mode 100644 index 871f4f55..00000000 --- a/wgpu/src/shader/triangle.vert.spv +++ /dev/null diff --git a/wgpu/src/shader/triangle.wgsl b/wgpu/src/shader/triangle.wgsl new file mode 100644 index 00000000..96eaabcc --- /dev/null +++ b/wgpu/src/shader/triangle.wgsl @@ -0,0 +1,31 @@ +[[block]] +struct Globals { + transform: mat4x4<f32>; +}; + +[[group(0), binding(0)]] var<uniform> globals: Globals; + +struct VertexInput { + [[location(0)]] position: vec2<f32>; + [[location(1)]] color: vec4<f32>; +}; + +struct VertexOutput { + [[builtin(position)]] position: vec4<f32>; + [[location(0)]] color: vec4<f32>; +}; + +[[stage(vertex)]] +fn vs_main(input: VertexInput) -> VertexOutput { + var out: VertexOutput; + + out.color = input.color; + out.position = globals.transform * vec4<f32>(input.position, 0.0, 1.0); + + return out; +} + +[[stage(fragment)]] +fn fs_main(input: VertexOutput) -> [[location(0)]] vec4<f32> { + return input.color; +} diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index 78999cf8..2b5b94c9 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -15,10 +15,12 @@ impl Pipeline { device: &wgpu::Device, format: wgpu::TextureFormat, default_font: Option<&[u8]>, + multithreading: bool, ) -> Self { let default_font = default_font.map(|slice| slice.to_vec()); // TODO: Font customization + #[cfg(not(target_os = "ios"))] #[cfg(feature = "default_system_font")] let default_font = { default_font.or_else(|| { @@ -45,7 +47,7 @@ impl Pipeline { let draw_brush = wgpu_glyph::GlyphBrushBuilder::using_font(font.clone()) .initial_cache_size((2048, 2048)) - .draw_cache_multithread(false) // TODO: Expose as a configuration flag + .draw_cache_multithread(multithreading) .build(device, format); let measure_brush = diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs index 61a771d8..65b2b7b0 100644 --- a/wgpu/src/triangle.rs +++ b/wgpu/src/triangle.rs @@ -86,8 +86,9 @@ impl Pipeline { entries: &[wgpu::BindGroupLayoutEntry { binding: 0, visibility: wgpu::ShaderStage::VERTEX, - ty: wgpu::BindingType::UniformBuffer { - dynamic: true, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: true, min_binding_size: wgpu::BufferSize::new( mem::size_of::<Uniforms>() as u64, ), @@ -110,9 +111,15 @@ impl Pipeline { entries: &[wgpu::BindGroupEntry { binding: 0, resource: wgpu::BindingResource::Buffer( - constants_buffer - .raw - .slice(0..std::mem::size_of::<Uniforms>() as u64), + wgpu::BufferBinding { + buffer: &constants_buffer.raw, + offset: 0, + size: wgpu::BufferSize::new(std::mem::size_of::< + Uniforms, + >( + ) + as u64), + }, ), }], }); @@ -124,73 +131,66 @@ impl Pipeline { bind_group_layouts: &[&constants_layout], }); - let vs_module = device.create_shader_module(wgpu::include_spirv!( - "shader/triangle.vert.spv" - )); - - let fs_module = device.create_shader_module(wgpu::include_spirv!( - "shader/triangle.frag.spv" - )); + let shader = + device.create_shader_module(&wgpu::ShaderModuleDescriptor { + label: Some("iced_wgpu::triangle::shader"), + source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed( + include_str!("shader/triangle.wgsl"), + )), + flags: wgpu::ShaderFlags::all(), + }); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: Some("iced_wgpu::triangle pipeline"), layout: Some(&layout), - vertex_stage: wgpu::ProgrammableStageDescriptor { - module: &vs_module, - entry_point: "main", - }, - fragment_stage: Some(wgpu::ProgrammableStageDescriptor { - module: &fs_module, - entry_point: "main", - }), - rasterization_state: Some(wgpu::RasterizationStateDescriptor { - front_face: wgpu::FrontFace::Cw, - cull_mode: wgpu::CullMode::None, - ..Default::default() - }), - primitive_topology: wgpu::PrimitiveTopology::TriangleList, - color_states: &[wgpu::ColorStateDescriptor { - format, - color_blend: wgpu::BlendDescriptor { - src_factor: wgpu::BlendFactor::SrcAlpha, - dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, - operation: wgpu::BlendOperation::Add, - }, - alpha_blend: wgpu::BlendDescriptor { - src_factor: wgpu::BlendFactor::One, - dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, - operation: wgpu::BlendOperation::Add, - }, - write_mask: wgpu::ColorWrite::ALL, - }], - depth_stencil_state: None, - vertex_state: wgpu::VertexStateDescriptor { - index_format: wgpu::IndexFormat::Uint32, - vertex_buffers: &[wgpu::VertexBufferDescriptor { - stride: mem::size_of::<Vertex2D>() as u64, + vertex: wgpu::VertexState { + module: &shader, + entry_point: "vs_main", + buffers: &[wgpu::VertexBufferLayout { + array_stride: mem::size_of::<Vertex2D>() as u64, step_mode: wgpu::InputStepMode::Vertex, - attributes: &[ + attributes: &wgpu::vertex_attr_array!( // Position - wgpu::VertexAttributeDescriptor { - shader_location: 0, - format: wgpu::VertexFormat::Float2, - offset: 0, - }, + 0 => Float32x2, // Color - wgpu::VertexAttributeDescriptor { - shader_location: 1, - format: wgpu::VertexFormat::Float4, - offset: 4 * 2, + 1 => Float32x4, + ), + }], + }, + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: "fs_main", + targets: &[wgpu::ColorTargetState { + format, + blend: Some(wgpu::BlendState { + color: wgpu::BlendComponent { + src_factor: wgpu::BlendFactor::SrcAlpha, + dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, + operation: wgpu::BlendOperation::Add, + }, + alpha: wgpu::BlendComponent { + src_factor: wgpu::BlendFactor::One, + dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, + operation: wgpu::BlendOperation::Add, }, - ], + }), + write_mask: wgpu::ColorWrite::ALL, }], + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + front_face: wgpu::FrontFace::Cw, + ..Default::default() + }, + depth_stencil: None, + multisample: wgpu::MultisampleState { + count: u32::from( + antialiasing.map(|a| a.sample_count()).unwrap_or(1), + ), + mask: !0, + alpha_to_coverage_enabled: false, }, - sample_count: u32::from( - antialiasing.map(|a| a.sample_count()).unwrap_or(1), - ), - sample_mask: !0, - alpha_to_coverage_enabled: false, }); Pipeline { @@ -253,9 +253,13 @@ impl Pipeline { entries: &[wgpu::BindGroupEntry { binding: 0, resource: wgpu::BindingResource::Buffer( - self.uniforms_buffer.raw.slice( - 0..std::mem::size_of::<Uniforms>() as u64, - ), + wgpu::BufferBinding { + buffer: &self.uniforms_buffer.raw, + offset: 0, + size: wgpu::BufferSize::new( + std::mem::size_of::<Uniforms>() as u64, + ), + }, ), }], }); @@ -356,13 +360,12 @@ impl Pipeline { let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[ - wgpu::RenderPassColorAttachmentDescriptor { - attachment, - resolve_target, - ops: wgpu::Operations { load, store: true }, - }, - ], + label: Some("iced_wgpu::triangle render pass"), + color_attachments: &[wgpu::RenderPassColorAttachment { + view: attachment, + resolve_target, + ops: wgpu::Operations { load, store: true }, + }], depth_stencil_attachment: None, }); @@ -390,6 +393,7 @@ impl Pipeline { self.index_buffer .raw .slice(index_offset * mem::size_of::<u32>() as u64..), + wgpu::IndexFormat::Uint32, ); render_pass.set_vertex_buffer( diff --git a/wgpu/src/triangle/msaa.rs b/wgpu/src/triangle/msaa.rs index db86f748..c099d518 100644 --- a/wgpu/src/triangle/msaa.rs +++ b/wgpu/src/triangle/msaa.rs @@ -20,9 +20,9 @@ impl Blit { address_mode_u: wgpu::AddressMode::ClampToEdge, address_mode_v: wgpu::AddressMode::ClampToEdge, address_mode_w: wgpu::AddressMode::ClampToEdge, - mag_filter: wgpu::FilterMode::Linear, - min_filter: wgpu::FilterMode::Linear, - mipmap_filter: wgpu::FilterMode::Linear, + mag_filter: wgpu::FilterMode::Nearest, + min_filter: wgpu::FilterMode::Nearest, + mipmap_filter: wgpu::FilterMode::Nearest, ..Default::default() }); @@ -32,7 +32,10 @@ impl Blit { entries: &[wgpu::BindGroupLayoutEntry { binding: 0, visibility: wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Sampler { comparison: false }, + ty: wgpu::BindingType::Sampler { + comparison: false, + filtering: false, + }, count: None, }], }); @@ -53,9 +56,11 @@ impl Blit { entries: &[wgpu::BindGroupLayoutEntry { binding: 0, visibility: wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::SampledTexture { - dimension: wgpu::TextureViewDimension::D2, - component_type: wgpu::TextureComponentType::Float, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { + filterable: false, + }, + view_dimension: wgpu::TextureViewDimension::D2, multisampled: false, }, count: None, @@ -69,54 +74,55 @@ impl Blit { bind_group_layouts: &[&constant_layout, &texture_layout], }); - let vs_module = device.create_shader_module(wgpu::include_spirv!( - "../shader/blit.vert.spv" - )); - - let fs_module = device.create_shader_module(wgpu::include_spirv!( - "../shader/blit.frag.spv" - )); + let shader = + device.create_shader_module(&wgpu::ShaderModuleDescriptor { + label: Some("iced_wgpu::triangle::blit_shader"), + source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed( + include_str!("../shader/blit.wgsl"), + )), + flags: wgpu::ShaderFlags::all(), + }); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: Some("iced_wgpu::triangle::msaa pipeline"), layout: Some(&layout), - vertex_stage: wgpu::ProgrammableStageDescriptor { - module: &vs_module, - entry_point: "main", + vertex: wgpu::VertexState { + module: &shader, + entry_point: "vs_main", + buffers: &[], }, - fragment_stage: Some(wgpu::ProgrammableStageDescriptor { - module: &fs_module, - entry_point: "main", + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: "fs_main", + targets: &[wgpu::ColorTargetState { + format, + blend: Some(wgpu::BlendState { + color: wgpu::BlendComponent { + src_factor: wgpu::BlendFactor::SrcAlpha, + dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, + operation: wgpu::BlendOperation::Add, + }, + alpha: wgpu::BlendComponent { + src_factor: wgpu::BlendFactor::One, + dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, + operation: wgpu::BlendOperation::Add, + }, + }), + write_mask: wgpu::ColorWrite::ALL, + }], }), - rasterization_state: Some(wgpu::RasterizationStateDescriptor { + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, front_face: wgpu::FrontFace::Cw, - cull_mode: wgpu::CullMode::None, ..Default::default() - }), - primitive_topology: wgpu::PrimitiveTopology::TriangleList, - color_states: &[wgpu::ColorStateDescriptor { - format, - color_blend: wgpu::BlendDescriptor { - src_factor: wgpu::BlendFactor::SrcAlpha, - dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, - operation: wgpu::BlendOperation::Add, - }, - alpha_blend: wgpu::BlendDescriptor { - src_factor: wgpu::BlendFactor::One, - dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, - operation: wgpu::BlendOperation::Add, - }, - write_mask: wgpu::ColorWrite::ALL, - }], - depth_stencil_state: None, - vertex_state: wgpu::VertexStateDescriptor { - index_format: wgpu::IndexFormat::Uint16, - vertex_buffers: &[], }, - sample_count: 1, - sample_mask: !0, - alpha_to_coverage_enabled: false, + depth_stencil: None, + multisample: wgpu::MultisampleState { + count: 1, + mask: !0, + alpha_to_coverage_enabled: false, + }, }); Blit { @@ -172,16 +178,15 @@ impl Blit { ) { let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[ - wgpu::RenderPassColorAttachmentDescriptor { - attachment: target, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Load, - store: true, - }, + label: Some("iced_wgpu::triangle::msaa render pass"), + color_attachments: &[wgpu::RenderPassColorAttachment { + view: target, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, + store: true, }, - ], + }], depth_stencil_attachment: None, }); @@ -217,7 +222,7 @@ impl Targets { let extent = wgpu::Extent3d { width, height, - depth: 1, + depth_or_array_layers: 1, }; let attachment = device.create_texture(&wgpu::TextureDescriptor { @@ -227,7 +232,7 @@ impl Targets { sample_count, dimension: wgpu::TextureDimension::D2, format, - usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + usage: wgpu::TextureUsage::RENDER_ATTACHMENT, }); let resolve = device.create_texture(&wgpu::TextureDescriptor { @@ -237,7 +242,7 @@ impl Targets { sample_count: 1, dimension: wgpu::TextureDimension::D2, format, - usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT + usage: wgpu::TextureUsage::RENDER_ATTACHMENT | wgpu::TextureUsage::SAMPLED, }); diff --git a/wgpu/src/widget.rs b/wgpu/src/widget.rs index 177ae1b6..a575d036 100644 --- a/wgpu/src/widget.rs +++ b/wgpu/src/widget.rs @@ -20,6 +20,8 @@ pub mod rule; pub mod scrollable; pub mod slider; pub mod text_input; +pub mod toggler; +pub mod tooltip; #[doc(no_inline)] pub use button::Button; @@ -43,6 +45,10 @@ pub use scrollable::Scrollable; pub use slider::Slider; #[doc(no_inline)] pub use text_input::TextInput; +#[doc(no_inline)] +pub use toggler::Toggler; +#[doc(no_inline)] +pub use tooltip::Tooltip; #[cfg(feature = "canvas")] #[cfg_attr(docsrs, doc(cfg(feature = "canvas")))] diff --git a/wgpu/src/widget/pane_grid.rs b/wgpu/src/widget/pane_grid.rs index c26dde48..fc36862c 100644 --- a/wgpu/src/widget/pane_grid.rs +++ b/wgpu/src/widget/pane_grid.rs @@ -6,12 +6,12 @@ //! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing, //! drag and drop, and hotkey support. //! -//! [`pane_grid` example]: https://github.com/hecrj/iced/tree/0.2/examples/pane_grid +//! [`pane_grid` example]: https://github.com/hecrj/iced/tree/0.3/examples/pane_grid use crate::Renderer; -pub use iced_native::pane_grid::{ - Axis, Configuration, Direction, DragEvent, Node, Pane, ResizeEvent, Split, - State, +pub use iced_graphics::pane_grid::{ + Axis, Configuration, Direction, DragEvent, Line, Node, Pane, ResizeEvent, + Split, State, StyleSheet, }; /// A collection of panes distributed using either vertical or horizontal splits diff --git a/wgpu/src/widget/toggler.rs b/wgpu/src/widget/toggler.rs new file mode 100644 index 00000000..dfcf759b --- /dev/null +++ b/wgpu/src/widget/toggler.rs @@ -0,0 +1,9 @@ +//! Show toggle controls using togglers. +use crate::Renderer; + +pub use iced_graphics::toggler::{Style, StyleSheet}; + +/// A toggler that can be toggled +/// +/// This is an alias of an `iced_native` toggler with an `iced_wgpu::Renderer`. +pub type Toggler<Message> = iced_native::Toggler<Message, Renderer>; diff --git a/wgpu/src/widget/tooltip.rs b/wgpu/src/widget/tooltip.rs new file mode 100644 index 00000000..89ab3a15 --- /dev/null +++ b/wgpu/src/widget/tooltip.rs @@ -0,0 +1,6 @@ +//! Display a widget over another. +/// A widget allowing the selection of a single value from a list of options. +pub type Tooltip<'a, Message> = + iced_native::Tooltip<'a, Message, crate::Renderer>; + +pub use iced_native::tooltip::Position; diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 072521ef..c21b0868 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -21,29 +21,38 @@ impl Compositor { /// Requests a new [`Compositor`] with the given [`Settings`]. /// /// Returns `None` if no compatible graphics adapter could be found. - pub async fn request(settings: Settings) -> Option<Self> { - let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY); + pub async fn request<W: HasRawWindowHandle>( + settings: Settings, + compatible_window: Option<&W>, + ) -> Option<Self> { + let instance = wgpu::Instance::new(settings.internal_backend); + + #[allow(unsafe_code)] + let compatible_surface = compatible_window + .map(|window| unsafe { instance.create_surface(window) }); let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: if settings.antialiasing.is_none() { - wgpu::PowerPreference::Default + wgpu::PowerPreference::LowPower } else { wgpu::PowerPreference::HighPerformance }, - compatible_surface: None, + compatible_surface: compatible_surface.as_ref(), }) .await?; let (device, queue) = adapter .request_device( &wgpu::DeviceDescriptor { + label: Some( + "iced_wgpu::window::compositor device descriptor", + ), features: wgpu::Features::empty(), limits: wgpu::Limits { max_bind_groups: 2, ..wgpu::Limits::default() }, - shader_validation: false, }, None, ) @@ -75,9 +84,15 @@ impl iced_graphics::window::Compositor for Compositor { type Surface = wgpu::Surface; type SwapChain = wgpu::SwapChain; - fn new(settings: Self::Settings) -> Result<(Self, Renderer), Error> { - let compositor = futures::executor::block_on(Self::request(settings)) - .ok_or(Error::AdapterNotFound)?; + fn new<W: HasRawWindowHandle>( + settings: Self::Settings, + compatible_window: Option<&W>, + ) -> Result<(Self, Renderer), Error> { + let compositor = futures::executor::block_on(Self::request( + settings, + compatible_window, + )) + .ok_or(Error::AdapterNotFound)?; let backend = compositor.create_backend(); @@ -103,7 +118,7 @@ impl iced_graphics::window::Compositor for Compositor { self.device.create_swap_chain( surface, &wgpu::SwapChainDescriptor { - usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + usage: wgpu::TextureUsage::RENDER_ATTACHMENT, format: self.settings.format, present_mode: self.settings.present_mode, width, @@ -129,31 +144,28 @@ impl iced_graphics::window::Compositor for Compositor { }, ); - let _ = - encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[ - wgpu::RenderPassColorAttachmentDescriptor { - attachment: &frame.output.view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear({ - let [r, g, b, a] = - background_color.into_linear(); - - wgpu::Color { - r: f64::from(r), - g: f64::from(g), - b: f64::from(b), - a: f64::from(a), - } - }), - store: true, - }, - }, - ], - depth_stencil_attachment: None, - }); - + let _ = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("iced_wgpu::window::Compositor render pass"), + color_attachments: &[wgpu::RenderPassColorAttachment { + view: &frame.output.view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear({ + let [r, g, b, a] = background_color.into_linear(); + + wgpu::Color { + r: f64::from(r), + g: f64::from(g), + b: f64::from(b), + a: f64::from(a), + } + }), + store: true, + }, + }], + depth_stencil_attachment: None, + }); + let mouse_interaction = renderer.backend_mut().draw( &mut self.device, &mut self.staging_belt, @@ -163,27 +175,29 @@ impl iced_graphics::window::Compositor for Compositor { output, overlay, ); - + // Submit work self.staging_belt.finish(); self.queue.submit(Some(encoder.finish())); - + // Recall staging buffers self.local_pool .spawner() .spawn(self.staging_belt.recall()) .expect("Recall staging belt"); - + self.local_pool.run_until_stalled(); - + Ok(mouse_interaction) } Err(error) => match error { - wgpu::SwapChainError::Outdated => { + wgpu::SwapChainError::OutOfMemory => { + panic!("Swapchain error: {:?}", error); + } + _ => { // Try again next frame. Err(()) } - _ => panic!("Swapchain error: {:?}", error), }, } } |