313 const size_t batch_size,
314 const int64_t*
const row_splits,
315 const T*
const voxel_size,
316 const T*
const points_range_min,
317 const T*
const points_range_max,
318 const int64_t max_points_per_voxel,
319 const int64_t max_voxels,
320 OUTPUT_ALLOCATOR& output_allocator) {
321 using namespace sycl_voxelize_detail;
326 const Vec_t points_range_min_vec(points_range_min);
327 const Vec_t points_range_max_vec(points_range_max);
329 ceil((points_range_max_vec - points_range_min_vec) *
inv_voxel_size)
330 .template cast<int32_t>();
332 for (
int i = 0; i < NDIM; ++i) {
334 for (
int j = 0; j < i; ++j) strides[i] *= extents[j];
336 const int64_t batch_hash = strides[NDIM - 1] * extents[NDIM - 1];
337 const int64_t invalid_hash = batch_hash * int64_t(batch_size);
341 if (num_points == 0) {
342 int64_t* out_batch_splits =
nullptr;
343 output_allocator.AllocVoxelBatchSplits(&out_batch_splits,
346 queue.fill(out_batch_splits, int64_t(0), batch_size + 1).wait();
347 int32_t* out_voxel_coords =
nullptr;
348 output_allocator.AllocVoxelCoords(&out_voxel_coords, 0, NDIM);
349 int64_t* out_voxel_row_splits =
nullptr;
350 output_allocator.AllocVoxelPointRowSplits(&out_voxel_row_splits, 1);
351 queue.fill(out_voxel_row_splits, int64_t(0), 1).wait();
352 int64_t* out_point_indices =
nullptr;
353 output_allocator.AllocVoxelPointIndices(&out_point_indices, 0);
358 int64_t* indices_batches = sycl::malloc_device<int64_t>(num_points,
queue);
360 int64_t* hashes = sycl::malloc_device<int64_t>(num_points,
queue);
362 sycl::event indices_batches_event = ComputeIndicesBatchesSYCL(
363 queue, indices_batches, row_splits, int64_t(batch_size));
365 auto dpl_policy = oneapi::dpl::execution::make_device_policy(
queue);
371 sycl::event hashes_event = ComputeHashSYCL<T, NDIM>(
372 queue, hashes, int64_t(num_points),
points, indices_batches,
373 points_range_min_vec, points_range_max_vec,
inv_voxel_size, strides,
374 batch_hash, invalid_hash, {indices_batches_event});
378 sycl::free(indices_batches,
queue);
387 oneapi::dpl::stable_sort_by_key(dpl_policy, hashes, hashes + num_points,
391 int64_t* unique_hashes = sycl::malloc_device<int64_t>(num_points,
queue);
392 int64_t* unique_hashes_count =
393 sycl::malloc_device<int64_t>(num_points,
queue);
396 RunLengthEncodeSYCL(
queue, hashes, int64_t(num_points),
397 unique_hashes, unique_hashes_count);
398 sycl::free(hashes,
queue);
400 const int64_t last_hash =
401 ReadScalar(
queue, unique_hashes + (num_voxels - 1));
402 if (last_hash == invalid_hash) {
409 int64_t* unique_hashes_count_prefix_sum = sycl::malloc_device<int64_t>(
410 num_voxels > 0 ? num_voxels : 1,
queue);
411 sycl::event scan1_event;
412 if (num_voxels > 0) {
413 scan1_event = oneapi::dpl::experimental::inclusive_scan_async(
414 dpl_policy, unique_hashes_count,
415 unique_hashes_count + num_voxels,
416 unique_hashes_count_prefix_sum)
429 sycl::event limit1_event;
430 if (max_points_per_voxel < int64_t(num_points)) {
431 limit1_event = LimitCountsSYCL(
queue, unique_hashes_count, num_voxels,
432 max_points_per_voxel, {scan1_event});
436 ComputeBatchIdSYCL(
queue, unique_hashes, num_voxels, batch_hash);
438 int64_t* unique_batches = sycl::malloc_device<int64_t>(
439 batch_size > 0 ? batch_size : 1,
queue);
440 int64_t* unique_batches_count = sycl::malloc_device<int64_t>(
441 batch_size > 0 ? batch_size : 1,
queue);
442 int64_t num_batches =
443 RunLengthEncodeSYCL(
queue, unique_hashes, num_voxels,
444 unique_batches, unique_batches_count);
445 sycl::free(unique_hashes,
queue);
447 int64_t* num_voxels_per_batch = sycl::malloc_device<int64_t>(
448 batch_size > 0 ? batch_size : 1,
queue);
449 queue.fill(num_voxels_per_batch, int64_t(0),
450 batch_size > 0 ? batch_size : 1)
452 ComputeVoxelPerBatchSYCL(
queue, num_voxels_per_batch, unique_batches_count,
453 unique_batches, num_batches);
454 sycl::free(unique_batches,
queue);
455 sycl::free(unique_batches_count,
queue);
460 int64_t* num_voxels_prefix_sum = sycl::malloc_device<int64_t>(
461 batch_size > 0 ? batch_size : 1,
queue);
462 sycl::event scan2_event;
463 if (batch_size > 0) {
464 scan2_event = oneapi::dpl::experimental::inclusive_scan_async(
465 dpl_policy, num_voxels_per_batch,
466 num_voxels_per_batch + batch_size,
467 num_voxels_prefix_sum)
476 sycl::event num_voxels_per_batch_ready = scan2_event;
477 if (num_voxels >= max_voxels) {
478 num_voxels_per_batch_ready =
479 LimitCountsSYCL(
queue, num_voxels_per_batch,
480 int64_t(batch_size), max_voxels, {scan2_event});
484 int64_t* out_batch_splits =
nullptr;
485 output_allocator.AllocVoxelBatchSplits(&out_batch_splits, batch_size + 1);
486 queue.fill(out_batch_splits, int64_t(0), 1).wait();
487 sycl::event scan3_event;
488 if (batch_size > 0) {
489 scan3_event = oneapi::dpl::experimental::inclusive_scan_async(
490 dpl_policy, num_voxels_per_batch,
491 num_voxels_per_batch + batch_size,
492 out_batch_splits + 1, num_voxels_per_batch_ready)
495 queue.ext_oneapi_submit_barrier({scan3_event}).wait();
496 sycl::free(num_voxels_per_batch,
queue);
498 const int64_t num_valid_voxels =
499 ReadScalar(
queue, out_batch_splits + batch_size);
502 int64_t* start_idx = sycl::malloc_device<int64_t>(
503 num_valid_voxels > 0 ? num_valid_voxels : 1,
queue);
504 int64_t* points_count =
nullptr;
505 bool points_count_is_alias =
false;
507 sycl::event start_idx_ready_event;
508 if (num_voxels <= max_voxels) {
511 queue.fill(start_idx, int64_t(0), 1).wait();
512 if (num_voxels > 1) {
514 start_idx_ready_event =
queue.memcpy(
515 start_idx + 1, unique_hashes_count_prefix_sum,
516 (num_voxels - 1) *
sizeof(int64_t), scan1_event);
518 points_count = unique_hashes_count;
519 points_count_is_alias =
true;
521 points_count = sycl::malloc_device<int64_t>(num_valid_voxels,
queue);
526 start_idx_ready_event = ComputeStartIdxSYCL(
527 queue, start_idx, points_count, num_voxels_prefix_sum,
528 unique_hashes_count_prefix_sum, out_batch_splits,
529 int64_t(batch_size), max_points_per_voxel,
530 {scan1_event, scan2_event});
535 start_idx_ready_event.wait();
536 sycl::free(num_voxels_prefix_sum,
queue);
537 sycl::free(unique_hashes_count_prefix_sum,
queue);
540 int64_t* out_voxel_row_splits =
nullptr;
541 output_allocator.AllocVoxelPointRowSplits(&out_voxel_row_splits,
542 num_valid_voxels + 1);
543 queue.fill(out_voxel_row_splits, int64_t(0), 1).wait();
544 sycl::event scan4_event;
545 if (num_valid_voxels > 0) {
552 oneapi::dpl::experimental::inclusive_scan_async(
553 dpl_policy, points_count,
554 points_count + num_valid_voxels,
555 out_voxel_row_splits + 1,
556 points_count_is_alias ? limit1_event : sycl::event())
561 int32_t* out_voxel_coords =
nullptr;
562 output_allocator.AllocVoxelCoords(&out_voxel_coords, num_valid_voxels,
569 ComputeVoxelCoordsSYCL<T, NDIM>(
573 const int64_t num_valid_points =
575 ? ReadScalar(
queue, out_voxel_row_splits + num_valid_voxels,
578 int64_t* out_point_indices =
nullptr;
579 output_allocator.AllocVoxelPointIndices(&out_point_indices,
585 out_voxel_row_splits + 1, num_valid_voxels);
587 sycl::free(start_idx,
queue);
588 if (!points_count_is_alias) sycl::free(points_count,
queue);
589 sycl::free(unique_hashes_count,
queue);