wgpu_examples/mesh_shader/
mod.rs

1use std::process::Stdio;
2
3// Same as in mesh shader tests
4fn compile_glsl(device: &wgpu::Device, shader_stage: &'static str) -> wgpu::ShaderModule {
5    let cmd = std::process::Command::new("glslc")
6        .args([
7            &format!(
8                "{}/src/mesh_shader/shader.{shader_stage}",
9                env!("CARGO_MANIFEST_DIR")
10            ),
11            "-o",
12            "-",
13            "--target-env=vulkan1.2",
14            "--target-spv=spv1.4",
15        ])
16        .stdin(Stdio::piped())
17        .stdout(Stdio::piped())
18        .spawn()
19        .expect("Failed to call glslc");
20    let output = cmd.wait_with_output().expect("Error waiting for glslc");
21    assert!(output.status.success());
22    unsafe {
23        device.create_shader_module_passthrough(wgpu::ShaderModuleDescriptorPassthrough {
24            entry_point: "main".into(),
25            label: None,
26            spirv: Some(wgpu::util::make_spirv_raw(&output.stdout)),
27            ..Default::default()
28        })
29    }
30}
31fn compile_hlsl(device: &wgpu::Device, entry: &str, stage_str: &str) -> wgpu::ShaderModule {
32    let out_path = format!(
33        "{}/src/mesh_shader/shader.{stage_str}.cso",
34        env!("CARGO_MANIFEST_DIR")
35    );
36    let cmd = std::process::Command::new("dxc")
37        .args([
38            "-T",
39            &format!("{stage_str}_6_5"),
40            "-E",
41            entry,
42            &format!("{}/src/mesh_shader/shader.hlsl", env!("CARGO_MANIFEST_DIR")),
43            "-Fo",
44            &out_path,
45        ])
46        .output()
47        .unwrap();
48    if !cmd.status.success() {
49        panic!("DXC failed:\n{}", String::from_utf8(cmd.stderr).unwrap());
50    }
51    let file = std::fs::read(&out_path).unwrap();
52    std::fs::remove_file(out_path).unwrap();
53    unsafe {
54        device.create_shader_module_passthrough(wgpu::ShaderModuleDescriptorPassthrough {
55            entry_point: entry.to_owned(),
56            label: None,
57            num_workgroups: (1, 1, 1),
58            dxil: Some(std::borrow::Cow::Owned(file)),
59            ..Default::default()
60        })
61    }
62}
63
64pub struct Example {
65    pipeline: wgpu::RenderPipeline,
66}
67impl crate::framework::Example for Example {
68    fn init(
69        config: &wgpu::SurfaceConfiguration,
70        adapter: &wgpu::Adapter,
71        device: &wgpu::Device,
72        _queue: &wgpu::Queue,
73    ) -> Self {
74        let (ts, ms, fs) = if adapter.get_info().backend == wgpu::Backend::Vulkan {
75            (
76                compile_glsl(device, "task"),
77                compile_glsl(device, "mesh"),
78                compile_glsl(device, "frag"),
79            )
80        } else if adapter.get_info().backend == wgpu::Backend::Dx12 {
81            (
82                compile_hlsl(device, "Task", "as"),
83                compile_hlsl(device, "Mesh", "ms"),
84                compile_hlsl(device, "Frag", "ps"),
85            )
86        } else {
87            panic!("Example can only run on vulkan or dx12");
88        };
89        let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
90            label: None,
91            bind_group_layouts: &[],
92            push_constant_ranges: &[],
93        });
94        let pipeline = device.create_mesh_pipeline(&wgpu::MeshPipelineDescriptor {
95            label: None,
96            layout: Some(&pipeline_layout),
97            task: Some(wgpu::TaskState {
98                module: &ts,
99                entry_point: Some("main"),
100                compilation_options: Default::default(),
101            }),
102            mesh: wgpu::MeshState {
103                module: &ms,
104                entry_point: Some("main"),
105                compilation_options: Default::default(),
106            },
107            fragment: Some(wgpu::FragmentState {
108                module: &fs,
109                entry_point: Some("main"),
110                compilation_options: Default::default(),
111                targets: &[Some(config.view_formats[0].into())],
112            }),
113            primitive: wgpu::PrimitiveState {
114                cull_mode: Some(wgpu::Face::Back),
115                ..Default::default()
116            },
117            depth_stencil: None,
118            multisample: Default::default(),
119            multiview: None,
120            cache: None,
121        });
122        Self { pipeline }
123    }
124    fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue) {
125        let mut encoder =
126            device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
127        {
128            let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
129                label: None,
130                color_attachments: &[Some(wgpu::RenderPassColorAttachment {
131                    view,
132                    resolve_target: None,
133                    ops: wgpu::Operations {
134                        load: wgpu::LoadOp::Clear(wgpu::Color {
135                            r: 0.1,
136                            g: 0.2,
137                            b: 0.3,
138                            a: 1.0,
139                        }),
140                        store: wgpu::StoreOp::Store,
141                    },
142                    depth_slice: None,
143                })],
144                depth_stencil_attachment: None,
145                timestamp_writes: None,
146                occlusion_query_set: None,
147            });
148            rpass.push_debug_group("Prepare data for draw.");
149            rpass.set_pipeline(&self.pipeline);
150            rpass.pop_debug_group();
151            rpass.insert_debug_marker("Draw!");
152            rpass.draw_mesh_tasks(1, 1, 1);
153        }
154        queue.submit(Some(encoder.finish()));
155    }
156    fn required_downlevel_capabilities() -> wgpu::DownlevelCapabilities {
157        Default::default()
158    }
159    fn required_features() -> wgpu::Features {
160        wgpu::Features::EXPERIMENTAL_MESH_SHADER | wgpu::Features::EXPERIMENTAL_PASSTHROUGH_SHADERS
161    }
162    fn required_limits() -> wgpu::Limits {
163        wgpu::Limits::defaults().using_recommended_minimum_mesh_shader_values()
164    }
165    fn resize(
166        &mut self,
167        _config: &wgpu::SurfaceConfiguration,
168        _device: &wgpu::Device,
169        _queue: &wgpu::Queue,
170    ) {
171        // empty
172    }
173    fn update(&mut self, _event: winit::event::WindowEvent) {
174        // empty
175    }
176}
177
178pub fn main() {
179    crate::framework::run::<Example>("mesh_shader");
180}