Blender V4.3
hiprt/device_impl.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2023 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#ifdef WITH_HIPRT
6
8
9# include "util/debug.h"
10# include "util/foreach.h"
11# include "util/log.h"
12# include "util/map.h"
13# include "util/md5.h"
14# include "util/path.h"
15# include "util/progress.h"
16# include "util/string.h"
17# include "util/system.h"
18# include "util/time.h"
19# include "util/types.h"
20# include "util/windows.h"
21
22# include "bvh/hiprt.h"
23
24# include "scene/hair.h"
25# include "scene/mesh.h"
26# include "scene/object.h"
27# include "scene/pointcloud.h"
28
30
31static void get_hiprt_transform(float matrix[][4], Transform &tfm)
32{
33 int row = 0;
34 int col = 0;
35 matrix[row][col++] = tfm.x.x;
36 matrix[row][col++] = tfm.x.y;
37 matrix[row][col++] = tfm.x.z;
38 matrix[row][col++] = tfm.x.w;
39 row++;
40 col = 0;
41 matrix[row][col++] = tfm.y.x;
42 matrix[row][col++] = tfm.y.y;
43 matrix[row][col++] = tfm.y.z;
44 matrix[row][col++] = tfm.y.w;
45 row++;
46 col = 0;
47 matrix[row][col++] = tfm.z.x;
48 matrix[row][col++] = tfm.z.y;
49 matrix[row][col++] = tfm.z.z;
50 matrix[row][col++] = tfm.z.w;
51}
52
53class HIPRTDevice;
54
55BVHLayoutMask HIPRTDevice::get_bvh_layout_mask(const uint /* kernel_features */) const
56{
57 return BVH_LAYOUT_HIPRT;
58}
59
60HIPRTDevice::HIPRTDevice(const DeviceInfo &info, Stats &stats, Profiler &profiler, bool headless)
61 : HIPDevice(info, stats, profiler, headless),
62 hiprt_context(NULL),
63 scene(NULL),
64 functions_table(NULL),
65 scratch_buffer_size(0),
66 scratch_buffer(this, "scratch_buffer", MEM_DEVICE_ONLY),
67 prim_visibility(this, "prim_visibility", MEM_GLOBAL),
68 instance_transform_matrix(this, "instance_transform_matrix", MEM_READ_ONLY),
69 transform_headers(this, "transform_headers", MEM_READ_ONLY),
70 user_instance_id(this, "user_instance_id", MEM_GLOBAL),
71 hiprt_blas_ptr(this, "hiprt_blas_ptr", MEM_READ_WRITE),
72 blas_ptr(this, "blas_ptr", MEM_GLOBAL),
73 custom_prim_info(this, "custom_prim_info", MEM_GLOBAL),
74 custom_prim_info_offset(this, "custom_prim_info_offset", MEM_GLOBAL),
75 prims_time(this, "prims_time", MEM_GLOBAL),
76 prim_time_offset(this, "prim_time_offset", MEM_GLOBAL)
77{
78 HIPContextScope scope(this);
79 global_stack_buffer = {0};
80 hiprtContextCreationInput hiprt_context_input = {0};
81 hiprt_context_input.ctxt = hipContext;
82 hiprt_context_input.device = hipDevice;
83 hiprt_context_input.deviceType = hiprtDeviceAMD;
84 hiprtError rt_result = hiprtCreateContext(
85 HIPRT_API_VERSION, hiprt_context_input, &hiprt_context);
86
87 if (rt_result != hiprtSuccess) {
88 set_error(string_printf("Failed to create HIPRT context"));
89 return;
90 }
91
92 rt_result = hiprtCreateFuncTable(
93 hiprt_context, Max_Primitive_Type, Max_Intersect_Filter_Function, functions_table);
94
95 if (rt_result != hiprtSuccess) {
96 set_error(string_printf("Failed to create HIPRT Function Table"));
97 return;
98 }
99
100 hiprtSetLogLevel(hiprtLogLevelNone);
101}
102
103HIPRTDevice::~HIPRTDevice()
104{
105 HIPContextScope scope(this);
106 user_instance_id.free();
107 prim_visibility.free();
108 hiprt_blas_ptr.free();
109 blas_ptr.free();
110 instance_transform_matrix.free();
111 transform_headers.free();
112 custom_prim_info_offset.free();
113 custom_prim_info.free();
114 prim_time_offset.free();
115 prims_time.free();
116
117 hiprtDestroyGlobalStackBuffer(hiprt_context, global_stack_buffer);
118 hiprtDestroyFuncTable(hiprt_context, functions_table);
119 hiprtDestroyScene(hiprt_context, scene);
120 hiprtDestroyContext(hiprt_context);
121}
122
123unique_ptr<DeviceQueue> HIPRTDevice::gpu_queue_create()
124{
125 return make_unique<HIPRTDeviceQueue>(this);
126}
127
128string HIPRTDevice::compile_kernel_get_common_cflags(const uint kernel_features)
129{
130 string cflags = HIPDevice::compile_kernel_get_common_cflags(kernel_features);
131
132 cflags += " -D __HIPRT__ ";
133
134 return cflags;
135}
136
137string HIPRTDevice::compile_kernel(const uint kernel_features, const char *name, const char *base)
138{
139 int major, minor;
140 hipDeviceGetAttribute(&major, hipDeviceAttributeComputeCapabilityMajor, hipDevId);
141 hipDeviceGetAttribute(&minor, hipDeviceAttributeComputeCapabilityMinor, hipDevId);
142 const std::string arch = hipDeviceArch(hipDevId);
143
144 if (!use_adaptive_compilation()) {
145 const string fatbin = path_get(string_printf("lib/%s_rt_gfx.hipfb.zst", name));
146 VLOG(1) << "Testing for pre-compiled kernel " << fatbin << ".";
147 if (path_exists(fatbin)) {
148 VLOG(1) << "Using precompiled kernel.";
149 return fatbin;
150 }
151 }
152
153 string source_path = path_get("source");
154 const string source_md5 = path_files_md5_hash(source_path);
155
156 string common_cflags = compile_kernel_get_common_cflags(kernel_features);
157 const string kernel_md5 = util_md5_string(source_md5 + common_cflags);
158
159 const string include_path = source_path;
160 const string cycles_bc = string_printf(
161 "cycles_%s_%s_%s.bc", name, arch.c_str(), kernel_md5.c_str());
162 const string cycles_bitcode = path_cache_get(path_join("kernels", cycles_bc));
163 const string fatbin_file = string_printf(
164 "cycles_%s_%s_%s.hipfb", name, arch.c_str(), kernel_md5.c_str());
165 const string fatbin = path_cache_get(path_join("kernels", fatbin_file));
166 const string hiprt_bc = string_printf(
167 "hiprt_%s_%s_%s.bc", name, arch.c_str(), kernel_md5.c_str());
168 const string hiprt_bitcode = path_cache_get(path_join("kernels", hiprt_bc));
169
170 const string hiprt_include_path = path_join(source_path, "kernel/device/hiprt");
171
172 VLOG(1) << "Testing for locally compiled kernel " << fatbin << ".";
173 if (path_exists(fatbin)) {
174 VLOG(1) << "Using locally compiled kernel.";
175 return fatbin;
176 }
177
178# ifdef _WIN32
179 if (!use_adaptive_compilation() && have_precompiled_kernels()) {
180 if (!hipSupportsDevice(hipDevId)) {
181 set_error(
182 string_printf("HIP backend requires compute capability 10.1 or up, but found %d.%d. "
183 "Your GPU is not supported.",
184 major,
185 minor));
186 }
187 else {
188 set_error(
189 string_printf("HIP binary kernel for this graphics card compute "
190 "capability (%d.%d) not found.",
191 major,
192 minor));
193 }
194 return string();
195 }
196# endif
197
198 const char *const hipcc = hipewCompilerPath();
199 if (hipcc == NULL) {
200 set_error(
201 "HIP hipcc compiler not found. "
202 "Install HIP toolkit in default location.");
203 return string();
204 }
205
206 const int hipcc_hip_version = hipewCompilerVersion();
207 VLOG_INFO << "Found hipcc " << hipcc << ", HIP version " << hipcc_hip_version << ".";
208 if (hipcc_hip_version < 40) {
209 printf(
210 "Unsupported HIP version %d.%d detected, "
211 "you need HIP 4.0 or newer.\n",
212 hipcc_hip_version / 10,
213 hipcc_hip_version % 10);
214 return string();
215 }
216
218
219 string rtc_options;
220 rtc_options.append(" --offload-arch=").append(arch.c_str());
221 rtc_options.append(" -D __HIPRT__");
222 rtc_options.append(" -ffast-math -O3 -std=c++17");
223 rtc_options.append(" -fgpu-rdc -c --gpu-bundle-output -c -emit-llvm");
224
225 source_path = path_join(path_join(source_path, "kernel"),
226 path_join("device", path_join(base, string_printf("%s.cpp", name))));
227
228 printf("Compiling %s and caching to %s", source_path.c_str(), fatbin.c_str());
229
230 double starttime = time_dt();
231
232 if (!path_exists(cycles_bitcode)) {
233
234 string command = string_printf("%s %s -I %s -I %s %s -o \"%s\"",
235 hipcc,
236 rtc_options.c_str(),
237 include_path.c_str(),
238 hiprt_include_path.c_str(),
239 source_path.c_str(),
240 cycles_bitcode.c_str());
241
242 printf("Compiling %sHIP kernel ...\n%s\n",
243 (use_adaptive_compilation()) ? "adaptive " : "",
244 command.c_str());
245
246# ifdef _WIN32
247 command = "call " + command;
248# endif
249 if (system(command.c_str()) != 0) {
250 set_error(
251 "Failed to execute compilation command, "
252 "see console for details.");
253 return string();
254 }
255 }
256
257 if (!path_exists(hiprt_bitcode)) {
258
259 rtc_options.append(" -x hip");
260 rtc_options.append(" -D HIPRT_BITCODE_LINKING ");
261
262 string source_path = path_join(hiprt_include_path, "/hiprt/impl/hiprt_kernels_bitcode.h");
263
264 string command = string_printf("%s %s -I %s %s -o \"%s\"",
265 hipcc,
266 rtc_options.c_str(),
267 hiprt_include_path.c_str(),
268 source_path.c_str(),
269 hiprt_bitcode.c_str());
270
271 printf("Compiling %sHIP kernel ...\n%s\n",
272 (use_adaptive_compilation()) ? "adaptive " : "",
273 command.c_str());
274
275# ifdef _WIN32
276 command = "call " + command;
277# endif
278 if (system(command.c_str()) != 0) {
279 set_error(
280 "Failed to execute compilation command, "
281 "see console for details.");
282 return string();
283 }
284 }
285
286 // After compilation, the bitcode produced is linked with HIP RT bitcode (containing
287 // implementations of HIP RT functions, e.g. traversal, to produce the final executable code
288 string linker_options;
289 linker_options.append(" --offload-arch=").append(arch.c_str());
290 linker_options.append(" -fgpu-rdc --hip-link --cuda-device-only ");
291
292 string linker_command = string_printf("clang++ %s \"%s\" \"%s\" -o \"%s\"",
293 linker_options.c_str(),
294 cycles_bitcode.c_str(),
295 hiprt_bitcode.c_str(),
296 fatbin.c_str());
297
298# ifdef _WIN32
299 linker_command = "call " + linker_command;
300# endif
301 if (system(linker_command.c_str()) != 0) {
302 set_error(
303 "Failed to execute linking command, "
304 "see console for details.");
305 return string();
306 }
307
308 printf("Kernel compilation finished in %.2lfs.\n", time_dt() - starttime);
309
310 return fatbin;
311}
312
313bool HIPRTDevice::load_kernels(const uint kernel_features)
314{
315 if (hipModule) {
316 if (use_adaptive_compilation()) {
317 VLOG(1) << "Skipping HIP kernel reload for adaptive compilation, not currently supported.";
318 }
319 return true;
320 }
321
322 if (hipContext == 0)
323 return false;
324
325 if (!support_device(kernel_features)) {
326 return false;
327 }
328
329 /* get kernel */
330 const char *kernel_name = "kernel";
331 string fatbin = compile_kernel(kernel_features, kernel_name);
332 if (fatbin.empty())
333 return false;
334
335 /* open module */
336 HIPContextScope scope(this);
337
338 string fatbin_data;
339 hipError_t result;
340
341 if (path_read_compressed_text(fatbin, fatbin_data)) {
342 result = hipModuleLoadData(&hipModule, fatbin_data.c_str());
343 }
344 else
345 result = hipErrorFileNotFound;
346
347 if (result != hipSuccess)
348 set_error(string_printf(
349 "Failed to load HIP kernel from '%s' (%s)", fatbin.c_str(), hipewErrorString(result)));
350
351 if (result == hipSuccess) {
352 kernels.load(this);
353 {
354 const DeviceKernel test_kernel = (kernel_features & KERNEL_FEATURE_NODE_RAYTRACE) ?
356 (kernel_features & KERNEL_FEATURE_MNEE) ?
359
360 HIPRTDeviceQueue queue(this);
361
362 device_ptr d_path_index = 0;
363 device_ptr d_render_buffer = 0;
364 int d_work_size = 0;
365 DeviceKernelArguments args(&d_path_index, &d_render_buffer, &d_work_size);
366
367 queue.init_execution();
368 queue.enqueue(test_kernel, 1, args);
369 queue.synchronize();
370 }
371 }
372
373 return (result == hipSuccess);
374}
375
376void HIPRTDevice::const_copy_to(const char *name, void *host, size_t size)
377{
378 HIPContextScope scope(this);
379 hipDeviceptr_t mem;
380 size_t bytes;
381
382 if (strcmp(name, "data") == 0) {
383 assert(size <= sizeof(KernelData));
384 KernelData *const data = (KernelData *)host;
385 *(hiprtScene *)&data->device_bvh = scene;
386 }
387
388 hip_assert(hipModuleGetGlobal(&mem, &bytes, hipModule, "kernel_params"));
389 assert(bytes == sizeof(KernelParamsHIPRT));
390
391# define KERNEL_DATA_ARRAY(data_type, data_name) \
392 if (strcmp(name, #data_name) == 0) { \
393 hip_assert(hipMemcpyHtoD(mem + offsetof(KernelParamsHIPRT, data_name), host, size)); \
394 return; \
395 }
397 KERNEL_DATA_ARRAY(IntegratorStateGPU, integrator_state)
398 KERNEL_DATA_ARRAY(int, user_instance_id)
399 KERNEL_DATA_ARRAY(uint64_t, blas_ptr)
400 KERNEL_DATA_ARRAY(int2, custom_prim_info_offset)
401 KERNEL_DATA_ARRAY(int2, custom_prim_info)
402 KERNEL_DATA_ARRAY(int, prim_time_offset)
403 KERNEL_DATA_ARRAY(float2, prims_time)
404
405# include "kernel/data_arrays.h"
406# undef KERNEL_DATA_ARRAY
407}
408
409hiprtGeometryBuildInput HIPRTDevice::prepare_triangle_blas(BVHHIPRT *bvh, Mesh *mesh)
410{
411 hiprtGeometryBuildInput geom_input;
412 geom_input.geomType = Triangle;
413
414 if (mesh->has_motion_blur()) {
415
417 const float3 *vert_steps = attr_mP->data_float3();
418 const size_t num_verts = mesh->get_verts().size();
419 const size_t num_steps = mesh->get_motion_steps();
420 const size_t num_triangles = mesh->num_triangles();
421 const float3 *verts = mesh->get_verts().data();
422 int num_bounds = 0;
423
424 if (bvh->params.num_motion_triangle_steps == 0 || bvh->params.use_spatial_split) {
425 bvh->custom_primitive_bound.alloc(num_triangles);
426 bvh->custom_prim_info.resize(num_triangles);
427 for (uint j = 0; j < num_triangles; j++) {
428 Mesh::Triangle t = mesh->get_triangle(j);
431 for (size_t step = 0; step < num_steps - 1; step++) {
432 t.bounds_grow(vert_steps + step * num_verts, bounds);
433 }
434
435 if (bounds.valid()) {
436 bvh->custom_primitive_bound[num_bounds] = bounds;
437 bvh->custom_prim_info[num_bounds].x = j;
438 bvh->custom_prim_info[num_bounds].y = mesh->primitive_type();
439 num_bounds++;
440 }
441 }
442 }
443 else {
444 const int num_bvh_steps = bvh->params.num_motion_triangle_steps * 2 + 1;
445 const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
446
447 bvh->custom_primitive_bound.alloc(num_triangles * num_bvh_steps);
448 bvh->custom_prim_info.resize(num_triangles * num_bvh_steps);
449 bvh->prims_time.resize(num_triangles * num_bvh_steps);
450
451 for (uint j = 0; j < num_triangles; j++) {
452 Mesh::Triangle t = mesh->get_triangle(j);
453 float3 prev_verts[3];
454 t.motion_verts(verts, vert_steps, num_verts, num_steps, 0.0f, prev_verts);
455 BoundBox prev_bounds = BoundBox::empty;
456 prev_bounds.grow(prev_verts[0]);
457 prev_bounds.grow(prev_verts[1]);
458 prev_bounds.grow(prev_verts[2]);
459
460 for (int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) {
461 const float curr_time = (float)(bvh_step)*num_bvh_steps_inv_1;
462 float3 curr_verts[3];
463 t.motion_verts(verts, vert_steps, num_verts, num_steps, curr_time, curr_verts);
464 BoundBox curr_bounds = BoundBox::empty;
465 curr_bounds.grow(curr_verts[0]);
466 curr_bounds.grow(curr_verts[1]);
467 curr_bounds.grow(curr_verts[2]);
468 BoundBox bounds = prev_bounds;
469 bounds.grow(curr_bounds);
470 if (bounds.valid()) {
471 const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1;
472 bvh->custom_primitive_bound[num_bounds] = bounds;
473 bvh->custom_prim_info[num_bounds].x = j;
474 bvh->custom_prim_info[num_bounds].y = mesh->primitive_type();
475 bvh->prims_time[num_bounds].x = curr_time;
476 bvh->prims_time[num_bounds].y = prev_time;
477 num_bounds++;
478 }
479 prev_bounds = curr_bounds;
480 }
481 }
482 }
483
484 bvh->custom_prim_aabb.aabbCount = num_bounds;
485 bvh->custom_prim_aabb.aabbStride = sizeof(BoundBox);
486 bvh->custom_primitive_bound.copy_to_device();
487 bvh->custom_prim_aabb.aabbs = (void *)bvh->custom_primitive_bound.device_pointer;
488
489 geom_input.type = hiprtPrimitiveTypeAABBList;
490 geom_input.primitive.aabbList = bvh->custom_prim_aabb;
491 geom_input.geomType = Motion_Triangle;
492 }
493 else {
494 size_t triangle_size = mesh->get_triangles().size();
495 void *triangle_data = mesh->get_triangles().data();
496
497 size_t vertex_size = mesh->get_verts().size();
498 void *vertex_data = mesh->get_verts().data();
499
500 bvh->triangle_mesh.triangleCount = mesh->num_triangles();
501 bvh->triangle_mesh.triangleStride = 3 * sizeof(int);
502 bvh->triangle_mesh.vertexCount = vertex_size;
503 bvh->triangle_mesh.vertexStride = sizeof(float3);
504
505 bvh->triangle_index.host_pointer = triangle_data;
506 bvh->triangle_index.data_elements = 1;
507 bvh->triangle_index.data_type = TYPE_INT;
508 bvh->triangle_index.data_size = triangle_size;
509 bvh->triangle_index.copy_to_device();
510 bvh->triangle_mesh.triangleIndices = (void *)(bvh->triangle_index.device_pointer);
511 // either has to set the host pointer to zero, or increment the refcount on triangle_data
512 bvh->triangle_index.host_pointer = 0;
513 bvh->vertex_data.host_pointer = vertex_data;
514 bvh->vertex_data.data_elements = 4;
515 bvh->vertex_data.data_type = TYPE_FLOAT;
516 bvh->vertex_data.data_size = vertex_size;
517 bvh->vertex_data.copy_to_device();
518 bvh->triangle_mesh.vertices = (void *)(bvh->vertex_data.device_pointer);
519 bvh->vertex_data.host_pointer = 0;
520
521 geom_input.type = hiprtPrimitiveTypeTriangleMesh;
522 geom_input.primitive.triangleMesh = bvh->triangle_mesh;
523 }
524
525 return geom_input;
526}
527
528hiprtGeometryBuildInput HIPRTDevice::prepare_curve_blas(BVHHIPRT *bvh, Hair *hair)
529{
530 hiprtGeometryBuildInput geom_input;
531
532 const PrimitiveType primitive_type = hair->primitive_type();
533 const size_t num_curves = hair->num_curves();
534 const size_t num_segments = hair->num_segments();
535 const Attribute *curve_attr_mP = NULL;
536
537 if (curve_attr_mP == NULL || bvh->params.num_motion_curve_steps == 0) {
538
539 bvh->custom_prim_info.resize(num_segments);
540 bvh->custom_primitive_bound.alloc(num_segments);
541 }
542 else {
543 size_t num_boxes = bvh->params.num_motion_curve_steps * 2 * num_segments;
544 bvh->custom_prim_info.resize(num_boxes);
545 bvh->prims_time.resize(num_boxes);
546 bvh->custom_primitive_bound.alloc(num_boxes);
547 curve_attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
548 }
549
550 int num_bounds = 0;
551 float3 *curve_keys = hair->get_curve_keys().data();
552
553 for (uint j = 0; j < num_curves; j++) {
554 const Hair::Curve curve = hair->get_curve(j);
555 const float *curve_radius = &hair->get_curve_radius()[0];
556 int first_key = curve.first_key;
557 for (int k = 0; k < curve.num_keys - 1; k++) {
558 if (curve_attr_mP == NULL) {
559 float3 current_keys[4];
560 current_keys[0] = curve_keys[max(first_key + k - 1, first_key)];
561 current_keys[1] = curve_keys[first_key + k];
562 current_keys[2] = curve_keys[first_key + k + 1];
563 current_keys[3] = curve_keys[min(first_key + k + 2, first_key + curve.num_keys - 1)];
564
565 if (current_keys[0].x == current_keys[1].x && current_keys[1].x == current_keys[2].x &&
566 current_keys[2].x == current_keys[3].x && current_keys[0].y == current_keys[1].y &&
567 current_keys[1].y == current_keys[2].y && current_keys[2].y == current_keys[3].y &&
568 current_keys[0].z == current_keys[1].z && current_keys[1].z == current_keys[2].z &&
569 current_keys[2].z == current_keys[3].z)
570 continue;
571
573 curve.bounds_grow(k, &hair->get_curve_keys()[0], curve_radius, bounds);
574 if (bounds.valid()) {
575 int type = PRIMITIVE_PACK_SEGMENT(primitive_type, k);
576 bvh->custom_prim_info[num_bounds].x = j;
577 bvh->custom_prim_info[num_bounds].y = type;
578 bvh->custom_primitive_bound[num_bounds] = bounds;
579 num_bounds++;
580 }
581 }
582 else {
583 const size_t num_steps = hair->get_motion_steps();
584 const float4 *key_steps = curve_attr_mP->data_float4();
585 const size_t num_keys = hair->get_curve_keys().size();
586
587 if (bvh->params.num_motion_curve_steps == 0 || bvh->params.use_spatial_split) {
589 curve.bounds_grow(k, &hair->get_curve_keys()[0], curve_radius, bounds);
590 for (size_t step = 0; step < num_steps - 1; step++) {
591 curve.bounds_grow(k, key_steps + step * num_keys, bounds);
592 }
593 if (bounds.valid()) {
594 int type = PRIMITIVE_PACK_SEGMENT(primitive_type, k);
595 bvh->custom_prim_info[num_bounds].x = j;
596 bvh->custom_prim_info[num_bounds].y = type;
597 bvh->custom_primitive_bound[num_bounds] = bounds;
598 num_bounds++;
599 }
600 }
601 else {
602 const int num_bvh_steps = bvh->params.num_motion_curve_steps * 2 + 1;
603 const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
604
605 float4 prev_keys[4];
606 curve.cardinal_motion_keys(curve_keys,
607 curve_radius,
608 key_steps,
609 num_keys,
610 num_steps,
611 0.0f,
612 k - 1,
613 k,
614 k + 1,
615 k + 2,
616 prev_keys);
617 BoundBox prev_bounds = BoundBox::empty;
618 curve.bounds_grow(prev_keys, prev_bounds);
619
620 for (int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) {
621 const float curr_time = (float)(bvh_step)*num_bvh_steps_inv_1;
622 float4 curr_keys[4];
623 curve.cardinal_motion_keys(curve_keys,
624 curve_radius,
625 key_steps,
626 num_keys,
627 num_steps,
628 curr_time,
629 k - 1,
630 k,
631 k + 1,
632 k + 2,
633 curr_keys);
634 BoundBox curr_bounds = BoundBox::empty;
635 curve.bounds_grow(curr_keys, curr_bounds);
636 BoundBox bounds = prev_bounds;
637 bounds.grow(curr_bounds);
638 if (bounds.valid()) {
639 const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1;
640 int packed_type = PRIMITIVE_PACK_SEGMENT(primitive_type, k);
641 bvh->custom_prim_info[num_bounds].x = j;
642 bvh->custom_prim_info[num_bounds].y = packed_type; // k
643 bvh->custom_primitive_bound[num_bounds] = bounds;
644 bvh->prims_time[num_bounds].x = curr_time;
645 bvh->prims_time[num_bounds].y = prev_time;
646 num_bounds++;
647 }
648 prev_bounds = curr_bounds;
649 }
650 }
651 }
652 }
653 }
654
655 bvh->custom_prim_aabb.aabbCount = num_bounds;
656 bvh->custom_prim_aabb.aabbStride = sizeof(BoundBox);
657 bvh->custom_primitive_bound.copy_to_device();
658 bvh->custom_prim_aabb.aabbs = (void *)bvh->custom_primitive_bound.device_pointer;
659
660 geom_input.type = hiprtPrimitiveTypeAABBList;
661 geom_input.primitive.aabbList = bvh->custom_prim_aabb;
662 geom_input.geomType = Curve;
663
664 return geom_input;
665}
666
667hiprtGeometryBuildInput HIPRTDevice::prepare_point_blas(BVHHIPRT *bvh, PointCloud *pointcloud)
668{
669 hiprtGeometryBuildInput geom_input;
670
671 const Attribute *point_attr_mP = NULL;
672 if (pointcloud->has_motion_blur()) {
673 point_attr_mP = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
674 }
675
676 const float3 *points_data = pointcloud->get_points().data();
677 const float *radius_data = pointcloud->get_radius().data();
678 const size_t num_points = pointcloud->num_points();
679 const float4 *motion_data = (point_attr_mP) ? point_attr_mP->data_float4() : NULL;
680 const size_t num_steps = pointcloud->get_motion_steps();
681
682 int num_bounds = 0;
683
684 if (point_attr_mP == NULL) {
685 bvh->custom_prim_info.resize(num_points);
686 bvh->custom_primitive_bound.alloc(num_points);
687 for (uint j = 0; j < num_points; j++) {
688 const PointCloud::Point point = pointcloud->get_point(j);
690 point.bounds_grow(points_data, radius_data, bounds);
691 if (bounds.valid()) {
692 bvh->custom_primitive_bound[num_bounds] = bounds;
693 bvh->custom_prim_info[num_bounds].x = j;
694 bvh->custom_prim_info[num_bounds].y = PRIMITIVE_POINT;
695 num_bounds++;
696 }
697 }
698 }
699 else if (bvh->params.num_motion_point_steps == 0 || bvh->params.use_spatial_split) {
700 bvh->custom_prim_info.resize(num_points);
701 bvh->custom_primitive_bound.alloc(num_points);
702
703 for (uint j = 0; j < num_points; j++) {
704 const PointCloud::Point point = pointcloud->get_point(j);
706 point.bounds_grow(points_data, radius_data, bounds);
707 for (size_t step = 0; step < num_steps - 1; step++) {
708 point.bounds_grow(motion_data[step * num_points + j], bounds);
709 }
710 if (bounds.valid()) {
711 bvh->custom_primitive_bound[num_bounds] = bounds;
712 bvh->custom_prim_info[num_bounds].x = j;
713 bvh->custom_prim_info[num_bounds].y = PRIMITIVE_MOTION_POINT;
714 num_bounds++;
715 }
716 }
717 }
718 else {
719 const int num_bvh_steps = bvh->params.num_motion_point_steps * 2 + 1;
720 const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
721
722 bvh->custom_prim_info.resize(num_points * num_bvh_steps);
723 bvh->custom_primitive_bound.alloc(num_points * num_bvh_steps);
724 bvh->prims_time.resize(num_points * num_bvh_steps);
725
726 for (uint j = 0; j < num_points; j++) {
727 const PointCloud::Point point = pointcloud->get_point(j);
728 const size_t num_steps = pointcloud->get_motion_steps();
729 const float4 *point_steps = point_attr_mP->data_float4();
730
731 float4 prev_key = point.motion_key(
732 points_data, radius_data, point_steps, num_points, num_steps, 0.0f, j);
733 BoundBox prev_bounds = BoundBox::empty;
734 point.bounds_grow(prev_key, prev_bounds);
735
736 for (int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) {
737 const float curr_time = (float)(bvh_step)*num_bvh_steps_inv_1;
738 float4 curr_key = point.motion_key(
739 points_data, radius_data, point_steps, num_points, num_steps, curr_time, j);
740 BoundBox curr_bounds = BoundBox::empty;
741 point.bounds_grow(curr_key, curr_bounds);
742 BoundBox bounds = prev_bounds;
743 bounds.grow(curr_bounds);
744 if (bounds.valid()) {
745 const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1;
746 bvh->custom_primitive_bound[num_bounds] = bounds;
747 bvh->custom_prim_info[num_bounds].x = j;
748 bvh->custom_prim_info[num_bounds].y = PRIMITIVE_MOTION_POINT;
749 bvh->prims_time[num_bounds].x = prev_time;
750 bvh->prims_time[num_bounds].y = curr_time;
751 num_bounds++;
752 }
753 prev_bounds = curr_bounds;
754 }
755 }
756 }
757
758 bvh->custom_prim_aabb.aabbCount = num_bounds;
759 bvh->custom_prim_aabb.aabbStride = sizeof(BoundBox);
760 bvh->custom_primitive_bound.copy_to_device();
761 bvh->custom_prim_aabb.aabbs = (void *)bvh->custom_primitive_bound.device_pointer;
762
763 geom_input.type = hiprtPrimitiveTypeAABBList;
764 geom_input.primitive.aabbList = bvh->custom_prim_aabb;
765 geom_input.geomType = Point;
766
767 return geom_input;
768}
769
770void HIPRTDevice::build_blas(BVHHIPRT *bvh, Geometry *geom, hiprtBuildOptions options)
771{
772 hiprtGeometryBuildInput geom_input = {};
773
774 switch (geom->geometry_type) {
775 case Geometry::MESH:
776 case Geometry::VOLUME: {
777 Mesh *mesh = static_cast<Mesh *>(geom);
778
779 if (mesh->num_triangles() == 0)
780 return;
781
782 geom_input = prepare_triangle_blas(bvh, mesh);
783 break;
784 }
785
786 case Geometry::HAIR: {
787 Hair *const hair = static_cast<Hair *const>(geom);
788
789 if (hair->num_segments() == 0)
790 return;
791
792 geom_input = prepare_curve_blas(bvh, hair);
793 break;
794 }
795
797 PointCloud *pointcloud = static_cast<PointCloud *>(geom);
798 if (pointcloud->num_points() == 0)
799 return;
800
801 geom_input = prepare_point_blas(bvh, pointcloud);
802 break;
803 }
804
805 default:
806 assert(geom_input.geomType != hiprtInvalidValue);
807 }
808
809 size_t blas_scratch_buffer_size = 0;
810 hiprtError rt_err = hiprtGetGeometryBuildTemporaryBufferSize(
811 hiprt_context, geom_input, options, blas_scratch_buffer_size);
812
813 if (rt_err != hiprtSuccess) {
814 set_error(string_printf("Failed to get scratch buffer size for BLAS!"));
815 }
816
817 rt_err = hiprtCreateGeometry(hiprt_context, geom_input, options, bvh->hiprt_geom);
818
819 if (rt_err != hiprtSuccess) {
820 set_error(string_printf("Failed to create BLAS!"));
821 }
822 bvh->geom_input = geom_input;
823 {
824 thread_scoped_lock lock(hiprt_mutex);
825 if (blas_scratch_buffer_size > scratch_buffer_size) {
826 scratch_buffer.alloc(blas_scratch_buffer_size);
827 scratch_buffer_size = blas_scratch_buffer_size;
828 scratch_buffer.zero_to_device();
829 }
830 rt_err = hiprtBuildGeometry(hiprt_context,
831 hiprtBuildOperationBuild,
832 bvh->geom_input,
833 options,
834 (void *)(scratch_buffer.device_pointer),
835 0,
836 bvh->hiprt_geom);
837 }
838 if (rt_err != hiprtSuccess) {
839 set_error(string_printf("Failed to build BLAS"));
840 }
841}
842
843hiprtScene HIPRTDevice::build_tlas(BVHHIPRT *bvh,
844 vector<Object *> objects,
845 hiprtBuildOptions options,
846 bool refit)
847{
848
849 size_t num_object = objects.size();
850 if (num_object == 0) {
851 return 0;
852 }
853
854 hiprtBuildOperation build_operation = refit ? hiprtBuildOperationUpdate :
855 hiprtBuildOperationBuild;
856
857 array<hiprtFrameMatrix> transform_matrix;
858
859 unordered_map<Geometry *, int2> prim_info_map;
860 size_t custom_prim_offset = 0;
861
862 unordered_map<Geometry *, int> prim_time_map;
863
864 size_t num_instances = 0;
865 int blender_instance_id = 0;
866
867 user_instance_id.alloc(num_object);
868 prim_visibility.alloc(num_object);
869 hiprt_blas_ptr.alloc(num_object);
870 blas_ptr.alloc(num_object);
871 transform_headers.alloc(num_object);
872 custom_prim_info_offset.alloc(num_object);
873 prim_time_offset.alloc(num_object);
874
875 foreach (Object *ob, objects) {
876 uint32_t mask = 0;
877 if (ob->is_traceable()) {
879 }
880
881 Transform current_transform = ob->get_tfm();
882 Geometry *geom = ob->get_geometry();
883 bool transform_applied = geom->transform_applied;
884
885 BVHHIPRT *current_bvh = static_cast<BVHHIPRT *>(geom->bvh);
886 bool is_valid_geometry = current_bvh->geom_input.geomType != hiprtInvalidValue;
887 hiprtGeometry hiprt_geom_current = current_bvh->hiprt_geom;
888
889 hiprtFrameMatrix hiprt_transform_matrix = {{{0}}};
890 Transform identity_matrix = transform_identity();
891 get_hiprt_transform(hiprt_transform_matrix.matrix, identity_matrix);
892
893 if (is_valid_geometry) {
894 bool is_custom_prim = current_bvh->custom_prim_info.size() > 0;
895
896 if (is_custom_prim) {
897
898 bool has_motion_blur = current_bvh->prims_time.size() > 0;
899
900 unordered_map<Geometry *, int2>::iterator it = prim_info_map.find(geom);
901
902 if (prim_info_map.find(geom) != prim_info_map.end()) {
903
904 custom_prim_info_offset[blender_instance_id] = it->second;
905
906 if (has_motion_blur) {
907
908 prim_time_offset[blender_instance_id] = prim_time_map[geom];
909 }
910 }
911 else {
912 int offset = bvh->custom_prim_info.size();
913
914 prim_info_map[geom].x = offset;
915 prim_info_map[geom].y = custom_prim_offset;
916
917 bvh->custom_prim_info.resize(offset + current_bvh->custom_prim_info.size());
918 memcpy(bvh->custom_prim_info.data() + offset,
919 current_bvh->custom_prim_info.data(),
920 current_bvh->custom_prim_info.size() * sizeof(int2));
921
922 custom_prim_info_offset[blender_instance_id].x = offset;
923 custom_prim_info_offset[blender_instance_id].y = custom_prim_offset;
924
925 if (geom->geometry_type == Geometry::HAIR) {
926 custom_prim_offset += ((Hair *)geom)->num_curves();
927 }
928 else if (geom->geometry_type == Geometry::POINTCLOUD) {
929 custom_prim_offset += ((PointCloud *)geom)->num_points();
930 }
931 else {
932 custom_prim_offset += ((Mesh *)geom)->num_triangles();
933 }
934
935 if (has_motion_blur) {
936 int time_offset = bvh->prims_time.size();
937 prim_time_map[geom] = time_offset;
938
939 bvh->prims_time.resize(time_offset + current_bvh->prims_time.size());
940 memcpy(bvh->prims_time.data() + time_offset,
941 current_bvh->prims_time.data(),
942 current_bvh->prims_time.size() * sizeof(float2));
943
944 prim_time_offset[blender_instance_id] = time_offset;
945 }
946 else
947 prim_time_offset[blender_instance_id] = -1;
948 }
949 }
950 else
951 custom_prim_info_offset[blender_instance_id] = {-1, -1};
952
953 hiprtTransformHeader current_header = {0};
954 current_header.frameCount = 1;
955 current_header.frameIndex = transform_matrix.size();
956 if (ob->get_motion().size()) {
957 int motion_size = ob->get_motion().size();
958 assert(motion_size != 1);
959
960 array<Transform> tfm_array = ob->get_motion();
961 float time_iternval = 1 / (float)(motion_size - 1);
962 current_header.frameCount = motion_size;
963
964 vector<hiprtFrameMatrix> tfm_hiprt_mb;
965 tfm_hiprt_mb.resize(motion_size);
966 for (int i = 0; i < motion_size; i++) {
967 get_hiprt_transform(tfm_hiprt_mb[i].matrix, tfm_array[i]);
968 tfm_hiprt_mb[i].time = (float)i * time_iternval;
969 transform_matrix.push_back_slow(tfm_hiprt_mb[i]);
970 }
971 }
972 else {
973 if (transform_applied)
974 current_transform = identity_matrix;
975 get_hiprt_transform(hiprt_transform_matrix.matrix, current_transform);
976 transform_matrix.push_back_slow(hiprt_transform_matrix);
977 }
978
979 transform_headers[num_instances] = current_header;
980
981 user_instance_id[num_instances] = blender_instance_id;
982 prim_visibility[num_instances] = mask;
983 hiprt_blas_ptr[num_instances].geometry = hiprt_geom_current;
984 hiprt_blas_ptr[num_instances].type = hiprtInstanceTypeGeometry;
985 num_instances++;
986 }
987 blas_ptr[blender_instance_id] = (uint64_t)hiprt_geom_current;
988 blender_instance_id++;
989 }
990
991 int frame_count = transform_matrix.size();
992 hiprtSceneBuildInput scene_input_ptr = {0};
993 scene_input_ptr.instanceCount = num_instances;
994 scene_input_ptr.frameCount = frame_count;
995 scene_input_ptr.frameType = hiprtFrameTypeMatrix;
996
997 user_instance_id.copy_to_device();
998 prim_visibility.copy_to_device();
999 hiprt_blas_ptr.copy_to_device();
1000 blas_ptr.copy_to_device();
1001 transform_headers.copy_to_device();
1002 {
1003 instance_transform_matrix.alloc(frame_count);
1004 instance_transform_matrix.host_free();
1005 instance_transform_matrix.host_pointer = transform_matrix.data();
1006 instance_transform_matrix.data_elements = sizeof(hiprtFrameMatrix);
1007 instance_transform_matrix.data_type = TYPE_UCHAR;
1008 instance_transform_matrix.data_size = frame_count;
1009 instance_transform_matrix.copy_to_device();
1010 instance_transform_matrix.host_pointer = 0;
1011 }
1012
1013 scene_input_ptr.instanceMasks = (void *)prim_visibility.device_pointer;
1014 scene_input_ptr.instances = (void *)hiprt_blas_ptr.device_pointer;
1015 scene_input_ptr.instanceTransformHeaders = (void *)transform_headers.device_pointer;
1016 scene_input_ptr.instanceFrames = (void *)instance_transform_matrix.device_pointer;
1017
1018 hiprtScene scene = 0;
1019
1020 hiprtError rt_err = hiprtCreateScene(hiprt_context, scene_input_ptr, options, scene);
1021
1022 if (rt_err != hiprtSuccess) {
1023 set_error(string_printf("Failed to create TLAS"));
1024 }
1025
1026 size_t tlas_scratch_buffer_size;
1027 rt_err = hiprtGetSceneBuildTemporaryBufferSize(
1028 hiprt_context, scene_input_ptr, options, tlas_scratch_buffer_size);
1029
1030 if (rt_err != hiprtSuccess) {
1031 set_error(string_printf("Failed to get scratch buffer size for TLAS"));
1032 }
1033
1034 if (tlas_scratch_buffer_size > scratch_buffer_size) {
1035 scratch_buffer.alloc(tlas_scratch_buffer_size);
1036 scratch_buffer.zero_to_device();
1037 }
1038
1039 rt_err = hiprtBuildScene(hiprt_context,
1040 build_operation,
1041 scene_input_ptr,
1042 options,
1043 (void *)scratch_buffer.device_pointer,
1044 0,
1045 scene);
1046
1047 if (rt_err != hiprtSuccess) {
1048 set_error(string_printf("Failed to build TLAS"));
1049 }
1050
1051 scratch_buffer.free();
1052 scratch_buffer_size = 0;
1053
1054 if (bvh->custom_prim_info.size()) {
1055 size_t data_size = bvh->custom_prim_info.size();
1056 custom_prim_info.alloc(data_size);
1057 custom_prim_info.host_free();
1058 custom_prim_info.host_pointer = bvh->custom_prim_info.data();
1059 custom_prim_info.data_elements = 2;
1060 custom_prim_info.data_type = TYPE_INT;
1061 custom_prim_info.data_size = data_size;
1062 custom_prim_info.copy_to_device();
1063 custom_prim_info.host_pointer = 0;
1064
1065 custom_prim_info_offset.copy_to_device();
1066 }
1067
1068 if (bvh->prims_time.size()) {
1069 size_t data_size = bvh->prims_time.size();
1070 prims_time.alloc(data_size);
1071 prims_time.host_free();
1072 prims_time.host_pointer = bvh->prims_time.data();
1073 prims_time.data_elements = 2;
1074 prims_time.data_type = TYPE_FLOAT;
1075 prims_time.data_size = data_size;
1076 prims_time.copy_to_device();
1077 prims_time.host_pointer = 0;
1078
1079 prim_time_offset.copy_to_device();
1080 }
1081
1082 size_t table_ptr_size = 0;
1083 hipDeviceptr_t table_device_ptr;
1084
1085 hip_assert(hipModuleGetGlobal(&table_device_ptr, &table_ptr_size, hipModule, "kernel_params"));
1086
1087 size_t kernel_param_offset[4];
1088 int table_index = 0;
1089 kernel_param_offset[table_index++] = offsetof(KernelParamsHIPRT, table_closest_intersect);
1090 kernel_param_offset[table_index++] = offsetof(KernelParamsHIPRT, table_shadow_intersect);
1091 kernel_param_offset[table_index++] = offsetof(KernelParamsHIPRT, table_local_intersect);
1092 kernel_param_offset[table_index++] = offsetof(KernelParamsHIPRT, table_volume_intersect);
1093
1094 for (int index = 0; index < table_index; index++) {
1095
1096 hip_assert(hipMemcpyHtoD(
1097 table_device_ptr + kernel_param_offset[index], &functions_table, sizeof(device_ptr)));
1098 }
1099
1100 return scene;
1101}
1102
1103void HIPRTDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
1104{
1105 progress.set_substatus("Building HIPRT acceleration structure");
1106
1107 hiprtBuildOptions options;
1108 options.buildFlags = hiprtBuildFlagBitPreferHighQualityBuild;
1109
1110 BVHHIPRT *bvh_rt = static_cast<BVHHIPRT *>(bvh);
1111 HIPContextScope scope(this);
1112
1113 if (!bvh_rt->is_tlas()) {
1114 vector<Geometry *> geometry = bvh_rt->geometry;
1115 assert(geometry.size() == 1);
1116 Geometry *geom = geometry[0];
1117 build_blas(bvh_rt, geom, options);
1118 }
1119 else {
1120
1121 const vector<Object *> objects = bvh_rt->objects;
1122 if (scene) {
1123 hiprtDestroyScene(hiprt_context, scene);
1124 }
1125 scene = build_tlas(bvh_rt, objects, options, refit);
1126 }
1127}
1129
1130#endif
unsigned int uint
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 Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture 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 point
volatile int lock
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
void refit(btStridingMeshInterface *triangles, const btVector3 &aabbMin, const btVector3 &aabbMax)
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
Attribute * find(ustring name) const
float3 * data_float3()
float4 * data_float4()
Definition bvh/bvh.h:66
Type geometry_type
bool transform_applied
bool has_motion_blur() const
AttributeSet attributes
Definition hair.h:14
Curve get_curve(size_t i) const
Definition hair.h:112
size_t num_curves() const
Definition hair.h:126
size_t num_segments() const
Definition hair.h:131
PrimitiveType primitive_type() const override
Definition hair.cpp:548
void set_substatus(const string &substatus_)
Definition progress.h:274
size_t size() const
void push_back_slow(const T &t)
#define printf
@ MEM_READ_WRITE
@ MEM_DEVICE_ONLY
@ MEM_READ_ONLY
CCL_NAMESPACE_BEGIN struct Options options
#define KERNEL_DATA_ARRAY(type, name)
Definition data_arrays.h:6
#define CCL_NAMESPACE_END
#define NULL
#define offsetof(t, d)
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
static float verts[][3]
uint col
#define PRIMITIVE_PACK_SEGMENT(type, segment)
PrimitiveType
@ PRIMITIVE_MOTION_POINT
@ PRIMITIVE_POINT
@ ATTR_STD_MOTION_VERTEX_POSITION
KernelData
@ BVH_LAYOUT_HIPRT
#define KERNEL_FEATURE_NODE_RAYTRACE
#define KERNEL_FEATURE_MNEE
DeviceKernel
@ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE
@ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE
@ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE
#define VLOG_INFO
Definition log.h:72
#define VLOG(severity)
Definition log.h:34
ccl_device_inline float4 mask(const int4 mask, const float4 a)
string util_md5_string(const string &str)
Definition md5.cpp:373
ThreadQueue * queue
all scheduled work for the cpu
T step(const T &edge, const T &value)
void index(const bNode &, void *r_value)
int BVHLayoutMask
Definition params.h:51
string path_cache_get(const string &sub)
Definition path.cpp:362
string path_get(const string &sub)
Definition path.cpp:339
string path_files_md5_hash(const string &dir)
Definition path.cpp:612
string path_join(const string &dir, const string &file)
Definition path.cpp:417
bool path_exists(const string &path)
Definition path.cpp:565
void path_create_directories(const string &filepath)
Definition path.cpp:648
bool path_read_compressed_text(const string &path, string &text)
Definition path.cpp:754
#define min(a, b)
Definition sort.c:32
unsigned int uint32_t
Definition stdint.h:80
unsigned __int64 uint64_t
Definition stdint.h:90
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
Definition string.cpp:23
__forceinline void grow(const float3 &pt)
Definition boundbox.h:36
void cardinal_motion_keys(const float3 *curve_keys, const float *curve_radius, const float4 *key_steps, size_t num_curve_keys, size_t num_steps, float time, size_t k0, size_t k1, size_t k2, size_t k3, float4 r_keys[4]) const
Definition hair.cpp:146
void bounds_grow(const int k, const float3 *curve_keys, const float *curve_radius, BoundBox &bounds) const
Definition hair.cpp:42
int first_key
Definition hair.h:20
int num_keys
Definition hair.h:21
void motion_verts(const float3 *verts, const float3 *vert_steps, size_t num_verts, size_t num_steps, float time, float3 r_verts[3]) const
void bounds_grow(const float3 *verts, BoundBox &bounds) const
Triangle get_triangle(size_t i) const
Definition scene/mesh.h:74
size_t num_triangles() const
Definition scene/mesh.h:80
PrimitiveType primitive_type() const override
bool is_traceable() const
uint visibility_for_tracing() const
Point get_point(int i) const
size_t num_points() const
float4 y
Definition transform.h:24
float4 x
Definition transform.h:24
float4 z
Definition transform.h:24
VecBase< float, 4 > float4
std::unique_lock< std::mutex > thread_scoped_lock
Definition thread.h:30
CCL_NAMESPACE_BEGIN double time_dt()
Definition time.cpp:36
ccl_device_inline Transform transform_identity()
Definition transform.h:296
float max
uint64_t device_ptr
Definition util/types.h:45