/* * SPDX-FileCopyrightText: Copyright (c) 1993-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include namespace nvinfer1 { namespace plugin { __global__ void generateVoxels_kernel( int max_num_points, float *points, unsigned int* points_size, float min_x_range, float max_x_range, float min_y_range, float max_y_range, float min_z_range, float max_z_range, float pillar_x_size, float pillar_y_size, float pillar_z_size, int grid_y_size, int grid_x_size, int num_point_values, int max_points_per_voxel, unsigned int *mask, float *voxels) { int point_idx = blockIdx.x * blockDim.x + threadIdx.x; int batch_idx = point_idx / max_num_points; int point_idx_in_frame = point_idx % max_num_points; if(point_idx_in_frame >= points_size[batch_idx]) return; float px = points[num_point_values * point_idx]; float py = points[num_point_values * point_idx + 1]; float pz = points[num_point_values * point_idx + 2]; float pw = points[num_point_values * point_idx + 3]; float pt; if (num_point_values == 5) { pt = points[num_point_values * point_idx + 4]; } if(px=max_x_range || py=max_y_range || pz=max_z_range) return; int voxel_idx = floorf((px - min_x_range)/pillar_x_size); int voxel_idy = floorf((py - min_y_range)/pillar_y_size); unsigned int voxel_index = (batch_idx * grid_y_size + voxel_idy) * grid_x_size + voxel_idx; unsigned int point_id = atomicAdd(&(mask[voxel_index]), 1); if(point_id >= max_points_per_voxel) return; float *address = voxels + (voxel_index*max_points_per_voxel + point_id)*num_point_values; atomicExch(address+0, px); atomicExch(address+1, py); atomicExch(address+2, pz); atomicExch(address+3, pw); if (num_point_values == 5) { atomicExch(address+4, pt); } } __global__ void generateBaseFeatures_kernel( int batch_size, unsigned int *mask, float *voxels, int grid_y_size, int grid_x_size, unsigned int *pillar_num, int max_pillar_num, int max_points_per_voxel, int num_point_values, float *voxel_features, unsigned int *voxel_num_points, unsigned int *coords) { int voxel_id = blockIdx.x * blockDim.x + threadIdx.x; int voxel_idx = voxel_id % grid_x_size; int voxel_idy = (voxel_id / grid_x_size) % grid_y_size; int batch_id = voxel_id / (grid_y_size * grid_x_size); if (batch_id >= batch_size) return; unsigned int count = mask[voxel_id]; if( !(count>0) ) return; count = count>> (max_num_points, points, points_size, min_x_range, max_x_range, min_y_range, max_y_range, min_z_range, max_z_range, pillar_x_size, pillar_y_size, pillar_z_size, grid_y_size, grid_x_size, num_point_values, max_points_per_voxel, mask, voxels); } void generateBaseFeatures_launch( int batch_size, unsigned int *mask, float *voxels, int grid_y_size, int grid_x_size, unsigned int *pillar_num, int max_pillar_num, int max_points_per_voxel, int num_point_values, float *voxel_features, unsigned int *voxel_num_points, unsigned int *coords, cudaStream_t stream) { int blockSize = 1024; dim3 threads(blockSize); dim3 blocks((batch_size * grid_y_size * grid_x_size + blockSize - 1) / blockSize); generateBaseFeatures_kernel<<>> ( batch_size, mask, voxels, grid_y_size, grid_x_size, pillar_num, max_pillar_num, max_points_per_voxel, num_point_values, voxel_features, voxel_num_points, coords ); } __global__ void generateFeatures_kernel( int batch_size, int dense_pillar_num, float* voxel_features, unsigned int* voxel_num_points, unsigned int* coords, unsigned int *params, float voxel_x, float voxel_y, float voxel_z, float range_min_x, float range_min_y, float range_min_z, unsigned int voxel_features_size, unsigned int max_points, unsigned int max_voxels, float* features) { int warp_size = max_points; int pillar_idx = blockIdx.x * 4 + threadIdx.x/warp_size; int point_idx = threadIdx.x % warp_size; // In case the actual number of points is less than warp_size // E.g., warp_size=32, max_points=20 if (point_idx >= max_points) return; int batch_idx = pillar_idx / max_voxels; if (batch_idx >= batch_size) return; int pillar_idx_in_frame = pillar_idx % max_voxels; int dense_pillar_idx = pillar_idx_in_frame + dense_pillar_num * batch_idx; int pillar_idx_inBlock = threadIdx.x/warp_size; // Limit number of voxels to max_voxels unsigned int num_pillars = params[batch_idx] > max_voxels ? max_voxels : params[batch_idx]; // Update max_voxel to actual number if (pillar_idx_in_frame == 0 && point_idx == 0) { params[batch_idx] = num_pillars; } if (pillar_idx_in_frame >= num_pillars) return; //load src __shared__ float pillarSM[4][64][5]; // up to 64 points per pillar __shared__ float4 pillarSumSM[4]; //4*4 __shared__ int4 cordsSM[4]; //4*4 __shared__ int pointsNumSM[4]; //4 __shared__ float pillarOutSM[4][64][11]; // up to 11 features per point if (point_idx == 0) { pointsNumSM[pillar_idx_inBlock] = voxel_num_points[dense_pillar_idx]; cordsSM[pillar_idx_inBlock] = ((int4*)coords)[dense_pillar_idx]; pillarSumSM[pillar_idx_inBlock] = {0,0,0,0}; } for(int k=0; k<5; k++) { pillarSM[pillar_idx_inBlock][point_idx][k] = voxel_features[5 * (dense_pillar_idx*max_points + point_idx) + k]; } __syncthreads(); //calculate sm if (point_idx < pointsNumSM[pillar_idx_inBlock]) { atomicAdd(&(pillarSumSM[pillar_idx_inBlock].x), pillarSM[pillar_idx_inBlock][point_idx][0]); atomicAdd(&(pillarSumSM[pillar_idx_inBlock].y), pillarSM[pillar_idx_inBlock][point_idx][1]); atomicAdd(&(pillarSumSM[pillar_idx_inBlock].z), pillarSM[pillar_idx_inBlock][point_idx][2]); } __syncthreads(); //feature-mean float4 mean; float validPoints = pointsNumSM[pillar_idx_inBlock]; mean.x = pillarSumSM[pillar_idx_inBlock].x / validPoints; mean.y = pillarSumSM[pillar_idx_inBlock].y / validPoints; mean.z = pillarSumSM[pillar_idx_inBlock].z / validPoints; mean.x = pillarSM[pillar_idx_inBlock][point_idx][0] - mean.x; mean.y = pillarSM[pillar_idx_inBlock][point_idx][1] - mean.y; mean.z = pillarSM[pillar_idx_inBlock][point_idx][2] - mean.z; //calculate offset float x_offset = voxel_x / 2.0f + cordsSM[pillar_idx_inBlock].w * voxel_x + range_min_x; float y_offset = voxel_y / 2.0f + cordsSM[pillar_idx_inBlock].z * voxel_y + range_min_y; float z_offset = voxel_z / 2.0f + cordsSM[pillar_idx_inBlock].y * voxel_z + range_min_z; //feature-offset float4 center; center.x = pillarSM[pillar_idx_inBlock][point_idx][0] - x_offset; center.y = pillarSM[pillar_idx_inBlock][point_idx][1] - y_offset; center.z = pillarSM[pillar_idx_inBlock][point_idx][2] - z_offset; //store output if (point_idx < pointsNumSM[pillar_idx_inBlock]) { for(int k=0; k<5; k++) pillarOutSM[pillar_idx_inBlock][point_idx][k] = pillarSM[pillar_idx_inBlock][point_idx][k]; pillarOutSM[pillar_idx_inBlock][point_idx][5] = mean.x; pillarOutSM[pillar_idx_inBlock][point_idx][5 + 1] = mean.y; pillarOutSM[pillar_idx_inBlock][point_idx][5 + 2] = mean.z; pillarOutSM[pillar_idx_inBlock][point_idx][5 + 3] = center.x; pillarOutSM[pillar_idx_inBlock][point_idx][5 + 4] = center.y; if (5 + 5 < voxel_features_size) pillarOutSM[pillar_idx_inBlock][point_idx][warp_size + 5] = center.z; } else { for (int k = 0; k < voxel_features_size; k++) pillarOutSM[pillar_idx_inBlock][point_idx][k] = 0; } __syncthreads(); for(int i = 0; i < voxel_features_size; i ++) { int outputSMId = pillar_idx_inBlock*64*11 + point_idx * 11 + i; int outputId = pillar_idx*max_points*voxel_features_size + point_idx * voxel_features_size + i; features[outputId] = ((float*)pillarOutSM)[outputSMId] ; } } __global__ void generateFeatures_kernel_4x( int batch_size, int dense_pillar_num, float* voxel_features, unsigned int* voxel_num_points, unsigned int* coords, unsigned int *params, float voxel_x, float voxel_y, float voxel_z, float range_min_x, float range_min_y, float range_min_z, unsigned int voxel_features_size, unsigned int max_points, unsigned int max_voxels, float* features) { int warp_size = max_points; int pillar_idx = blockIdx.x * 4 + threadIdx.x / warp_size; int point_idx = threadIdx.x % warp_size; // In case the actual number of points is less than warp_size // E.g., warp_size=32, max_points=20 if (point_idx >= max_points) return; int batch_idx = pillar_idx / max_voxels; if (batch_idx >= batch_size) return; int pillar_idx_in_frame = pillar_idx % max_voxels; int dense_pillar_idx = pillar_idx_in_frame + dense_pillar_num * batch_idx; int pillar_idx_inBlock = threadIdx.x / warp_size; // Limit number of voxels to max_voxels unsigned int num_pillars = params[batch_idx] > max_voxels ? max_voxels : params[batch_idx]; // Update max_voxel to actual number if (pillar_idx_in_frame == 0 && point_idx == 0) { params[batch_idx] = num_pillars; } if (pillar_idx_in_frame >= num_pillars) return; //load src __shared__ float4 pillarSM[4][64]; // up to 64 points per pillar __shared__ float4 pillarSumSM[4]; //4*4 __shared__ int4 cordsSM[4]; //4*4 __shared__ int pointsNumSM[4]; //4 __shared__ float pillarOutSM[4][64][11]; // up to 11 output features per point if (point_idx == 0) { pointsNumSM[pillar_idx_inBlock] = voxel_num_points[dense_pillar_idx]; cordsSM[pillar_idx_inBlock] = ((int4*)coords)[pillar_idx]; pillarSumSM[pillar_idx_inBlock] = {0,0,0,0}; } pillarSM[pillar_idx_inBlock][point_idx] = ((float4*)voxel_features)[dense_pillar_idx*max_points + point_idx]; __syncthreads(); //calculate sm if (point_idx < pointsNumSM[pillar_idx_inBlock]) { atomicAdd(&(pillarSumSM[pillar_idx_inBlock].x), pillarSM[pillar_idx_inBlock][point_idx].x); atomicAdd(&(pillarSumSM[pillar_idx_inBlock].y), pillarSM[pillar_idx_inBlock][point_idx].y); atomicAdd(&(pillarSumSM[pillar_idx_inBlock].z), pillarSM[pillar_idx_inBlock][point_idx].z); } __syncthreads(); //feature-mean float4 mean; float validPoints = pointsNumSM[pillar_idx_inBlock]; mean.x = pillarSumSM[pillar_idx_inBlock].x / validPoints; mean.y = pillarSumSM[pillar_idx_inBlock].y / validPoints; mean.z = pillarSumSM[pillar_idx_inBlock].z / validPoints; mean.x = pillarSM[pillar_idx_inBlock][point_idx].x - mean.x; mean.y = pillarSM[pillar_idx_inBlock][point_idx].y - mean.y; mean.z = pillarSM[pillar_idx_inBlock][point_idx].z - mean.z; //calculate offset float x_offset = voxel_x / 2.0f + cordsSM[pillar_idx_inBlock].w * voxel_x + range_min_x; float y_offset = voxel_y / 2.0f + cordsSM[pillar_idx_inBlock].z * voxel_y + range_min_y; float z_offset = voxel_z / 2.0f + cordsSM[pillar_idx_inBlock].y * voxel_z + range_min_z; //feature-offset float4 center; center.x = pillarSM[pillar_idx_inBlock][point_idx].x - x_offset; center.y = pillarSM[pillar_idx_inBlock][point_idx].y - y_offset; center.z = pillarSM[pillar_idx_inBlock][point_idx].z - z_offset; //store output if (point_idx < pointsNumSM[pillar_idx_inBlock]) { pillarOutSM[pillar_idx_inBlock][point_idx][0] = pillarSM[pillar_idx_inBlock][point_idx].x; pillarOutSM[pillar_idx_inBlock][point_idx][1] = pillarSM[pillar_idx_inBlock][point_idx].y; pillarOutSM[pillar_idx_inBlock][point_idx][2] = pillarSM[pillar_idx_inBlock][point_idx].z; pillarOutSM[pillar_idx_inBlock][point_idx][3] = pillarSM[pillar_idx_inBlock][point_idx].w; pillarOutSM[pillar_idx_inBlock][point_idx][4] = mean.x; pillarOutSM[pillar_idx_inBlock][point_idx][5] = mean.y; pillarOutSM[pillar_idx_inBlock][point_idx][6] = mean.z; pillarOutSM[pillar_idx_inBlock][point_idx][7] = center.x; pillarOutSM[pillar_idx_inBlock][point_idx][8] = center.y; pillarOutSM[pillar_idx_inBlock][point_idx][9] = center.z; } else { pillarOutSM[pillar_idx_inBlock][point_idx][0] = 0; pillarOutSM[pillar_idx_inBlock][point_idx][1] = 0; pillarOutSM[pillar_idx_inBlock][point_idx][2] = 0; pillarOutSM[pillar_idx_inBlock][point_idx][3] = 0; pillarOutSM[pillar_idx_inBlock][point_idx][4] = 0; pillarOutSM[pillar_idx_inBlock][point_idx][5] = 0; pillarOutSM[pillar_idx_inBlock][point_idx][6] = 0; pillarOutSM[pillar_idx_inBlock][point_idx][7] = 0; pillarOutSM[pillar_idx_inBlock][point_idx][8] = 0; pillarOutSM[pillar_idx_inBlock][point_idx][9] = 0; } __syncthreads(); for(int i = 0; i < voxel_features_size; i ++) { int outputSMId = pillar_idx_inBlock*64*11 + point_idx * 11 + i; int outputId = pillar_idx*max_points*voxel_features_size + point_idx * voxel_features_size + i; features[outputId] = ((float*)pillarOutSM)[outputSMId] ; } } int generateFeatures_launch( int batch_size, int dense_pillar_num, float* voxel_features, unsigned int* voxel_num_points, unsigned int* coords, unsigned int *params, float voxel_x, float voxel_y, float voxel_z, float range_min_x, float range_min_y, float range_min_z, unsigned int voxel_features_size, unsigned int max_points, unsigned int max_voxels, unsigned int num_point_values, float* features, cudaStream_t stream) { unsigned int warp_size = max_points; dim3 blocks((batch_size * max_voxels + 3) / 4); dim3 threads(4*warp_size); if (num_point_values == 4) { generateFeatures_kernel_4x<<>> (batch_size, dense_pillar_num, voxel_features, voxel_num_points, coords, params, voxel_x, voxel_y, voxel_z, range_min_x, range_min_y, range_min_z, voxel_features_size, max_points, max_voxels, features); } else { generateFeatures_kernel<<>> (batch_size, dense_pillar_num, voxel_features, voxel_num_points, coords, params, voxel_x, voxel_y, voxel_z, range_min_x, range_min_y, range_min_z, voxel_features_size, max_points, max_voxels, features); } auto err = cudaGetLastError(); if (cudaSuccess != err) { fprintf(stderr, "CUDA kernel failed : %s\n", cudaGetErrorString(err)); exit(-1); } return err; } } // namespace plugin } // namespace nvinfer1