Skip to content

Commit 074c0e7

Browse files
Add mesh shading api to wgpu & wgpu-core (#7345)
1 parent 68a10a0 commit 074c0e7

File tree

50 files changed

+2202
-667
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+2202
-667
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ By @Vecvec in [#7829](https://github.com/gfx-rs/wgpu/pull/7829).
157157
- Add acceleration structure limits. By @Vecvec in [#7845](https://github.com/gfx-rs/wgpu/pull/7845).
158158
- Add support for clip-distances feature for Vulkan and GL backends. By @dzamkov in [#7730](https://github.com/gfx-rs/wgpu/pull/7730)
159159
- Added `wgpu_types::error::{ErrorType, WebGpuError}` for classification of errors according to WebGPU's [`GPUError`]'s classification scheme, and implement `WebGpuError` for existing errors. This allows users of `wgpu-core` to offload error classification onto the WGPU ecosystem, rather than having to do it themselves without sufficient information. By @ErichDonGubler in [#6547](https://github.com/gfx-rs/wgpu/pull/6547).
160+
- Added mesh shader support to `wgpu`, with examples. Requires passthrough. By @SupaMaggie70Incorporated in [#7345](https://github.com/gfx-rs/wgpu/pull/7345).
160161

161162
[`GPUError`]: https://www.w3.org/TR/webgpu/#gpuerror
162163

cts_runner/tests/integration.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ impl Display for JsError {
3434

3535
impl Debug for JsError {
3636
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37-
write!(f, "{}", self)
37+
write!(f, "{self}")
3838
}
3939
}
4040

examples/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ These examples use a common framework to handle wgpu init, window creation, and
4343
- `ray_cube_fragment` - Demonstrates using ray queries with a fragment shader.
4444
- `ray_scene` - Demonstrates using ray queries and model loading
4545
- `ray_shadows` - Demonstrates a simple use of ray queries - high quality shadows - uses a light set with push constants to raytrace through an untransformed scene and detect whether there is something obstructing the light.
46+
- `mesh_shader` - Rrenders a triangle to a window with mesh shaders, while showcasing most mesh shader related features(task shaders, payloads, per primitive data).
4647

4748
#### Compute
4849

examples/features/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub mod hello_synchronization;
1313
pub mod hello_triangle;
1414
pub mod hello_windows;
1515
pub mod hello_workgroups;
16+
pub mod mesh_shader;
1617
pub mod mipmap;
1718
pub mod msaa_line;
1819
pub mod multiple_render_targets;

examples/features/src/main.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,12 @@ const EXAMPLES: &[ExampleDesc] = &[
182182
webgl: false, // No Ray-tracing extensions
183183
webgpu: false, // No Ray-tracing extensions (yet)
184184
},
185+
ExampleDesc {
186+
name: "mesh_shader",
187+
function: wgpu_examples::mesh_shader::main,
188+
webgl: false,
189+
webgpu: false,
190+
},
185191
];
186192

187193
fn get_example_name() -> Option<String> {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# mesh_shader
2+
3+
This example renders a triangle to a window with mesh shaders, while showcasing most mesh shader related features(task shaders, payloads, per primitive data).
4+
5+
## To Run
6+
7+
```
8+
cargo run --bin wgpu-examples mesh_shader
9+
```
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
use std::{io::Write, process::Stdio};
2+
3+
// Same as in mesh shader tests
4+
fn 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::SpirV(
28+
wgpu::ShaderModuleDescriptorSpirV {
29+
label: None,
30+
source: wgpu::util::make_spirv_raw(&output.stdout),
31+
},
32+
))
33+
}
34+
}
35+
36+
pub struct Example {
37+
pipeline: wgpu::RenderPipeline,
38+
}
39+
impl 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::SPIRV_SHADER_PASSTHROUGH
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+
140+
pub fn main() {
141+
crate::framework::run::<Example>("mesh_shader");
142+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#version 450
2+
#extension GL_EXT_mesh_shader : require
3+
4+
in VertexInput { layout(location = 0) vec4 color; }
5+
vertexInput;
6+
layout(location = 1) perprimitiveEXT in PrimitiveInput { vec4 colorMask; }
7+
primitiveInput;
8+
9+
layout(location = 0) out vec4 fragColor;
10+
11+
void main() { fragColor = vertexInput.color * primitiveInput.colorMask; }
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#version 450
2+
#extension GL_EXT_mesh_shader : require
3+
4+
const vec4[3] positions = {vec4(0., 1.0, 0., 1.0), vec4(-1.0, -1.0, 0., 1.0),
5+
vec4(1.0, -1.0, 0., 1.0)};
6+
const vec4[3] colors = {vec4(0., 1., 0., 1.), vec4(0., 0., 1., 1.),
7+
vec4(1., 0., 0., 1.)};
8+
9+
// This is an inefficient workgroup size.Ideally the total thread count would be
10+
// a multiple of 64
11+
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
12+
struct PayloadData {
13+
vec4 colorMask;
14+
bool visible;
15+
};
16+
taskPayloadSharedEXT PayloadData payloadData;
17+
18+
out VertexOutput { layout(location = 0) vec4 color; }
19+
vertexOutput[];
20+
layout(location = 1) perprimitiveEXT out PrimitiveOutput { vec4 colorMask; }
21+
primitiveOutput[];
22+
23+
shared uint sharedData;
24+
25+
layout(triangles, max_vertices = 3, max_primitives = 1) out;
26+
void main() {
27+
sharedData = 5;
28+
SetMeshOutputsEXT(3, 1);
29+
gl_MeshVerticesEXT[0].gl_Position = positions[0];
30+
gl_MeshVerticesEXT[1].gl_Position = positions[1];
31+
gl_MeshVerticesEXT[2].gl_Position = positions[2];
32+
vertexOutput[0].color = colors[0] * payloadData.colorMask;
33+
vertexOutput[1].color = colors[1] * payloadData.colorMask;
34+
vertexOutput[2].color = colors[2] * payloadData.colorMask;
35+
gl_PrimitiveTriangleIndicesEXT[gl_LocalInvocationIndex] = uvec3(0, 1, 2);
36+
primitiveOutput[0].colorMask = vec4(1.0, 0.0, 1.0, 1.0);
37+
gl_MeshPrimitivesEXT[0].gl_CullPrimitiveEXT = !payloadData.visible;
38+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#version 450
2+
#extension GL_EXT_mesh_shader : require
3+
4+
layout(local_size_x = 4, local_size_y = 1, local_size_z = 1) in;
5+
6+
struct TaskPayload {
7+
vec4 colorMask;
8+
bool visible;
9+
};
10+
taskPayloadSharedEXT TaskPayload taskPayload;
11+
12+
void main() {
13+
taskPayload.colorMask = vec4(1.0, 1.0, 0.0, 1.0);
14+
taskPayload.visible = true;
15+
EmitMeshTasksEXT(3, 1, 1);
16+
}

0 commit comments

Comments
 (0)