wgpu_examples/mesh_shader/
mod.rs1fn compile_wgsl(device: &wgpu::Device) -> wgpu::ShaderModule {
3 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 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 }
168 fn update(&mut self, _event: winit::event::WindowEvent) {
169 }
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 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};