32 bool CUDADevice::have_precompiled_kernels()
34 string cubins_path =
path_get(
"lib");
43 void CUDADevice::set_error(
const string &
error)
48 fprintf(stderr,
"\nRefer to the Cycles GPU rendering documentation for possible solutions:\n");
50 "https://docs.blender.org/manual/en/latest/render/cycles/gpu_rendering.html\n\n");
56 :
Device(info, stats, profiler), texture_info(this,
"texture_info",
MEM_GLOBAL)
66 need_texture_info =
false;
68 device_texture_headroom = 0;
69 device_working_headroom = 0;
70 move_texture_to_host =
false;
77 CUresult
result = cuInit(0);
78 if (
result != CUDA_SUCCESS) {
79 set_error(
string_printf(
"Failed to initialize CUDA runtime (%s)", cuewErrorString(
result)));
84 result = cuDeviceGet(&cuDevice, cuDevId);
85 if (
result != CUDA_SUCCESS) {
86 set_error(
string_printf(
"Failed to get CUDA device handle from ordinal (%s)",
95 cuDeviceGetAttribute(&can_map_host, CU_DEVICE_ATTRIBUTE_CAN_MAP_HOST_MEMORY, cuDevice));
97 cuda_assert(cuDeviceGetAttribute(
98 &pitch_alignment, CU_DEVICE_ATTRIBUTE_TEXTURE_PITCH_ALIGNMENT, cuDevice));
100 unsigned int ctx_flags = CU_CTX_LMEM_RESIZE_TO_MAX;
102 ctx_flags |= CU_CTX_MAP_HOST;
107 result = cuCtxCreate(&cuContext, ctx_flags, cuDevice);
109 if (
result != CUDA_SUCCESS) {
115 cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, cuDevId);
116 cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, cuDevId);
117 cuDevArchitecture = major * 100 + minor * 10;
120 cuCtxPopCurrent(
NULL);
123 CUDADevice::~CUDADevice()
127 cuda_assert(cuCtxDestroy(cuContext));
130 bool CUDADevice::support_device(
const uint )
133 cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, cuDevId);
134 cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, cuDevId);
139 "CUDA backend requires compute capability 3.0 or up, but found %d.%d.", major, minor));
146 bool CUDADevice::check_peer_access(
Device *peer_device)
148 if (peer_device ==
this) {
155 CUDADevice *
const peer_device_cuda =
static_cast<CUDADevice *
>(peer_device);
158 cuda_assert(cuDeviceCanAccessPeer(&can_access, cuDevice, peer_device_cuda->cuDevice));
159 if (can_access == 0) {
164 cuda_assert(cuDeviceGetP2PAttribute(&can_access,
165 CU_DEVICE_P2P_ATTRIBUTE_CUDA_ARRAY_ACCESS_SUPPORTED,
167 peer_device_cuda->cuDevice));
168 if (can_access == 0) {
174 const CUDAContextScope scope(
this);
175 CUresult
result = cuCtxEnablePeerAccess(peer_device_cuda->cuContext, 0);
176 if (
result != CUDA_SUCCESS) {
177 set_error(
string_printf(
"Failed to enable peer access on CUDA context (%s)",
178 cuewErrorString(
result)));
183 const CUDAContextScope scope(peer_device_cuda);
184 CUresult
result = cuCtxEnablePeerAccess(cuContext, 0);
185 if (
result != CUDA_SUCCESS) {
186 set_error(
string_printf(
"Failed to enable peer access on CUDA context (%s)",
187 cuewErrorString(
result)));
195 bool CUDADevice::use_adaptive_compilation()
203 string CUDADevice::compile_kernel_get_common_cflags(
const uint kernel_features)
206 const string source_path =
path_get(
"source");
207 const string include_path = source_path;
210 "--ptxas-options=\"-v\" "
215 include_path.c_str());
216 if (use_adaptive_compilation()) {
217 cflags +=
" -D__KERNEL_FEATURES__=" +
to_string(kernel_features);
219 const char *extra_cflags = getenv(
"CYCLES_CUDA_EXTRA_CFLAGS");
225 cflags +=
" -DWITH_NANOVDB";
228 # ifdef WITH_CYCLES_DEBUG
229 cflags +=
" -DWITH_CYCLES_DEBUG";
235 string CUDADevice::compile_kernel(
const uint kernel_features,
242 cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, cuDevId);
243 cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, cuDevId);
246 if (!use_adaptive_compilation()) {
249 VLOG_INFO <<
"Testing for pre-compiled kernel " << cubin <<
".";
251 VLOG_INFO <<
"Using precompiled kernel.";
257 int ptx_major = major, ptx_minor = minor;
258 while (ptx_major >= 3) {
260 string_printf(
"lib/%s_compute_%d%d.ptx", name, ptx_major, ptx_minor));
261 VLOG_INFO <<
"Testing for pre-compiled kernel " << ptx <<
".";
263 VLOG_INFO <<
"Using precompiled kernel.";
278 string source_path =
path_get(
"source");
284 string common_cflags = compile_kernel_get_common_cflags(kernel_features);
287 const char *
const kernel_ext = force_ptx ?
"ptx" :
"cubin";
288 const char *
const kernel_arch = force_ptx ?
"compute" :
"sm";
290 "cycles_%s_%s_%d%d_%s.%s", name, kernel_arch, major, minor, kernel_md5.c_str(), kernel_ext);
292 VLOG_INFO <<
"Testing for locally compiled kernel " << cubin <<
".";
294 VLOG_INFO <<
"Using locally compiled kernel.";
299 if (!use_adaptive_compilation() && have_precompiled_kernels()) {
302 string_printf(
"CUDA backend requires compute capability 3.0 or up, but found %d.%d. "
303 "Your GPU is not supported.",
309 string_printf(
"CUDA binary kernel for this graphics card compute "
310 "capability (%d.%d) not found.",
319 const char *
const nvcc = cuewCompilerPath();
322 "CUDA nvcc compiler not found. "
323 "Install CUDA toolkit in default location.");
327 const int nvcc_cuda_version = cuewCompilerVersion();
328 VLOG_INFO <<
"Found nvcc " << nvcc <<
", CUDA version " << nvcc_cuda_version <<
".";
329 if (nvcc_cuda_version < 101) {
331 "Unsupported CUDA version %d.%d detected, "
332 "you need CUDA 10.1 or newer.\n",
333 nvcc_cuda_version / 10,
334 nvcc_cuda_version % 10);
337 else if (!(nvcc_cuda_version == 101 || nvcc_cuda_version == 102 || nvcc_cuda_version == 111 ||
338 nvcc_cuda_version == 112 || nvcc_cuda_version == 113 || nvcc_cuda_version == 114)) {
340 "CUDA version %d.%d detected, build may succeed but only "
341 "CUDA 10.1 to 11.4 are officially supported.\n",
342 nvcc_cuda_version / 10,
343 nvcc_cuda_version % 10);
366 common_cflags.c_str());
368 printf(
"Compiling %sCUDA kernel ...\n%s\n",
369 (use_adaptive_compilation()) ?
"adaptive " :
"",
373 command =
"call " + command;
375 if (system(command.c_str()) != 0) {
377 "Failed to execute compilation command, "
378 "see console for details.");
385 "CUDA kernel compilation failed, "
386 "see console for details.");
390 printf(
"Kernel compilation finished in %.2lfs.\n",
time_dt() - starttime);
395 bool CUDADevice::load_kernels(
const uint kernel_features)
403 if (use_adaptive_compilation()) {
405 <<
"Skipping CUDA kernel reload for adaptive compilation, not currently supported.";
415 if (!support_device(kernel_features))
419 const char *kernel_name =
"kernel";
420 string cubin = compile_kernel(kernel_features, kernel_name);
425 CUDAContextScope scope(
this);
431 result = cuModuleLoadData(&cuModule, cubin_data.c_str());
433 result = CUDA_ERROR_FILE_NOT_FOUND;
435 if (
result != CUDA_SUCCESS)
437 "Failed to load CUDA kernel from '%s' (%s)", cubin.c_str(), cuewErrorString(
result)));
439 if (
result == CUDA_SUCCESS) {
441 reserve_local_memory(kernel_features);
444 return (
result == CUDA_SUCCESS);
447 void CUDADevice::reserve_local_memory(
const uint kernel_features)
452 size_t total = 0, free_before = 0, free_after = 0;
455 CUDAContextScope scope(
this);
456 cuMemGetInfo(&free_before, &total);
470 CUDADeviceQueue
queue(
this);
477 queue.init_execution();
478 queue.enqueue(test_kernel, 1, args);
483 CUDAContextScope scope(
this);
484 cuMemGetInfo(&free_after, &total);
492 const size_t keep_mb = 1024;
494 while (free_after > keep_mb * 1024 * 1024LL) {
496 cuda_assert(cuMemAlloc(&tmp, 10 * 1024 * 1024LL));
497 cuMemGetInfo(&free_after, &total);
502 void CUDADevice::init_host_memory()
507 size_t default_limit = 4 * 1024 * 1024 * 1024LL;
510 if (system_ram > 0) {
511 if (system_ram / 2 > default_limit) {
512 map_host_limit = system_ram - default_limit;
515 map_host_limit = system_ram / 2;
519 VLOG_WARNING <<
"Mapped host memory disabled, failed to get system RAM";
527 device_working_headroom = 32 * 1024 * 1024LL;
528 device_texture_headroom = 128 * 1024 * 1024LL;
534 void CUDADevice::load_texture_info()
536 if (need_texture_info) {
539 need_texture_info =
false;
540 texture_info.copy_to_device();
544 void CUDADevice::move_textures_to_host(
size_t size,
bool for_texture)
547 static bool any_device_moving_textures_to_host =
false;
548 if (any_device_moving_textures_to_host) {
553 move_texture_to_host =
true;
559 bool max_is_image =
false;
562 foreach (CUDAMemMap::value_type &pair, cuda_mem_map) {
564 CUDAMem *cmem = &pair.second;
568 if (!mem.
is_resident(
this) || cmem->use_mapped_host) {
573 (&mem != &texture_info);
574 bool is_image = is_texture && (mem.
data_height > 1);
577 if (!is_texture || cmem->array) {
582 if (for_texture && !is_image) {
587 if (is_image > max_is_image || (is_image == max_is_image && mem.
device_size > max_size)) {
588 max_is_image = is_image;
599 VLOG_WORK <<
"Move memory from device to host: " << max_mem->
name;
604 any_device_moving_textures_to_host =
true;
616 any_device_moving_textures_to_host =
false;
624 move_texture_to_host =
false;
630 CUDADevice::CUDAMem *CUDADevice::generic_alloc(
device_memory &mem,
size_t pitch_padding)
632 CUDAContextScope scope(
this);
634 CUdeviceptr device_pointer = 0;
637 CUresult mem_alloc_result = CUDA_ERROR_OUT_OF_MEMORY;
638 const char *status =
"";
648 bool is_image = is_texture && (mem.
data_height > 1);
650 size_t headroom = (is_texture) ? device_texture_headroom : device_working_headroom;
652 size_t total = 0,
free = 0;
653 cuMemGetInfo(&
free, &total);
656 if (!move_texture_to_host && !is_image && (
size + headroom) >=
free && can_map_host) {
657 move_textures_to_host(
size + headroom -
free, is_texture);
658 cuMemGetInfo(&
free, &total);
662 if (!move_texture_to_host && (
size + headroom) <
free) {
663 mem_alloc_result = cuMemAlloc(&device_pointer,
size);
664 if (mem_alloc_result == CUDA_SUCCESS) {
665 status =
" in device memory";
671 void *shared_pointer = 0;
676 mem_alloc_result = CUDA_SUCCESS;
679 else if (map_host_used +
size < map_host_limit) {
681 mem_alloc_result = cuMemHostAlloc(
682 &shared_pointer,
size, CU_MEMHOSTALLOC_DEVICEMAP | CU_MEMHOSTALLOC_WRITECOMBINED);
684 assert((mem_alloc_result == CUDA_SUCCESS && shared_pointer != 0) ||
685 (mem_alloc_result != CUDA_SUCCESS && shared_pointer == 0));
688 if (mem_alloc_result == CUDA_SUCCESS) {
689 cuda_assert(cuMemHostGetDevicePointer_v2(&device_pointer, shared_pointer, 0));
690 map_host_used +=
size;
691 status =
" in host memory";
695 if (mem_alloc_result != CUDA_SUCCESS) {
697 status =
" failed, out of device memory";
698 set_error(
"System is out of GPU memory");
701 status =
" failed, out of device and host memory";
702 set_error(
"System is out of GPU and shared host memory");
722 CUDAMem *cmem = &cuda_mem_map[&mem];
723 if (shared_pointer != 0) {
729 if (!move_texture_to_host && pitch_padding == 0 && mem.
host_pointer &&
745 cmem->use_mapped_host =
true;
748 cmem->use_mapped_host =
false;
765 const CUDAContextScope scope(
this);
774 CUDAContextScope scope(
this);
776 DCHECK(cuda_mem_map.find(&mem) != cuda_mem_map.end());
777 const CUDAMem &cmem = cuda_mem_map[&mem];
782 if (cmem.use_mapped_host) {
805 cuda_mem_map.erase(cuda_mem_map.find(&mem));
812 assert(!
"mem_alloc not supported for textures.");
815 assert(!
"mem_alloc not supported for global memory.");
836 generic_copy_to(mem);
840 void CUDADevice::mem_copy_from(
device_memory &mem,
size_t y,
size_t w,
size_t h,
size_t elem)
843 assert(!
"mem_copy_from not supported for textures.");
846 const size_t size = elem *
w * h;
850 const CUDAContextScope scope(
this);
851 cuda_assert(cuMemcpyDtoH(
873 const CUDAContextScope scope(
this);
899 void CUDADevice::const_copy_to(
const char *name,
void *host,
size_t size)
901 CUDAContextScope scope(
this);
905 cuda_assert(cuModuleGetGlobal(&mem, &bytes, cuModule,
"kernel_params"));
909 # define KERNEL_DATA_ARRAY(data_type, data_name) \
910 if (strcmp(name, #data_name) == 0) { \
911 cuda_assert(cuMemcpyHtoD(mem + offsetof(KernelParamsCUDA, data_name), host, size)); \
916 # include "kernel/data_arrays.h"
917 # undef KERNEL_DATA_ARRAY
924 generic_copy_to(mem);
939 CUDAContextScope scope(
this);
944 CUaddress_mode address_mode = CU_TR_ADDRESS_MODE_WRAP;
947 address_mode = CU_TR_ADDRESS_MODE_WRAP;
950 address_mode = CU_TR_ADDRESS_MODE_CLAMP;
953 address_mode = CU_TR_ADDRESS_MODE_BORDER;
960 CUfilter_mode filter_mode;
962 filter_mode = CU_TR_FILTER_MODE_POINT;
965 filter_mode = CU_TR_FILTER_MODE_LINEAR;
969 CUarray_format_enum
format;
972 format = CU_AD_FORMAT_UNSIGNED_INT8;
975 format = CU_AD_FORMAT_UNSIGNED_INT16;
978 format = CU_AD_FORMAT_UNSIGNED_INT32;
981 format = CU_AD_FORMAT_SIGNED_INT32;
984 format = CU_AD_FORMAT_FLOAT;
987 format = CU_AD_FORMAT_HALF;
994 CUDAMem *cmem =
NULL;
995 CUarray array_3d =
NULL;
997 size_t dst_pitch = src_pitch;
1001 cmem = &cuda_mem_map[&mem];
1002 cmem->texobject = 0;
1006 cmem->array = array_3d;
1009 dst_pitch =
align_up(src_pitch, pitch_alignment);
1014 CUDA_ARRAY3D_DESCRIPTOR desc;
1027 cuda_assert(cuArray3DCreate(&array_3d, &desc));
1033 CUDA_MEMCPY3D param;
1034 memset(¶m, 0,
sizeof(param));
1035 param.dstMemoryType = CU_MEMORYTYPE_ARRAY;
1036 param.dstArray = array_3d;
1037 param.srcMemoryType = CU_MEMORYTYPE_HOST;
1039 param.srcPitch = src_pitch;
1040 param.WidthInBytes = param.srcPitch;
1044 cuda_assert(cuMemcpy3D(¶m));
1051 cmem = &cuda_mem_map[&mem];
1052 cmem->texobject = 0;
1053 cmem->array = array_3d;
1057 dst_pitch =
align_up(src_pitch, pitch_alignment);
1060 cmem = generic_alloc(mem, dst_size - mem.
memory_size());
1065 CUDA_MEMCPY2D param;
1066 memset(¶m, 0,
sizeof(param));
1067 param.dstMemoryType = CU_MEMORYTYPE_DEVICE;
1069 param.dstPitch = dst_pitch;
1070 param.srcMemoryType = CU_MEMORYTYPE_HOST;
1072 param.srcPitch = src_pitch;
1073 param.WidthInBytes = param.srcPitch;
1076 cuda_assert(cuMemcpy2DUnaligned(¶m));
1080 cmem = generic_alloc(mem);
1090 if (slot >= texture_info.size()) {
1093 texture_info.resize(slot + 128);
1097 texture_info[slot] = mem.
info;
1098 need_texture_info =
true;
1104 CUDA_RESOURCE_DESC resDesc;
1105 memset(&resDesc, 0,
sizeof(resDesc));
1108 resDesc.resType = CU_RESOURCE_TYPE_ARRAY;
1109 resDesc.res.array.hArray = array_3d;
1113 resDesc.resType = CU_RESOURCE_TYPE_PITCH2D;
1115 resDesc.res.pitch2D.format =
format;
1119 resDesc.res.pitch2D.pitchInBytes = dst_pitch;
1122 resDesc.resType = CU_RESOURCE_TYPE_LINEAR;
1124 resDesc.res.linear.format =
format;
1129 CUDA_TEXTURE_DESC texDesc;
1130 memset(&texDesc, 0,
sizeof(texDesc));
1131 texDesc.addressMode[0] = address_mode;
1132 texDesc.addressMode[1] = address_mode;
1133 texDesc.addressMode[2] = address_mode;
1134 texDesc.filterMode = filter_mode;
1135 texDesc.flags = CU_TRSF_NORMALIZED_COORDINATES;
1138 cmem = &cuda_mem_map[&mem];
1140 cuda_assert(cuTexObjectCreate(&cmem->texobject, &resDesc, &texDesc,
NULL));
1142 texture_info[slot].data = (
uint64_t)cmem->texobject;
1152 CUDAContextScope scope(
this);
1154 DCHECK(cuda_mem_map.find(&mem) != cuda_mem_map.end());
1155 const CUDAMem &cmem = cuda_mem_map[&mem];
1157 if (cmem.texobject) {
1159 cuTexObjectDestroy(cmem.texobject);
1164 cuda_mem_map.erase(cuda_mem_map.find(&mem));
1166 else if (cmem.array) {
1168 cuArrayDestroy(cmem.array);
1173 cuda_mem_map.erase(cuda_mem_map.find(&mem));
1182 unique_ptr<DeviceQueue> CUDADevice::gpu_queue_create()
1184 return make_unique<CUDADeviceQueue>(
this);
1187 bool CUDADevice::should_use_graphics_interop()
1195 CUDAContextScope scope(
this);
1197 int num_all_devices = 0;
1198 cuda_assert(cuDeviceGetCount(&num_all_devices));
1200 if (num_all_devices == 0) {
1205 uint num_gl_devices = 0;
1206 cuGLGetDevices(&num_gl_devices, gl_devices.data(), num_all_devices, CU_GL_DEVICE_LIST_ALL);
1208 for (
uint i = 0; i < num_gl_devices; ++i) {
1209 if (gl_devices[i] == cuDevice) {
1217 int CUDADevice::get_num_multiprocessors()
1219 return get_device_default_attribute(CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT, 0);
1222 int CUDADevice::get_max_num_threads_per_multiprocessor()
1224 return get_device_default_attribute(CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_MULTIPROCESSOR, 0);
1227 bool CUDADevice::get_device_attribute(CUdevice_attribute
attribute,
int *value)
1229 CUDAContextScope scope(
this);
1231 return cuDeviceGetAttribute(value,
attribute, cuDevice) == CUDA_SUCCESS;
1234 int CUDADevice::get_device_default_attribute(CUdevice_attribute
attribute,
int default_value)
1237 if (!get_device_attribute(
attribute, &value)) {
1238 return default_value;
void BLI_kdtree_nd_() free(KDTree *tree)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
virtual void set_error(const string &error)
void mem_free(size_t size)
void mem_alloc(size_t size)
bool is_resident(Device *sub_device) const
size_t memory_elements_size(int elements)
device_ptr device_pointer
#define CCL_NAMESPACE_END
static constexpr size_t datatype_size(DataType datatype)
#define KERNEL_DATA_ARRAY(type, name)
DebugFlags & DebugFlags()
static const char * to_string(const Interpolation &interp)
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
@ KERNEL_FEATURE_NODE_RAYTRACE
@ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE
@ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE
@ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE
#define DCHECK(expression)
string util_md5_string(const string &str)
static void error(const char *str)
string path_cache_get(const string &sub)
string path_get(const string &sub)
string path_files_md5_hash(const string &dir)
string path_join(const string &dir, const string &file)
bool path_exists(const string &path)
void path_create_directories(const string &filepath)
bool path_read_text(const string &path, string &text)
unsigned __int64 uint64_t
string string_human_readable_size(size_t size)
string string_human_readable_number(size_t num)
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
size_t system_physical_ram()
std::unique_lock< std::mutex > thread_scoped_lock
CCL_NAMESPACE_BEGIN typedef std::mutex thread_mutex
CCL_NAMESPACE_BEGIN double time_dt()
@ IMAGE_DATA_TYPE_NANOVDB_FP16
@ IMAGE_DATA_TYPE_NANOVDB_FLOAT
@ IMAGE_DATA_TYPE_NANOVDB_FLOAT3
@ IMAGE_DATA_TYPE_NANOVDB_FPN
ccl_device_inline size_t align_up(size_t offset, size_t alignment)