const IMAGE_VERTEX_ATTRS: [wgpu::VertexAttribute; 9] = [
wgpu::VertexAttribute { shader_location: 0, offset: 0, format: wgpu::VertexFormat::Float32x2 },
wgpu::VertexAttribute { shader_location: 1, offset: 8, format: wgpu::VertexFormat::Float32x2 },
wgpu::VertexAttribute { shader_location: 2, offset: 16, format: wgpu::VertexFormat::Float32x2 },
wgpu::VertexAttribute { shader_location: 3, offset: 24, format: wgpu::VertexFormat::Float32 },
wgpu::VertexAttribute { shader_location: 4, offset: 28, format: wgpu::VertexFormat::Float32 },
wgpu::VertexAttribute { shader_location: 5, offset: 32, format: wgpu::VertexFormat::Float32 },
wgpu::VertexAttribute { shader_location: 6, offset: 36, format: wgpu::VertexFormat::Float32 },
wgpu::VertexAttribute { shader_location: 7, offset: 40, format: wgpu::VertexFormat::Float32 },
wgpu::VertexAttribute { shader_location: 8, offset: 44, format: wgpu::VertexFormat::Float32 },
];
const COLOR_VERTEX_ATTRS: [wgpu::VertexAttribute; 2] = [
wgpu::VertexAttribute { shader_location: 0, offset: 0, format: wgpu::VertexFormat::Float32x2 },
wgpu::VertexAttribute { shader_location: 1, offset: 8, format: wgpu::VertexFormat::Float32x4 },
];
pub(super) fn image_vertex_layout() -> wgpu::VertexBufferLayout<'static> {
wgpu::VertexBufferLayout {
array_stride: 48,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &IMAGE_VERTEX_ATTRS,
}
}
pub(super) fn color_vertex_layout() -> wgpu::VertexBufferLayout<'static> {
wgpu::VertexBufferLayout {
array_stride: 24,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &COLOR_VERTEX_ATTRS,
}
}
pub(super) fn blend_normal() -> wgpu::BlendState { wgpu::BlendState::ALPHA_BLENDING }
pub(super) fn blend_add() -> wgpu::BlendState {
wgpu::BlendState {
color: wgpu::BlendComponent { src_factor: wgpu::BlendFactor::SrcAlpha, dst_factor: wgpu::BlendFactor::One, operation: wgpu::BlendOperation::Add },
alpha: wgpu::BlendComponent { src_factor: wgpu::BlendFactor::One, dst_factor: wgpu::BlendFactor::One, operation: wgpu::BlendOperation::Add },
}
}
pub(super) fn blend_mul() -> wgpu::BlendState {
wgpu::BlendState {
color: wgpu::BlendComponent { src_factor: wgpu::BlendFactor::Dst, dst_factor: wgpu::BlendFactor::Zero, operation: wgpu::BlendOperation::Add },
alpha: wgpu::BlendComponent { src_factor: wgpu::BlendFactor::One, dst_factor: wgpu::BlendFactor::Zero, operation: wgpu::BlendOperation::Add },
}
}
pub(super) fn blend_normal_pm() -> wgpu::BlendState {
wgpu::BlendState {
color: wgpu::BlendComponent { src_factor: wgpu::BlendFactor::One, 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 },
}
}
pub(super) fn blend_add_pm() -> wgpu::BlendState {
wgpu::BlendState {
color: wgpu::BlendComponent { src_factor: wgpu::BlendFactor::One, dst_factor: wgpu::BlendFactor::One, operation: wgpu::BlendOperation::Add },
alpha: wgpu::BlendComponent { src_factor: wgpu::BlendFactor::One, dst_factor: wgpu::BlendFactor::One, operation: wgpu::BlendOperation::Add },
}
}
pub(super) fn build_image_pipeline_trio(
device: &wgpu::Device,
label_prefix: &str,
shader: &wgpu::ShaderModule,
layout: &wgpu::PipelineLayout,
format: wgpu::TextureFormat,
premultiplied: bool,
) -> [wgpu::RenderPipeline; 3] {
let vbl = image_vertex_layout();
let (normal, add) = if premultiplied {
(blend_normal_pm(), blend_add_pm())
} else {
(blend_normal(), blend_add())
};
let mul = blend_mul();
let build = |label: String, blend: wgpu::BlendState| {
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some(&label),
layout: Some(layout),
vertex: wgpu::VertexState { module: shader, entry_point: Some("vs"), buffers: &[vbl.clone()], compilation_options: Default::default() },
fragment: Some(wgpu::FragmentState {
module: shader, entry_point: Some("fs"),
targets: &[Some(wgpu::ColorTargetState { format, blend: Some(blend), write_mask: wgpu::ColorWrites::ALL })],
compilation_options: Default::default(),
}),
primitive: wgpu::PrimitiveState { topology: wgpu::PrimitiveTopology::TriangleList, ..Default::default() },
depth_stencil: None,
multisample: wgpu::MultisampleState::default(),
multiview: None,
cache: None,
})
};
[
build(label_prefix.to_string(), normal),
build(format!("{label_prefix}_add"), add),
build(format!("{label_prefix}_mul"), mul),
]
}
pub(super) fn build_color_pipeline(
device: &wgpu::Device,
label: &str,
shader: &wgpu::ShaderModule,
layout: &wgpu::PipelineLayout,
format: wgpu::TextureFormat,
blend: wgpu::BlendState,
) -> wgpu::RenderPipeline {
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some(label),
layout: Some(layout),
vertex: wgpu::VertexState { module: shader, entry_point: Some("vs"), buffers: &[color_vertex_layout()], compilation_options: Default::default() },
fragment: Some(wgpu::FragmentState {
module: shader, entry_point: Some("fs"),
targets: &[Some(wgpu::ColorTargetState { format, blend: Some(blend), write_mask: wgpu::ColorWrites::ALL })],
compilation_options: Default::default(),
}),
primitive: wgpu::PrimitiveState { topology: wgpu::PrimitiveTopology::TriangleList, ..Default::default() },
depth_stencil: None,
multisample: wgpu::MultisampleState::default(),
multiview: None,
cache: None,
})
}
pub(super) fn create_render_target(
device: &wgpu::Device,
label: Option<&str>,
w: u32, h: u32,
extra_usage: wgpu::TextureUsages,
) -> (wgpu::Texture, wgpu::TextureView) {
let texture = device.create_texture(&wgpu::TextureDescriptor {
label,
size: wgpu::Extent3d { width: w, height: h, depth_or_array_layers: 1 },
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8Unorm,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING | extra_usage,
view_formats: &[],
});
let view = texture.create_view(&Default::default());
(texture, view)
}