Open3D (C++ API)  0.19.0
Loading...
Searching...
No Matches
Namespaces | Macros | Functions
KnnSearchOpsSYCL.cpp File Reference

(bba9247 (Tue Jul 28 21:42:19 2026 -0700))

Host driver for SYCL nearest-neighbor search (KNN, fixed-radius, hybrid). More...

#include <algorithm>
#include <functional>
#include <limits>
#include <numeric>
#include <oneapi/dpl/algorithm>
#include <oneapi/dpl/execution>
#include <oneapi/dpl/numeric>
#include <sycl/sycl.hpp>
#include "open3d/core/SYCLUtils.h"
#include "open3d/core/Tensor.h"
#include "open3d/core/linalg/AddMM.h"
#include "open3d/core/nns/FixedRadiusIndex.h"
#include "open3d/core/nns/KnnIndex.h"
#include "open3d/core/nns/NeighborSearchAllocator.h"
#include "open3d/core/nns/kernel/FixedRadiusSearchSYCLImpl.h"
#include "open3d/core/nns/kernel/KnnSearchSYCLImpl.h"
#include "open3d/utility/Logging.h"

Namespaces

namespace  open3d
 
namespace  open3d::core
 
namespace  open3d::core::nns
 

Macros

#define INSTANTIATE(T, TIndex)
 

Functions

template<class T , class TIndex >
void open3d::core::nns::KnnSearchSYCL (const Tensor &points, const Tensor &points_row_splits, const Tensor &queries, const Tensor &queries_row_splits, int knn, Tensor &neighbors_index, Tensor &neighbors_row_splits, Tensor &neighbors_distance, int64_t tile_bytes, int64_t max_tile_queries, int64_t tile_points_alignment, bool force_addmm_path)
 
template<class T , class TIndex >
void open3d::core::nns::FixedRadiusSearchSYCL (const Tensor &points, const Tensor &queries, double radius, const Tensor &points_row_splits, const Tensor &queries_row_splits, const Tensor &hash_table_splits, const Tensor &hash_table_index, const Tensor &hash_table_cell_splits, const Metric metric, const bool ignore_query_point, const bool return_distances, const bool sort, Tensor &neighbors_index, Tensor &neighbors_row_splits, Tensor &neighbors_distance, int64_t)
 
template<class T , class TIndex >
void open3d::core::nns::HybridSearchSYCL (const Tensor &points, const Tensor &queries, double radius, int max_knn, const Tensor &points_row_splits, const Tensor &queries_row_splits, const Tensor &hash_table_splits, const Tensor &hash_table_index, const Tensor &hash_table_cell_splits, const Metric metric, Tensor &neighbors_index, Tensor &neighbors_count, Tensor &neighbors_distance, int64_t)
 
template void open3d::core::nns::BuildSpatialHashTableSYCL< float > (const Tensor &points, double radius, const Tensor &points_row_splits, const Tensor &hash_table_splits, Tensor &hash_table_index, Tensor &hash_table_cell_splits)
 
template void open3d::core::nns::BuildSpatialHashTableSYCL< double > (const Tensor &points, double radius, const Tensor &points_row_splits, const Tensor &hash_table_splits, Tensor &hash_table_index, Tensor &hash_table_cell_splits)
 

Detailed Description

Host driver for SYCL nearest-neighbor search (KNN, fixed-radius, hybrid).

What lives here

Callers: NearestNeighborSearch / KnnIndex / FixedRadiusIndex when dataset and query tensors are on a SYCL device. CPU tensors use NanoFlann.

Includes: KNN device code in kernel/KnnSearchSYCLImpl.h; uniform-grid kernels in kernel/FixedRadiusSearchSYCLImpl.h. Short index: nns/SYCL_DESIGN.md. This file header is the maintainer reference for path selection and end-to-end flow.

Three search modes in this file

Function Purpose
KnnSearchSYCL Fixed k nearest neighbors (L2), batched queries ×

dataset | | FixedRadiusSearchSYCL | All neighbors within radius (variable output size per query) | | HybridSearchSYCL | Up to max_knn closest neighbors within radius + in-radius count |

Fixed-radius and hybrid share the same spatial-hash grid index built in FixedRadiusIndex::SetTensorData (see FixedRadiusSearchSYCLImpl.h). The sections below focus on KNN; grid search is summarized at the end.

KNN path selection

For each batch, batch_knn = min(knn, num_points) (convention C5). CUDA KNN uses two strategies (small brute + GEMM + FAISS warp/block select); SYCL uses three paths:

Decision tree

force_addmm_path=true is for benchmarks only — always skips Direct.

| Path | When | CUDA analogue | SYCL implementation | |---—|---—|------------—|------------------—| | Direct | !force_addmm ∧ dim∈[1,8] ∧ k≤32 | Small dim/k brute kernel | Sub-group SLM tiles + shuffle-merge top-k | | AddMM fused | else, k≤512 | GEMM + FAISS BlockSelect / heap | oneMKL AddMM + fused UpdateTopKFromTile | | AddMM large-k | else, k>512 | Multi-pass FAISS select | Tile select/merge + serial partial_sort (P8) |

Constants: kSYCLKnnSmallKMax = 32, kSYCLKnnMidKMax = 512 (see KnnSearchSYCLImpl.h).

Direct path (<tt>DispatchKnnDirect</tt>)

Idea: Compute L2 as Σ_d (p_d − q_d)² directly — no AddMM, no data centering, no deferred ‖q‖² term.

Algorithm

Typical use: 3D point clouds, small k — often the fastest path on Intel Xe.

AddMM fused path (k ≤ 512)

Idea: Expand squared L2 as ‖q‖² − 2 q·p + ‖p‖². oneMKL AddMM builds the −2 q·p tile for each (query-tile × point-tile) pair; top-k selection fuses ‖p‖² and running heap updates (UpdateTopKFromTile, FinalizeTopK).

Algorithm

  1. Center points and queries (subtract first dataset row) — reduces float32 cancellation in ‖p‖² and ‖q‖² when coordinates or features have large norm (CUDA GEMM KNN does not center; Direct SYCL path does not need it).
  2. Precompute ‖p‖² per point and ‖q‖² per query (or equivalent norms).
  3. For each tile pair: AddMM → partial tile −2qp; add ‖p‖², clamp ≥ 0, update per-query max-heap (size = KBucket(batch_knn)).
  4. FinalizeTopK: heap-sort, add ‖q‖², write batch_knn neighbors.

Heap storage: k ≤ 32 → GRF-resident; k ∈ {64…512} → per-work-item scratch.

AddMM large-k path (k > 512)

Idea: Same tiled AddMM and centering as fused path, but SelectTopKQueries

Algorithm

P8 caveat: For very large k, merge/select may fall back to per-query serial partial_sort (oneDPL has no cheap segmented top-k) — correct but slow.

KNN: SYCL vs CUDA (design differences)

Topic CUDA SYCL (this file)
Small k, low dim Brute + GEMM paths + Direct sub-group path (no

GEMM) | | GEMM | cuBLAS | oneMKL via AddMM | | Top-k on GEMM tiles | FAISS warp/block select | Custom heap / select-merge / oneDPL | | Float32 stability | Uses norms as-is on GEMM path | Centers data before AddMM | | Large k | Multi-pass masking (1024/2048) | Select/merge + partial_sort per query |

AddMM KNN conventions (all non-Direct paths)

Id Rule
P2 Tile stores partial distance −2qp + ‖p‖²; ‖q‖² added once in

finalize | | C1 | Clamp partial / final distance ≥ 0 | | C4 | Equal distance → smaller point index wins | | C5 | batch_knn = min(knn, num_points) (caller / driver) |

Fixed-radius (\ref FixedRadiusSearchSYCL) — summary

Idea: Return every dataset point within radius of each query; output length varies per query (CSR layout). Ported from CUDA FixedRadiusSearchImpl.cuh; device detail in FixedRadiusSearchSYCLImpl.h.

Grid build (once per index, FixedRadiusIndex::SetTensorData):

Query algorithm

  1. Count: CountNeighborsSYCL — for each query, visit 8 corner-adjacent bins; count points with squared L2 ≤ radius².
  2. Inclusive scan of counts → neighbors_row_splits; allocate index (and optional distance) buffers for the total neighbor count.
  3. Gather: WriteNeighborsSYCL — same 8 bins; write indices and squared distances.
  4. Optional **sort=true:** SortNeighborsByDistanceSYCL — segmented oneDPL sort_by_key per query (ties not secondarily ordered by index; matches CUDA cub::DeviceSegmentedRadixSort::SortPairs).

Typical use: full neighborhood inside a ball, not a fixed-k cap.

Hybrid (\ref HybridSearchSYCL) — summary

Idea: Count all in-radius neighbors, but store only the closest max_knn in fixed (num_queries, max_knn) tensors plus per-query in-radius counts. Same grid as fixed-radius (BuildSpatialHashTableSYCL).

Algorithm

Typical use: FPFH, normals, covariances — “up to K neighbors inside radius.”

Note: Could be expressed as KNN-then-filter; deferred because the grid port already avoids O(queries × points) brute force.

Shared primitive map (CUDA → SYCL)

Role CUDA SYCL
Dense GEMM cuBLAS oneMKL
Prefix sum CUB oneDPL / work-group scan
Segmented sort CUB radix oneDPL sort_by_key
Parallel loops CUDA kernels SYCL queues / ParallelFor

Maintenance notes

Related source files

File Role
KnnSearchSYCLImpl.h Direct / AddMM SYCL kernels, KBucket, thresholds

| | FixedRadiusSearchSYCLImpl.h | Grid build, count/write/sort/hybrid kernels | | NearestNeighborSearch.cpp | Device dispatch to this driver | | AddMM.h | oneMKL batched GEMM for KNN tiles |

Macro Definition Documentation

◆ INSTANTIATE

#define INSTANTIATE (   T,
  TIndex 
)
Value:
template void KnnSearchSYCL<T, TIndex>( \
const Tensor& points, const Tensor& points_row_splits, \
const Tensor& queries, const Tensor& queries_row_splits, int knn, \
Tensor& neighbors_index, Tensor& neighbors_row_splits, \
Tensor& neighbors_distance, int64_t tile_bytes, \
int64_t max_tile_queries, int64_t tile_points_alignment, \
bool force_addmm_path); \
template void FixedRadiusSearchSYCL<T, TIndex>( \
const Tensor& points, const Tensor& queries, double radius, \
const Tensor& points_row_splits, const Tensor& queries_row_splits, \
const Tensor&, const Tensor&, const Tensor&, const Metric metric, \
const bool ignore_query_point, const bool return_distances, \
const bool sort, Tensor& neighbors_index, \
Tensor& neighbors_row_splits, Tensor& neighbors_distance, \
int64_t tile_bytes); \
template void HybridSearchSYCL<T, TIndex>( \
const Tensor& points, const Tensor& queries, double radius, \
int max_knn, const Tensor& points_row_splits, \
const Tensor& queries_row_splits, const Tensor&, const Tensor&, \
const Tensor&, const Metric metric, Tensor& neighbors_index, \
Tensor& neighbors_count, Tensor& neighbors_distance, \
int64_t tile_bytes);
int points
Definition FilePCD.cpp:55