librashader_runtime_wgpu/
mipmap.rs1use librashader_common::map::FastHashMap;
2use std::borrow::Cow;
3
4pub struct MipmapGen {
5 shader: wgpu::ShaderModule,
6 pipeline_cache: FastHashMap<wgpu::TextureFormat, wgpu::RenderPipeline>,
7}
8
9impl MipmapGen {
10 fn create_pipeline(
11 device: &wgpu::Device,
12 shader: &wgpu::ShaderModule,
13 format: wgpu::TextureFormat,
14 ) -> wgpu::RenderPipeline {
15 let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
16 label: Some("blit"),
17 layout: None,
18 vertex: wgpu::VertexState {
19 module: &shader,
20 entry_point: Some("vs_main"),
21 compilation_options: wgpu::PipelineCompilationOptions::default(),
22 buffers: &[],
23 },
24 fragment: Some(wgpu::FragmentState {
25 module: &shader,
26 entry_point: Some("fs_main"),
27 compilation_options: wgpu::PipelineCompilationOptions::default(),
28 targets: &[Some(format.into())],
29 }),
30 primitive: wgpu::PrimitiveState {
31 topology: wgpu::PrimitiveTopology::TriangleList,
32 ..Default::default()
33 },
34 depth_stencil: None,
35 multisample: wgpu::MultisampleState::default(),
36 multiview_mask: None,
37 cache: None,
38 });
39
40 pipeline
41 }
42 pub fn new(device: &wgpu::Device) -> Self {
43 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
44 label: None,
45 source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("../shader/blit.wgsl"))),
46 });
47
48 Self {
49 shader,
50 pipeline_cache: Default::default(),
51 }
52 }
53
54 pub fn generate_mipmaps(
55 &mut self,
56 device: &wgpu::Device,
57 cmd: &mut wgpu::CommandEncoder,
58 texture: &wgpu::Texture,
59 sampler: &wgpu::Sampler,
60 miplevels: u32,
61 ) {
62 let format = texture.format();
63 let pipeline = &*self
64 .pipeline_cache
65 .entry(format)
66 .or_insert_with(|| Self::create_pipeline(&device, &self.shader, format));
67
68 let views = (0..miplevels)
69 .map(|mip| {
70 texture.create_view(&wgpu::TextureViewDescriptor {
71 label: Some("mip"),
72 format: None,
73 dimension: None,
74 usage: None,
75 aspect: wgpu::TextureAspect::All,
76 base_mip_level: mip,
77 mip_level_count: Some(1),
78 base_array_layer: 0,
79 array_layer_count: None,
80 })
81 })
82 .collect::<Vec<_>>();
83
84 for target_mip in 1..miplevels as usize {
85 let bind_group_layout = pipeline.get_bind_group_layout(0);
86 let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
87 layout: &bind_group_layout,
88 entries: &[
89 wgpu::BindGroupEntry {
90 binding: 0,
91 resource: wgpu::BindingResource::TextureView(&views[target_mip - 1]),
92 },
93 wgpu::BindGroupEntry {
94 binding: 1,
95 resource: wgpu::BindingResource::Sampler(&sampler),
96 },
97 ],
98 label: None,
99 });
100
101 let mut pass = cmd.begin_render_pass(&wgpu::RenderPassDescriptor {
102 label: None,
103 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
104 view: &views[target_mip],
105 depth_slice: None,
106 resolve_target: None,
107 ops: wgpu::Operations {
108 load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
109 store: wgpu::StoreOp::Store,
110 },
111 })],
112 depth_stencil_attachment: None,
113 timestamp_writes: None,
114 occlusion_query_set: None,
115 multiview_mask: None,
116 });
117
118 pass.set_pipeline(&pipeline);
119 pass.set_bind_group(0, &bind_group, &[]);
120 pass.draw(0..3, 0..1);
121 }
122 }
123}