Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
f038e59
rt pipelines in naga IR (w/ partial validation).
Vecvec Nov 16, 2025
ec60bfa
WGSL in
Vecvec Nov 23, 2025
08925f2
add and rerun snapshots
Vecvec Nov 23, 2025
780f1a9
add to rt spec
Vecvec Nov 24, 2025
d8c62a6
Attempt to fix ci
Vecvec Nov 25, 2025
50e9936
satisfy taplo
Vecvec Nov 25, 2025
263c0f2
Fix typo
Vecvec Nov 25, 2025
9139d15
2nd typo
Vecvec Nov 25, 2025
e6b000a
Format from typo fixes
Vecvec Nov 25, 2025
af57d7c
Merge branch 'trunk' into naga-ray-tracing-pipelines
Vecvec Nov 25, 2025
bee83af
Add tests (plus some spots that had incorrect errors)
Vecvec Nov 26, 2025
ee8883c
Fix test broken by allowing 2 caps
Vecvec Nov 26, 2025
d4574d5
Apply suggestions
Vecvec Nov 27, 2025
fc50128
Allow some previously available builtins
Vecvec Nov 27, 2025
c72f643
Merge branch 'trunk' into naga-ray-tracing-pipelines
Vecvec Nov 27, 2025
04eaa66
Merge branch 'trunk' into naga-ray-tracing-pipelines
Vecvec Nov 27, 2025
ec1c25b
Changelog
Vecvec Nov 28, 2025
e06b382
Merge remote-tracking branch 'gfx-rs/trunk' into naga-ray-tracing-pip…
Vecvec Nov 30, 2025
7ecef07
Fix merge
Vecvec Nov 30, 2025
caf72db
Merge remote-tracking branch 'gfx-rs/trunk' into naga-ray-tracing-pip…
Vecvec Dec 3, 2025
3e1dd6f
Merge branch 'trunk' into naga-ray-tracing-pipelines
Vecvec Dec 3, 2025
fd5e909
Merge branch 'trunk' into naga-ray-tracing-pipelines
Vecvec Dec 7, 2025
08fba0e
Merge remote-tracking branch 'trunk/trunk' into naga-ray-tracing-pipe…
Vecvec Dec 13, 2025
5184979
update error message
Vecvec Dec 13, 2025
0d653d5
update wgsl_errors
Vecvec Dec 13, 2025
90dcea3
update error message in tests
Vecvec Dec 13, 2025
282c090
format
Vecvec Dec 13, 2025
a2fdffd
Update flags
Vecvec Dec 16, 2025
edcee6d
Merge branch 'trunk' into naga-ray-tracing-pipelines
Vecvec Dec 16, 2025
790858d
Merge remote-tracking branch 'trunk/trunk' into naga-ray-tracing-pipe…
Vecvec Dec 18, 2025
347a636
Fix changelog
Vecvec Dec 18, 2025
959764d
Fix formatting
Vecvec Dec 18, 2025
3345efc
Merge branch 'trunk' into naga-ray-tracing-pipelines
Vecvec Dec 19, 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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ Bottom level categories:

## Unreleased

### New Features

- Initial wgsl-in ray tracing pipelines. By @Vecvec in [#8570](https://github.com/gfx-rs/wgpu/pull/8570).

## v28.0.0 (2025-12-17)

### Major Changes
Expand Down
43 changes: 39 additions & 4 deletions docs/api-specs/ray_tracing.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,12 @@ fn render(/*whatever args you need to render*/) {

## `naga`'s raytracing API:

`naga` supports ray queries (also known as inline raytracing) only. To enable basic ray query functions you must add
`naga` supports ray queries (also known as inline raytracing). To enable basic ray query functions you must add
`enable wgpu_ray_query` to the shader, ray queries and acceleration structures also support tags which require extra
`enable` extensions (see Acceleration structure tags for more info). Ray tracing pipelines
are currently unsupported. Naming is mostly taken from vulkan.
`enable` extensions (see Acceleration structure tags for more info). Ray tracing pipelines are currently in
development. Naming is mostly taken from vulkan.

### Ray Queries

```wgsl
// - Initializes the `ray_query` to check where (if anywhere) the ray defined by `ray_desc` hits in `acceleration_structure`
Expand Down Expand Up @@ -148,7 +150,7 @@ getCandidateHitVertexPositions(rq: ptr<function, ray_query<vertex_return>>) -> a

> [!CAUTION]
>
> ### ⚠️Undefined behavior ⚠️:
> #### ⚠️Undefined behavior ⚠️:
> - Calling `rayQueryGetCommittedIntersection` or `rayQueryGetCandidateIntersection` when `rayQueryProceed` has not been
> called on this ray query since it was initialized (or if the ray query has not been previously initialized).
> - Calling `rayQueryGetCommittedIntersection` when `rayQueryProceed`'s latest return on this ray query is considered
Expand Down Expand Up @@ -272,6 +274,39 @@ const RAY_QUERY_INTERSECTION_GENERATED = 2;
const RAY_QUERY_INTERSECTION_AABB = 3;
```

### Ray Tracing Pipelines

Functions
```wgsl
// Begins to check where (if anywhere) the ray defined by `ray_desc` hits in `acceleration_structure` calling through the `any_hit` shaders and `closest_hit` shader if something was hit or the `miss` shader if no hit was found
traceRay<T>(acceleration_structure: acceleration_structure, ray_desc: RayDesc, payload: ptr<ray_payload, T>)
```

> [!CAUTION]
>
> #### ⚠️Undefined behavior ⚠️:
> Calling `traceRay` inside another `traceRay` more than `max_recursion_depth` times
>
> *this is only known undefined behaviour, and will be worked around in the future.

New shader stages
```wgsl
// First stage to be called, allowed to call `traceRay`
@ray_generation
fn rg() {}

// Stage called on any hit that is not opaque, not allowed to call `traceRay`
@any_hit
fn ah() {}

// Stage called on the closest hit, allowed to call `traceRay`
@closest_hit
fn ch() {}

// Stage call if there was never a hit, allowed to call `traceRay`
@miss
fn miss() {}
```
### Acceleration structure tags

These are tags that can be added to a acceleration structure (`acceleration_structure` ->
Expand Down
16 changes: 16 additions & 0 deletions naga/src/back/dot/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,22 @@ impl StatementGraph {
},
}
}
S::RayPipelineFunction(func) => match func {
crate::RayPipelineFunction::TraceRay {
acceleration_structure,
descriptor,
payload,
} => {
self.dependencies.push((
id,
acceleration_structure,
"acceleration_structure",
));
self.dependencies.push((id, descriptor, "descriptor"));
self.dependencies.push((id, payload, "payload"));
"TraceRay"
}
},
};
// Set the last node to the merge node
last_node = merge_id;
Expand Down
17 changes: 15 additions & 2 deletions naga/src/back/glsl/conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,20 @@ pub(in crate::back::glsl) const fn glsl_built_in(
| Bi::VertexCount
| Bi::PrimitiveCount
| Bi::Vertices
| Bi::Primitives => {
| Bi::Primitives
| Bi::RayInvocationId
| Bi::NumRayInvocations
| Bi::InstanceCustomData
| Bi::GeometryIndex
| Bi::WorldRayOrigin
| Bi::WorldRayDirection
| Bi::ObjectRayOrigin
| Bi::ObjectRayDirection
| Bi::RayTmin
| Bi::RayTCurrentMax
| Bi::ObjectToWorld
| Bi::WorldToObject
| Bi::HitKind => {
unimplemented!()
}
}
Expand All @@ -145,7 +158,7 @@ pub(in crate::back::glsl) const fn glsl_storage_qualifier(
As::Handle => Some("uniform"),
As::WorkGroup => Some("shared"),
As::Immediate => Some("uniform"),
As::TaskPayload => unreachable!(),
As::TaskPayload | As::RayPayload | As::IncomingRayPayload => unreachable!(),
}
}

Expand Down
21 changes: 19 additions & 2 deletions naga/src/back/glsl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ impl crate::AddressSpace {
| crate::AddressSpace::Handle
| crate::AddressSpace::Immediate
| crate::AddressSpace::TaskPayload => false,

crate::AddressSpace::RayPayload | crate::AddressSpace::IncomingRayPayload => {
unreachable!()
}
}
}
}
Expand Down Expand Up @@ -510,7 +514,15 @@ impl fmt::Display for VaryingName<'_> {
(ShaderStage::Vertex, true) | (ShaderStage::Fragment, false) => "vs2fs",
// fragment to pipeline
(ShaderStage::Fragment, true) => "fs2p",
(ShaderStage::Task | ShaderStage::Mesh, _) => unreachable!(),
(
ShaderStage::Task
| ShaderStage::Mesh
| ShaderStage::RayGeneration
| ShaderStage::AnyHit
| ShaderStage::ClosestHit
| ShaderStage::Miss,
_,
) => unreachable!(),
};
write!(f, "_{prefix}_location{location}",)
}
Expand All @@ -527,7 +539,12 @@ impl ShaderStage {
ShaderStage::Compute => "cs",
ShaderStage::Fragment => "fs",
ShaderStage::Vertex => "vs",
ShaderStage::Task | ShaderStage::Mesh => unreachable!(),
ShaderStage::Task
| ShaderStage::Mesh
| ShaderStage::RayGeneration
| ShaderStage::AnyHit
| ShaderStage::ClosestHit
| ShaderStage::Miss => unreachable!(),
}
}
}
Expand Down
12 changes: 11 additions & 1 deletion naga/src/back/glsl/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,10 @@ impl<'a, W: Write> Writer<'a, W> {
crate::AddressSpace::Function => unreachable!(),
// Textures and samplers are handled directly in `Writer::write`.
crate::AddressSpace::Handle => unreachable!(),
// ray tracing pipelines unsupported
crate::AddressSpace::RayPayload | crate::AddressSpace::IncomingRayPayload => {
unreachable!()
}
}

Ok(())
Expand Down Expand Up @@ -1093,7 +1097,12 @@ impl<'a, W: Write> Writer<'a, W> {
ShaderStage::Vertex => output,
ShaderStage::Fragment => !output,
ShaderStage::Compute => false,
ShaderStage::Task | ShaderStage::Mesh => unreachable!(),
ShaderStage::Task
| ShaderStage::Mesh
| ShaderStage::RayGeneration
| ShaderStage::AnyHit
| ShaderStage::ClosestHit
| ShaderStage::Miss => unreachable!(),
};

// Write the I/O locations, if allowed
Expand Down Expand Up @@ -2228,6 +2237,7 @@ impl<'a, W: Write> Writer<'a, W> {
}
writeln!(self.out, ");")?;
}
Statement::RayPipelineFunction(_) => unimplemented!(),
}

Ok(())
Expand Down
13 changes: 13 additions & 0 deletions naga/src/back/hlsl/conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,19 @@ impl crate::BuiltIn {
| Self::PrimitiveCount
| Self::Vertices
| Self::Primitives => unreachable!(),
Self::RayInvocationId
| Self::NumRayInvocations
| Self::InstanceCustomData
| Self::GeometryIndex
| Self::WorldRayOrigin
| Self::WorldRayDirection
| Self::ObjectRayOrigin
| Self::ObjectRayDirection
| Self::RayTmin
| Self::RayTCurrentMax
| Self::ObjectToWorld
| Self::WorldToObject
| Self::HitKind => unreachable!(),
})
}
}
Expand Down
1 change: 1 addition & 0 deletions naga/src/back/hlsl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ impl crate::ShaderStage {
Self::Compute => "cs",
Self::Task => "as",
Self::Mesh => "ms",
Self::RayGeneration | Self::AnyHit | Self::ClosestHit | Self::Miss => "lib",
}
}
}
Expand Down
8 changes: 7 additions & 1 deletion naga/src/back/hlsl/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1008,6 +1008,9 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
write!(self.out, "ConstantBuffer<")?;
"b"
}
crate::AddressSpace::RayPayload | crate::AddressSpace::IncomingRayPayload => {
unimplemented!()
}
};

// If the global is a immediate data write the type now because it will be a
Expand Down Expand Up @@ -2756,6 +2759,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
}
writeln!(self.out, ");")?;
}
Statement::RayPipelineFunction(_) => unreachable!(),
}

Ok(())
Expand Down Expand Up @@ -3086,7 +3090,9 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
| crate::AddressSpace::Private
| crate::AddressSpace::WorkGroup
| crate::AddressSpace::Immediate
| crate::AddressSpace::TaskPayload,
| crate::AddressSpace::TaskPayload
| crate::AddressSpace::RayPayload
| crate::AddressSpace::IncomingRayPayload,
)
| None => true,
Some(crate::AddressSpace::Uniform) => {
Expand Down
15 changes: 14 additions & 1 deletion naga/src/back/msl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,20 @@ impl ResolvedBinding {
| Bi::VertexCount
| Bi::PrimitiveCount
| Bi::Vertices
| Bi::Primitives => unreachable!(),
| Bi::Primitives
| Bi::RayInvocationId
| Bi::NumRayInvocations
| Bi::InstanceCustomData
| Bi::GeometryIndex
| Bi::WorldRayOrigin
| Bi::WorldRayDirection
| Bi::ObjectRayOrigin
| Bi::ObjectRayDirection
| Bi::RayTmin
| Bi::RayTCurrentMax
| Bi::ObjectToWorld
| Bi::WorldToObject
| Bi::HitKind => unreachable!(),
};
write!(out, "{name}")?;
}
Expand Down
16 changes: 14 additions & 2 deletions naga/src/back/msl/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,7 @@ impl crate::AddressSpace {
| Self::Handle
| Self::TaskPayload => true,
Self::Function => false,
Self::RayPayload | Self::IncomingRayPayload => unreachable!(),
}
}

Expand All @@ -609,7 +610,7 @@ impl crate::AddressSpace {
// may end up with "const" even if the binding is read-write,
// and that should be OK.
Self::Storage { .. } => true,
Self::TaskPayload => unimplemented!(),
Self::TaskPayload | Self::RayPayload | Self::IncomingRayPayload => unimplemented!(),
// These should always be read-write.
Self::Private | Self::WorkGroup => false,
// These translate to `constant` address space, no need for qualifiers.
Expand All @@ -624,9 +625,13 @@ impl crate::AddressSpace {
Self::Handle => None,
Self::Uniform | Self::Immediate => Some("constant"),
Self::Storage { .. } => Some("device"),
Self::Private | Self::Function => Some("thread"),
// note for `RayPayload`, this probably needs to be emulated as a
// private variable, as metal has essentially an inout input
// for where it is passed.
Self::Private | Self::Function | Self::RayPayload => Some("thread"),
Self::WorkGroup => Some("threadgroup"),
Self::TaskPayload => Some("object_data"),
Self::IncomingRayPayload => Some("ray_data"),
}
}
}
Expand Down Expand Up @@ -4194,6 +4199,7 @@ impl<W: Write> Writer<W> {
}
writeln!(self.out, ");")?;
}
crate::Statement::RayPipelineFunction(_) => unreachable!(),
}
}

Expand Down Expand Up @@ -6672,6 +6678,10 @@ template <typename A>
false,
),
crate::ShaderStage::Task | crate::ShaderStage::Mesh => unimplemented!(),
crate::ShaderStage::RayGeneration
| crate::ShaderStage::AnyHit
| crate::ShaderStage::ClosestHit
| crate::ShaderStage::Miss => unimplemented!(),
};

// Should this entry point be modified to do vertex pulling?
Expand Down Expand Up @@ -6744,6 +6754,8 @@ template <typename A>
crate::AddressSpace::Function
| crate::AddressSpace::Private
| crate::AddressSpace::WorkGroup => {}
crate::AddressSpace::RayPayload
| crate::AddressSpace::IncomingRayPayload => unimplemented!(),
}
}
if needs_buffer_sizes {
Expand Down
11 changes: 11 additions & 0 deletions naga/src/back/pipeline_constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,17 @@ fn adjust_stmt(new_pos: &HandleVec<Expression, Handle<Expression>>, stmt: &mut S
crate::RayQueryFunction::Terminate => {}
}
}
Statement::RayPipelineFunction(ref mut func) => match *func {
crate::RayPipelineFunction::TraceRay {
ref mut acceleration_structure,
ref mut descriptor,
ref mut payload,
} => {
adjust(acceleration_structure);
adjust(descriptor);
adjust(payload);
}
},
Statement::Break
| Statement::Continue
| Statement::Kill
Expand Down
1 change: 1 addition & 0 deletions naga/src/back/spv/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3699,6 +3699,7 @@ impl BlockContext<'_> {
} => {
self.write_subgroup_gather(mode, argument, result, &mut block)?;
}
Statement::RayPipelineFunction(_) => unreachable!(),
}
}

Expand Down
1 change: 1 addition & 0 deletions naga/src/back/spv/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ pub(super) const fn map_storage_class(space: crate::AddressSpace) -> spirv::Stor
crate::AddressSpace::WorkGroup => spirv::StorageClass::Workgroup,
crate::AddressSpace::Immediate => spirv::StorageClass::PushConstant,
crate::AddressSpace::TaskPayload => spirv::StorageClass::TaskPayloadWorkgroupEXT,
crate::AddressSpace::IncomingRayPayload | crate::AddressSpace::RayPayload => unreachable!(),
}
}

Expand Down
Loading