Skip to main content

librashader_runtime_wgpu/
mipmap.rs

1use 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}