Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
113 commits
Select commit Hold shift + click to select a range
1c90d19
Initial commit
inner-daemons Aug 14, 2025
8c3e550
Other initial changes
inner-daemons Aug 14, 2025
85bbc5a
Updated shader snapshots
inner-daemons Aug 14, 2025
ccf8467
Added new HLSL limitation
inner-daemons Aug 17, 2025
e55c02f
Moved error to global variable error
inner-daemons Aug 17, 2025
f3a31a4
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Aug 17, 2025
0f6da75
Added docs to per_primitive
inner-daemons Aug 20, 2025
3017214
Added a little bit more docs here and there in IR
inner-daemons Aug 20, 2025
19b55b5
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Aug 20, 2025
198437b
Adding validation to ensure that task shaders have a task payload
inner-daemons Aug 20, 2025
64000e4
Updated spec to reflect the change to payload variables
inner-daemons Aug 20, 2025
0575e98
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Aug 22, 2025
b572ec7
Updated the mesh shading spec because it was goofy
inner-daemons Aug 24, 2025
34d0411
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Aug 24, 2025
02664e4
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Aug 24, 2025
7bec4dd
some doc tweaks
jimblandy Aug 25, 2025
2fcb853
Tried to clarify docs a little
inner-daemons Aug 25, 2025
3009b5a
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Aug 25, 2025
8bfe106
Tried to update spec
inner-daemons Aug 25, 2025
6ccaeec
Removed a warning
inner-daemons Aug 25, 2025
5b7ba11
Addressed comment about docs mistake
inner-daemons Aug 25, 2025
29c6972
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Aug 30, 2025
63fa8b5
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Sep 1, 2025
26c8681
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Sep 4, 2025
d9cac9c
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Sep 5, 2025
c112cb4
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Sep 8, 2025
e1ff67d
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Sep 11, 2025
64644f7
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Sep 15, 2025
739948b
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Sep 22, 2025
7ca25a4
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Sep 24, 2025
09ddbec
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Oct 1, 2025
2d6a647
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Oct 2, 2025
4657646
Review in progress
jimblandy Sep 2, 2025
41b654c
mesh_shading.md: more tweaks
jimblandy Oct 2, 2025
33ed0a6
Ran cargo fmt
inner-daemons Oct 2, 2025
53ecb39
Small tweaks
inner-daemons Oct 2, 2025
0ead329
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Oct 11, 2025
07bfb1f
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Oct 13, 2025
ba51fa2
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Oct 15, 2025
c4e3eef
[naga] Move definition of `ShaderStage::compute_like` to `proc`.
jimblandy Oct 15, 2025
8c9287d
Replace TODO comment with followup issue.
jimblandy Oct 16, 2025
8f04d4f
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Oct 16, 2025
3a8399d
Update analyzer.rs
inner-daemons Oct 16, 2025
879b79b
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Oct 16, 2025
d92fe67
Removed stuff in accordance with Jim's recommendation
inner-daemons Oct 16, 2025
2dc4090
minor changes for readability
jimblandy Oct 16, 2025
1ec734b
Pull mesh shader output type validation out into its own function.
jimblandy Oct 16, 2025
9ef0ed5
doc fixes
jimblandy Oct 16, 2025
1173b0f
remove duplicated task payload validation
jimblandy Oct 16, 2025
258e7e6
Quick little changes
inner-daemons Oct 16, 2025
8885c5d
Another quick fix
inner-daemons Oct 16, 2025
1cc3e85
Quick fix
inner-daemons Oct 16, 2025
3be2c25
Removed unnecessary TODO statement
inner-daemons Oct 16, 2025
21d3cc7
A
inner-daemons Oct 16, 2025
d5c11d3
Tried to be more expressive
inner-daemons Oct 16, 2025
82ec9c2
Merge branch 'trunk' into mesh-shading/naga-ir
inner-daemons Oct 16, 2025
e7faff6
Made functions only work in mesh shader entry points
inner-daemons Oct 17, 2025
385535a
Various validation fix attempts
inner-daemons Oct 17, 2025
c3f9acd
Undid capabilities resize
inner-daemons Oct 17, 2025
d15ba19
WGSL PR is up :)
inner-daemons Oct 17, 2025
f14e0f0
Update naga/src/ir/mod.rs
inner-daemons Oct 17, 2025
7e12d30
Update naga/src/front/wgsl/error.rs
inner-daemons Oct 17, 2025
ce517bb
Update naga/src/ir/mod.rs
inner-daemons Oct 17, 2025
083959e
Other Erich suggestion
inner-daemons Oct 17, 2025
16aa7d0
Updated docs & validation for some builtins
inner-daemons Oct 17, 2025
76bfca0
Added some docs & removed contentious "// TODO"
inner-daemons Oct 17, 2025
e68d0d2
Merge branch 'trunk' into mesh-shading/wgsl-parse
inner-daemons Oct 22, 2025
0fd0fdd
Merge remote-tracking branch 'upstream/trunk' into mesh-shading/wgsl-…
inner-daemons Oct 30, 2025
e100034
Fixed bad validation, formatted mesh shader wgsl
inner-daemons Oct 30, 2025
edea07e
Rewrote the IR and parser significantly
inner-daemons Oct 31, 2025
3905ae8
Improved validation slightly, remvoed obselete crap, fixed bug in com…
inner-daemons Oct 31, 2025
8f6332d
Merge remote-tracking branch 'upstream/trunk' into mesh-shading/wgsl-…
inner-daemons Oct 31, 2025
64798dd
Added changelog entry
inner-daemons Nov 1, 2025
c8dccd3
Merge branch 'trunk' into mesh-shading/wgsl-parse
inner-daemons Nov 3, 2025
bd923cd
Made parser respect enable extension
inner-daemons Nov 3, 2025
d95070a
Updated mesh shader spec
inner-daemons Nov 3, 2025
ace7e17
Cleaned up the mesh shader analyzer function
inner-daemons Nov 3, 2025
f55dbd9
Merge branch 'trunk' into mesh-shading/wgsl-parse
inner-daemons Nov 5, 2025
5bd8385
Initial Commit
Slightlyclueless Nov 5, 2025
3de9940
cargo fmt
Slightlyclueless Nov 5, 2025
8fd04d4
Yeet unused import
Slightlyclueless Nov 5, 2025
3b7ad04
I Forgor
Slightlyclueless Nov 5, 2025
74ba2fc
Fix merge conflicts
Slightlyclueless Nov 5, 2025
d69df5e
Fix per primitive stuff
Slightlyclueless Nov 6, 2025
b797538
Add task payload storage class
Slightlyclueless Nov 6, 2025
e5438e3
Change snapshot
Slightlyclueless Nov 9, 2025
694a188
Write the mesh output variable, in quite possibly the laziest way
Slightlyclueless Nov 16, 2025
c131238
Correct feature detection. I hope...
Slightlyclueless Nov 16, 2025
250ae47
Merge branch 'trunk' into naga-mesh-wgpu-writer
Slightlyclueless Nov 16, 2025
9d78bc5
setting the variable got dropped in merge conflicts...
Slightlyclueless Nov 17, 2025
03445d2
Commit snapshots
Slightlyclueless Nov 17, 2025
f0b9a9e
Add space to mesh stage output attr
Slightlyclueless Nov 17, 2025
e19131d
Didn't need to change that
Slightlyclueless Nov 17, 2025
a1008bf
Chage to pushing to mutable vecs instead of clunky if-else blocks
Slightlyclueless Nov 17, 2025
93d051a
Change TOMLs
Slightlyclueless Nov 17, 2025
fdb3abb
Change feature name
Slightlyclueless Nov 17, 2025
c3522c4
Custom WGSL attribute for Mesh Stage
Slightlyclueless Nov 17, 2025
7ef6a46
Delete random newline
Slightlyclueless Nov 17, 2025
6be03c5
Cargo FMT
Slightlyclueless Nov 17, 2025
8f23552
cargo xtask test output
Slightlyclueless Nov 17, 2025
acf055f
Change mesh shader feature name
Slightlyclueless Nov 27, 2025
ade61e9
Remove shader stage check, it's no longer needed
Slightlyclueless Nov 27, 2025
c445f71
Revert "Cargo FMT"
Slightlyclueless Nov 27, 2025
c9c9910
cargo xtask test
Slightlyclueless Nov 27, 2025
42465ae
Missed these two builtins
Slightlyclueless Nov 27, 2025
95b8923
Cargo Xtask Test
Slightlyclueless Nov 27, 2025
dfd5f9d
cargo + taplo format
Slightlyclueless Nov 27, 2025
78aeb58
Taplo format, but for real this time
Slightlyclueless Nov 27, 2025
cdf5ddf
Add task var checking
Slightlyclueless Nov 27, 2025
cef35d2
redo how imported
Slightlyclueless Nov 27, 2025
f2ee2ec
Change to unreachable
Slightlyclueless Nov 27, 2025
86d75b0
Give Builtins a sensible order
Slightlyclueless Nov 27, 2025
b236293
Changelog entry
Slightlyclueless Nov 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ By @SupaMaggie70Incorporated in [#8206](https://github.com/gfx-rs/wgpu/pull/8206
- The `STORAGE_READ_ONLY` texture usage is now permitted to coexist with other read-only usages. By @andyleiserson in [#8490](https://github.com/gfx-rs/wgpu/pull/8490).
- Validate that buffers are unmapped in `write_buffer` calls. By @ErichDonGubler in [#8454](https://github.com/gfx-rs/wgpu/pull/8454).
- Add WGSL parsing for mesh shaders. By @inner-daemons in [#8370](https://github.com/gfx-rs/wgpu/pull/8370).
- Add WGSL writing for mesh shaders. By @Slightlyclueless [#8481](https://github.com/gfx-rs/wgpu/pull/8481).

#### DX12

Expand Down
120 changes: 106 additions & 14 deletions naga/src/back/wgsl/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ enum Attribute {
BlendSrc(u32),
Stage(ShaderStage),
WorkGroupSize([u32; 3]),
MeshStage(String),
TaskPayload(String),
PerPrimitive,
}

/// The WGSL form that `write_expr_with_indirection` should use to render a Naga
Expand Down Expand Up @@ -207,9 +210,37 @@ impl<W: Write> Writer<W> {
Attribute::Stage(ShaderStage::Compute),
Attribute::WorkGroupSize(ep.workgroup_size),
],
ShaderStage::Mesh | ShaderStage::Task => unreachable!(),
ShaderStage::Mesh => {
let mesh_output_name = module.global_variables
[ep.mesh_info.as_ref().unwrap().output_variable]
.name
.clone()
.unwrap();
let mut mesh_attrs = vec![
Attribute::MeshStage(mesh_output_name),
Attribute::WorkGroupSize(ep.workgroup_size),
];
if ep.task_payload.is_some() {
let payload_name = module.global_variables[ep.task_payload.unwrap()]
.name
.clone()
.unwrap();
mesh_attrs.push(Attribute::TaskPayload(payload_name));
}
mesh_attrs
}
ShaderStage::Task => {
let payload_name = module.global_variables[ep.task_payload.unwrap()]
.name
.clone()
.unwrap();
vec![
Attribute::Stage(ShaderStage::Task),
Attribute::TaskPayload(payload_name),
Attribute::WorkGroupSize(ep.workgroup_size),
]
}
};

self.write_attributes(&attributes)?;
// Add a newline after attribute
writeln!(self.out)?;
Expand Down Expand Up @@ -243,6 +274,7 @@ impl<W: Write> Writer<W> {
let mut needs_f16 = false;
let mut needs_dual_source_blending = false;
let mut needs_clip_distances = false;
let mut needs_mesh_shaders = false;

// Determine which `enable` declarations are needed
for (_, ty) in module.types.iter() {
Expand All @@ -263,6 +295,25 @@ impl<W: Write> Writer<W> {
crate::Binding::BuiltIn(crate::BuiltIn::ClipDistance) => {
needs_clip_distances = true;
}
crate::Binding::Location {
per_primitive: true,
..
} => {
needs_mesh_shaders = true;
}
crate::Binding::BuiltIn(
crate::BuiltIn::MeshTaskSize
| crate::BuiltIn::CullPrimitive
| crate::BuiltIn::PointIndex
| crate::BuiltIn::LineIndices
| crate::BuiltIn::TriangleIndices
| crate::BuiltIn::VertexCount
| crate::BuiltIn::Vertices
| crate::BuiltIn::PrimitiveCount
| crate::BuiltIn::Primitives,
) => {
needs_mesh_shaders = true;
}
_ => {}
}
}
Expand All @@ -271,6 +322,22 @@ impl<W: Write> Writer<W> {
}
}

if module
.entry_points
.iter()
.any(|ep| matches!(ep.stage, ShaderStage::Mesh | ShaderStage::Task))
{
needs_mesh_shaders = true;
}

if module
.global_variables
.iter()
.any(|gv| gv.1.space == crate::AddressSpace::TaskPayload)
{
needs_mesh_shaders = true;
}
Comment on lines +333 to +339
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good stuff

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😄 I literally wrote that about 5 minutes before rushing out the door to go to work, was surprised it even compiled


// Write required declarations
let mut any_written = false;
if needs_f16 {
Expand All @@ -285,6 +352,10 @@ impl<W: Write> Writer<W> {
writeln!(self.out, "enable clip_distances;")?;
any_written = true;
}
if needs_mesh_shaders {
writeln!(self.out, "enable wgpu_mesh_shader;")?;
any_written = true;
}
if any_written {
// Empty line for readability
writeln!(self.out)?;
Expand Down Expand Up @@ -403,8 +474,10 @@ impl<W: Write> Writer<W> {
ShaderStage::Vertex => "vertex",
ShaderStage::Fragment => "fragment",
ShaderStage::Compute => "compute",
ShaderStage::Task | ShaderStage::Mesh => unreachable!(),
ShaderStage::Task => "task",
ShaderStage::Mesh => unreachable!(),
};

write!(self.out, "@{stage_str} ")?;
}
Attribute::WorkGroupSize(size) => {
Expand Down Expand Up @@ -433,6 +506,13 @@ impl<W: Write> Writer<W> {
write!(self.out, "@interpolate({interpolation}) ")?;
}
}
Attribute::MeshStage(ref name) => {
write!(self.out, "@mesh({name}) ")?;
}
Attribute::TaskPayload(ref payload_name) => {
write!(self.out, "@payload({payload_name}) ")?;
}
Attribute::PerPrimitive => write!(self.out, "@per_primitive ")?,
};
}
Ok(())
Expand Down Expand Up @@ -1822,21 +1902,33 @@ fn map_binding_to_attribute(binding: &crate::Binding) -> Vec<Attribute> {
interpolation,
sampling,
blend_src: None,
per_primitive: _,
} => vec![
Attribute::Location(location),
Attribute::Interpolate(interpolation, sampling),
],
per_primitive,
} => {
let mut attrs = vec![
Attribute::Location(location),
Attribute::Interpolate(interpolation, sampling),
];
if per_primitive {
attrs.push(Attribute::PerPrimitive);
}
attrs
}
crate::Binding::Location {
location,
interpolation,
sampling,
blend_src: Some(blend_src),
per_primitive: _,
} => vec![
Attribute::Location(location),
Attribute::BlendSrc(blend_src),
Attribute::Interpolate(interpolation, sampling),
],
per_primitive,
} => {
let mut attrs = vec![
Attribute::Location(location),
Attribute::BlendSrc(blend_src),
Attribute::Interpolate(interpolation, sampling),
];
if per_primitive {
attrs.push(Attribute::PerPrimitive);
}
attrs
}
}
}
23 changes: 12 additions & 11 deletions naga/src/common/wgsl/to_wgsl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,22 +183,23 @@ impl TryToWgsl for crate::BuiltIn {
Bi::SubgroupInvocationId => "subgroup_invocation_id",

// Non-standard built-ins.
Bi::MeshTaskSize => "mesh_task_size",
Bi::TriangleIndices => "triangle_indices",
Bi::LineIndices => "line_indices",
Bi::PointIndex => "point_index",
Bi::Vertices => "vertices",
Bi::Primitives => "primitives",
Bi::VertexCount => "vertex_count",
Bi::PrimitiveCount => "primitive_count",
Bi::CullPrimitive => "cull_primitive",

Bi::BaseInstance
| Bi::BaseVertex
| Bi::CullDistance
| Bi::PointSize
| Bi::DrawID
| Bi::PointCoord
| Bi::WorkGroupSize
| Bi::CullPrimitive
| Bi::TriangleIndices
| Bi::LineIndices
| Bi::MeshTaskSize
| Bi::PointIndex
| Bi::VertexCount
| Bi::PrimitiveCount
| Bi::Vertices
| Bi::Primitives => return None,
| Bi::WorkGroupSize => return None,
})
}
}
Expand Down Expand Up @@ -362,7 +363,7 @@ pub const fn address_space_str(
As::WorkGroup => "workgroup",
As::Handle => return (None, None),
As::Function => "function",
As::TaskPayload => return (None, None),
As::TaskPayload => "task_payload",
}),
None,
)
Expand Down
2 changes: 1 addition & 1 deletion naga/tests/in/wgsl/mesh-shader-empty.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
god_mode = true
targets = "IR | ANALYSIS"
targets = "IR | ANALYSIS | WGSL"
2 changes: 1 addition & 1 deletion naga/tests/in/wgsl/mesh-shader-lines.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
god_mode = true
targets = "IR | ANALYSIS"
targets = "IR | ANALYSIS | WGSL"
2 changes: 1 addition & 1 deletion naga/tests/in/wgsl/mesh-shader-points.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
god_mode = true
targets = "IR | ANALYSIS"
targets = "IR | ANALYSIS | WGSL"
2 changes: 1 addition & 1 deletion naga/tests/in/wgsl/mesh-shader.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
god_mode = true
targets = "IR | ANALYSIS"
targets = "IR | ANALYSIS | WGSL"
33 changes: 33 additions & 0 deletions naga/tests/out/wgsl/wgsl-mesh-shader-empty.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
enable wgpu_mesh_shader;

struct TaskPayload {
dummy: u32,
}

struct VertexOutput {
@builtin(position) position: vec4<f32>,
}

struct PrimitiveOutput {
@builtin(triangle_indices) indices: vec3<u32>,
}

struct MeshOutput {
@builtin(vertices) vertices: array<VertexOutput, 3>,
@builtin(primitives) primitives: array<PrimitiveOutput, 1>,
@builtin(vertex_count) vertex_count: u32,
@builtin(primitive_count) primitive_count: u32,
}

var<task_payload> taskPayload: TaskPayload;
var<workgroup> mesh_output: MeshOutput;

@task @payload(taskPayload) @workgroup_size(1, 1, 1)
fn ts_main() -> @builtin(mesh_task_size) vec3<u32> {
return vec3<u32>(1u, 1u, 1u);
}

@mesh(mesh_output) @workgroup_size(1, 1, 1) @payload(taskPayload)
fn ms_main() {
return;
}
33 changes: 33 additions & 0 deletions naga/tests/out/wgsl/wgsl-mesh-shader-lines.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
enable wgpu_mesh_shader;

struct TaskPayload {
dummy: u32,
}

struct VertexOutput {
@builtin(position) position: vec4<f32>,
}

struct PrimitiveOutput {
@builtin(line_indices) indices: vec2<u32>,
}

struct MeshOutput {
@builtin(vertices) vertices: array<VertexOutput, 2>,
@builtin(primitives) primitives: array<PrimitiveOutput, 1>,
@builtin(vertex_count) vertex_count: u32,
@builtin(primitive_count) primitive_count: u32,
}

var<task_payload> taskPayload: TaskPayload;
var<workgroup> mesh_output: MeshOutput;

@task @payload(taskPayload) @workgroup_size(1, 1, 1)
fn ts_main() -> @builtin(mesh_task_size) vec3<u32> {
return vec3<u32>(1u, 1u, 1u);
}

@mesh(mesh_output) @workgroup_size(1, 1, 1) @payload(taskPayload)
fn ms_main() {
return;
}
33 changes: 33 additions & 0 deletions naga/tests/out/wgsl/wgsl-mesh-shader-points.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
enable wgpu_mesh_shader;

struct TaskPayload {
dummy: u32,
}

struct VertexOutput {
@builtin(position) position: vec4<f32>,
}

struct PrimitiveOutput {
@builtin(point_index) indices: u32,
}

struct MeshOutput {
@builtin(vertices) vertices: array<VertexOutput, 1>,
@builtin(primitives) primitives: array<PrimitiveOutput, 1>,
@builtin(vertex_count) vertex_count: u32,
@builtin(primitive_count) primitive_count: u32,
}

var<task_payload> taskPayload: TaskPayload;
var<workgroup> mesh_output: MeshOutput;

@task @payload(taskPayload) @workgroup_size(1, 1, 1)
fn ts_main() -> @builtin(mesh_task_size) vec3<u32> {
return vec3<u32>(1u, 1u, 1u);
}

@mesh(mesh_output) @workgroup_size(1, 1, 1) @payload(taskPayload)
fn ms_main() {
return;
}
Loading
Loading