diff --git a/crates/kas-wgpu/Cargo.toml b/crates/kas-wgpu/Cargo.toml index a4d0e5f57..f35ea6049 100644 --- a/crates/kas-wgpu/Cargo.toml +++ b/crates/kas-wgpu/Cargo.toml @@ -31,7 +31,7 @@ bytemuck = "1.7.0" futures = "0.3" log = "0.4" smallvec = "1.6.1" -wgpu = { version = "0.11.0", features = ["spirv"] } +wgpu = { version = "0.13.0", features = ["spirv"] } winit = "0.26" thiserror = "1.0.23" window_clipboard = { version = "0.2.0", optional = true } diff --git a/crates/kas-wgpu/src/draw/atlases.rs b/crates/kas-wgpu/src/draw/atlases.rs index 4e24c2356..ae5da6853 100644 --- a/crates/kas-wgpu/src/draw/atlases.rs +++ b/crates/kas-wgpu/src/draw/atlases.rs @@ -96,6 +96,7 @@ impl Pipeline { /// - `tex_format`: texture format pub fn new( device: &wgpu::Device, + label: Option<&'static str>, bg_common: &wgpu::BindGroupLayout, tex_size: i32, tex_format: wgpu::TextureFormat, @@ -118,10 +119,7 @@ impl Pipeline { wgpu::BindGroupLayoutEntry { binding: 1, visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Sampler { - filtering: false, - comparison: false, - }, + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::NonFiltering), count: None, }, ], @@ -134,7 +132,7 @@ impl Pipeline { }); let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("atlas render pipeline"), + label, layout: Some(&pipeline_layout), vertex, primitive: wgpu::PrimitiveState { @@ -142,13 +140,14 @@ impl Pipeline { strip_index_format: None, front_face: wgpu::FrontFace::Cw, cull_mode: Some(wgpu::Face::Back), // not required - clamp_depth: false, + unclipped_depth: false, polygon_mode: wgpu::PolygonMode::Fill, conservative: false, }, depth_stencil: None, multisample: Default::default(), fragment: Some(fragment), + multiview: None, }); let sampler = device.create_sampler(&wgpu::SamplerDescriptor { diff --git a/crates/kas-wgpu/src/draw/draw_pipe.rs b/crates/kas-wgpu/src/draw/draw_pipe.rs index e76962f4e..044d68676 100644 --- a/crates/kas-wgpu/src/draw/draw_pipe.rs +++ b/crates/kas-wgpu/src/draw/draw_pipe.rs @@ -27,7 +27,6 @@ impl DrawPipe { // Create staging belt and a local pool let staging_belt = wgpu::util::StagingBelt::new(1024); - let local_pool = futures::executor::LocalPool::new(); let bgl_common = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { label: Some("common bind group layout"), @@ -38,7 +37,7 @@ impl DrawPipe { ty: wgpu::BindingType::Buffer { ty: wgpu::BufferBindingType::Uniform, has_dynamic_offset: false, - min_binding_size: None, // TODO + min_binding_size: wgpu::BufferSize::new(16), }, count: None, }, @@ -48,7 +47,7 @@ impl DrawPipe { ty: wgpu::BindingType::Buffer { ty: wgpu::BufferBindingType::Uniform, has_dynamic_offset: false, - min_binding_size: None, // TODO + min_binding_size: wgpu::BufferSize::new(16), }, count: None, }, @@ -63,7 +62,7 @@ impl DrawPipe { let a = (dir.0.sin(), dir.0.cos()); // We normalise intensity: let f = a.0 / a.1; - let light_norm = [dir.1.sin() * f, -dir.1.cos() * f, 1.0]; + let light_norm = [dir.1.sin() * f, -dir.1.cos() * f, 1.0, 0.0]; let light_norm_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("light_norm_buf"), @@ -82,7 +81,6 @@ impl DrawPipe { DrawPipe { device, queue, - local_pool, staging_belt, bgl_common, light_norm_buf, @@ -225,14 +223,14 @@ impl DrawPipe { .text .write_buffers(&self.device, &mut self.staging_belt, &mut encoder); - let mut color_attachments = [wgpu::RenderPassColorAttachment { + let mut color_attachments = [Some(wgpu::RenderPassColorAttachment { view: frame_view, resolve_target: None, ops: wgpu::Operations { load: wgpu::LoadOp::Clear(clear_color), store: true, }, - }]; + })]; // We use a separate render pass for each clipped region. for (pass, (rect, _)) in window.clip_regions.iter().enumerate() { @@ -274,7 +272,7 @@ impl DrawPipe { self.text.render(&window.text, pass, &mut rpass, bg_common); } - color_attachments[0].ops.load = wgpu::LoadOp::Load; + color_attachments[0].as_mut().unwrap().ops.load = wgpu::LoadOp::Load; } let size = window.clip_regions[0].0.size; @@ -293,12 +291,7 @@ impl DrawPipe { self.staging_belt.finish(); self.queue.submit(std::iter::once(encoder.finish())); - use futures::task::SpawnExt; - self.local_pool - .spawner() - .spawn(self.staging_belt.recall()) - .expect("Recall staging belt"); - self.local_pool.run_until_stalled(); + self.staging_belt.recall(); } } diff --git a/crates/kas-wgpu/src/draw/flat_round.rs b/crates/kas-wgpu/src/draw/flat_round.rs index 5a4d0e7fc..d2af8c6af 100644 --- a/crates/kas-wgpu/src/draw/flat_round.rs +++ b/crates/kas-wgpu/src/draw/flat_round.rs @@ -85,7 +85,7 @@ impl Pipeline { strip_index_format: None, front_face: wgpu::FrontFace::Cw, cull_mode: Some(wgpu::Face::Back), // not required - clamp_depth: false, + unclipped_depth: false, polygon_mode: wgpu::PolygonMode::Fill, conservative: false, }, @@ -94,12 +94,13 @@ impl Pipeline { fragment: Some(wgpu::FragmentState { module: &shaders.frag_flat_round, entry_point: "main", - targets: &[wgpu::ColorTargetState { + targets: &[Some(wgpu::ColorTargetState { format: super::RENDER_TEX_FORMAT, blend: Some(wgpu::BlendState::ALPHA_BLENDING), write_mask: wgpu::ColorWrites::ALL, - }], + })], }), + multiview: None, }); Pipeline { render_pipeline } diff --git a/crates/kas-wgpu/src/draw/images.rs b/crates/kas-wgpu/src/draw/images.rs index 49ea11508..0b00436a8 100644 --- a/crates/kas-wgpu/src/draw/images.rs +++ b/crates/kas-wgpu/src/draw/images.rs @@ -89,6 +89,7 @@ impl Images { ) -> Self { let atlas_pipe = atlases::Pipeline::new( device, + Some("images pipe"), bgl_common, 2048, wgpu::TextureFormat::Rgba8UnormSrgb, @@ -109,11 +110,11 @@ impl Images { wgpu::FragmentState { module: &shaders.frag_image, entry_point: "main", - targets: &[wgpu::ColorTargetState { + targets: &[Some(wgpu::ColorTargetState { format: super::RENDER_TEX_FORMAT, blend: Some(wgpu::BlendState::ALPHA_BLENDING), write_mask: wgpu::ColorWrites::ALL, - }], + })], }, ); Images { diff --git a/crates/kas-wgpu/src/draw/mod.rs b/crates/kas-wgpu/src/draw/mod.rs index 328e6f9cc..a09544afb 100644 --- a/crates/kas-wgpu/src/draw/mod.rs +++ b/crates/kas-wgpu/src/draw/mod.rs @@ -38,7 +38,6 @@ type Scale = [f32; 4]; pub struct DrawPipe { pub(crate) device: wgpu::Device, queue: wgpu::Queue, - local_pool: futures::executor::LocalPool, staging_belt: wgpu::util::StagingBelt, bgl_common: wgpu::BindGroupLayout, light_norm_buf: wgpu::Buffer, diff --git a/crates/kas-wgpu/src/draw/round_2col.rs b/crates/kas-wgpu/src/draw/round_2col.rs index 4d51961df..faa3cae18 100644 --- a/crates/kas-wgpu/src/draw/round_2col.rs +++ b/crates/kas-wgpu/src/draw/round_2col.rs @@ -73,7 +73,7 @@ impl Pipeline { strip_index_format: None, front_face: wgpu::FrontFace::Cw, cull_mode: Some(wgpu::Face::Back), // not required - clamp_depth: false, + unclipped_depth: false, polygon_mode: wgpu::PolygonMode::Fill, conservative: false, }, @@ -82,12 +82,13 @@ impl Pipeline { fragment: Some(wgpu::FragmentState { module: &shaders.frag_round_2col, entry_point: "main", - targets: &[wgpu::ColorTargetState { + targets: &[Some(wgpu::ColorTargetState { format: super::RENDER_TEX_FORMAT, blend: Some(wgpu::BlendState::ALPHA_BLENDING), write_mask: wgpu::ColorWrites::ALL, - }], + })], }), + multiview: None, }); Pipeline { render_pipeline } diff --git a/crates/kas-wgpu/src/draw/shaded_round.rs b/crates/kas-wgpu/src/draw/shaded_round.rs index 845709fcd..8792bc3c2 100644 --- a/crates/kas-wgpu/src/draw/shaded_round.rs +++ b/crates/kas-wgpu/src/draw/shaded_round.rs @@ -80,7 +80,7 @@ impl Pipeline { strip_index_format: None, front_face: wgpu::FrontFace::Cw, cull_mode: Some(wgpu::Face::Back), // not required - clamp_depth: false, + unclipped_depth: false, polygon_mode: wgpu::PolygonMode::Fill, conservative: false, }, @@ -89,12 +89,13 @@ impl Pipeline { fragment: Some(wgpu::FragmentState { module: &shaders.frag_shaded_round, entry_point: "main", - targets: &[wgpu::ColorTargetState { + targets: &[Some(wgpu::ColorTargetState { format: super::RENDER_TEX_FORMAT, blend: Some(wgpu::BlendState::ALPHA_BLENDING), write_mask: wgpu::ColorWrites::ALL, - }], + })], }), + multiview: None, }); Pipeline { render_pipeline } diff --git a/crates/kas-wgpu/src/draw/shaded_square.rs b/crates/kas-wgpu/src/draw/shaded_square.rs index 10f283071..2077ff3a9 100644 --- a/crates/kas-wgpu/src/draw/shaded_square.rs +++ b/crates/kas-wgpu/src/draw/shaded_square.rs @@ -48,12 +48,16 @@ impl Pipeline { label: Some("SS render_pipeline"), layout: Some(&pipeline_layout), vertex: wgpu::VertexState { - module: &shaders.vert_shaded_square, - entry_point: "main", + module: &shaders.shaded_square, + entry_point: "vert", buffers: &[wgpu::VertexBufferLayout { array_stride: size_of::() as wgpu::BufferAddress, step_mode: wgpu::VertexStepMode::Vertex, - attributes: &wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x4, 2 => Float32x2], + attributes: &wgpu::vertex_attr_array![ + 0 => Float32x2, + 1 => Float32x4, + 2 => Float32x2, + ], }], }, primitive: wgpu::PrimitiveState { @@ -61,21 +65,22 @@ impl Pipeline { strip_index_format: None, front_face: wgpu::FrontFace::Cw, cull_mode: Some(wgpu::Face::Back), // not required - clamp_depth: false, + unclipped_depth: false, polygon_mode: wgpu::PolygonMode::Fill, conservative: false, }, depth_stencil: None, multisample: Default::default(), fragment: Some(wgpu::FragmentState { - module: &shaders.frag_shaded_square, - entry_point: "main", - targets: &[wgpu::ColorTargetState { + module: &shaders.shaded_square, + entry_point: "frag", + targets: &[Some(wgpu::ColorTargetState { format: super::RENDER_TEX_FORMAT, blend: Some(wgpu::BlendState::ALPHA_BLENDING), write_mask: wgpu::ColorWrites::ALL, - }], + })], }), + multiview: None, }); Pipeline { render_pipeline } diff --git a/crates/kas-wgpu/src/draw/shaders.rs b/crates/kas-wgpu/src/draw/shaders.rs index 96422ed6d..d0e12a83f 100644 --- a/crates/kas-wgpu/src/draw/shaders.rs +++ b/crates/kas-wgpu/src/draw/shaders.rs @@ -5,27 +5,26 @@ //! Shader management -use wgpu::{include_spirv, ShaderModule}; +use wgpu::{include_spirv, include_wgsl, ShaderModule}; /// Shader manager pub struct ShaderManager { pub vert_flat_round: ShaderModule, pub vert_round_2col: ShaderModule, - pub vert_shaded_square: ShaderModule, pub vert_shaded_round: ShaderModule, pub vert_image: ShaderModule, pub vert_glyph: ShaderModule, pub frag_flat_round: ShaderModule, pub frag_round_2col: ShaderModule, - pub frag_shaded_square: ShaderModule, pub frag_shaded_round: ShaderModule, pub frag_image: ShaderModule, pub frag_glyph: ShaderModule, + pub shaded_square: ShaderModule, } macro_rules! create { ($device:ident, $path:expr) => {{ - $device.create_shader_module(&include_spirv!($path)) + $device.create_shader_module(include_spirv!($path)) }}; } @@ -33,31 +32,31 @@ impl ShaderManager { pub fn new(device: &wgpu::Device) -> Self { let vert_flat_round = create!(device, "shaders/flat_round.vert.spv"); let vert_round_2col = create!(device, "shaders/round_2col.vert.spv"); - let vert_shaded_square = create!(device, "shaders/shaded_square.vert.spv"); let vert_shaded_round = create!(device, "shaders/shaded_round.vert.spv"); let vert_image = create!(device, "shaders/image.vert.spv"); let vert_glyph = create!(device, "shaders/glyph.vert.spv"); let frag_flat_round = create!(device, "shaders/flat_round.frag.spv"); let frag_round_2col = create!(device, "shaders/round_2col.frag.spv"); - let frag_shaded_square = create!(device, "shaders/shaded_square.frag.spv"); let frag_shaded_round = create!(device, "shaders/shaded_round.frag.spv"); let frag_image = create!(device, "shaders/image.frag.spv"); let frag_glyph = create!(device, "shaders/glyph.frag.spv"); + let shaded_square = + device.create_shader_module(include_wgsl!("shaders/shaded_square.wgsl")); + ShaderManager { vert_image, vert_glyph, vert_flat_round, vert_round_2col, - vert_shaded_square, vert_shaded_round, frag_flat_round, frag_round_2col, - frag_shaded_square, frag_shaded_round, frag_image, frag_glyph, + shaded_square, } } } diff --git a/crates/kas-wgpu/src/draw/shaders/shaded_round.frag b/crates/kas-wgpu/src/draw/shaders/shaded_round.frag index 41e4674b4..12c3b2f9e 100644 --- a/crates/kas-wgpu/src/draw/shaders/shaded_round.frag +++ b/crates/kas-wgpu/src/draw/shaders/shaded_round.frag @@ -17,6 +17,9 @@ layout(location = 0) out vec4 outColor; layout(set = 0, binding = 1) uniform FragCommon { vec3 lightNorm; + // Note: since WGPU v0.12 this type is interpreted as 16 bytes. + // For compatibility, we explicitly pad to 16 bytes. + float _padding; }; float sample_a(vec2 dir) { diff --git a/crates/kas-wgpu/src/draw/shaders/shaded_round.frag.spv b/crates/kas-wgpu/src/draw/shaders/shaded_round.frag.spv index 4c3418e3c..a3a88b879 100644 Binary files a/crates/kas-wgpu/src/draw/shaders/shaded_round.frag.spv and b/crates/kas-wgpu/src/draw/shaders/shaded_round.frag.spv differ diff --git a/crates/kas-wgpu/src/draw/shaders/shaded_square.frag b/crates/kas-wgpu/src/draw/shaders/shaded_square.frag index 699ed1507..46f38c9f0 100644 --- a/crates/kas-wgpu/src/draw/shaders/shaded_square.frag +++ b/crates/kas-wgpu/src/draw/shaders/shaded_square.frag @@ -15,9 +15,11 @@ layout(location = 0) out vec4 outColor; layout(set = 0, binding = 1) uniform FragCommon { vec3 lightNorm; + // Note: since WGPU v0.12 this type is interpreted as 16 bytes. + // For compatibility, we explicitly pad to 16 bytes. + float _padding; }; - void main() { float n3 = 1.0 - sqrt(norm2.x * norm2.x + norm2.y * norm2.y); vec3 norm = vec3(norm2, n3); diff --git a/crates/kas-wgpu/src/draw/shaders/shaded_square.frag.spv b/crates/kas-wgpu/src/draw/shaders/shaded_square.frag.spv index 92727167a..bd3dea484 100644 Binary files a/crates/kas-wgpu/src/draw/shaders/shaded_square.frag.spv and b/crates/kas-wgpu/src/draw/shaders/shaded_square.frag.spv differ diff --git a/crates/kas-wgpu/src/draw/shaders/shaded_square.wgsl b/crates/kas-wgpu/src/draw/shaders/shaded_square.wgsl new file mode 100644 index 000000000..111b506b8 --- /dev/null +++ b/crates/kas-wgpu/src/draw/shaders/shaded_square.wgsl @@ -0,0 +1,51 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License in the LICENSE-APACHE file or at: +// https://www.apache.org/licenses/LICENSE-2.0 + +struct VertexCommon { + offset: vec2, + scale: vec2, +} +@group(0) @binding(0) +var global: VertexCommon; + +struct FragCommon { + lightNorm: vec3, + _padding: f32, +} +@group(0) @binding(1) +var global2: FragCommon; + +struct VertexOutput { + @location(0) fragColor: vec4, + @location(1) norm2: vec2, + @builtin(position) member: vec4, +} + +struct FragmentOutput { + @location(0) outColor: vec4, +} + +@vertex +fn vert( + @location(0) a_pos: vec2, + @location(1) a_col: vec4, + @location(2) a1: vec2, +) -> VertexOutput { + let pos = global.scale * (a_pos.xy + global.offset); + let gl_Position = vec4(pos.x, pos.y, 0.0, 1.0); + return VertexOutput(a_col, a1, gl_Position); +} + +@fragment +fn frag( + @location(0) fragColor: vec4, + @location(1) norm2: vec2, +) -> FragmentOutput { + let n3: f32 = 1.0 - sqrt(norm2.x * norm2.x + norm2.y * norm2.y); + let norm = vec3(norm2.x, norm2.y, n3); + let c: vec3 = (fragColor.xyz * dot(norm, global2.lightNorm)); + let outColor = vec4(c.x, c.y, c.z, fragColor.w); + return FragmentOutput(outColor); +} diff --git a/crates/kas-wgpu/src/draw/text_pipe.rs b/crates/kas-wgpu/src/draw/text_pipe.rs index 96c79faec..8d1ee6b5f 100644 --- a/crates/kas-wgpu/src/draw/text_pipe.rs +++ b/crates/kas-wgpu/src/draw/text_pipe.rs @@ -91,6 +91,7 @@ impl Pipeline { ) -> Self { let atlas_pipe = atlases::Pipeline::new( device, + Some("text pipe"), bgl_common, 512, wgpu::TextureFormat::R8Unorm, @@ -112,11 +113,11 @@ impl Pipeline { wgpu::FragmentState { module: &shaders.frag_glyph, entry_point: "main", - targets: &[wgpu::ColorTargetState { + targets: &[Some(wgpu::ColorTargetState { format: super::RENDER_TEX_FORMAT, blend: Some(wgpu::BlendState::ALPHA_BLENDING), write_mask: wgpu::ColorWrites::ALL, - }], + })], }, ); Pipeline { diff --git a/crates/kas-widgets/src/adapter/reserve.rs b/crates/kas-widgets/src/adapter/reserve.rs index d54604542..96d396e8c 100644 --- a/crates/kas-widgets/src/adapter/reserve.rs +++ b/crates/kas-widgets/src/adapter/reserve.rs @@ -51,7 +51,6 @@ impl_scope! { #[derive(Clone, Default)] #[widget{ derive = self.inner; }] pub struct Reserve { - core: widget_core!(), #[widget] pub inner: W, reserve: R, @@ -88,7 +87,6 @@ impl_scope! { #[inline] pub fn new(inner: W, reserve: R) -> Self { Reserve { - core: Default::default(), inner, reserve, } diff --git a/examples/mandlebrot/Cargo.toml b/examples/mandlebrot/Cargo.toml index 3d408e1c2..6a77d8504 100644 --- a/examples/mandlebrot/Cargo.toml +++ b/examples/mandlebrot/Cargo.toml @@ -12,7 +12,7 @@ kas = { version = "0.11.0", path = "../.." } chrono = "0.4" env_logger = "0.9" log = "0.4" -wgpu = "0.11.0" +wgpu = "0.13.0" bytemuck = "1.7.0" [features] diff --git a/examples/mandlebrot/mandlebrot.rs b/examples/mandlebrot/mandlebrot.rs index 69ccb7fbe..ee092d590 100644 --- a/examples/mandlebrot/mandlebrot.rs +++ b/examples/mandlebrot/mandlebrot.rs @@ -42,10 +42,10 @@ struct Shaders { impl Shaders { fn new(device: &wgpu::Device) -> Self { - let vertex = device.create_shader_module(&include_spirv!("shader.vert.spv")); + let vertex = device.create_shader_module(include_spirv!("shader.vert.spv")); // Note: we don't use wgpu::include_spirv since it forces validation, // which cannot currently deal with double precision floats (dvec2). - let fragment = device.create_shader_module(&wgpu::ShaderModuleDescriptor { + let fragment = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: Some("fragment shader"), source: wgpu::util::make_spirv(FRAG_SHADER), }); @@ -144,7 +144,7 @@ impl CustomPipeBuilder for PipeBuilder { strip_index_format: None, front_face: wgpu::FrontFace::Cw, cull_mode: Some(wgpu::Face::Back), // not required - clamp_depth: false, + unclipped_depth: false, polygon_mode: wgpu::PolygonMode::Fill, conservative: false, }, @@ -153,12 +153,13 @@ impl CustomPipeBuilder for PipeBuilder { fragment: Some(wgpu::FragmentState { module: &shaders.fragment, entry_point: "main", - targets: &[wgpu::ColorTargetState { + targets: &[Some(wgpu::ColorTargetState { format: tex_format, blend: None, write_mask: wgpu::ColorWrites::ALL, - }], + })], }), + multiview: None, }); Pipe { render_pipeline } diff --git a/examples/mandlebrot/shader64.frag b/examples/mandlebrot/shader64.frag index b906fed90..72396d748 100644 --- a/examples/mandlebrot/shader64.frag +++ b/examples/mandlebrot/shader64.frag @@ -28,7 +28,11 @@ void main() { double x = (z.x * z.x - z.y * z.y) + c.x; double y = (z.y * z.x + z.x * z.y) + c.y; - if((x * x + y * y) > 4.0) break; + // Reducing precision here gives a small speed-up with minimal loss: + float xf = float(x); + float yf = float(y); + if((xf * xf + yf * yf) > 4.0) break; + z.x = x; z.y = y; } diff --git a/examples/mandlebrot/shader64.frag.spv b/examples/mandlebrot/shader64.frag.spv index 99df0da2c..4b5114898 100644 Binary files a/examples/mandlebrot/shader64.frag.spv and b/examples/mandlebrot/shader64.frag.spv differ