Skip to content

Add vendor-agnostic wgpu compute backend - #44

Open
naitikpahwa18 wants to merge 11 commits into
IOES-Lab:ros2from
naitikpahwa18:wgpu_integration
Open

Add vendor-agnostic wgpu compute backend#44
naitikpahwa18 wants to merge 11 commits into
IOES-Lab:ros2from
naitikpahwa18:wgpu_integration

Conversation

@naitikpahwa18

Copy link
Copy Markdown

Summary

This PR removes the CUDA dependency from the multibeam sonar implementation and introduces a modular compute backend architecture. A new WGPU-based compute backend is added along with a CPU reference backend used as a fallback when GPU execution is unavailable.

The sonar sensor was refactored to use this backend interface instead of calling CUDA kernels directly. The WGPU implementation runs the sonar compute stages on the GPU using WGSL shaders, while the CPU implementation preserves the existing physics model for deterministic results.

The build system was updated to remove CUDA requirements and integrate a Rust-based WGPU vendor package. Runtime backend selection is also supported.

Validation

The WGPU backend has been tested on Vulkan; support for Metal and DirectX backends is expected via WGPU but remains untested.

Signed-off-by: Naitik Pahwa <naitikpahwa11@gmail.com>
Copilot AI review requested due to automatic review settings March 16, 2026 20:44

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR replaces the CUDA-dependent multibeam sonar compute pipeline with a modular backend architecture. A WGPU-based GPU backend (using Rust + WGSL shaders) and a CPU reference backend are introduced, selectable at runtime via the DAVE_SONAR_COMPUTE_BACKEND environment variable. The sonar sensor is refactored to use a ComputeBackend interface, and computation is moved to a background thread to avoid blocking the rendering pipeline.

Changes:

  • New ComputeBackend abstraction with WGPU (GPU via WGSL shaders + Rust FFI) and CPU implementations, replacing direct CUDA kernel calls
  • Background compute thread in MultibeamSonarSensor with snapshot-based decoupling from the render thread, plus consistent timestamping for ROS messages
  • Build system migrated from CUDA to a Rust-based wgpu_vendor package with CMake integration, and runtime backend selection via launch arguments

Reviewed changes

Copilot reviewed 26 out of 27 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
multibeam_sonar/sonar_compute_backend.hh New abstract backend interface and data structures
multibeam_sonar/sonar_compute_cpu.cc CPU backend implementation and backend factory
multibeam_sonar/sonar_compute_wgpu.cc/hh WGPU backend: C++ wrapper calling Rust FFI with CPU fallback
multibeam_sonar/MultibeamSonarSensor.cc/hh Background compute thread, snapshot-based pipeline, backend integration
multibeam_sonar/CMakeLists.txt Removed CUDA, added wgpu_vendor dependency
wgpu_vendor/sonar_wgpu_rust/src/lib.rs Rust FFI entry point: GPU dispatch, staging readback, CPU FFT fallback
wgpu_vendor/sonar_wgpu_rust/src/pipeline.rs GPU context singleton: device init, buffer management, pipeline compilation
wgpu_vendor/sonar_wgpu_rust/src/fft.rs CPU FFT (Cooley-Tukey + Bluestein)
wgpu_vendor/sonar_wgpu_rust/src/shaders/*.wgsl WGSL compute shaders: backscatter, convert, matmul, FFT
wgpu_vendor/CMakeLists.txt Rust cargo build integration with CMake
multibeam_sonar_system/CMakeLists.txt Simplified: removed CUDA conditionals
multibeam_sonar_demo/launch/multibeam_sonar_demo.launch.py Added compute_backend launch argument
multibeam_sonar_demo/scripts/plotdata.py Save to file instead of plt.show()
dave_interfaces/CMakeLists.txt Removed gz-cmake3/gz-msgs10 dependencies
models/.../model.sdf Debug comment for non-power-of-2 FFT testing

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread gazebo/dave_gz_multibeam_sonar/wgpu_vendor/sonar_wgpu_rust/src/lib.rs Outdated
Comment thread gazebo/dave_gz_multibeam_sonar/wgpu_vendor/sonar_wgpu_rust/src/lib.rs Outdated
Comment thread gazebo/dave_gz_multibeam_sonar/wgpu_vendor/sonar_wgpu_rust/src/lib.rs Outdated
Comment thread gazebo/dave_gz_multibeam_sonar/wgpu_vendor/sonar_wgpu_rust/src/pipeline.rs Outdated
Comment thread gazebo/dave_gz_multibeam_sonar/wgpu_vendor/CMakeLists.txt Outdated
Comment thread gazebo/dave_gz_multibeam_sonar/wgpu_vendor/sonar_wgpu_rust/src/fft.rs Outdated
Comment thread gazebo/dave_gz_multibeam_sonar/multibeam_sonar/sonar_compute_wgpu.cc Outdated
Comment thread gazebo/dave_gz_multibeam_sonar/wgpu_vendor/sonar_wgpu_rust/src/pipeline.rs Outdated
Comment thread gazebo/dave_gz_multibeam_sonar/multibeam_sonar/CMakeLists.txt
Comment thread gazebo/dave_gz_multibeam_sonar/wgpu_vendor/sonar_wgpu_rust/src/fft.rs Outdated
naitikpahwa18 and others added 2 commits March 19, 2026 00:45
naitikpahwa18 and others added 2 commits April 13, 2026 23:57
@woensug-choi

Copy link
Copy Markdown

@naitikpahwa18 Could you provide quick how-to test document?

Signed-off-by: Naitik Pahwa <naitikpahwa11@gmail.com>
@naitikpahwa18

Copy link
Copy Markdown
Author

Hi @woensug-choi, I've added a quick demo guide in the latest commit. Please let me know if anything else needs to be added.

@kickflipin2

Copy link
Copy Markdown

@naitikpahwa18 Thank you for the quick response! I will give it a spin sometime next week on MacOS

@woensug-choi

woensug-choi commented May 22, 2026

Copy link
Copy Markdown

@naitikpahwa18 I've tested on MacOSX with some changes. Note at https://github.com/naitikpahwa18/dave/blob/wgpu_integration/gazebo/DEMO_GUIDE_AppleSilicon_MacOSX.md. Dave currently assumes ROS2 Jazzy and Gazebo Harmonic.

Multibeam Sonar Demo

@naitikpahwa18

Copy link
Copy Markdown
Author

Thanks for testing on MacOSX and updating the docs! (I'm on ROS2 Rolling + Gazebo Jetty on my end)

woensug-choi and others added 2 commits May 25, 2026 23:38
Signed-off-by: Naitik Pahwa <naitikpahwa11@gmail.com>
@naitikpahwa18

Copy link
Copy Markdown
Author

@woensug-choi I have tested the current wgpu implementation with rays=3000, raySkips=10 - it works, though the output is slightly more distorted compared to before.
cuda.webm
wgpu.webm
Perf-wise, CUDA sonar frame calc time is ~36ms vs wgpu's ~60ms.

@woensug-choi

Copy link
Copy Markdown

@naitikpahwa18 Apologies for the delayed response. Although I'm aware of the late ping-pong, I would be delighted to see this agnostic sonar plugin upstreamed. Lack of rays is especially visible when grazing the seabed (e.g. 4. Local Search Scenario at Wiki Doc showing stripe pattern). What do you mean by slightly more distorted?

@naitikpahwa18

Copy link
Copy Markdown
Author

Agreed, increasing rays from 300 to 9000 significantly reduces the stripe pattern, consistent with what you described. Please ignore the "slightly more distorted" comment, I was misinterpreting the RViz visualization at the time.
I’d be happy to keep improving the implementation and work toward getting it upstreamed.

WGPU

Signed-off-by: Yeseol Gwon <172019512+yeseorizi@users.noreply.github.com>
Signed-off-by: Yeseol Gwon <172019512+yeseorizi@users.noreply.github.com>
@yeseorizi

Copy link
Copy Markdown
Collaborator

Hi @naitikpahwa18,

I validated the WGPU multibeam-sonar backend on Apple M2 / Metal and found a possible range-axis mismatch in the non-power-of-two FFT path. I pushed two separate signed-off commits for review:

  • 9a08fa9: candidate fft.wgsl writeback correction
  • 050244d: validation report, CSV results, and figures

Why I changed it

For the default n_freq = 399, the WGPU path zero-pads to padded_n = 512. The original shader then copied smem[i] directly into the original 399-bin output. Because the published ROS range vector still represents 399 physical bins, the measured peak followed approximately the 512 / 399 scale and the far-range tail approached clipping near 10 * 399 / 512 = 7.793 m.

Candidate change

The candidate keeps the 512-point FFT, but during writeback samples the complex padded spectrum at i * padded_n / n_freq and linearly interpolates it back onto the original 399-bin physical range grid.

Controlled validation

  • 2, 4, 6, and 8 m planar targets
  • 0, 15, 30, and 45 degree incidence angles
  • Five frames per backend-condition
  • Independent PointCloud range used to check target placement
Backend Range RMSE
PR #44 CPU 0.0134 m
Original PR #44 WGPU 1.4532 m
Candidate WGPU 0.0540 m

This is a 96.28% RMSE reduction relative to the original WGPU writeback in the 16-condition matrix.

WGPU range-axis validation

Full evidence: WGPU padded-FFT range-axis validation

I also checked n_freq = 301, 511, 512, and 513. The large scaling error was reproduced for 301 -> 512 and 513 -> 1024, while the unmodified 512 -> 512 control remained accurate. The 511 -> 512 case is an important edge case: linear interpolation did not improve its already small error, so an adaptive or no-op policy near a unity padding ratio may be preferable.

NVIDIA CUDA equivalence has not been tested yet, so I am not claiming complete backend equivalence. Could you please review whether this range-axis interpretation matches the intended FFT/writeback design? I would also appreciate your opinion on the 511 -> 512 edge case and any CUDA comparison you think should be run before merging.

We are considering preparing a paper from this numerical analysis and validation. I plan to lead the remaining experiments, analysis, and initial draft; once the technical direction is agreed, I would like to discuss separately how you would like to contribute.

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.

6 participants