wgpu_examples/mesh_shader/
mod.rs

1use std::{io::Write, process::Stdio};
2
3// Same as in mesh shader tests
4fn compile_glsl(
5    device: &wgpu::Device,
6    data: &[u8],
7    shader_stage: &'static str,
8) -> wgpu::ShaderModule {
9    let cmd = std::process::Command::new("glslc")
10        .args([
11            &format!("-fshader-stage={shader_stage}"),
12            "-",
13            "-o",
14            "-",
15            "--target-env=vulkan1.2",
16            "--target-spv=spv1.4",
17        ])
18        .stdin(Stdio::piped())
19        .stdout(Stdio::piped())
20        .spawn()
21        .expect("Failed to call glslc");
22    cmd.stdin.as_ref().unwrap().write_all(data).unwrap();
23    println!("{shader_stage}");
24    let output = cmd.wait_with_output().expect("Error waiting for glslc");
25    assert!(output.status.success());
26    unsafe {
27        device.create_shader_module_passthrough(wgpu::ShaderModuleDescriptorPassthrough {
28            entry_point: "main".into(),
29            label: None,
30            spirv: Some(wgpu::util::make_spirv_raw(&output.stdout)),
31            ..Default::default()
32        })
33    }
34}
35
36pub struct Example {
37    pipeline: wgpu::RenderPipeline,
38}
39impl crate::framework::Example for Example {
40    fn init(
41        config: &wgpu::SurfaceConfiguration,
42        _adapter: &wgpu::Adapter,
43        device: &wgpu::Device,
44        _queue: &wgpu::Queue,
45    ) -> Self {
46        let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
47            label: None,
48            bind_group_layouts: &[],
49            push_constant_ranges: &[],
50        });
51        let (ts, ms, fs) = (
52            compile_glsl(device, include_bytes!("shader.task"), "task"),
53            compile_glsl(device, include_bytes!("shader.mesh"), "mesh"),
54            compile_glsl(device, include_bytes!("shader.frag"), "frag"),
55        );
56        let pipeline = device.create_mesh_pipeline(&wgpu::MeshPipelineDescriptor {
57            label: None,
58            layout: Some(&pipeline_layout),
59            task: Some(wgpu::TaskState {
60                module: &ts,
61                entry_point: Some("main"),
62                compilation_options: Default::default(),
63            }),
64            mesh: wgpu::MeshState {
65                module: &ms,
66                entry_point: Some("main"),
67                compilation_options: Default::default(),
68            },
69            fragment: Some(wgpu::FragmentState {
70                module: &fs,
71                entry_point: Some("main"),
72                compilation_options: Default::default(),
73                targets: &[Some(config.view_formats[0].into())],
74            }),
75            primitive: wgpu::PrimitiveState {
76                cull_mode: Some(wgpu::Face::Back),
77                ..Default::default()
78            },
79            depth_stencil: None,
80            multisample: Default::default(),
81            multiview: None,
82            cache: None,
83        });
84        Self { pipeline }
85    }
86    fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue) {
87        let mut encoder =
88            device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
89        {
90            let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
91                label: None,
92                color_attachments: &[Some(wgpu::RenderPassColorAttachment {
93                    view,
94                    resolve_target: None,
95                    ops: wgpu::Operations {
96                        load: wgpu::LoadOp::Clear(wgpu::Color {
97                            r: 0.1,
98                            g: 0.2,
99                            b: 0.3,
100                            a: 1.0,
101                        }),
102                        store: wgpu::StoreOp::Store,
103                    },
104                    depth_slice: None,
105                })],
106                depth_stencil_attachment: None,
107                timestamp_writes: None,
108                occlusion_query_set: None,
109            });
110            rpass.push_debug_group("Prepare data for draw.");
111            rpass.set_pipeline(&self.pipeline);
112            rpass.pop_debug_group();
113            rpass.insert_debug_marker("Draw!");
114            rpass.draw_mesh_tasks(1, 1, 1);
115        }
116        queue.submit(Some(encoder.finish()));
117    }
118    fn required_downlevel_capabilities() -> wgpu::DownlevelCapabilities {
119        Default::default()
120    }
121    fn required_features() -> wgpu::Features {
122        wgpu::Features::EXPERIMENTAL_MESH_SHADER | wgpu::Features::EXPERIMENTAL_PASSTHROUGH_SHADERS
123    }
124    fn required_limits() -> wgpu::Limits {
125        wgpu::Limits::defaults().using_recommended_minimum_mesh_shader_values()
126    }
127    fn resize(
128        &mut self,
129        _config: &wgpu::SurfaceConfiguration,
130        _device: &wgpu::Device,
131        _queue: &wgpu::Queue,
132    ) {
133        // empty
134    }
135    fn update(&mut self, _event: winit::event::WindowEvent) {
136        // empty
137    }
138}
139
140pub fn main() {
141    crate::framework::run::<Example>("mesh_shader");
142}