OpenVDB 13.0.1
Loading...
Searching...
No Matches
ComputePrimitives.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: Apache-2.0
3
4/// @file ComputePrimitives.h
5/// @brief A collection of parallel compute primitives
6
7#pragma once
8
9#if defined(NANOVDB_USE_CUDA)
10#include <cuda_runtime_api.h>
11#endif
12
13#if defined(NANOVDB_USE_TBB)
14#include <tbb/parallel_for.h>
15#include <tbb/blocked_range.h>
16#endif
17
18#include <utility>
19#include <tuple>
20
21
22#if defined(__CUDACC__)
23
24static inline bool checkCUDA(cudaError_t result, const char* file, const int line)
25{
26 if (result != cudaSuccess) {
27 std::cerr << "CUDA Runtime API error " << result << " in file " << file << ", line " << line << " : " << cudaGetErrorString(result) << ".\n";
28 return false;
29 }
30 return true;
31}
32
33#define NANOVDB_CUDA_SAFE_CALL(x) checkCUDA(x, __FILE__, __LINE__)
34
35static inline void checkErrorCUDA(cudaError_t result, const char* file, const int line)
36{
37 if (result != cudaSuccess) {
38 std::cerr << "CUDA Runtime API error " << result << " in file " << file << ", line " << line << " : " << cudaGetErrorString(result) << ".\n";
39 exit(1);
40 }
41}
42
43#define NANOVDB_CUDA_CHECK_ERROR(result, file, line) checkErrorCUDA(result, file, line)
44
45#endif
46
47template<typename Fn, typename... Args>
49{
50public:
51 ApplyFunc(int count, int blockSize, const Fn& fn, Args... args)
52 : mCount(count)
53 , mBlockSize(blockSize)
54 , mArgs(args...)
55 , mFunc(fn)
56 {
57 }
58
59 template<std::size_t... Is>
60 void call(int start, int end, std::index_sequence<Is...>) const
61 {
62 mFunc(start, end, std::get<Is>(mArgs)...);
63 }
64
65 void operator()(int i) const
66 {
67 int start = i * mBlockSize;
68 int end = i * mBlockSize + mBlockSize;
69 if (end > mCount)
70 end = mCount;
71 call(start, end, std::make_index_sequence<sizeof...(Args)>());
72 }
73
74#if defined(NANOVDB_USE_TBB)
75 void operator()(const tbb::blocked_range<int>& r) const
76 {
77 int start = r.begin();
78 int end = r.end();
79 if (end > mCount)
80 end = mCount;
81 call(start, end, std::make_index_sequence<sizeof...(Args)>());
82 }
83#endif
84
85private:
86 int mCount;
87 int mBlockSize;
88 Fn mFunc;
89 std::tuple<Args...> mArgs;
90};
91
92#if defined(__CUDACC__)
93
94template<int WorkPerThread, typename FnT, typename... Args>
95__global__ void parallelForKernel(int numItems, FnT f, Args... args)
96{
97 for (int j=0;j<WorkPerThread;++j)
98 {
99 int i = threadIdx.x + blockIdx.x * blockDim.x + j * blockDim.x * gridDim.x;
100 if (i < numItems)
101 f(i, i + 1, args...);
102 }
103}
104
105#endif
106
107inline void computeSync(bool useCuda, const char* file, int line)
108{
109#if defined(__CUDACC__)
110 if (useCuda) {
111 NANOVDB_CUDA_CHECK_ERROR(cudaDeviceSynchronize(), file, line);
112 }
113#endif
114}
115
116inline void computeFill(bool useCuda, void* data, uint8_t value, size_t size)
117{
118 if (useCuda) {
119#if defined(__CUDACC__)
120 cudaMemset(data, value, size);
121#endif
122 } else {
123 std::memset(data, value, size);
124 }
125}
126
127template<typename FunctorT, typename... Args>
128inline void computeForEach(bool useCuda, int numItems, int blockSize, const char* file, int line, const FunctorT& op, Args... args)
129{
130 if (numItems == 0)
131 return;
132
133 if (useCuda) {
134#if defined(__CUDACC__)
135 static const int WorkPerThread = 1;
136 int blockCount = ((numItems/WorkPerThread) + (blockSize - 1)) / blockSize;
137 parallelForKernel<WorkPerThread, FunctorT, Args...><<<blockCount, blockSize, 0, 0>>>(numItems, op, args...);
138 NANOVDB_CUDA_CHECK_ERROR(cudaGetLastError(), file, line);
139#endif
140 } else {
141#if defined(NANOVDB_USE_TBB)
142 tbb::blocked_range<int> range(0, numItems, blockSize);
143 tbb::parallel_for(range, ApplyFunc<FunctorT, Args...>(numItems, blockSize, op, args...));
144#else
145 for (int i = 0; i < numItems; ++i)
146 op(i, i + 1, args...);
147#endif
148 }
149}
150
151inline void computeDownload(bool useCuda, void* dst, const void* src, size_t size)
152{
153 if (useCuda) {
154#if defined(__CUDACC__)
155 cudaMemcpy(dst, src, size, cudaMemcpyDeviceToHost);
156#endif
157 } else {
158 std::memcpy(dst, src, size);
159 }
160}
161
162inline void computeCopy(bool useCuda, void* dst, const void* src, size_t size)
163{
164 if (useCuda) {
165#if defined(__CUDACC__)
166 cudaMemcpy(dst, src, size, cudaMemcpyDeviceToDevice);
167#endif
168 } else {
169 std::memcpy(dst, src, size);
170 }
171}
void computeForEach(bool useCuda, int numItems, int blockSize, const char *file, int line, const FunctorT &op, Args... args)
Definition ComputePrimitives.h:128
void computeDownload(bool useCuda, void *dst, const void *src, size_t size)
Definition ComputePrimitives.h:151
void computeSync(bool useCuda, const char *file, int line)
Definition ComputePrimitives.h:107
void computeFill(bool useCuda, void *data, uint8_t value, size_t size)
Definition ComputePrimitives.h:116
void computeCopy(bool useCuda, void *dst, const void *src, size_t size)
Definition ComputePrimitives.h:162
Definition ComputePrimitives.h:49
void operator()(int i) const
Definition ComputePrimitives.h:65
ApplyFunc(int count, int blockSize, const Fn &fn, Args... args)
Definition ComputePrimitives.h:51
void call(int start, int end, std::index_sequence< Is... >) const
Definition ComputePrimitives.h:60
#define __global__
Definition Util.h:79