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