#![allow(unused)]
use crate::vertex::{CustomVertex, InstanceColor, InstanceMetadata, InstanceTransform};
use wgpu::util::DeviceExt;
use wgpu::{
BindGroup, BindGroupLayout, ComputePipeline, Device, RenderPass, RenderPipeline,
StencilFaceState, StoreOp, Texture, TextureView,
};
#[repr(C)]
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
pub struct Uniforms {
pub canvas_size: [f32; 2],
pub scale_factor: f32,
pub fringe_width: f32,
}
impl Uniforms {
pub fn new(width: f32, height: f32, scale_factor: f32, fringe_width: f32) -> Self {
Self {
canvas_size: [width, height],
scale_factor,
fringe_width,
}
}
}
fn create_equal_increment_stencil_state() -> wgpu::StencilState {
let face_state = wgpu::StencilFaceState {
compare: wgpu::CompareFunction::Equal,
fail_op: wgpu::StencilOperation::Keep,
depth_fail_op: wgpu::StencilOperation::Keep,
pass_op: wgpu::StencilOperation::IncrementClamp,
};
wgpu::StencilState {
front: face_state,
back: face_state,
read_mask: 0xff,
write_mask: 0xff,
}
}
fn create_equal_decrement_stencil_state() -> wgpu::StencilState {
let face_state = wgpu::StencilFaceState {
compare: wgpu::CompareFunction::Equal,
fail_op: wgpu::StencilOperation::Keep,
depth_fail_op: wgpu::StencilOperation::Keep,
pass_op: wgpu::StencilOperation::DecrementClamp,
};
wgpu::StencilState {
front: face_state,
back: face_state,
read_mask: 0xff,
write_mask: 0xff,
}
}
pub fn create_uniform_bind_group_layout(device: &Device) -> BindGroupLayout {
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: None,
entries: &[wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
}],
})
}
pub fn create_equal_increment_depth_state() -> wgpu::DepthStencilState {
wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: true,
depth_compare: wgpu::CompareFunction::Always,
stencil: create_equal_increment_stencil_state(),
bias: wgpu::DepthBiasState::default(),
}
}
pub fn create_depth_stencil_state_for_text() -> wgpu::DepthStencilState {
wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: true,
depth_compare: wgpu::CompareFunction::Equal,
stencil: wgpu::StencilState {
front: StencilFaceState::IGNORE,
back: StencilFaceState::IGNORE,
read_mask: 0,
write_mask: 0,
},
bias: wgpu::DepthBiasState::default(),
}
}
pub fn create_equal_decrement_depth_state() -> wgpu::DepthStencilState {
wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: false,
depth_compare: wgpu::CompareFunction::Always,
stencil: create_equal_decrement_stencil_state(),
bias: wgpu::DepthBiasState::default(),
}
}
pub fn write_on_equal_depth_stencil_state() -> wgpu::DepthStencilState {
let face_state = wgpu::StencilFaceState {
compare: wgpu::CompareFunction::Equal,
fail_op: wgpu::StencilOperation::Keep,
depth_fail_op: wgpu::StencilOperation::Keep,
pass_op: wgpu::StencilOperation::Replace,
};
let stencil = wgpu::StencilState {
front: face_state,
back: face_state,
read_mask: 0xff,
write_mask: 0xff,
};
wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: false,
depth_compare: wgpu::CompareFunction::Always,
stencil,
bias: wgpu::DepthBiasState::default(),
}
}
pub fn always_pass_and_keep_stencil_state() -> wgpu::DepthStencilState {
let face_state = wgpu::StencilFaceState {
compare: wgpu::CompareFunction::Always,
fail_op: wgpu::StencilOperation::Keep,
depth_fail_op: wgpu::StencilOperation::Keep,
pass_op: wgpu::StencilOperation::Keep,
};
let stencil = wgpu::StencilState {
front: face_state,
back: face_state,
read_mask: 0xff,
write_mask: 0xff,
};
wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: false,
depth_compare: wgpu::CompareFunction::Always,
stencil,
bias: wgpu::DepthBiasState::default(),
}
}
pub enum PipelineType {
EqualIncrementStencil,
EqualDecrementStencil,
}
pub fn create_gradient_bind_group_layout(device: &Device) -> BindGroupLayout {
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
multisampled: false,
view_dimension: wgpu::TextureViewDimension::D1,
sample_type: wgpu::TextureSampleType::Float { filterable: false },
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::NonFiltering),
count: None,
},
],
label: Some("gradient_bind_group_layout"),
})
}
pub fn create_pipeline(
canvas_logical_size: (f32, f32),
scale_factor: f64,
fringe_width: f32,
device: &Device,
config: &wgpu::SurfaceConfiguration,
pipeline_type: PipelineType,
sample_count: u32,
) -> (
Uniforms,
wgpu::Buffer,
BindGroup,
BindGroupLayout,
BindGroupLayout,
RenderPipeline,
) {
let (depth_stencil_state, targets) = match pipeline_type {
PipelineType::EqualIncrementStencil => (
create_equal_increment_depth_state(),
[Some(wgpu::ColorTargetState {
format: config.format,
blend: Some(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,
},
}),
write_mask: wgpu::ColorWrites::ALL,
})],
),
PipelineType::EqualDecrementStencil => (
create_equal_decrement_depth_state(),
[Some(wgpu::ColorTargetState {
format: config.format,
blend: Some(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,
},
}),
write_mask: wgpu::ColorWrites::empty(),
})],
),
};
let uniforms = Uniforms::new(
canvas_logical_size.0,
canvas_logical_size.1,
scale_factor as f32,
fringe_width,
);
let uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: None,
contents: bytemuck::cast_slice(&[uniforms]),
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
});
let bind_group_layout = create_uniform_bind_group_layout(device);
let texture_bind_group_layout_layer0 =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
multisampled: false,
view_dimension: wgpu::TextureViewDimension::D2,
sample_type: wgpu::TextureSampleType::Float { filterable: true },
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
],
label: Some("shape_texture_bind_group_layout_layer0"),
});
let texture_bind_group_layout_layer1 =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
multisampled: false,
view_dimension: wgpu::TextureViewDimension::D2,
sample_type: wgpu::TextureSampleType::Float { filterable: true },
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
],
label: Some("shape_texture_bind_group_layout_layer1"),
});
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &bind_group_layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: uniform_buffer.as_entire_binding(),
}],
label: None,
});
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: None,
source: wgpu::ShaderSource::Wgsl(include_str!("shaders/shader.wgsl").into()),
});
let render_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: None,
bind_group_layouts: &[
&bind_group_layout,
&texture_bind_group_layout_layer0,
&texture_bind_group_layout_layer1,
],
push_constant_ranges: &[],
});
let fragment_entry_point = match pipeline_type {
PipelineType::EqualIncrementStencil => "fs_passthrough",
PipelineType::EqualDecrementStencil => "fs_stencil_only",
};
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: None,
layout: Some(&render_pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main"),
compilation_options: Default::default(),
buffers: &[
CustomVertex::desc(),
InstanceTransform::desc(),
InstanceColor::desc(),
InstanceMetadata::desc(),
],
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some(fragment_entry_point),
compilation_options: Default::default(),
targets: &targets,
}),
primitive: wgpu::PrimitiveState::default(),
depth_stencil: Some(depth_stencil_state),
multisample: wgpu::MultisampleState {
count: sample_count,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
});
(
uniforms,
uniform_buffer,
bind_group,
texture_bind_group_layout_layer0,
texture_bind_group_layout_layer1,
render_pipeline,
)
}
pub fn create_gradient_increment_pipeline(
device: &Device,
format: wgpu::TextureFormat,
sample_count: u32,
uniform_bgl: &wgpu::BindGroupLayout,
texture_bgl_layer0: &wgpu::BindGroupLayout,
texture_bgl_layer1: &wgpu::BindGroupLayout,
gradient_bgl: &wgpu::BindGroupLayout,
) -> RenderPipeline {
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("gradient_increment_shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("shaders/shader.wgsl").into()),
});
let render_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("gradient_increment_pipeline_layout"),
bind_group_layouts: &[
uniform_bgl,
texture_bgl_layer0,
texture_bgl_layer1,
gradient_bgl,
],
push_constant_ranges: &[],
});
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("gradient_increment_pipeline"),
layout: Some(&render_pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main_gradient"),
compilation_options: Default::default(),
buffers: &[
CustomVertex::desc(),
InstanceTransform::desc(),
InstanceColor::desc(),
InstanceMetadata::desc(),
],
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs_passthrough_gradient"),
compilation_options: Default::default(),
targets: &[Some(wgpu::ColorTargetState {
format,
blend: Some(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,
},
}),
write_mask: wgpu::ColorWrites::ALL,
})],
}),
primitive: wgpu::PrimitiveState::default(),
depth_stencil: Some(create_equal_increment_depth_state()),
multisample: wgpu::MultisampleState {
count: sample_count,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
})
}
pub fn create_render_pass<'a, 'b: 'a>(
encoder: &'a mut wgpu::CommandEncoder,
msaa_texture_view: Option<&'b TextureView>,
output_texture_view: &'b TextureView,
depth_texture_view: &'b TextureView,
) -> RenderPass<'a> {
let (view, resolve_target) = if let Some(msaa_view) = msaa_texture_view {
(msaa_view, Some(output_texture_view))
} else {
(output_texture_view, None)
};
let render_pass = begin_render_pass_with_load_ops(
encoder,
None,
view,
resolve_target,
depth_texture_view,
RenderPassLoadOperations {
color_load_op: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
depth_load_op: wgpu::LoadOp::Clear(1.0),
stencil_load_op: wgpu::LoadOp::Clear(0),
},
);
render_pass
}
pub struct RenderPassLoadOperations {
pub color_load_op: wgpu::LoadOp<wgpu::Color>,
pub depth_load_op: wgpu::LoadOp<f32>,
pub stencil_load_op: wgpu::LoadOp<u32>,
}
pub fn begin_render_pass_with_load_ops<'a, 'b: 'a>(
encoder: &'a mut wgpu::CommandEncoder,
label: Option<&'a str>,
color_texture_view: &'b TextureView,
resolve_target: Option<&'b TextureView>,
depth_texture_view: &'b TextureView,
load_operations: RenderPassLoadOperations,
) -> RenderPass<'a> {
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label,
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: color_texture_view,
resolve_target,
ops: wgpu::Operations {
load: load_operations.color_load_op,
store: StoreOp::Store,
},
})],
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
view: depth_texture_view,
depth_ops: Some(wgpu::Operations {
load: load_operations.depth_load_op,
store: StoreOp::Store,
}),
stencil_ops: Some(wgpu::Operations {
load: load_operations.stencil_load_op,
store: StoreOp::Store,
}),
}),
timestamp_writes: None,
occlusion_query_set: None,
})
}
pub fn create_and_depth_texture(device: &Device, size: (u32, u32), sample_count: u32) -> Texture {
let size = wgpu::Extent3d {
width: size.0,
height: size.1,
depth_or_array_layers: 1,
};
device.create_texture(&wgpu::TextureDescriptor {
label: None,
size,
mip_level_count: 1,
sample_count,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Depth24PlusStencil8,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT
| wgpu::TextureUsages::COPY_SRC
| wgpu::TextureUsages::COPY_DST,
view_formats: &[],
})
}
pub fn render_buffer_range_to_texture(
index_range: (usize, usize), render_pass: &mut RenderPass<'_>,
parent_stencil_reference: u32,
) {
render_pass.set_stencil_reference(parent_stencil_reference);
let index_start = index_range.0 as u32;
let index_end = (index_range.0 + index_range.1) as u32;
render_pass.draw_indexed(index_start..index_end, 0, 0..1);
}
pub fn create_offscreen_color_texture(
device: &Device,
size: (u32, u32),
format: wgpu::TextureFormat,
) -> Texture {
device.create_texture(&wgpu::TextureDescriptor {
label: Some("offscreen_render_texture_argb"),
size: wgpu::Extent3d {
width: size.0,
height: size.1,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
view_formats: &[],
})
}
pub fn create_argb_swizzle_pipeline(device: &Device) -> (BindGroupLayout, ComputePipeline) {
let cs_module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("argb_swizzle_cs"),
source: wgpu::ShaderSource::Wgsl(include_str!("shaders/argb_swizzle.wgsl").into()),
});
let bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("argb_swizzle_bgl"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: false },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
],
});
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("argb_swizzle_pl"),
bind_group_layouts: &[&bgl],
push_constant_ranges: &[],
});
let pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
label: Some("argb_swizzle_pipeline"),
layout: Some(&pipeline_layout),
module: &cs_module,
entry_point: Some("cs_main"),
compilation_options: Default::default(),
cache: None,
});
(bgl, pipeline)
}
pub fn create_argb_swizzle_bind_group(
device: &Device,
bgl: &BindGroupLayout,
input_bytes: &wgpu::Buffer,
output_words: &wgpu::Buffer,
params: &wgpu::Buffer,
) -> BindGroup {
device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("argb_swizzle_bg"),
layout: bgl,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: input_bytes.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 1,
resource: output_words.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 2,
resource: params.as_entire_binding(),
},
],
})
}
pub fn compute_padded_bytes_per_row(width: u32, bytes_per_pixel: u32) -> (u32, u32) {
let unpadded = width * bytes_per_pixel;
let align = wgpu::COPY_BYTES_PER_ROW_ALIGNMENT;
let padded = unpadded.div_ceil(align) * align;
(unpadded, padded)
}
pub fn create_buffer(
device: &Device,
label: Option<&str>,
size: u64,
usage: wgpu::BufferUsages,
) -> wgpu::Buffer {
device.create_buffer(&wgpu::BufferDescriptor {
label,
size,
usage,
mapped_at_creation: false,
})
}
pub fn create_buffer_init(
device: &Device,
label: Option<&str>,
bytes: &[u8],
usage: wgpu::BufferUsages,
) -> wgpu::Buffer {
device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label,
contents: bytes,
usage,
})
}
pub fn encode_copy_texture_to_buffer(
encoder: &mut wgpu::CommandEncoder,
texture: &wgpu::Texture,
buffer: &wgpu::Buffer,
width: u32,
height: u32,
padded_bytes_per_row: u32,
) {
encoder.copy_texture_to_buffer(
wgpu::TexelCopyTextureInfo {
texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
},
wgpu::TexelCopyBufferInfo {
buffer,
layout: wgpu::TexelCopyBufferLayout {
offset: 0,
bytes_per_row: Some(padded_bytes_per_row),
rows_per_image: Some(height),
},
},
wgpu::Extent3d {
width,
height,
depth_or_array_layers: 1,
},
);
}
pub fn create_readback_buffer(device: &Device, label: Option<&str>, size: u64) -> wgpu::Buffer {
create_buffer(
device,
label,
size,
wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
)
}
pub fn create_storage_input_buffer(
device: &Device,
label: Option<&str>,
size: u64,
) -> wgpu::Buffer {
create_buffer(
device,
label,
size,
wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::STORAGE,
)
}
pub fn create_storage_output_buffer(
device: &Device,
label: Option<&str>,
size: u64,
) -> wgpu::Buffer {
create_buffer(
device,
label,
size,
wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_SRC,
)
}
#[repr(C)]
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
pub struct ArgbParams {
pub width: u32,
pub height: u32,
pub padded_bpr: u32,
pub _pad: u32,
}
pub fn create_argb_params_buffer(device: &Device, params: &ArgbParams) -> wgpu::Buffer {
create_buffer_init(
device,
Some("argb_params"),
bytemuck::bytes_of(params),
wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
)
}
pub fn create_msaa_color_texture(
device: &Device,
size: (u32, u32),
format: wgpu::TextureFormat,
sample_count: u32,
) -> Texture {
device.create_texture(&wgpu::TextureDescriptor {
label: Some("msaa_color_texture"),
size: wgpu::Extent3d {
width: size.0,
height: size.1,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count,
dimension: wgpu::TextureDimension::D2,
format,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
view_formats: &[],
})
}
pub fn create_stencil_only_pipeline(
device: &Device,
format: wgpu::TextureFormat,
sample_count: u32,
uniform_bgl: &wgpu::BindGroupLayout,
texture_bgl_layer0: &wgpu::BindGroupLayout,
texture_bgl_layer1: &wgpu::BindGroupLayout,
) -> RenderPipeline {
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("stencil_only_shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("shaders/shader.wgsl").into()),
});
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("stencil_only_pipeline_layout"),
bind_group_layouts: &[uniform_bgl, texture_bgl_layer0, texture_bgl_layer1],
push_constant_ranges: &[],
});
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("stencil_only_pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main"),
compilation_options: Default::default(),
buffers: &[
CustomVertex::desc(),
InstanceTransform::desc(),
InstanceColor::desc(),
InstanceMetadata::desc(),
],
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs_stencil_only"),
compilation_options: Default::default(),
targets: &[Some(wgpu::ColorTargetState {
format,
blend: None,
write_mask: wgpu::ColorWrites::empty(),
})],
}),
primitive: wgpu::PrimitiveState::default(),
depth_stencil: Some(create_equal_increment_depth_state()),
multisample: wgpu::MultisampleState {
count: sample_count,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
})
}
pub fn create_stencil_keep_color_pipeline(
device: &Device,
format: wgpu::TextureFormat,
sample_count: u32,
uniform_bgl: &wgpu::BindGroupLayout,
texture_bgl_layer0: &wgpu::BindGroupLayout,
texture_bgl_layer1: &wgpu::BindGroupLayout,
) -> RenderPipeline {
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("stencil_keep_color_shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("shaders/shader.wgsl").into()),
});
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("stencil_keep_color_pipeline_layout"),
bind_group_layouts: &[uniform_bgl, texture_bgl_layer0, texture_bgl_layer1],
push_constant_ranges: &[],
});
let stencil_face = wgpu::StencilFaceState {
compare: wgpu::CompareFunction::Equal,
fail_op: wgpu::StencilOperation::Keep,
depth_fail_op: wgpu::StencilOperation::Keep,
pass_op: wgpu::StencilOperation::Keep,
};
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("stencil_keep_color_pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main"),
compilation_options: Default::default(),
buffers: &[
CustomVertex::desc(),
InstanceTransform::desc(),
InstanceColor::desc(),
InstanceMetadata::desc(),
],
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs_main"),
compilation_options: Default::default(),
targets: &[Some(wgpu::ColorTargetState {
format,
blend: Some(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,
},
}),
write_mask: wgpu::ColorWrites::ALL,
})],
}),
primitive: wgpu::PrimitiveState::default(),
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: true,
depth_compare: wgpu::CompareFunction::Always,
stencil: wgpu::StencilState {
front: stencil_face,
back: stencil_face,
read_mask: 0xff,
write_mask: 0x00,
},
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState {
count: sample_count,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
})
}
pub fn create_gradient_stencil_keep_color_pipeline(
device: &Device,
format: wgpu::TextureFormat,
sample_count: u32,
uniform_bgl: &wgpu::BindGroupLayout,
texture_bgl_layer0: &wgpu::BindGroupLayout,
texture_bgl_layer1: &wgpu::BindGroupLayout,
gradient_bgl: &wgpu::BindGroupLayout,
) -> RenderPipeline {
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("gradient_stencil_keep_color_shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("shaders/shader.wgsl").into()),
});
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("gradient_stencil_keep_color_pipeline_layout"),
bind_group_layouts: &[
uniform_bgl,
texture_bgl_layer0,
texture_bgl_layer1,
gradient_bgl,
],
push_constant_ranges: &[],
});
let stencil_face = wgpu::StencilFaceState {
compare: wgpu::CompareFunction::Equal,
fail_op: wgpu::StencilOperation::Keep,
depth_fail_op: wgpu::StencilOperation::Keep,
pass_op: wgpu::StencilOperation::Keep,
};
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("gradient_stencil_keep_color_pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main_gradient"),
compilation_options: Default::default(),
buffers: &[
CustomVertex::desc(),
InstanceTransform::desc(),
InstanceColor::desc(),
InstanceMetadata::desc(),
],
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs_main_gradient"),
compilation_options: Default::default(),
targets: &[Some(wgpu::ColorTargetState {
format,
blend: Some(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,
},
}),
write_mask: wgpu::ColorWrites::ALL,
})],
}),
primitive: wgpu::PrimitiveState::default(),
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: true,
depth_compare: wgpu::CompareFunction::Always,
stencil: wgpu::StencilState {
front: stencil_face,
back: stencil_face,
read_mask: 0xff,
write_mask: 0x00,
},
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState {
count: sample_count,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
})
}