Skip to content

[hal metal] ray tracing acceleration structures #7660

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 25 commits into
base: trunk
Choose a base branch
from

Conversation

Lichtso
Copy link
Contributor

@Lichtso Lichtso commented May 2, 2025

Connections
Fixes: #7402

Description
Implements the missing ray tracing acceleration structures in the HAL metal backend.

Testing
The examples ray_scene, ray_shadows, ray_cube_compute, ray_cube_fragment and ray_traced_triangle all work.
That is if invoked via cargo run --bin wgpu-examples ray_traced_triangle, but not via cargo xtask test ray_traced_triangle. It seems this is caused by a race condition between the CPU uploading the scratch buffer and the GPU reading it to build the acceleration structure. Which indicates that the lack of barriers in the acceleration structure building is an issue.

Squash or Rebase?
Squash

Checklist

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

@Lichtso Lichtso requested a review from a team as a code owner May 2, 2025 22:41
@Lichtso Lichtso force-pushed the metal/ray_tracing_acceleration_structures branch 2 times, most recently from e30b663 to f3830cb Compare May 2, 2025 22:52
Copy link
Collaborator

@Vecvec Vecvec left a comment

Choose a reason for hiding this comment

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

Good job! Glad there didn't need to be any wgpu-core changes. Largely looks good, but I'm not extremely knowledgeable about metal. One question / comment, but haven't yet checked everything with spec.

descriptor.set_index_buffer(indices.buffer.map(|buffer| &*buffer.raw));
descriptor.set_index_buffer_offset(indices.offset as u64);
descriptor.set_index_type(map_index_format(indices.format).1);
descriptor.set_triangle_count(indices.count as u64 / 3);
Copy link
Collaborator

@Vecvec Vecvec May 3, 2025

Choose a reason for hiding this comment

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

It feels like the triangle count shouldn't be set just if the index buffer is set, but I can't see other places where this is set. Is this correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added a fallback to use the vertex count in the else branch if there are no indices.

Copy link
Collaborator

@Vecvec Vecvec left a comment

Choose a reason for hiding this comment

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

Done checks against the Metal spec. It seems this requires MacOS 13.0+ not 11.0+ due to some more recent functions being used. Confusingly, the vertex buffer field suggests that the only format supported is f32x3 so I'm not sure what descriptor.set_vertex_format does.

@@ -890,6 +890,11 @@ impl super::PrivateCapabilities {
&& (device.supports_family(MTLGPUFamily::Apple7)
|| device.supports_family(MTLGPUFamily::Mac2)),
supports_shared_event: version.at_least((10, 14), (12, 0), os_is_mac),
supports_raytracing: if version.at_least((11, 0), (14, 0), os_is_mac) {
device.supports_raytracing()
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think raytracing support needs supportsRaytracingFromRender due to support of ray queries in fragment shaders (Requires MacOS 12.0+).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That function is not exposed in the Rust metal crate. But I did bump the min required versions to macOS 13 and iOS 16.

Copy link
Collaborator

Choose a reason for hiding this comment

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

If the metal crate is still taking PRs (Idk what state of deprecated they are in) it would probably be a good idea to add this (and the other later ones).

Comment on lines +400 to +409
descriptor.set_vertex_format(unsafe {
core::mem::transmute::<MTLVertexFormat, MTLAttributeFormat>(
map_vertex_format(triangles.vertex_format),
)
});
if let Some(transform) = triangles.transform.as_ref() {
descriptor.set_transformation_matrix_buffer(Some(&*transform.buffer.raw));
descriptor.set_transformation_matrix_buffer_offset(transform.offset as u64);
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

On the spec these are listed as being MacOS 13.0+ while what is being checked is MacOS 11.0+, so it may be worth requiring MacOS 13.0+.

) {
unimplemented!()
let command_encoder = self.enter_acceleration_structure_builder();
command_encoder.write_compacted_acceleration_structure_size_with_type(
Copy link
Collaborator

Choose a reason for hiding this comment

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

@Lichtso Lichtso force-pushed the metal/ray_tracing_acceleration_structures branch from f3830cb to 234e75b Compare May 3, 2025 08:33
}

unsafe fn destroy_acceleration_structure(
&self,
_acceleration_structure: super::AccelerationStructure,
) {
unimplemented!()
// self.counters.acceleration_structures.sub(1);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I there a reason not to have HalCounters::acceleration_structures?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Looking back at the history I couldn't find a reason, but it's possible it's buried somewhere.

for descriptor in descriptors {
let acceleration_structure_descriptor =
conv::map_acceleration_structure_descriptor(descriptor.entries);
/* The Rust metal crate does not expose metal::MTLAccelerationStructureUsage yet
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Again, not exposed in the Rust metal crate.

@@ -35,6 +35,7 @@ var acc_struct: acceleration_structure;

struct PushConstants {
light: vec3<f32>,
padding: f32,
Copy link
Contributor Author

@Lichtso Lichtso May 3, 2025

Choose a reason for hiding this comment

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

It seems that metal always sends at least 16 bytes for push constants, even if we only pass in 12 bytes. And then the shader validation complains that the receiver here only expects 12 bytes.

@Lichtso Lichtso force-pushed the metal/ray_tracing_acceleration_structures branch from 234e75b to 5f1c464 Compare May 3, 2025 11:01
@Lichtso Lichtso force-pushed the metal/ray_tracing_acceleration_structures branch from 5f1c464 to 2a6d9b6 Compare May 3, 2025 11:13
@Lichtso
Copy link
Contributor Author

Lichtso commented May 3, 2025

Glad there didn't need to be any wgpu-core changes

Almost, had to remove the Option<> around the buffers and always pass the dummy zero buffer when computing the size of the acceleration structures and their scratch buffers because Metal does not like nil.

I can split those first four commits into a separate PR if that helps with the review.

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.

Implement Ray Tracing on Metal
2 participants