Merge pull request #2099 from jim-ec/master

Compute vertex positions in the shader
This commit is contained in:
Héctor Ramón 2024-01-19 20:54:09 +01:00 committed by GitHub
commit b3e3f6e3c9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 114 additions and 229 deletions

View file

@ -35,8 +35,6 @@ pub struct Pipeline {
vector_cache: RefCell<vector::Cache>, vector_cache: RefCell<vector::Cache>,
pipeline: wgpu::RenderPipeline, pipeline: wgpu::RenderPipeline,
vertices: wgpu::Buffer,
indices: wgpu::Buffer,
nearest_sampler: wgpu::Sampler, nearest_sampler: wgpu::Sampler,
linear_sampler: wgpu::Sampler, linear_sampler: wgpu::Sampler,
texture: wgpu::BindGroup, texture: wgpu::BindGroup,
@ -172,20 +170,14 @@ impl Data {
fn render<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) { fn render<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) {
render_pass.set_bind_group(0, &self.constants, &[]); render_pass.set_bind_group(0, &self.constants, &[]);
render_pass.set_vertex_buffer(1, self.instances.slice(..)); render_pass.set_vertex_buffer(0, self.instances.slice(..));
render_pass.draw_indexed( render_pass.draw(0..6, 0..self.instance_count as u32);
0..QUAD_INDICES.len() as u32,
0,
0..self.instance_count as u32,
);
} }
} }
impl Pipeline { impl Pipeline {
pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self { pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self {
use wgpu::util::DeviceExt;
let nearest_sampler = device.create_sampler(&wgpu::SamplerDescriptor { let nearest_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
address_mode_u: wgpu::AddressMode::ClampToEdge, address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge, address_mode_v: wgpu::AddressMode::ClampToEdge,
@ -261,7 +253,11 @@ impl Pipeline {
device.create_shader_module(wgpu::ShaderModuleDescriptor { device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("iced_wgpu image shader"), label: Some("iced_wgpu image shader"),
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed( source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(
include_str!("shader/image.wgsl"), concat!(
include_str!("shader/vertex.wgsl"),
"\n",
include_str!("shader/image.wgsl"),
),
)), )),
}); });
@ -272,28 +268,22 @@ impl Pipeline {
vertex: wgpu::VertexState { vertex: wgpu::VertexState {
module: &shader, module: &shader,
entry_point: "vs_main", entry_point: "vs_main",
buffers: &[ buffers: &[wgpu::VertexBufferLayout {
wgpu::VertexBufferLayout { array_stride: mem::size_of::<Instance>() as u64,
array_stride: mem::size_of::<Vertex>() as u64, step_mode: wgpu::VertexStepMode::Instance,
step_mode: wgpu::VertexStepMode::Vertex, attributes: &wgpu::vertex_attr_array!(
attributes: &[wgpu::VertexAttribute { // Position
shader_location: 0, 0 => Float32x2,
format: wgpu::VertexFormat::Float32x2, // Scale
offset: 0, 1 => Float32x2,
}], // Atlas position
}, 2 => Float32x2,
wgpu::VertexBufferLayout { // Atlas scale
array_stride: mem::size_of::<Instance>() as u64, 3 => Float32x2,
step_mode: wgpu::VertexStepMode::Instance, // Layer
attributes: &wgpu::vertex_attr_array!( 4 => Sint32,
1 => Float32x2, ),
2 => Float32x2, }],
3 => Float32x2,
4 => Float32x2,
5 => Sint32,
),
},
],
}, },
fragment: Some(wgpu::FragmentState { fragment: Some(wgpu::FragmentState {
module: &shader, module: &shader,
@ -329,20 +319,6 @@ impl Pipeline {
multiview: None, multiview: None,
}); });
let vertices =
device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("iced_wgpu::image vertex buffer"),
contents: bytemuck::cast_slice(&QUAD_VERTICES),
usage: wgpu::BufferUsages::VERTEX,
});
let indices =
device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("iced_wgpu::image index buffer"),
contents: bytemuck::cast_slice(&QUAD_INDICES),
usage: wgpu::BufferUsages::INDEX,
});
let texture_atlas = Atlas::new(device); let texture_atlas = Atlas::new(device);
let texture = device.create_bind_group(&wgpu::BindGroupDescriptor { let texture = device.create_bind_group(&wgpu::BindGroupDescriptor {
@ -364,8 +340,6 @@ impl Pipeline {
vector_cache: RefCell::new(vector::Cache::default()), vector_cache: RefCell::new(vector::Cache::default()),
pipeline, pipeline,
vertices,
indices,
nearest_sampler, nearest_sampler,
linear_sampler, linear_sampler,
texture, texture,
@ -542,11 +516,6 @@ impl Pipeline {
); );
render_pass.set_bind_group(1, &self.texture, &[]); render_pass.set_bind_group(1, &self.texture, &[]);
render_pass.set_index_buffer(
self.indices.slice(..),
wgpu::IndexFormat::Uint16,
);
render_pass.set_vertex_buffer(0, self.vertices.slice(..));
layer.render(render_pass); layer.render(render_pass);
} }
@ -563,29 +532,6 @@ impl Pipeline {
} }
} }
#[repr(C)]
#[derive(Clone, Copy, Zeroable, Pod)]
pub struct Vertex {
_position: [f32; 2],
}
const QUAD_INDICES: [u16; 6] = [0, 1, 2, 0, 2, 3];
const QUAD_VERTICES: [Vertex; 4] = [
Vertex {
_position: [0.0, 0.0],
},
Vertex {
_position: [1.0, 0.0],
},
Vertex {
_position: [1.0, 1.0],
},
Vertex {
_position: [0.0, 1.0],
},
];
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy, Zeroable, Pod)] #[derive(Debug, Clone, Copy, Zeroable, Pod)]
struct Instance { struct Instance {

View file

@ -9,7 +9,6 @@ use crate::graphics::color;
use crate::graphics::{self, Transformation}; use crate::graphics::{self, Transformation};
use bytemuck::{Pod, Zeroable}; use bytemuck::{Pod, Zeroable};
use wgpu::util::DeviceExt;
use std::mem; use std::mem;
@ -23,8 +22,6 @@ pub struct Pipeline {
solid: solid::Pipeline, solid: solid::Pipeline,
gradient: gradient::Pipeline, gradient: gradient::Pipeline,
constant_layout: wgpu::BindGroupLayout, constant_layout: wgpu::BindGroupLayout,
vertices: wgpu::Buffer,
indices: wgpu::Buffer,
layers: Vec<Layer>, layers: Vec<Layer>,
prepare_layer: usize, prepare_layer: usize,
} }
@ -48,23 +45,7 @@ impl Pipeline {
}], }],
}); });
let vertices =
device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("iced_wgpu::quad vertex buffer"),
contents: bytemuck::cast_slice(&VERTICES),
usage: wgpu::BufferUsages::VERTEX,
});
let indices =
device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("iced_wgpu::quad index buffer"),
contents: bytemuck::cast_slice(&INDICES),
usage: wgpu::BufferUsages::INDEX,
});
Self { Self {
vertices,
indices,
solid: solid::Pipeline::new(device, format, &constant_layout), solid: solid::Pipeline::new(device, format, &constant_layout),
gradient: gradient::Pipeline::new(device, format, &constant_layout), gradient: gradient::Pipeline::new(device, format, &constant_layout),
layers: Vec::new(), layers: Vec::new(),
@ -105,11 +86,6 @@ impl Pipeline {
bounds.width, bounds.width,
bounds.height, bounds.height,
); );
render_pass.set_index_buffer(
self.indices.slice(..),
wgpu::IndexFormat::Uint16,
);
render_pass.set_vertex_buffer(0, self.vertices.slice(..));
let mut solid_offset = 0; let mut solid_offset = 0;
let mut gradient_offset = 0; let mut gradient_offset = 0;
@ -311,43 +287,6 @@ fn color_target_state(
})] })]
} }
#[repr(C)]
#[derive(Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)]
pub struct Vertex {
_position: [f32; 2],
}
impl Vertex {
fn buffer_layout<'a>() -> wgpu::VertexBufferLayout<'a> {
wgpu::VertexBufferLayout {
array_stride: mem::size_of::<Self>() as u64,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &[wgpu::VertexAttribute {
shader_location: 0,
format: wgpu::VertexFormat::Float32x2,
offset: 0,
}],
}
}
}
const INDICES: [u16; 6] = [0, 1, 2, 0, 2, 3];
const VERTICES: [Vertex; 4] = [
Vertex {
_position: [0.0, 0.0],
},
Vertex {
_position: [1.0, 0.0],
},
Vertex {
_position: [1.0, 1.0],
},
Vertex {
_position: [0.0, 1.0],
},
];
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)] #[derive(Debug, Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)]
struct Uniforms { struct Uniforms {

View file

@ -83,6 +83,8 @@ impl Pipeline {
concat!( concat!(
include_str!("../shader/quad.wgsl"), include_str!("../shader/quad.wgsl"),
"\n", "\n",
include_str!("../shader/vertex.wgsl"),
"\n",
include_str!("../shader/quad/gradient.wgsl"), include_str!("../shader/quad/gradient.wgsl"),
"\n", "\n",
include_str!("../shader/color/oklab.wgsl") include_str!("../shader/color/oklab.wgsl")
@ -91,6 +93,8 @@ impl Pipeline {
concat!( concat!(
include_str!("../shader/quad.wgsl"), include_str!("../shader/quad.wgsl"),
"\n", "\n",
include_str!("../shader/vertex.wgsl"),
"\n",
include_str!("../shader/quad/gradient.wgsl"), include_str!("../shader/quad/gradient.wgsl"),
"\n", "\n",
include_str!("../shader/color/linear_rgb.wgsl") include_str!("../shader/color/linear_rgb.wgsl")
@ -106,36 +110,32 @@ impl Pipeline {
vertex: wgpu::VertexState { vertex: wgpu::VertexState {
module: &shader, module: &shader,
entry_point: "gradient_vs_main", entry_point: "gradient_vs_main",
buffers: &[ buffers: &[wgpu::VertexBufferLayout {
quad::Vertex::buffer_layout(), array_stride: std::mem::size_of::<Gradient>() as u64,
wgpu::VertexBufferLayout { step_mode: wgpu::VertexStepMode::Instance,
array_stride: std::mem::size_of::<Gradient>() attributes: &wgpu::vertex_attr_array!(
as u64, // Colors 1-2
step_mode: wgpu::VertexStepMode::Instance, 0 => Uint32x4,
attributes: &wgpu::vertex_attr_array!( // Colors 3-4
// Colors 1-2 1 => Uint32x4,
1 => Uint32x4, // Colors 5-6
// Colors 3-4 2 => Uint32x4,
2 => Uint32x4, // Colors 7-8
// Colors 5-6 3 => Uint32x4,
3 => Uint32x4, // Offsets 1-8
// Colors 7-8 4 => Uint32x4,
4 => Uint32x4, // Direction
// Offsets 1-8 5 => Float32x4,
5 => Uint32x4, // Position & Scale
// Direction 6 => Float32x4,
6 => Float32x4, // Border color
// Position & Scale 7 => Float32x4,
7 => Float32x4, // Border radius
// Border color 8 => Float32x4,
8 => Float32x4, // Border width
// Border radius 9 => Float32
9 => Float32x4, ),
// Border width }],
10 => Float32
),
},
],
}, },
fragment: Some(wgpu::FragmentState { fragment: Some(wgpu::FragmentState {
module: &shader, module: &shader,
@ -171,12 +171,8 @@ impl Pipeline {
render_pass.set_pipeline(&self.pipeline); render_pass.set_pipeline(&self.pipeline);
render_pass.set_bind_group(0, constants, &[]); render_pass.set_bind_group(0, constants, &[]);
render_pass.set_vertex_buffer(1, layer.instances.slice(..)); render_pass.set_vertex_buffer(0, layer.instances.slice(..));
render_pass.draw_indexed( render_pass.draw(0..6, range.start as u32..range.end as u32);
0..quad::INDICES.len() as u32,
0,
range.start as u32..range.end as u32,
);
} }
} }

View file

@ -75,6 +75,8 @@ impl Pipeline {
concat!( concat!(
include_str!("../shader/quad.wgsl"), include_str!("../shader/quad.wgsl"),
"\n", "\n",
include_str!("../shader/vertex.wgsl"),
"\n",
include_str!("../shader/quad/solid.wgsl"), include_str!("../shader/quad/solid.wgsl"),
), ),
)), )),
@ -87,27 +89,24 @@ impl Pipeline {
vertex: wgpu::VertexState { vertex: wgpu::VertexState {
module: &shader, module: &shader,
entry_point: "solid_vs_main", entry_point: "solid_vs_main",
buffers: &[ buffers: &[wgpu::VertexBufferLayout {
quad::Vertex::buffer_layout(), array_stride: std::mem::size_of::<Solid>() as u64,
wgpu::VertexBufferLayout { step_mode: wgpu::VertexStepMode::Instance,
array_stride: std::mem::size_of::<Solid>() as u64, attributes: &wgpu::vertex_attr_array!(
step_mode: wgpu::VertexStepMode::Instance, // Color
attributes: &wgpu::vertex_attr_array!( 0 => Float32x4,
// Color // Position
1 => Float32x4, 1 => Float32x2,
// Position // Size
2 => Float32x2, 2 => Float32x2,
// Size // Border color
3 => Float32x2, 3 => Float32x4,
// Border color // Border radius
4 => Float32x4, 4 => Float32x4,
// Border radius // Border width
5 => Float32x4, 5 => Float32,
// Border width ),
6 => Float32, }],
),
},
],
}, },
fragment: Some(wgpu::FragmentState { fragment: Some(wgpu::FragmentState {
module: &shader, module: &shader,
@ -143,12 +142,8 @@ impl Pipeline {
render_pass.set_pipeline(&self.pipeline); render_pass.set_pipeline(&self.pipeline);
render_pass.set_bind_group(0, constants, &[]); render_pass.set_bind_group(0, constants, &[]);
render_pass.set_vertex_buffer(1, layer.instances.slice(..)); render_pass.set_vertex_buffer(0, layer.instances.slice(..));
render_pass.draw_indexed( render_pass.draw(0..6, range.start as u32..range.end as u32);
0..quad::INDICES.len() as u32,
0,
range.start as u32..range.end as u32,
);
} }
} }

View file

@ -7,12 +7,12 @@ struct Globals {
@group(1) @binding(0) var u_texture: texture_2d_array<f32>; @group(1) @binding(0) var u_texture: texture_2d_array<f32>;
struct VertexInput { struct VertexInput {
@location(0) v_pos: vec2<f32>, @builtin(vertex_index) vertex_index: u32,
@location(1) pos: vec2<f32>, @location(0) pos: vec2<f32>,
@location(2) scale: vec2<f32>, @location(1) scale: vec2<f32>,
@location(3) atlas_pos: vec2<f32>, @location(2) atlas_pos: vec2<f32>,
@location(4) atlas_scale: vec2<f32>, @location(3) atlas_scale: vec2<f32>,
@location(5) layer: i32, @location(4) layer: i32,
} }
struct VertexOutput { struct VertexOutput {
@ -25,7 +25,9 @@ struct VertexOutput {
fn vs_main(input: VertexInput) -> VertexOutput { fn vs_main(input: VertexInput) -> VertexOutput {
var out: VertexOutput; var out: VertexOutput;
out.uv = vec2<f32>(input.v_pos * input.atlas_scale + input.atlas_pos); let v_pos = vertex_position(input.vertex_index);
out.uv = vec2<f32>(v_pos * input.atlas_scale + input.atlas_pos);
out.layer = f32(input.layer); out.layer = f32(input.layer);
var transform: mat4x4<f32> = mat4x4<f32>( var transform: mat4x4<f32> = mat4x4<f32>(
@ -35,7 +37,7 @@ fn vs_main(input: VertexInput) -> VertexOutput {
vec4<f32>(input.pos, 0.0, 1.0) vec4<f32>(input.pos, 0.0, 1.0)
); );
out.position = globals.transform * transform * vec4<f32>(input.v_pos, 0.0, 1.0); out.position = globals.transform * transform * vec4<f32>(v_pos, 0.0, 1.0);
return out; return out;
} }

View file

@ -1,15 +1,15 @@
struct GradientVertexInput { struct GradientVertexInput {
@location(0) v_pos: vec2<f32>, @builtin(vertex_index) vertex_index: u32,
@location(1) @interpolate(flat) colors_1: vec4<u32>, @location(0) @interpolate(flat) colors_1: vec4<u32>,
@location(2) @interpolate(flat) colors_2: vec4<u32>, @location(1) @interpolate(flat) colors_2: vec4<u32>,
@location(3) @interpolate(flat) colors_3: vec4<u32>, @location(2) @interpolate(flat) colors_3: vec4<u32>,
@location(4) @interpolate(flat) colors_4: vec4<u32>, @location(3) @interpolate(flat) colors_4: vec4<u32>,
@location(5) @interpolate(flat) offsets: vec4<u32>, @location(4) @interpolate(flat) offsets: vec4<u32>,
@location(6) direction: vec4<f32>, @location(5) direction: vec4<f32>,
@location(7) position_and_scale: vec4<f32>, @location(6) position_and_scale: vec4<f32>,
@location(8) border_color: vec4<f32>, @location(7) border_color: vec4<f32>,
@location(9) border_radius: vec4<f32>, @location(8) border_radius: vec4<f32>,
@location(10) border_width: f32, @location(9) border_width: f32,
} }
struct GradientVertexOutput { struct GradientVertexOutput {
@ -48,7 +48,7 @@ fn gradient_vs_main(input: GradientVertexInput) -> GradientVertexOutput {
vec4<f32>(pos - vec2<f32>(0.5, 0.5), 0.0, 1.0) vec4<f32>(pos - vec2<f32>(0.5, 0.5), 0.0, 1.0)
); );
out.position = globals.transform * transform * vec4<f32>(input.v_pos, 0.0, 1.0); out.position = globals.transform * transform * vec4<f32>(vertex_position(input.vertex_index), 0.0, 1.0);
out.colors_1 = input.colors_1; out.colors_1 = input.colors_1;
out.colors_2 = input.colors_2; out.colors_2 = input.colors_2;
out.colors_3 = input.colors_3; out.colors_3 = input.colors_3;

View file

@ -1,11 +1,11 @@
struct SolidVertexInput { struct SolidVertexInput {
@location(0) v_pos: vec2<f32>, @builtin(vertex_index) vertex_index: u32,
@location(1) color: vec4<f32>, @location(0) color: vec4<f32>,
@location(2) pos: vec2<f32>, @location(1) pos: vec2<f32>,
@location(3) scale: vec2<f32>, @location(2) scale: vec2<f32>,
@location(4) border_color: vec4<f32>, @location(3) border_color: vec4<f32>,
@location(5) border_radius: vec4<f32>, @location(4) border_radius: vec4<f32>,
@location(6) border_width: f32, @location(5) border_width: f32,
} }
struct SolidVertexOutput { struct SolidVertexOutput {
@ -40,7 +40,7 @@ fn solid_vs_main(input: SolidVertexInput) -> SolidVertexOutput {
vec4<f32>(pos - vec2<f32>(0.5, 0.5), 0.0, 1.0) vec4<f32>(pos - vec2<f32>(0.5, 0.5), 0.0, 1.0)
); );
out.position = globals.transform * transform * vec4<f32>(input.v_pos, 0.0, 1.0); out.position = globals.transform * transform * vec4<f32>(vertex_position(input.vertex_index), 0.0, 1.0);
out.color = input.color; out.color = input.color;
out.border_color = input.border_color; out.border_color = input.border_color;
out.pos = pos; out.pos = pos;

View file

@ -0,0 +1,7 @@
// Compute the normalized quad coordinates based on the vertex index.
fn vertex_position(vertex_index: u32) -> vec2<f32> {
// #: 0 1 2 3 4 5
// x: 1 1 0 0 0 1
// y: 1 0 0 0 1 1
return vec2<f32>((vec2(1u, 2u) + vertex_index) % vec2(6u) < vec2(3u));
}