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