Skip to content

Conversation

@Slightlyclueless
Copy link

@Slightlyclueless Slightlyclueless commented Nov 5, 2025

Connections
Based off of #8370

Description

Adds a WGSL writer for mesh shader functionality.

Testing
TODO

Squash or Rebase?
Squash

Checklist

  • Run cargo fmt.
  • Run taplo format.
  • Run cargo clippy --tests. If applicable, add:
    • --target wasm32-unknown-unknown
  • Run cargo xtask test to run tests.
  • If this contains user-facing changes, add a CHANGELOG.md entry.

inner-daemons and others added 30 commits August 14, 2025 12:53
@Slightlyclueless
Copy link
Author

All changes are in naga/src/back/wgsl/writer.rs and naga/src/back/wgsl/to_wgsl.rs. Code is ugly and I absolutely want to clean it up before I mark as ready to merge

Dunno what's up with the PR history lol.

@inner-daemons
Copy link
Collaborator

inner-daemons commented Nov 6, 2025

First comments

  • Logic to detect mesh shader logic is incorrect. You also need to check for mesh shader builtins, per primitive attributes anywhere, task payload variables. This is because files might contain types/data that isn't used in any shaders
  • The generated task payload variable doesn't have a storage class
  • I don't understand why the shader stage, workgroup size, task payload come in different orders between mesh and task shaders
  • Mesh thing doesn't have the variable it needs (@mesh(variable))
  • Per primitive isn't written correctly
  • You will want to make sure that the snapshot is correctly written

@inner-daemons inner-daemons self-assigned this Nov 6, 2025
@inner-daemons inner-daemons mentioned this pull request Nov 6, 2025
36 tasks
@Slightlyclueless
Copy link
Author

Slightlyclueless commented Nov 6, 2025

Logic to detect mesh shader logic is incorrect. You also need to check for mesh shader builtins, per primitive attributes anywhere, task payload variables. This is because files might contain types/data that isn't used in any shaders

I though so, but wasn't sure. Will change,

The generated task payload variable doesn't have a storage class

Ah yep, not sure how I missed that one.

I don't understand why the shader stage, workgroup size, task payload come in different orders between mesh and task shaders

Because I am a clutz, and didn't sanity check that after going "Yay it no longer crashes".

Mesh thing doesn't have the variable it needs (@mesh(variable))

Whoops, that's what I get for not looking at the correct spec document.

Per primitive isn't written correctly

Not sure what you mean by this?

You will want to make sure that the snapshot is correctly written

Again, not sure what you mean. I may just be being a bit thick though

@inner-daemons
Copy link
Collaborator

For the snapshot, you will want to go to naga/tests/in/wgsl/mesh-shader.toml and change to this line
targets = "IR | ANALYSIS | WGSL"

Then run cargo xtask test snapshot before every commit. Snapshots are how WGPU tracks how shaders are written between commits, and how we check that naga continues to work on many shaders.

@inner-daemons inner-daemons mentioned this pull request Nov 10, 2025
6 tasks
@inner-daemons inner-daemons self-requested a review November 16, 2025 23:48
Copy link
Collaborator

@inner-daemons inner-daemons left a comment

Choose a reason for hiding this comment

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

Generally pretty good, some comments. Also please format your code and make sure that CI passes. At the bottom of the github page it'll say stuff like "CI / Test Linux x86_64 (pull_request) Failing after 4m", you can usually figure out the error by reading through these logs

if shader_stage == ShaderStage::Mesh {
write!(
self.out,
"@{stage_str}({})",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
"@{stage_str}({})",
"@{stage_str}({}) ",

Comment on lines +5 to +19

[msl]
fake_missing_bindings = true
lang_version = [2, 4]
spirv_cross_compatibility = false
zero_initialize_workgroup_memory = false

[hlsl]
shader_model = "V6_5"
fake_missing_bindings = true
zero_initialize_workgroup_memory = true

[spv]
version = [1, 4]
capabilities = ["MeshShadingEXT"]
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
[msl]
fake_missing_bindings = true
lang_version = [2, 4]
spirv_cross_compatibility = false
zero_initialize_workgroup_memory = false
[hlsl]
shader_model = "V6_5"
fake_missing_bindings = true
zero_initialize_workgroup_memory = true
[spv]
version = [1, 4]
capabilities = ["MeshShadingEXT"]

Comment on lines +1 to +2
# Stolen from ray-query.toml

Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
# Stolen from ray-query.toml


god_mode = true
targets = "IR | ANALYSIS"
targets = "IR | ANALYSIS | WGSL"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you apply this change to the other files here, like mesh-shader-lines.toml etc

let det = (m[0][0] * adj[0][0] + m[0][1] * adj[1][0] + m[0][2] * adj[2][0] + m[0][3] * adj[3][0]);

return adj * (1 / det);
fn _naga_inverse_4x4_f32(m: mat4x4<f32>) -> mat4x4<f32> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you undo this? You can just run git checkout trunk -- naga/tests/out/wgsl/glsl-inverse-pollyfill.frag.wgsl

Unsure if this is due to changing the tabs to spaces/vice versa or due to line endings, I suspect the first

fn write_attributes(
&mut self,
attributes: &[Attribute],
mesh_output_variable: Option<String>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Lets not have this as another args, can you change the mesh stage attribute to being a special enum variant with this?

Comment on lines +1936 to +1949
if per_primitive {
vec![
Attribute::PerPrimitive,
Attribute::Location(location),
Attribute::BlendSrc(blend_src),
Attribute::Interpolate(interpolation, sampling),
]
} else {
vec![
Attribute::Location(location),
Attribute::BlendSrc(blend_src),
Attribute::Interpolate(interpolation, sampling),
]
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Lets try to just have one vector, and add an extra PerPrimitive element to it if needed

Comment on lines 201 to +202
| Bi::LineIndices
| Bi::MeshTaskSize
| Bi::PointIndex
| Bi::VertexCount
| Bi::PrimitiveCount
| Bi::Vertices
| Bi::Primitives => return None,
| Bi::PointIndex => return None,
Copy link
Collaborator

Choose a reason for hiding this comment

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

These should also be written, just like TriangleIndices

Comment on lines +1916 to +1927
if per_primitive {
vec![
Attribute::PerPrimitive,
Attribute::Location(location),
Attribute::Interpolate(interpolation, sampling),
]
} else {
vec![
Attribute::Location(location),
Attribute::Interpolate(interpolation, sampling),
]
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Lets try to just have one vector, and add an extra PerPrimitive element to it if needed

Comment on lines +220 to +235
if ep.task_payload.is_some() {
let payload_name = module.global_variables[ep.task_payload.unwrap()]
.name
.clone()
.unwrap();
vec![
Attribute::Stage(ShaderStage::Mesh),
Attribute::MeshTaskPayload(payload_name),
Attribute::WorkGroupSize(ep.workgroup_size),
]
} else {
vec![
Attribute::Stage(ShaderStage::Mesh),
Attribute::WorkGroupSize(ep.workgroup_size),
]
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Lets try to just have one vector, and add an extra TaskPayload element to it if needed

@inner-daemons
Copy link
Collaborator

inner-daemons commented Nov 17, 2025

Also feel free to mark this as no longer a draft

And just to manage expectations, this probably won't be merged until at least the 26th, as I don't have the power to do that so it'll have to have a second review (hopefully with fewer comments)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants