|
|
|
//
|
|
|
|
// Created by 14727 on 2022/11/7.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
#include "NurbsEvaluator.cuh"
|
|
|
|
#include "cstdio"
|
|
|
|
#include "utils.h"
|
|
|
|
|
|
|
|
__host__ NurbsSurface::Evaluator::Evaluator(std::vector<std::vector<std::vector<float>>> controlPoints,
|
|
|
|
std::vector<float> knots_u, std::vector<float> knots_v) {
|
|
|
|
this->knots_u = std::move(knots_u);
|
|
|
|
this->knots_v = std::move(knots_v);
|
|
|
|
this->controlPoints = std::move(controlPoints);
|
|
|
|
recordTime = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
__host__ std::vector<std::map<std::pair<float, float>, std::vector<float>>>
|
|
|
|
NurbsSurface::Evaluator::calculate(int sampleCnt_u, int sampleCnt_v) {
|
|
|
|
// 构造指向device的controlPoints
|
|
|
|
const int pointsCntU = controlPoints.size(), pointsCntV = controlPoints[0].size(), pointSize = controlPoints[0][0].size();
|
|
|
|
const int pointsBytes = pointsCntU * pointsCntV * pointSize * sizeof(float);
|
|
|
|
auto *h_points = (float *) malloc(pointsBytes);
|
|
|
|
for (int i = 0; i < pointsCntU; i++) {
|
|
|
|
for (int j = 0; j < pointsCntV; j++) {
|
|
|
|
for (int k = 0; k < pointSize; k++) {
|
|
|
|
h_points[(i * pointsCntV + j) * pointSize + k] = controlPoints[i][j][k];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
float *d_points;
|
|
|
|
cudaMalloc((void **) &d_points, pointsBytes);
|
|
|
|
cudaMemcpy(d_points, h_points, pointsBytes, cudaMemcpyHostToDevice);
|
|
|
|
|
|
|
|
// 构造指向device的knots
|
|
|
|
const int knotsCnt_u = knots_u.size(), knotsCnt_v = knots_v.size();
|
|
|
|
const int knotsBytesU = knotsCnt_u * sizeof(float), knotsBytesV = knotsCnt_v * sizeof(float);
|
|
|
|
auto *h_knotsU = (float *) malloc(knotsBytesU), *h_knotsV = (float *) malloc(knotsBytesV);
|
|
|
|
for (int i = 0; i < knotsCnt_u; i++) h_knotsU[i] = knots_u[i];
|
|
|
|
for (int i = 0; i < knotsCnt_v; i++) h_knotsV[i] = knots_v[i];
|
|
|
|
|
|
|
|
float *d_knots_u;
|
|
|
|
float *d_knots_v;
|
|
|
|
cudaMalloc((void **) &d_knots_u, knotsBytesU);
|
|
|
|
cudaMalloc((void **) &d_knots_v, knotsBytesV);
|
|
|
|
cudaMemcpy(d_knots_u, h_knotsU, knotsBytesU, cudaMemcpyHostToDevice);
|
|
|
|
cudaMemcpy(d_knots_v, h_knotsV, knotsBytesV, cudaMemcpyHostToDevice);
|
|
|
|
|
|
|
|
// 构造线程层级,调用核函数
|
|
|
|
dim3 block(32, 32);
|
|
|
|
dim3 grid((sampleCnt_u + block.x - 1) / block.x, (sampleCnt_v + block.y - 1) / block.y);
|
|
|
|
// 记录用时
|
|
|
|
double time_cost_device;
|
|
|
|
if(recordTime) time_cost_device = utils::get_time_windows();
|
|
|
|
calculate_kernel <<<grid, block>>>(d_points, d_knots_u, d_knots_v, pointsCntU, pointsCntV, pointSize,
|
|
|
|
knots_u.size(), knots_v.size(), sampleCnt_u, sampleCnt_v);
|
|
|
|
if(recordTime) {
|
|
|
|
cudaDeviceSynchronize(); // 所用线程结束后再获取结束时间。cudaThreadSynchronize()在CUDA1.0后被弃用
|
|
|
|
time_cost_device = utils::get_time_windows() - time_cost_device;
|
|
|
|
printf("GPU time cost of surface evaluation for %d samples: %lf\n", sampleCnt_u * sampleCnt_v, time_cost_device);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 释放内存
|
|
|
|
free(h_points);
|
|
|
|
free(h_knotsU);
|
|
|
|
free(h_knotsV);
|
|
|
|
cudaFree(d_points);
|
|
|
|
cudaFree(d_knots_u);
|
|
|
|
cudaFree(d_knots_v);
|
|
|
|
|
|
|
|
cudaDeviceReset();
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__global__ void
|
|
|
|
NurbsSurface::calculate_kernel(const float *d_points, const float *d_knots_u, const float *d_knots_v, int d_pointsCnt_u,
|
|
|
|
int d_pointsCnt_v, int d_pointSize, int d_knotsCnt_u, int d_knotsCnt_v,
|
|
|
|
int d_sampleCnt_u, int d_sampleCnt_v) {
|
|
|
|
// 二维grid和二维的block
|
|
|
|
int ix = int(blockIdx.x * blockDim.x + threadIdx.x);
|
|
|
|
int iy = int(blockIdx.y * blockDim.y + threadIdx.y);
|
|
|
|
|
|
|
|
float d_paramCeil_u = d_knots_u[d_knotsCnt_u - 1];
|
|
|
|
float d_paramCeil_v = d_knots_v[d_knotsCnt_v - 1];
|
|
|
|
|
|
|
|
float u = ix * d_paramCeil_u / (d_sampleCnt_u - 1);
|
|
|
|
float v = iy * d_paramCeil_v / (d_sampleCnt_v - 1);
|
|
|
|
|
|
|
|
if (u > 1.0 * d_paramCeil_u || v > 1.0 * d_paramCeil_v) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int d_degree_u = d_knotsCnt_u - 1 - d_pointsCnt_u;
|
|
|
|
int d_degree_v = d_knotsCnt_v - 1 - d_pointsCnt_v;
|
|
|
|
// 注意,在device中,全局内存还是以malloc和free的方式分配和回收的,而不是使用cudaMalloc和cudaFree
|
|
|
|
auto *N_Texture_U = (float *) malloc((d_degree_u + 1) * (d_knotsCnt_u - 1) * sizeof(float));
|
|
|
|
auto *N_Texture_V = (float *) malloc((d_degree_v + 1) * (d_knotsCnt_v - 1) * sizeof(float));
|
|
|
|
d_basisFunction(N_Texture_U, d_knots_u, u, d_degree_u, d_knotsCnt_u);
|
|
|
|
d_basisFunction(N_Texture_V, d_knots_v, v, d_degree_v, d_knotsCnt_v);
|
|
|
|
float x = 0., y = 0., z = 0.;
|
|
|
|
for (int i = 0; i < d_pointsCnt_u; i++) {
|
|
|
|
for (int j = 0; j < d_pointsCnt_v; j++) {
|
|
|
|
float N_U = N_Texture_U[d_degree_u * (d_knotsCnt_u - 1) + i];
|
|
|
|
float N_V = N_Texture_V[d_degree_v * (d_knotsCnt_v - 1) + j];
|
|
|
|
int idx = (i * d_pointsCnt_v + j) * d_pointSize;
|
|
|
|
x += N_U * N_V * d_points[idx];
|
|
|
|
y += N_U * N_V * d_points[idx + 1];
|
|
|
|
z += N_U * N_V * d_points[idx + 2];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
printf("(%g, %g)-->(%g, %g, %g)\n", u, v, x, y, z); // %g输出,舍弃无意义的0
|
|
|
|
free(N_Texture_U);
|
|
|
|
free(N_Texture_V);
|
|
|
|
}
|
|
|
|
|
|
|
|
__global__ void
|
|
|
|
NurbsCurve::calculate_kernel(const float *d_points, const float *d_knots, int d_pointsCnt, int d_pointSize,
|
|
|
|
int d_knotsCnt, int d_sampleCnt) {
|
|
|
|
// 二维grid和一维的block
|
|
|
|
int idx = (blockIdx.y * gridDim.x + blockIdx.x) * blockDim.x + threadIdx.x;
|
|
|
|
float d_paramCeil = d_knots[d_knotsCnt - 1];
|
|
|
|
float u = idx * d_paramCeil / (d_sampleCnt - 1);
|
|
|
|
if (u > 1.0 * d_paramCeil) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int d_degree = d_knotsCnt - 1 - d_pointsCnt;
|
|
|
|
// 注意,在device中,全局内存还是以malloc和free的方式分配和回收的,而不是使用cudaMalloc和cudaFree
|
|
|
|
auto *N_Texture = (float *) malloc((d_degree + 1) * (d_knotsCnt - 1) * sizeof(float));
|
|
|
|
d_basisFunction(N_Texture, d_knots, u, d_degree, d_knotsCnt);
|
|
|
|
float x = 0., y = 0., z = 0.;
|
|
|
|
for (int i = 0; i < d_pointsCnt; i++) {
|
|
|
|
float N = N_Texture[d_degree * (d_knotsCnt - 1) + i];
|
|
|
|
int baseIdx = i * d_pointSize;
|
|
|
|
x += N * d_points[baseIdx];
|
|
|
|
y += N * d_points[baseIdx + 1];
|
|
|
|
z += N * d_points[baseIdx + 2];
|
|
|
|
}
|
|
|
|
printf("(%g)-->(%g, %g, %g)\n", u, x, y, z); // %g输出,舍弃无意义的0
|
|
|
|
free(N_Texture);
|
|
|
|
}
|
|
|
|
|
|
|
|
__host__ NurbsCurve::Evaluator::Evaluator(std::vector<std::vector<float>> controlPoints,
|
|
|
|
std::vector<float> knots) {
|
|
|
|
this->knots = std::move(knots);
|
|
|
|
this->controlPoints = std::move(controlPoints);
|
|
|
|
recordTime = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
__host__ std::vector<std::map<float, std::vector<float>>>
|
|
|
|
NurbsCurve::Evaluator::calculate(int sampleCnt) {
|
|
|
|
// 构造指向device的controlPoints
|
|
|
|
const int pointsCnt = controlPoints.size(), pointSize = controlPoints[0].size();
|
|
|
|
const int pointsBytes = pointsCnt * pointSize * sizeof(float);
|
|
|
|
auto *h_points = (float *) malloc(pointsBytes);
|
|
|
|
for (int i = 0; i < pointsCnt; i++) {
|
|
|
|
for (int j = 0; j < pointSize; j++) {
|
|
|
|
h_points[i * pointSize + j] = controlPoints[i][j];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
float *d_points;
|
|
|
|
cudaMalloc((void **) &d_points, pointsBytes);
|
|
|
|
cudaMemcpy(d_points, h_points, pointsBytes, cudaMemcpyHostToDevice);
|
|
|
|
|
|
|
|
// 构造指向device的knots
|
|
|
|
const int knotsCnt = knots.size();
|
|
|
|
const int knotsBytes = knotsCnt * sizeof(float);
|
|
|
|
auto *h_knots = (float *) malloc(knotsBytes);
|
|
|
|
for (int i = 0; i < knotsCnt; i++) h_knots[i] = knots[i];
|
|
|
|
float *d_knots;
|
|
|
|
cudaMalloc((void **) &d_knots, knotsBytes);
|
|
|
|
cudaMemcpy(d_knots, h_knots, knotsBytes, cudaMemcpyHostToDevice);
|
|
|
|
|
|
|
|
// 构造线程层级,调用核函数
|
|
|
|
dim3 block(32, 32);
|
|
|
|
dim3 grid((sampleCnt + block.x * block.y - 1) / (block.x * block.y));
|
|
|
|
// 记录用时
|
|
|
|
double time_cost_device;
|
|
|
|
if(recordTime) time_cost_device = utils::get_time_windows();
|
|
|
|
calculate_kernel <<<grid, block>>>(d_points, d_knots, pointsCnt, pointSize, knotsCnt, sampleCnt);
|
|
|
|
if(recordTime) {
|
|
|
|
cudaDeviceSynchronize(); // 所用线程结束后再获取结束时间。cudaThreadSynchronize()在CUDA1.0后被弃用
|
|
|
|
time_cost_device = utils::get_time_windows() - time_cost_device;
|
|
|
|
printf("GPU time cost of surface evaluation for %d samples: %lf\n", sampleCnt * sampleCnt, time_cost_device);
|
|
|
|
}
|
|
|
|
free(h_points);
|
|
|
|
free(h_knots);
|
|
|
|
cudaFree(d_points);
|
|
|
|
cudaFree(d_knots);
|
|
|
|
|
|
|
|
cudaDeviceReset();
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
__device__ void d_basisFunction(float *N_Texture, const float *knots, float u, int degree, int d_knotsCnt) {
|
|
|
|
int m = d_knotsCnt - 1;
|
|
|
|
for (int p = 0; p <= degree; p++) {
|
|
|
|
for (int i = 0; i + p <= m - 1; i++) {
|
|
|
|
if (p == 0) {
|
|
|
|
if ((u > knots[i] || d_floatEqual(u, knots[i])) && (u < knots[i + 1])
|
|
|
|
||
|
|
|
|
d_floatEqual(u, knots[i + 1]) && d_floatEqual(u, knots[m])) {
|
|
|
|
N_Texture[p * m + i] = 1.0;
|
|
|
|
} else {
|
|
|
|
N_Texture[p * m + i] = 0.0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
float Nip_1 = N_Texture[(p - 1) * m + i];
|
|
|
|
float Ni1p_1 = N_Texture[(p - 1) * m + i + 1];
|
|
|
|
float left = d_floatEqual(knots[i + p], knots[i]) ? 0 : (u - knots[i]) * Nip_1 /
|
|
|
|
(knots[i + p] - knots[i]);
|
|
|
|
float right = d_floatEqual(knots[i + p + 1], knots[i + 1]) ? 0 : (knots[i + p + 1] - u) * Ni1p_1 /
|
|
|
|
(knots[i + p + 1] - knots[i + 1]);
|
|
|
|
N_Texture[p * m + i] = left + right;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
__device__ bool d_floatEqual(float a, float b) {
|
|
|
|
return abs(a - b) < 0.00001;
|
|
|
|
}
|
|
|
|
|
|
|
|
void NurbsCurve::Evaluator::setRecordTime(bool r){
|
|
|
|
recordTime = r;
|
|
|
|
}
|
|
|
|
|
|
|
|
void NurbsSurface::Evaluator::setRecordTime(bool r){
|
|
|
|
recordTime = r;
|
|
|
|
}
|
|
|
|
|