use wgpu::ShaderStages;
pub(crate) fn wgsl_module<'a>(
device: &wgpu::Device,
label: &str,
source: impl Into<std::borrow::Cow<'a, str>>,
) -> wgpu::ShaderModule {
device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some(label),
source: wgpu::ShaderSource::Wgsl(source.into()),
})
}
macro_rules! wgsl_source {
($name:literal) => {
include_str!(concat!(env!("OUT_DIR"), "/", $name, ".wgsl"))
};
}
pub(crate) use wgsl_source;
pub(crate) fn uniform_entry(binding: u32, visibility: ShaderStages) -> wgpu::BindGroupLayoutEntry {
wgpu::BindGroupLayoutEntry {
binding,
visibility,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
}
}
pub(crate) fn texture_entry(binding: u32, visibility: ShaderStages) -> wgpu::BindGroupLayoutEntry {
wgpu::BindGroupLayoutEntry {
binding,
visibility,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
}
}
pub(crate) fn sampler_entry(binding: u32, visibility: ShaderStages) -> wgpu::BindGroupLayoutEntry {
wgpu::BindGroupLayoutEntry {
binding,
visibility,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
}
}
pub(crate) fn uniform_bgl(
device: &wgpu::Device,
label: &str,
visibility: ShaderStages,
) -> wgpu::BindGroupLayout {
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some(label),
entries: &[uniform_entry(0, visibility)],
})
}
pub(crate) fn texture_sampler_bgl(
device: &wgpu::Device,
label: &str,
visibility: ShaderStages,
) -> wgpu::BindGroupLayout {
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some(label),
entries: &[texture_entry(0, visibility), sampler_entry(1, visibility)],
})
}
pub(crate) fn uniform_texture_sampler_bgl(
device: &wgpu::Device,
label: &str,
uniform_vis: ShaderStages,
tex_vis: ShaderStages,
) -> wgpu::BindGroupLayout {
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some(label),
entries: &[
uniform_entry(0, uniform_vis),
texture_entry(1, tex_vis),
sampler_entry(2, tex_vis),
],
})
}
pub(crate) fn clamp_linear_sampler(device: &wgpu::Device, label: &str) -> wgpu::Sampler {
device.create_sampler(&wgpu::SamplerDescriptor {
label: Some(label),
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,
..Default::default()
})
}
pub(crate) fn clamp_nearest_sampler(device: &wgpu::Device, label: &str) -> wgpu::Sampler {
device.create_sampler(&wgpu::SamplerDescriptor {
label: Some(label),
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
address_mode_w: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Nearest,
min_filter: wgpu::FilterMode::Nearest,
..Default::default()
})
}
pub(crate) fn repeat_linear_sampler(
device: &wgpu::Device,
label: &str,
mipmap_filter: wgpu::FilterMode,
) -> wgpu::Sampler {
device.create_sampler(&wgpu::SamplerDescriptor {
label: Some(label),
address_mode_u: wgpu::AddressMode::Repeat,
address_mode_v: wgpu::AddressMode::Repeat,
address_mode_w: wgpu::AddressMode::Repeat,
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Linear,
mipmap_filter,
..Default::default()
})
}
pub(crate) fn env_sampler(device: &wgpu::Device, label: &str) -> wgpu::Sampler {
device.create_sampler(&wgpu::SamplerDescriptor {
label: Some(label),
address_mode_u: wgpu::AddressMode::Repeat,
address_mode_v: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Linear,
mipmap_filter: wgpu::FilterMode::Linear,
..Default::default()
})
}
pub(crate) const ADDITIVE_BLEND: 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(crate) const PREMULTIPLIED_BLEND: 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(crate) struct DualPipelineDesc<'a> {
pub label: &'a str,
pub layout: &'a wgpu::PipelineLayout,
pub shader: &'a wgpu::ShaderModule,
pub vertex_entry: &'a str,
pub fragment_entry: &'a str,
pub vertex_buffers: &'a [wgpu::VertexBufferLayout<'a>],
pub blend: Option<wgpu::BlendState>,
pub topology: wgpu::PrimitiveTopology,
pub cull_mode: Option<wgpu::Face>,
pub depth_write: bool,
pub depth_compare: wgpu::CompareFunction,
pub sample_count: u32,
pub ldr_format: wgpu::TextureFormat,
}
pub(crate) fn build_dual_pipeline(
device: &wgpu::Device,
desc: &DualPipelineDesc,
) -> crate::resources::types::DualPipeline {
let make = |format: wgpu::TextureFormat| {
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some(desc.label),
layout: Some(desc.layout),
vertex: wgpu::VertexState {
module: desc.shader,
entry_point: Some(desc.vertex_entry),
buffers: desc.vertex_buffers,
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: desc.shader,
entry_point: Some(desc.fragment_entry),
targets: &[Some(wgpu::ColorTargetState {
format,
blend: desc.blend,
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState {
topology: desc.topology,
cull_mode: desc.cull_mode,
..Default::default()
},
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: desc.depth_write,
depth_compare: desc.depth_compare,
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState {
count: desc.sample_count,
..Default::default()
},
multiview: None,
cache: None,
})
};
crate::resources::types::DualPipeline {
ldr: make(desc.ldr_format),
hdr: make(wgpu::TextureFormat::Rgba16Float),
}
}
pub(crate) fn build_fullscreen_pipeline(
device: &wgpu::Device,
label: &str,
layout: &wgpu::PipelineLayout,
shader: &wgpu::ShaderModule,
target_format: wgpu::TextureFormat,
blend: Option<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_main"),
buffers: &[],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: target_format,
blend,
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
cull_mode: None,
..Default::default()
},
depth_stencil: None,
multisample: wgpu::MultisampleState::default(),
multiview: None,
cache: None,
})
}
pub(crate) fn build_outline_mask_pipeline(
device: &wgpu::Device,
label: &str,
layout: &wgpu::PipelineLayout,
shader: &wgpu::ShaderModule,
mask_format: wgpu::TextureFormat,
vertex_buffers: &[wgpu::VertexBufferLayout],
cull: Option<wgpu::Face>,
depth_write: bool,
depth_compare: wgpu::CompareFunction,
) -> wgpu::RenderPipeline {
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some(label),
layout: Some(layout),
vertex: wgpu::VertexState {
module: shader,
entry_point: Some("vs_main"),
buffers: vertex_buffers,
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: mask_format,
blend: None,
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
cull_mode: cull,
..Default::default()
},
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: depth_write,
depth_compare,
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState::default(),
multiview: None,
cache: None,
})
}
pub(crate) fn compute_pipeline(
device: &wgpu::Device,
label: &str,
layout: &wgpu::PipelineLayout,
shader: &wgpu::ShaderModule,
entry: &str,
) -> wgpu::ComputePipeline {
device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
label: Some(label),
layout: Some(layout),
module: shader,
entry_point: Some(entry),
compilation_options: wgpu::PipelineCompilationOptions::default(),
cache: None,
})
}
pub(crate) fn standard_scene_layout(
device: &wgpu::Device,
label: &str,
camera_bgl: &wgpu::BindGroupLayout,
per_item_bgl: &wgpu::BindGroupLayout,
) -> wgpu::PipelineLayout {
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some(label),
bind_group_layouts: &[camera_bgl, per_item_bgl],
push_constant_ranges: &[],
})
}