413 lines
16 KiB
Plaintext
413 lines
16 KiB
Plaintext
/*
|
|
* 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 <iostream>
|
|
#include <cuda_runtime_api.h>
|
|
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<min_x_range||px>=max_x_range
|
|
|| py<min_y_range||py>=max_y_range
|
|
|| pz<min_z_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_points_per_voxel?count:max_points_per_voxel;
|
|
int current_pillarId = 0;
|
|
current_pillarId = atomicAdd(pillar_num + batch_id, 1);
|
|
voxel_num_points[batch_id * grid_y_size * grid_x_size + current_pillarId] = count;
|
|
int4 coord = {0, 0, voxel_idy, voxel_idx};
|
|
((int4*)coords)[batch_id * max_pillar_num + current_pillarId] = coord;
|
|
for (int i=0; i<count; i++){
|
|
int inIndex = voxel_id*max_points_per_voxel + i;
|
|
int outIndex = (batch_id * grid_x_size * grid_y_size + current_pillarId)*max_points_per_voxel + i;
|
|
if (num_point_values == 4) {
|
|
((float4*)voxel_features)[outIndex] = ((float4*)voxels)[inIndex];
|
|
}
|
|
else if (num_point_values == 5) {
|
|
for(int k=0; k<5;k++)
|
|
voxel_features[5 * outIndex + k] = voxels[5 * inIndex + k];
|
|
}
|
|
}
|
|
}
|
|
|
|
void generateVoxels_launch(
|
|
int batch_size, 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,
|
|
cudaStream_t stream)
|
|
{
|
|
int threadNum = 256;
|
|
dim3 blocks((batch_size * max_num_points + threadNum - 1) / threadNum);
|
|
dim3 threads(threadNum);
|
|
generateVoxels_kernel<<<blocks, threads, 0, stream>>>
|
|
(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<<<blocks, threads, 0, stream>>>
|
|
(
|
|
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<<<blocks, threads, 0, stream>>>
|
|
(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<<<blocks, threads, 0, stream>>>
|
|
(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
|