Skip to content

Commit 05cc6dc

Browse files
inner-daemonscwfitzgeraldCopilot
authored
[hal/dx12] Mesh Shaders (#8110)
* Features and draw commands added * Tried to implement the pipeline creation (completely untested) * Fixed clippy issues * Fixed something I think * A little bit of work on the mesh shader example (currently doesn't work on dx12) * Reached a new kind of error state * Fixed an alignment issue * DirectX 12 mesh shaders working :party: * Removed stupid change and updated changelog * Fixed typo * Added backends option to example framework * Removed silly no write fragment shader from tests to see if anything breaks * Tried to make mesh shader tests run elsewhere too * Removed printlns and checked that dx12 mesh shader tests run * Documented very strange issue * I'm so lost * Fixed stupid typos * Fixed all issues * Removed unnecessary example stuff, updated tests * Updated typos.toml * Updated limits * Apply suggestion from @cwfitzgerald Co-authored-by: Connor Fitzgerald <[email protected]> * Apply suggestion from @cwfitzgerald Co-authored-by: Connor Fitzgerald <[email protected]> * Removed supported backends, made example & tests always pass the filename to shader compilers * Removed excessive bools in test params * Added new tests to the list * I'm a sinner for this one (unused import) * Replaced random stuff with test params hashing * Updated typos.toml * Updated -Fo typo thing * Actually fixed typo issue this time * Update CHANGELOG.md Co-authored-by: Connor Fitzgerald <[email protected]> * Update tests/tests/wgpu-gpu/mesh_shader/mod.rs Co-authored-by: Copilot <[email protected]> * Update wgpu-hal/src/dx12/mod.rs Co-authored-by: Connor Fitzgerald <[email protected]> * Addressed comments * Lmao --------- Co-authored-by: Connor Fitzgerald <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent 1f10d0c commit 05cc6dc

File tree

16 files changed

+730
-216
lines changed

16 files changed

+730
-216
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ By @cwfitzgerald in [#8162](https://github.com/gfx-rs/wgpu/pull/8162).
202202
#### DX12
203203

204204
- Allow disabling waiting for latency waitable object. By @marcpabst in [#7400](https://github.com/gfx-rs/wgpu/pull/7400)
205+
- Add mesh shader support, including to the example. By @SupaMaggie70Incorporated in [#8110](https://github.com/gfx-rs/wgpu/issues/8110)
205206

206207
### Bug Fixes
207208

examples/features/src/framework.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,9 @@ impl ExampleContext {
268268
async fn init_async<E: Example>(surface: &mut SurfaceWrapper, window: Arc<Window>) -> Self {
269269
log::info!("Initializing wgpu...");
270270

271-
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::from_env_or_default());
271+
let instance_descriptor = wgpu::InstanceDescriptor::from_env_or_default();
272+
let instance = wgpu::Instance::new(&instance_descriptor);
272273
surface.pre_adapter(&instance, window);
273-
274274
let adapter = get_adapter_with_capabilities_or_from_env(
275275
&instance,
276276
&E::required_features(),

examples/features/src/mesh_shader/mod.rs

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
1-
use std::{io::Write, process::Stdio};
1+
use std::process::Stdio;
22

33
// 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 {
4+
fn compile_glsl(device: &wgpu::Device, shader_stage: &'static str) -> wgpu::ShaderModule {
95
let cmd = std::process::Command::new("glslc")
106
.args([
11-
&format!("-fshader-stage={shader_stage}"),
12-
"-",
7+
&format!(
8+
"{}/src/mesh_shader/shader.{shader_stage}",
9+
env!("CARGO_MANIFEST_DIR")
10+
),
1311
"-o",
1412
"-",
1513
"--target-env=vulkan1.2",
@@ -19,8 +17,6 @@ fn compile_glsl(
1917
.stdout(Stdio::piped())
2018
.spawn()
2119
.expect("Failed to call glslc");
22-
cmd.stdin.as_ref().unwrap().write_all(data).unwrap();
23-
println!("{shader_stage}");
2420
let output = cmd.wait_with_output().expect("Error waiting for glslc");
2521
assert!(output.status.success());
2622
unsafe {
@@ -32,27 +28,69 @@ fn compile_glsl(
3228
})
3329
}
3430
}
31+
fn 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+
}
3563

3664
pub struct Example {
3765
pipeline: wgpu::RenderPipeline,
3866
}
3967
impl crate::framework::Example for Example {
4068
fn init(
4169
config: &wgpu::SurfaceConfiguration,
42-
_adapter: &wgpu::Adapter,
70+
adapter: &wgpu::Adapter,
4371
device: &wgpu::Device,
4472
_queue: &wgpu::Queue,
4573
) -> 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+
};
4689
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
4790
label: None,
4891
bind_group_layouts: &[],
4992
push_constant_ranges: &[],
5093
});
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-
);
5694
let pipeline = device.create_mesh_pipeline(&wgpu::MeshPipelineDescriptor {
5795
label: None,
5896
layout: Some(&pipeline_layout),
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
struct OutVertex {
2+
float4 Position : SV_POSITION;
3+
float4 Color: COLOR;
4+
};
5+
struct OutPrimitive {
6+
float4 ColorMask : COLOR_MASK : PRIMITIVE;
7+
bool CullPrimitive: SV_CullPrimitive;
8+
};
9+
struct InVertex {
10+
float4 Color: COLOR;
11+
};
12+
struct InPrimitive {
13+
float4 ColorMask : COLOR_MASK : PRIMITIVE;
14+
};
15+
struct PayloadData {
16+
float4 ColorMask;
17+
bool Visible;
18+
};
19+
20+
21+
static const float4 positions[3] = {float4(0., 1.0, 0., 1.0), float4(-1.0, -1.0, 0., 1.0), float4(1.0, -1.0, 0., 1.0)};
22+
static const float4 colors[3] = {float4(0., 1., 0., 1.), float4(0., 0., 1., 1.), float4(1., 0., 0., 1.)};
23+
24+
groupshared PayloadData outPayload;
25+
26+
[numthreads(1, 1, 1)]
27+
void Task() {
28+
outPayload.ColorMask = float4(1.0, 1.0, 0.0, 1.0);
29+
outPayload.Visible = true;
30+
DispatchMesh(3, 1, 1, outPayload);
31+
}
32+
33+
[outputtopology("triangle")]
34+
[numthreads(1, 1, 1)]
35+
void Mesh(out indices uint3 triangles[1], out vertices OutVertex vertices[3], out primitives OutPrimitive primitives[1], in payload PayloadData payload) {
36+
SetMeshOutputCounts(3, 1);
37+
38+
vertices[0].Position = positions[0];
39+
vertices[1].Position = positions[1];
40+
vertices[2].Position = positions[2];
41+
42+
vertices[0].Color = colors[0] * payload.ColorMask;
43+
vertices[1].Color = colors[1] * payload.ColorMask;
44+
vertices[2].Color = colors[2] * payload.ColorMask;
45+
46+
triangles[0] = uint3(0, 1, 2);
47+
primitives[0].ColorMask = float4(1.0, 0.0, 0.0, 1.0);
48+
primitives[0].CullPrimitive = !payload.Visible;
49+
}
50+
51+
float4 Frag(InVertex vertex, InPrimitive primitive) : SV_Target {
52+
return vertex.Color * primitive.ColorMask;
53+
}

examples/features/src/mesh_shader/shader.mesh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,18 @@ vertexOutput[];
2020
layout(location = 1) perprimitiveEXT out PrimitiveOutput { vec4 colorMask; }
2121
primitiveOutput[];
2222

23-
shared uint sharedData;
24-
2523
layout(triangles, max_vertices = 3, max_primitives = 1) out;
2624
void main() {
27-
sharedData = 5;
2825
SetMeshOutputsEXT(3, 1);
26+
2927
gl_MeshVerticesEXT[0].gl_Position = positions[0];
3028
gl_MeshVerticesEXT[1].gl_Position = positions[1];
3129
gl_MeshVerticesEXT[2].gl_Position = positions[2];
30+
3231
vertexOutput[0].color = colors[0] * payloadData.colorMask;
3332
vertexOutput[1].color = colors[1] * payloadData.colorMask;
3433
vertexOutput[2].color = colors[2] * payloadData.colorMask;
34+
3535
gl_PrimitiveTriangleIndicesEXT[gl_LocalInvocationIndex] = uvec3(0, 1, 2);
3636
primitiveOutput[0].colorMask = vec4(1.0, 0.0, 1.0, 1.0);
3737
gl_MeshPrimitivesEXT[0].gl_CullPrimitiveEXT = !payloadData.visible;

examples/features/src/mesh_shader/shader.task

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#version 450
22
#extension GL_EXT_mesh_shader : require
33

4-
layout(local_size_x = 4, local_size_y = 1, local_size_z = 1) in;
4+
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
55

66
struct TaskPayload {
77
vec4 colorMask;

naga/src/back/hlsl/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,8 @@ impl crate::ShaderStage {
283283
Self::Vertex => "vs",
284284
Self::Fragment => "ps",
285285
Self::Compute => "cs",
286-
Self::Task | Self::Mesh => unreachable!(),
286+
Self::Task => "as",
287+
Self::Mesh => "ms",
287288
}
288289
}
289290
}

tests/src/run.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::{
1212
GpuTestConfiguration,
1313
};
1414

15+
#[derive(Hash)]
1516
/// Parameters and resources handed to the test function.
1617
pub struct TestingContext {
1718
pub instance: Instance,
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
struct OutVertex {
2+
float4 Position : SV_POSITION;
3+
float4 Color: COLOR;
4+
};
5+
struct InVertex {
6+
float4 Color: COLOR;
7+
};
8+
9+
10+
static const float4 positions[3] = {float4(0., 1.0, 0., 1.0), float4(-1.0, -1.0, 0., 1.0), float4(1.0, -1.0, 0., 1.0)};
11+
static const float4 colors[3] = {float4(0., 1., 0., 1.), float4(0., 0., 1., 1.), float4(1., 0., 0., 1.)};
12+
13+
struct EmptyPayload {
14+
uint _nullField;
15+
};
16+
groupshared EmptyPayload _emptyPayload;
17+
18+
[numthreads(4, 1, 1)]
19+
void Task() {
20+
DispatchMesh(1, 1, 1, _emptyPayload);
21+
}
22+
23+
[outputtopology("triangle")]
24+
[numthreads(1, 1, 1)]
25+
void Mesh(out indices uint3 triangles[1], out vertices OutVertex vertices[3], in payload EmptyPayload _emptyPayload) {
26+
SetMeshOutputCounts(3, 1);
27+
28+
vertices[0].Position = positions[0];
29+
vertices[1].Position = positions[1];
30+
vertices[2].Position = positions[2];
31+
32+
vertices[0].Color = colors[0];
33+
vertices[1].Color = colors[1];
34+
vertices[2].Color = colors[2];
35+
36+
triangles[0] = uint3(0, 1, 2);
37+
}
38+
39+
float4 Frag(InVertex vertex) : SV_Target {
40+
return vertex.Color;
41+
}

0 commit comments

Comments
 (0)