use std::num::NonZeroU64;
use super::pool::UNIFORM_SIZE;
pub(super) const TARGET_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Rgba8Unorm;
pub(super) struct Programs {
pub(super) pipeline: wgpu::RenderPipeline,
pub(super) frame_layout: wgpu::BindGroupLayout,
pub(super) tile_layout: wgpu::BindGroupLayout,
pub(super) sampler: wgpu::Sampler,
pub(super) shader: wgpu::ShaderModule,
pub(super) pipeline_layout: wgpu::PipelineLayout,
}
impl Programs {
pub(super) fn new(device: &wgpu::Device) -> Self {
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("ass-gpu-shader"),
source: wgpu::ShaderSource::Wgsl(super::shader::SHADER.into()),
});
let frame_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("ass-gpu-frame-bgl"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: true,
min_binding_size: NonZeroU64::new(u64::from(UNIFORM_SIZE)),
},
count: None,
},
],
});
let tile_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("ass-gpu-tile-bgl"),
entries: &[wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
}],
});
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("ass-gpu-pipeline-layout"),
bind_group_layouts: &[&frame_layout, &tile_layout],
push_constant_ranges: &[],
});
let pipeline = build_pipeline(device, &shader, &pipeline_layout, TARGET_FORMAT);
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
label: Some("ass-gpu-sampler"),
mag_filter: wgpu::FilterMode::Nearest,
min_filter: wgpu::FilterMode::Nearest,
mipmap_filter: wgpu::FilterMode::Nearest,
..Default::default()
});
Self {
pipeline,
frame_layout,
tile_layout,
sampler,
shader,
pipeline_layout,
}
}
}
pub(super) fn build_pipeline(
device: &wgpu::Device,
shader: &wgpu::ShaderModule,
layout: &wgpu::PipelineLayout,
format: wgpu::TextureFormat,
) -> wgpu::RenderPipeline {
let blend = wgpu::BlendComponent {
src_factor: wgpu::BlendFactor::One,
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
operation: wgpu::BlendOperation::Add,
};
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("ass-gpu-pipeline"),
layout: Some(layout),
vertex: wgpu::VertexState {
module: shader,
entry_point: "vs_main",
buffers: &[],
},
fragment: Some(wgpu::FragmentState {
module: shader,
entry_point: "fs_main",
targets: &[Some(wgpu::ColorTargetState {
format,
blend: Some(wgpu::BlendState {
color: blend,
alpha: blend,
}),
write_mask: wgpu::ColorWrites::ALL,
})],
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
..Default::default()
},
depth_stencil: None,
multisample: wgpu::MultisampleState::default(),
multiview: None,
})
}