use easy_wgpu::{
bind_group::{BindGroupBuilder, BindGroupDesc, BindGroupWrapper},
bind_group_layout::{BindGroupLayoutBuilder, BindGroupLayoutDesc},
gpu::Gpu,
pipeline::RenderPipelineDescBuilder,
texture::Texture,
};
use log::debug;
#[include_wgsl_oil::include_wgsl_oil("../../../shaders/blit.wgsl")]
mod shader_code {}
pub struct BlitPass {
render_pipeline: wgpu::RenderPipeline,
sampler: wgpu::Sampler,
input_layout: wgpu::BindGroupLayout,
input_bind_group: Option<BindGroupWrapper>,
}
impl BlitPass {
pub fn new(gpu: &Gpu, surface_format: &wgpu::TextureFormat) -> Self {
let input_layout_desc = Self::input_layout_desc();
let input_layout = input_layout_desc.clone().into_bind_group_layout(gpu.device());
let render_pipeline = RenderPipelineDescBuilder::new()
.label("blit pipeline")
.shader_code(shader_code::SOURCE)
.shader_label("blit_shader")
.add_bind_group_layout_desc(input_layout_desc) .add_render_target(wgpu::ColorTargetState {
format: *surface_format,
blend: Some(wgpu::BlendState::REPLACE),
write_mask: wgpu::ColorWrites::ALL,
})
.depth_state(None)
.multisample(wgpu::MultisampleState::default())
.build_pipeline(gpu.device());
let sampler = gpu.device().create_sampler(&wgpu::SamplerDescriptor {
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Linear,
mipmap_filter: wgpu::FilterMode::Linear,
..Default::default()
});
Self {
render_pipeline,
sampler,
input_layout,
input_bind_group: None,
}
}
pub fn run(&mut self, gpu: &Gpu, src_texture: &Texture, out_view: &wgpu::TextureView) {
let mut encoder = gpu
.device()
.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("Blit Encoder") });
{
self.update_input_bind_group(gpu, src_texture);
{
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Blit Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: out_view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
});
render_pass.set_pipeline(&self.render_pipeline);
render_pass.set_bind_group(0, self.input_bind_group.as_ref().unwrap().bg(), &[]);
render_pass.draw(0..4, 0..1);
}
}
gpu.queue().submit(Some(encoder.finish()));
}
fn input_layout_desc() -> BindGroupLayoutDesc {
BindGroupLayoutBuilder::new()
.label("blit_texture_layout")
.add_entry_tex(wgpu::ShaderStages::FRAGMENT, wgpu::TextureSampleType::Float { filterable: true })
.add_entry_sampler(wgpu::ShaderStages::FRAGMENT, wgpu::SamplerBindingType::Filtering)
.build()
}
fn update_input_bind_group(&mut self, gpu: &Gpu, src_texture: &Texture) {
let entries = BindGroupBuilder::new()
.add_entry_tex(src_texture)
.add_entry_sampler(&self.sampler)
.build_entries();
let stale = self.input_bind_group.as_ref().is_none_or(|b| b.is_stale(&entries));
if stale {
debug!("blit bind group is stale, recreating");
self.input_bind_group = Some(BindGroupDesc::new("blit_bg", entries).into_bind_group_wrapper(gpu.device(), &self.input_layout));
}
}
}