wgpu_examples/mesh_shader/
mod.rs

1// Same as in mesh shader tests
2fn compile_wgsl(device: &wgpu::Device) -> wgpu::ShaderModule {
3    // Workgroup memory zero initialization can be expensive for mesh shaders
4    unsafe {
5        device.create_shader_module_trusted(
6            wgpu::ShaderModuleDescriptor {
7                label: None,
8                source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()),
9            },
10            wgpu::ShaderRuntimeChecks::unchecked(),
11        )
12    }
13}
14
15fn compile_msl(device: &wgpu::Device) -> wgpu::ShaderModule {
16    unsafe {
17        device.create_shader_module_passthrough(wgpu::ShaderModuleDescriptorPassthrough {
18            label: None,
19            msl: Some(std::borrow::Cow::Borrowed(include_str!("shader.metal"))),
20            num_workgroups: (1, 1, 1),
21            ..Default::default()
22        })
23    }
24}
25
26struct Shaders {
27    ts: wgpu::ShaderModule,
28    ms: wgpu::ShaderModule,
29    fs: wgpu::ShaderModule,
30    ts_name: &'static str,
31    ms_name: &'static str,
32    fs_name: &'static str,
33}
34
35fn get_shaders(device: &wgpu::Device, backend: wgpu::Backend) -> Shaders {
36    // In the case that the platform does support mesh shaders, the dummy
37    // shader is used to avoid requiring PASSTHROUGH_SHADERS.
38    match backend {
39        wgpu::Backend::Vulkan | wgpu::Backend::Dx12 => {
40            let compiled = compile_wgsl(device);
41            Shaders {
42                ts: compiled.clone(),
43                ms: compiled.clone(),
44                fs: compiled.clone(),
45                ts_name: "ts_main",
46                ms_name: "ms_main",
47                fs_name: "fs_main",
48            }
49        }
50        wgpu::Backend::Metal => {
51            let compiled = compile_msl(device);
52            Shaders {
53                ts: compiled.clone(),
54                ms: compiled.clone(),
55                fs: compiled.clone(),
56                ts_name: "taskShader",
57                ms_name: "meshShader",
58                fs_name: "fragShader",
59            }
60        }
61        _ => unreachable!(),
62    }
63}
64
65pub struct Example {
66    pipeline: wgpu::RenderPipeline,
67}
68impl crate::framework::Example for Example {
69    fn init(
70        config: &wgpu::SurfaceConfiguration,
71        adapter: &wgpu::Adapter,
72        device: &wgpu::Device,
73        _queue: &wgpu::Queue,
74    ) -> Self {
75        let Shaders {
76            ts,
77            ms,
78            fs,
79            ts_name,
80            ms_name,
81            fs_name,
82        } = get_shaders(device, adapter.get_info().backend);
83        let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
84            label: None,
85            bind_group_layouts: &[],
86            immediate_size: 0,
87        });
88        let pipeline = device.create_mesh_pipeline(&wgpu::MeshPipelineDescriptor {
89            label: None,
90            layout: Some(&pipeline_layout),
91            task: Some(wgpu::TaskState {
92                module: &ts,
93                entry_point: Some(ts_name),
94                compilation_options: Default::default(),
95            }),
96            mesh: wgpu::MeshState {
97                module: &ms,
98                entry_point: Some(ms_name),
99                compilation_options: Default::default(),
100            },
101            fragment: Some(wgpu::FragmentState {
102                module: &fs,
103                entry_point: Some(fs_name),
104                compilation_options: Default::default(),
105                targets: &[Some(config.view_formats[0].into())],
106            }),
107            primitive: wgpu::PrimitiveState {
108                cull_mode: Some(wgpu::Face::Back),
109                ..Default::default()
110            },
111            depth_stencil: None,
112            multisample: Default::default(),
113            multiview: None,
114            cache: None,
115        });
116        Self { pipeline }
117    }
118    fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue) {
119        let mut encoder =
120            device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
121        {
122            let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
123                label: None,
124                color_attachments: &[Some(wgpu::RenderPassColorAttachment {
125                    view,
126                    resolve_target: None,
127                    ops: wgpu::Operations {
128                        load: wgpu::LoadOp::Clear(wgpu::Color {
129                            r: 0.1,
130                            g: 0.2,
131                            b: 0.3,
132                            a: 1.0,
133                        }),
134                        store: wgpu::StoreOp::Store,
135                    },
136                    depth_slice: None,
137                })],
138                depth_stencil_attachment: None,
139                timestamp_writes: None,
140                occlusion_query_set: None,
141                multiview_mask: None,
142            });
143            rpass.push_debug_group("Prepare data for draw.");
144            rpass.set_pipeline(&self.pipeline);
145            rpass.pop_debug_group();
146            rpass.insert_debug_marker("Draw!");
147            rpass.draw_mesh_tasks(1, 1, 1);
148        }
149        queue.submit(Some(encoder.finish()));
150    }
151    fn required_downlevel_capabilities() -> wgpu::DownlevelCapabilities {
152        Default::default()
153    }
154    fn required_features() -> wgpu::Features {
155        wgpu::Features::EXPERIMENTAL_MESH_SHADER | wgpu::Features::PASSTHROUGH_SHADERS
156    }
157    fn required_limits() -> wgpu::Limits {
158        wgpu::Limits::defaults().using_recommended_minimum_mesh_shader_values()
159    }
160    fn resize(
161        &mut self,
162        _config: &wgpu::SurfaceConfiguration,
163        _device: &wgpu::Device,
164        _queue: &wgpu::Queue,
165    ) {
166        // empty
167    }
168    fn update(&mut self, _event: winit::event::WindowEvent) {
169        // empty
170    }
171}
172
173pub fn main() {
174    crate::framework::run::<Example>("mesh_shader");
175}
176
177#[cfg(test)]
178#[wgpu_test::gpu_test]
179pub static TEST: crate::framework::ExampleTestParams = crate::framework::ExampleTestParams {
180    name: "mesh_shader",
181    image_path: "/examples/features/src/mesh_shader/screenshot.png",
182    width: 1024,
183    height: 768,
184    optional_features: wgpu::Features::default(),
185    base_test_parameters: wgpu_test::TestParameters::default()
186        .features(wgpu::Features::EXPERIMENTAL_MESH_SHADER | wgpu::Features::PASSTHROUGH_SHADERS)
187        .instance_flags(wgpu::InstanceFlags::advanced_debugging())
188        .limits(wgpu::Limits::defaults().using_recommended_minimum_mesh_shader_values())
189        .skip(wgpu_test::FailureCase {
190            backends: None,
191            // Skip Mesa because LLVMPIPE has what is believed to be a driver bug
192            vendor: Some(0x10005),
193            adapter: None,
194            driver: None,
195            reasons: vec![],
196            behavior: wgpu_test::FailureBehavior::Ignore,
197        }),
198    comparisons: &[wgpu_test::ComparisonType::Mean(0.005)],
199    _phantom: std::marker::PhantomData::<Example>,
200};