Added support for gradients as background variants + other optimizations.

This commit is contained in:
Bingus 2023-05-11 09:12:06 -07:00
parent 669f7cc74b
commit 6551a0b2ab
No known key found for this signature in database
GPG key ID: 5F84D2AA40A9F170
41 changed files with 1658 additions and 1489 deletions

View file

@ -1,26 +1,19 @@
//! Draw meshes of triangles.
mod msaa;
use crate::buffer::r#static::Buffer;
use crate::buffer::Buffer;
use crate::core::Size;
use crate::graphics::{Antialiasing, Transformation};
use crate::layer::mesh::{self, Mesh};
#[cfg(not(target_arch = "wasm32"))]
use crate::core::Gradient;
#[cfg(feature = "tracing")]
use tracing::info_span;
const INITIAL_INDEX_COUNT: usize = 1_000;
const INITIAL_VERTEX_COUNT: usize = 1_000;
#[derive(Debug)]
pub struct Pipeline {
blit: Option<msaa::Blit>,
solid: solid::Pipeline,
/// Gradients are currently not supported on WASM targets due to their need of storage buffers.
#[cfg(not(target_arch = "wasm32"))]
gradient: gradient::Pipeline,
layers: Vec<Layer>,
prepare_layer: usize,
}
@ -30,8 +23,6 @@ struct Layer {
index_buffer: Buffer<u32>,
index_strides: Vec<u32>,
solid: solid::Layer,
#[cfg(not(target_arch = "wasm32"))]
gradient: gradient::Layer,
}
@ -39,18 +30,17 @@ impl Layer {
fn new(
device: &wgpu::Device,
solid: &solid::Pipeline,
#[cfg(not(target_arch = "wasm32"))] gradient: &gradient::Pipeline,
gradient: &gradient::Pipeline,
) -> Self {
Self {
index_buffer: Buffer::new(
device,
"iced_wgpu::triangle index buffer",
"iced_wgpu.triangle.index_buffer",
INITIAL_INDEX_COUNT,
wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
),
index_strides: Vec::new(),
solid: solid::Layer::new(device, &solid.constants_layout),
#[cfg(not(target_arch = "wasm32"))]
gradient: gradient::Layer::new(device, &gradient.constants_layout),
}
}
@ -60,7 +50,7 @@ impl Layer {
device: &wgpu::Device,
queue: &wgpu::Queue,
solid: &solid::Pipeline,
#[cfg(not(target_arch = "wasm32"))] gradient: &gradient::Pipeline,
gradient: &gradient::Pipeline,
meshes: &[Mesh<'_>],
transformation: Transformation,
) {
@ -73,177 +63,92 @@ impl Layer {
// the majority of use cases. Therefore we will write GPU data every frame (for now).
let _ = self.index_buffer.resize(device, count.indices);
let _ = self.solid.vertices.resize(device, count.solid_vertices);
#[cfg(not(target_arch = "wasm32"))]
let _ = self
.gradient
.vertices
.resize(device, count.gradient_vertices);
// Prepare dynamic buffers & data store for writing
self.index_buffer.clear();
self.index_strides.clear();
self.solid.vertices.clear();
self.solid.uniforms.clear();
#[cfg(not(target_arch = "wasm32"))]
{
self.gradient.uniforms.clear();
self.gradient.vertices.clear();
self.gradient.storage.clear();
if self.solid.uniforms.resize(device, count.solids) {
self.solid.constants = solid::Layer::bind_group(
device,
&self.solid.uniforms.raw,
&solid.constants_layout,
);
}
let mut solid_vertex_offset = 0;
let mut index_offset = 0;
if self.gradient.uniforms.resize(device, count.gradients) {
self.gradient.constants = gradient::Layer::bind_group(
device,
&self.gradient.uniforms.raw,
&gradient.constants_layout,
);
}
#[cfg(not(target_arch = "wasm32"))]
self.index_strides.clear();
self.index_buffer.clear();
self.solid.vertices.clear();
self.solid.uniforms.clear();
self.gradient.vertices.clear();
self.gradient.uniforms.clear();
let mut solid_vertex_offset = 0;
let mut solid_uniform_offset = 0;
let mut gradient_vertex_offset = 0;
let mut gradient_uniform_offset = 0;
let mut index_offset = 0;
for mesh in meshes {
let origin = mesh.origin();
let indices = mesh.indices();
let transform =
transformation * Transformation::translate(origin.x, origin.y);
let uniforms = Uniforms::new(
transformation * Transformation::translate(origin.x, origin.y),
);
let new_index_offset =
index_offset +=
self.index_buffer.write(queue, index_offset, indices);
index_offset += new_index_offset;
self.index_strides.push(indices.len() as u32);
//push uniform data to CPU buffers
match mesh {
Mesh::Solid { buffers, .. } => {
self.solid.uniforms.push(&solid::Uniforms::new(transform));
let written_bytes = self.solid.vertices.write(
solid_vertex_offset += self.solid.vertices.write(
queue,
solid_vertex_offset,
&buffers.vertices,
);
solid_vertex_offset += written_bytes;
solid_uniform_offset += self.solid.uniforms.write(
queue,
solid_uniform_offset,
&[uniforms],
);
}
#[cfg(not(target_arch = "wasm32"))]
Mesh::Gradient {
buffers, gradient, ..
} => {
let written_bytes = self.gradient.vertices.write(
Mesh::Gradient { buffers, .. } => {
gradient_vertex_offset += self.gradient.vertices.write(
queue,
gradient_vertex_offset,
&buffers.vertices,
);
gradient_vertex_offset += written_bytes;
match gradient {
Gradient::Linear(linear) => {
use glam::{IVec4, Vec4};
let start_offset = self.gradient.color_stop_offset;
let end_offset = (linear.color_stops.len() as i32)
+ start_offset
- 1;
self.gradient.uniforms.push(&gradient::Uniforms {
transform: transform.into(),
direction: Vec4::new(
linear.start.x,
linear.start.y,
linear.end.x,
linear.end.y,
),
stop_range: IVec4::new(
start_offset,
end_offset,
0,
0,
),
});
self.gradient.color_stop_offset = end_offset + 1;
let stops: Vec<gradient::ColorStop> = linear
.color_stops
.iter()
.map(|stop| {
let [r, g, b, a] = stop.color.into_linear();
gradient::ColorStop {
offset: stop.offset,
color: Vec4::new(r, g, b, a),
}
})
.collect();
self.gradient
.color_stops_pending_write
.color_stops
.extend(stops);
}
}
gradient_uniform_offset += self.gradient.uniforms.write(
queue,
gradient_uniform_offset,
&[uniforms],
);
}
#[cfg(target_arch = "wasm32")]
Mesh::Gradient { .. } => {}
}
}
// Write uniform data to GPU
if count.solid_vertices > 0 {
let uniforms_resized = self.solid.uniforms.resize(device);
if uniforms_resized {
self.solid.constants = solid::Layer::bind_group(
device,
self.solid.uniforms.raw(),
&solid.constants_layout,
)
}
self.solid.uniforms.write(queue);
}
#[cfg(not(target_arch = "wasm32"))]
if count.gradient_vertices > 0 {
// First write the pending color stops to the CPU buffer
self.gradient
.storage
.push(&self.gradient.color_stops_pending_write);
// Resize buffers if needed
let uniforms_resized = self.gradient.uniforms.resize(device);
let storage_resized = self.gradient.storage.resize(device);
if uniforms_resized || storage_resized {
self.gradient.constants = gradient::Layer::bind_group(
device,
self.gradient.uniforms.raw(),
self.gradient.storage.raw(),
&gradient.constants_layout,
);
}
// Write to GPU
self.gradient.uniforms.write(queue);
self.gradient.storage.write(queue);
// Cleanup
self.gradient.color_stop_offset = 0;
self.gradient.color_stops_pending_write.color_stops.clear();
}
}
fn render<'a>(
&'a self,
solid: &'a solid::Pipeline,
#[cfg(not(target_arch = "wasm32"))] gradient: &'a gradient::Pipeline,
gradient: &'a gradient::Pipeline,
meshes: &[Mesh<'_>],
scale_factor: f32,
render_pass: &mut wgpu::RenderPass<'a>,
) {
let mut num_solids = 0;
#[cfg(not(target_arch = "wasm32"))]
let mut num_gradients = 0;
let mut last_is_solid = None;
@ -268,7 +173,8 @@ impl Layer {
render_pass.set_bind_group(
0,
&self.solid.constants,
&[self.solid.uniforms.offset_at_index(num_solids)],
&[(num_solids * std::mem::size_of::<Uniforms>())
as u32],
);
render_pass.set_vertex_buffer(
@ -278,7 +184,6 @@ impl Layer {
num_solids += 1;
}
#[cfg(not(target_arch = "wasm32"))]
Mesh::Gradient { .. } => {
if last_is_solid.unwrap_or(true) {
render_pass.set_pipeline(&gradient.pipeline);
@ -289,10 +194,8 @@ impl Layer {
render_pass.set_bind_group(
0,
&self.gradient.constants,
&[self
.gradient
.uniforms
.offset_at_index(num_gradients)],
&[(num_gradients * std::mem::size_of::<Uniforms>())
as u32],
);
render_pass.set_vertex_buffer(
@ -302,8 +205,6 @@ impl Layer {
num_gradients += 1;
}
#[cfg(target_arch = "wasm32")]
Mesh::Gradient { .. } => {}
};
render_pass.set_index_buffer(
@ -325,10 +226,7 @@ impl Pipeline {
Pipeline {
blit: antialiasing.map(|a| msaa::Blit::new(device, format, a)),
solid: solid::Pipeline::new(device, format, antialiasing),
#[cfg(not(target_arch = "wasm32"))]
gradient: gradient::Pipeline::new(device, format, antialiasing),
layers: Vec::new(),
prepare_layer: 0,
}
@ -342,15 +240,11 @@ impl Pipeline {
transformation: Transformation,
) {
#[cfg(feature = "tracing")]
let _ = info_span!("Wgpu::Triangle", "PREPARE").entered();
let _ = tracing::info_span!("Wgpu::Triangle", "PREPARE").entered();
if self.layers.len() <= self.prepare_layer {
self.layers.push(Layer::new(
device,
&self.solid,
#[cfg(not(target_arch = "wasm32"))]
&self.gradient,
));
self.layers
.push(Layer::new(device, &self.solid, &self.gradient));
}
let layer = &mut self.layers[self.prepare_layer];
@ -358,7 +252,6 @@ impl Pipeline {
device,
queue,
&self.solid,
#[cfg(not(target_arch = "wasm32"))]
&self.gradient,
meshes,
transformation,
@ -378,9 +271,8 @@ impl Pipeline {
scale_factor: f32,
) {
#[cfg(feature = "tracing")]
let _ = info_span!("Wgpu::Triangle", "DRAW").entered();
let _ = tracing::info_span!("Wgpu::Triangle", "DRAW").entered();
// Configure render pass
{
let (attachment, resolve_target, load) = if let Some(blit) =
&mut self.blit
@ -397,12 +289,9 @@ impl Pipeline {
(target, None, wgpu::LoadOp::Load)
};
#[cfg(feature = "tracing")]
let _ = info_span!("Wgpu::Triangle", "BEGIN_RENDER_PASS").enter();
let mut render_pass =
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("iced_wgpu::triangle render pass"),
label: Some("iced_wgpu.triangle.render_pass"),
color_attachments: &[Some(
wgpu::RenderPassColorAttachment {
view: attachment,
@ -417,7 +306,6 @@ impl Pipeline {
layer.render(
&self.solid,
#[cfg(not(target_arch = "wasm32"))]
&self.gradient,
meshes,
scale_factor,
@ -463,14 +351,48 @@ fn multisample_state(
}
}
mod solid {
use crate::buffer::dynamic;
use crate::buffer::r#static::Buffer;
use crate::graphics::primitive;
use crate::graphics::{Antialiasing, Transformation};
use crate::triangle;
#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
#[repr(C)]
pub struct Uniforms {
transform: [f32; 16],
/// Uniform values must be 256-aligned;
/// see: [`wgpu::Limits`] `min_uniform_buffer_offset_alignment`.
_padding: [f32; 48],
}
use encase::ShaderType;
impl Uniforms {
pub fn new(transform: Transformation) -> Self {
Self {
transform: transform.into(),
_padding: [0.0; 48],
}
}
pub fn entry() -> wgpu::BindGroupLayoutEntry {
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: true,
min_binding_size: wgpu::BufferSize::new(
std::mem::size_of::<Self>() as u64,
),
},
count: None,
}
}
pub fn min_size() -> Option<wgpu::BufferSize> {
wgpu::BufferSize::new(std::mem::size_of::<Self>() as u64)
}
}
mod solid {
use crate::buffer::Buffer;
use crate::graphics::primitive;
use crate::graphics::Antialiasing;
use crate::triangle;
#[derive(Debug)]
pub struct Pipeline {
@ -481,7 +403,7 @@ mod solid {
#[derive(Debug)]
pub struct Layer {
pub vertices: Buffer<primitive::ColoredVertex2D>,
pub uniforms: dynamic::Buffer<Uniforms>,
pub uniforms: Buffer<triangle::Uniforms>,
pub constants: wgpu::BindGroup,
}
@ -492,17 +414,20 @@ mod solid {
) -> Self {
let vertices = Buffer::new(
device,
"iced_wgpu::triangle::solid vertex buffer",
"iced_wgpu.triangle.solid.vertex_buffer",
triangle::INITIAL_VERTEX_COUNT,
wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
);
let uniforms = dynamic::Buffer::uniform(
let uniforms = Buffer::new(
device,
"iced_wgpu::triangle::solid uniforms",
"iced_wgpu.triangle.solid.uniforms",
1,
wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
);
let constants =
Self::bind_group(device, uniforms.raw(), constants_layout);
Self::bind_group(device, &uniforms.raw, constants_layout);
Self {
vertices,
@ -517,7 +442,7 @@ mod solid {
layout: &wgpu::BindGroupLayout,
) -> wgpu::BindGroup {
device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("iced_wgpu::triangle::solid bind group"),
label: Some("iced_wgpu.triangle.solid.bind_group"),
layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
@ -525,7 +450,7 @@ mod solid {
wgpu::BufferBinding {
buffer,
offset: 0,
size: Some(Uniforms::min_size()),
size: triangle::Uniforms::min_size(),
},
),
}],
@ -533,21 +458,7 @@ mod solid {
}
}
#[derive(Debug, Clone, Copy, ShaderType)]
pub struct Uniforms {
transform: glam::Mat4,
}
impl Uniforms {
pub fn new(transform: Transformation) -> Self {
Self {
transform: transform.into(),
}
}
}
impl Pipeline {
/// Creates a new [SolidPipeline] using `solid.wgsl` shader.
pub fn new(
device: &wgpu::Device,
format: wgpu::TextureFormat,
@ -555,23 +466,14 @@ mod solid {
) -> Self {
let constants_layout = device.create_bind_group_layout(
&wgpu::BindGroupLayoutDescriptor {
label: Some("iced_wgpu::triangle::solid bind group layout"),
entries: &[wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: true,
min_binding_size: Some(Uniforms::min_size()),
},
count: None,
}],
label: Some("iced_wgpu.triangle.solid.bind_group_layout"),
entries: &[triangle::Uniforms::entry()],
},
);
let layout = device.create_pipeline_layout(
&wgpu::PipelineLayoutDescriptor {
label: Some("iced_wgpu::triangle::solid pipeline layout"),
label: Some("iced_wgpu.triangle.solid.pipeline_layout"),
bind_group_layouts: &[&constants_layout],
push_constant_ranges: &[],
},
@ -579,12 +481,10 @@ mod solid {
let shader =
device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some(
"iced_wgpu triangle solid create shader module",
),
label: Some("iced_wgpu.triangle.solid.shader"),
source: wgpu::ShaderSource::Wgsl(
std::borrow::Cow::Borrowed(include_str!(
"shader/solid.wgsl"
"shader/triangle.wgsl"
)),
),
});
@ -595,7 +495,7 @@ mod solid {
layout: Some(&layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: "vs_main",
entry_point: "solid_vs_main",
buffers: &[wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<
primitive::ColoredVertex2D,
@ -612,7 +512,7 @@ mod solid {
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_main",
entry_point: "solid_fs_main",
targets: &[triangle::fragment_target(format)],
}),
primitive: triangle::primitive_state(),
@ -630,16 +530,11 @@ mod solid {
}
}
#[cfg(not(target_arch = "wasm32"))]
mod gradient {
use crate::buffer::dynamic;
use crate::buffer::r#static::Buffer;
use crate::graphics::Antialiasing;
use crate::graphics::{primitive, Antialiasing};
use crate::triangle;
use encase::ShaderType;
use glam::{IVec4, Vec4};
use iced_graphics::primitive;
use crate::buffer::Buffer;
#[derive(Debug)]
pub struct Pipeline {
@ -649,14 +544,9 @@ mod gradient {
#[derive(Debug)]
pub struct Layer {
pub vertices: Buffer<primitive::Vertex2D>,
pub uniforms: dynamic::Buffer<Uniforms>,
pub storage: dynamic::Buffer<Storage>,
pub vertices: Buffer<primitive::GradientVertex2D>,
pub uniforms: Buffer<triangle::Uniforms>,
pub constants: wgpu::BindGroup,
pub color_stop_offset: i32,
//Need to store these and then write them all at once
//or else they will be padded to 256 and cause gaps in the storage buffer
pub color_stops_pending_write: Storage,
}
impl Layer {
@ -666,94 +556,52 @@ mod gradient {
) -> Self {
let vertices = Buffer::new(
device,
"iced_wgpu::triangle::gradient vertex buffer",
"iced_wgpu.triangle.gradient.vertex_buffer",
triangle::INITIAL_VERTEX_COUNT,
wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
);
let uniforms = dynamic::Buffer::uniform(
let uniforms = Buffer::new(
device,
"iced_wgpu::triangle::gradient uniforms",
"iced_wgpu.triangle.gradient.uniforms",
1,
wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
);
// Note: with a WASM target storage buffers are not supported. Will need to use UBOs & static
// sized array (eg like the 32-sized array on OpenGL side right now) to make gradients work
let storage = dynamic::Buffer::storage(
device,
"iced_wgpu::triangle::gradient storage",
);
let constants = Self::bind_group(
device,
uniforms.raw(),
storage.raw(),
constants_layout,
);
let constants =
Self::bind_group(device, &uniforms.raw, constants_layout);
Self {
vertices,
uniforms,
storage,
constants,
color_stop_offset: 0,
color_stops_pending_write: Storage {
color_stops: vec![],
},
}
}
pub fn bind_group(
device: &wgpu::Device,
uniform_buffer: &wgpu::Buffer,
storage_buffer: &wgpu::Buffer,
layout: &wgpu::BindGroupLayout,
) -> wgpu::BindGroup {
device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("iced_wgpu::triangle::gradient bind group"),
label: Some("iced_wgpu.triangle.gradient.bind_group"),
layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Buffer(
wgpu::BufferBinding {
buffer: uniform_buffer,
offset: 0,
size: Some(Uniforms::min_size()),
},
),
},
wgpu::BindGroupEntry {
binding: 1,
resource: storage_buffer.as_entire_binding(),
},
],
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Buffer(
wgpu::BufferBinding {
buffer: uniform_buffer,
offset: 0,
size: triangle::Uniforms::min_size(),
},
),
}],
})
}
}
#[derive(Debug, ShaderType)]
pub struct Uniforms {
pub transform: glam::Mat4,
//xy = start, zw = end
pub direction: Vec4,
//x = start stop, y = end stop, zw = padding
pub stop_range: IVec4,
}
#[derive(Debug, ShaderType)]
pub struct ColorStop {
pub color: Vec4,
pub offset: f32,
}
#[derive(Debug, ShaderType)]
pub struct Storage {
#[size(runtime)]
pub color_stops: Vec<ColorStop>,
}
impl Pipeline {
/// Creates a new [GradientPipeline] using `gradient.wgsl` shader.
pub(super) fn new(
pub fn new(
device: &wgpu::Device,
format: wgpu::TextureFormat,
antialiasing: Option<Antialiasing>,
@ -761,40 +609,15 @@ mod gradient {
let constants_layout = device.create_bind_group_layout(
&wgpu::BindGroupLayoutDescriptor {
label: Some(
"iced_wgpu::triangle::gradient bind group layout",
"iced_wgpu.triangle.gradient.bind_group_layout",
),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: true,
min_binding_size: Some(Uniforms::min_size()),
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage {
read_only: true,
},
has_dynamic_offset: false,
min_binding_size: Some(Storage::min_size()),
},
count: None,
},
],
entries: &[triangle::Uniforms::entry()],
},
);
let layout = device.create_pipeline_layout(
&wgpu::PipelineLayoutDescriptor {
label: Some(
"iced_wgpu::triangle::gradient pipeline layout",
),
label: Some("iced_wgpu.triangle.gradient.pipeline_layout"),
bind_group_layouts: &[&constants_layout],
push_constant_ranges: &[],
},
@ -802,48 +625,66 @@ mod gradient {
let shader =
device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some(
"iced_wgpu::triangle::gradient create shader module",
),
label: Some("iced_wgpu.triangle.gradient.shader"),
source: wgpu::ShaderSource::Wgsl(
std::borrow::Cow::Borrowed(include_str!(
"shader/gradient.wgsl"
"shader/triangle.wgsl"
)),
),
});
let pipeline =
device.create_render_pipeline(
&wgpu::RenderPipelineDescriptor {
label: Some("iced_wgpu::triangle::gradient pipeline"),
layout: Some(&layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: "vs_main",
buffers: &[wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<
primitive::Vertex2D,
>(
)
as u64,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &wgpu::vertex_attr_array!(
// Position
0 => Float32x2,
),
}],
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_main",
targets: &[triangle::fragment_target(format)],
}),
primitive: triangle::primitive_state(),
depth_stencil: None,
multisample: triangle::multisample_state(antialiasing),
multiview: None,
let pipeline = device.create_render_pipeline(
&wgpu::RenderPipelineDescriptor {
label: Some("iced_wgpu.triangle.gradient.pipeline"),
layout: Some(&layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: "gradient_vs_main",
buffers: &[wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<
primitive::GradientVertex2D,
>()
as u64,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &wgpu::vertex_attr_array!(
// Position
0 => Float32x2,
// Color 1
1 => Float32x4,
// Color 2
2 => Float32x4,
// Color 3
3 => Float32x4,
// Color 4
4 => Float32x4,
// Color 5
5 => Float32x4,
// Color 6
6 => Float32x4,
// Color 7
7 => Float32x4,
// Color 8
8 => Float32x4,
// Offsets 1-4
9 => Float32x4,
// Offsets 5-8
10 => Float32x4,
// Direction
11 => Float32x4
),
}],
},
);
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "gradient_fs_main",
targets: &[triangle::fragment_target(format)],
}),
primitive: triangle::primitive_state(),
depth_stencil: None,
multisample: triangle::multisample_state(antialiasing),
multiview: None,
},
);
Self {
pipeline,