wgpu_examples/mesh_shader/
mod.rs1use std::{io::Write, process::Stdio};
2
3fn 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 }
135 fn update(&mut self, _event: winit::event::WindowEvent) {
136 }
138}
139
140pub fn main() {
141 crate::framework::run::<Example>("mesh_shader");
142}