21# if EMBREE_MAJOR_VERSION >= 4
22# include <embree4/rtcore_geometry.h>
24# include <embree3/rtcore_geometry.h>
46 "Object and Embree max motion steps inconsistent");
48 "Object and Geometry max motion steps inconsistent");
50static size_t unaccounted_mem = 0;
52static bool rtc_memory_monitor_func(
void *userPtr,
const ssize_t bytes,
const bool)
75static void rtc_error_func(
void *,
enum RTCError,
const char *
str)
80static double progress_start_time = 0.0;
82static bool rtc_progress_func(
void *user_ptr,
const double n)
86 if (
time_dt() - progress_start_time < 0.25) {
92 progress_start_time =
time_dt();
97BVHEmbree::BVHEmbree(
const BVHParams ¶ms_,
100 :
BVH(params_, geometry_, objects_),
103 build_quality(RTC_BUILD_QUALITY_REFIT)
108BVHEmbree::~BVHEmbree()
111 rtcReleaseScene(scene);
115void BVHEmbree::build(
Progress &progress,
117 RTCDevice rtc_device_,
118 const bool rtc_device_is_sycl_)
120 rtc_device = rtc_device_;
121 rtc_device_is_sycl = rtc_device_is_sycl_;
124 rtcSetDeviceErrorFunction(rtc_device, rtc_error_func,
NULL);
125 rtcSetDeviceMemoryMonitorFunction(rtc_device, rtc_memory_monitor_func, stats);
130 rtcReleaseScene(scene);
135 const bool compact =
params.use_compact_structure;
137 scene = rtcNewScene(rtc_device);
138 const RTCSceneFlags scene_flags = (dynamic ? RTC_SCENE_FLAG_DYNAMIC : RTC_SCENE_FLAG_NONE) |
139 (compact ? RTC_SCENE_FLAG_COMPACT : RTC_SCENE_FLAG_NONE) |
140 RTC_SCENE_FLAG_ROBUST
141# if EMBREE_MAJOR_VERSION >= 4
142 | RTC_SCENE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS
145 rtcSetSceneFlags(scene, scene_flags);
146 build_quality = dynamic ? RTC_BUILD_QUALITY_LOW :
147 (
params.use_spatial_split ? RTC_BUILD_QUALITY_HIGH :
148 RTC_BUILD_QUALITY_MEDIUM);
149 rtcSetSceneBuildQuality(scene, build_quality);
152 foreach (
Object *ob, objects) {
158 if (!ob->get_geometry()->is_instanced()) {
177 rtcSetSceneProgressMonitorFunction(scene, rtc_progress_func, &progress);
178 rtcCommitScene(scene);
181const char *BVHEmbree::get_error_string(RTCError error_code)
183 switch (error_code) {
186 case RTC_ERROR_UNKNOWN:
187 return "unknown error";
188 case RTC_ERROR_INVALID_ARGUMENT:
189 return "invalid argument error";
190 case RTC_ERROR_INVALID_OPERATION:
191 return "invalid operation error";
192 case RTC_ERROR_OUT_OF_MEMORY:
193 return "out of memory error";
194 case RTC_ERROR_UNSUPPORTED_CPU:
195 return "unsupported cpu error";
196 case RTC_ERROR_CANCELLED:
200 return "unknown error";
204# if defined(WITH_EMBREE_GPU) && RTC_VERSION >= 40302
213 for (
const RTCScene &embree_scene : scenes) {
214 RTCSceneFlags scene_flags = rtcGetSceneFlags(embree_scene);
215 scene_flags = scene_flags | RTC_SCENE_FLAG_PREFETCH_USM_SHARED_ON_GPU;
216 rtcSetSceneFlags(embree_scene, scene_flags);
217 rtcCommitScene(embree_scene);
220 RTCError error_code = rtcGetDeviceError(rtc_device);
221 if (error_code != RTC_ERROR_NONE)
224 return RTC_ERROR_NONE;
228void BVHEmbree::add_object(
Object *ob,
int i)
230 Geometry *geom = ob->get_geometry();
233 Mesh *mesh =
static_cast<Mesh *
>(geom);
234 if (mesh->num_triangles() > 0) {
235 add_triangles(ob, mesh, i);
239 Hair *hair =
static_cast<Hair *
>(geom);
240 if (hair->num_curves() > 0) {
247 add_points(ob, pointcloud, i);
252void BVHEmbree::add_instance(
Object *ob,
int i)
254 BVHEmbree *instance_bvh = (BVHEmbree *)(ob->get_geometry()->bvh);
255 assert(instance_bvh !=
NULL);
257 const size_t num_object_motion_steps = ob->
use_motion() ? ob->get_motion().size() : 1;
258 const size_t num_motion_steps =
min(num_object_motion_steps, (
size_t)RTC_MAX_TIME_STEP_COUNT);
259 assert(num_object_motion_steps <= RTC_MAX_TIME_STEP_COUNT);
261 RTCGeometry geom_id = rtcNewGeometry(rtc_device, RTC_GEOMETRY_TYPE_INSTANCE);
262 rtcSetGeometryInstancedScene(geom_id, instance_bvh->scene);
263 rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
268 for (
size_t step = 0;
step < num_motion_steps; ++
step) {
269 RTCQuaternionDecomposition rtc_decomp;
270 rtcInitQuaternionDecomposition(&rtc_decomp);
271 rtcQuaternionDecompositionSetQuaternion(
272 &rtc_decomp, decomp[step].x.w, decomp[step].x.x, decomp[step].x.y, decomp[step].x.z);
273 rtcQuaternionDecompositionSetScale(
274 &rtc_decomp, decomp[step].y.w, decomp[step].z.w, decomp[step].w.w);
275 rtcQuaternionDecompositionSetTranslation(
276 &rtc_decomp, decomp[step].y.x, decomp[step].y.y, decomp[step].y.z);
277 rtcQuaternionDecompositionSetSkew(
278 &rtc_decomp, decomp[step].
z.x, decomp[step].z.y, decomp[step].w.x);
279 rtcSetGeometryTransformQuaternion(geom_id, step, &rtc_decomp);
283 rtcSetGeometryTransform(
284 geom_id, 0, RTC_FORMAT_FLOAT3X4_ROW_MAJOR, (
const float *)&ob->get_tfm());
287 rtcSetGeometryUserData(geom_id, (
void *)instance_bvh->scene);
289# if EMBREE_MAJOR_VERSION >= 4
290 rtcSetGeometryEnableFilterFunctionFromArguments(geom_id,
true);
293 rtcCommitGeometry(geom_id);
294 rtcAttachGeometryByID(scene, geom_id, i * 2);
295 rtcReleaseGeometry(geom_id);
298void BVHEmbree::add_triangles(
const Object *ob,
const Mesh *mesh,
int i)
300 size_t prim_offset = mesh->prim_offset;
303 size_t num_motion_steps = 1;
304 if (mesh->has_motion_blur()) {
307 num_motion_steps = mesh->get_motion_steps();
311 assert(num_motion_steps <= RTC_MAX_TIME_STEP_COUNT);
312 num_motion_steps =
min(num_motion_steps, (
size_t)RTC_MAX_TIME_STEP_COUNT);
314 const size_t num_triangles = mesh->num_triangles();
316 RTCGeometry geom_id = rtcNewGeometry(rtc_device, RTC_GEOMETRY_TYPE_TRIANGLE);
317 rtcSetGeometryBuildQuality(geom_id, build_quality);
318 rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
320 const int *triangles = mesh->get_triangles().data();
321 if (!rtc_device_is_sycl) {
322 rtcSetSharedGeometryBuffer(geom_id,
323 RTC_BUFFER_TYPE_INDEX,
336 int *triangles_buffer = (
int *)rtcSetNewGeometryBuffer(
337 geom_id, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3,
sizeof(
int) * 3, num_triangles);
338 assert(triangles_buffer);
339 if (triangles_buffer) {
340 static_assert(
sizeof(
int) ==
sizeof(
uint));
341 std::memcpy(triangles_buffer, triangles,
sizeof(
int) * 3 * (num_triangles));
344 set_tri_vertex_buffer(geom_id, mesh,
false);
346 rtcSetGeometryUserData(geom_id, (
void *)prim_offset);
348# if EMBREE_MAJOR_VERSION >= 4
349 rtcSetGeometryEnableFilterFunctionFromArguments(geom_id,
true);
355 rtcCommitGeometry(geom_id);
356 rtcAttachGeometryByID(scene, geom_id, i * 2);
357 rtcReleaseGeometry(geom_id);
360void BVHEmbree::set_tri_vertex_buffer(RTCGeometry geom_id,
const Mesh *mesh,
const bool update)
363 size_t num_motion_steps = 1;
365 if (mesh->has_motion_blur()) {
368 num_motion_steps = mesh->get_motion_steps();
369 t_mid = (num_motion_steps - 1) / 2;
370 if (num_motion_steps > RTC_MAX_TIME_STEP_COUNT) {
372 num_motion_steps = RTC_MAX_TIME_STEP_COUNT;
376 const size_t num_verts = mesh->get_verts().size();
378 for (
int t = 0; t < num_motion_steps; ++t) {
381 verts = mesh->get_verts().data();
384 int t_ = (t > t_mid) ? (t - 1) : t;
389 rtcUpdateGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t);
392 if (!rtc_device_is_sycl) {
393 static_assert(
sizeof(
float3) == 16,
394 "Embree requires that each buffer element be readable with 16-byte SSE load "
396 rtcSetSharedGeometryBuffer(geom_id,
397 RTC_BUFFER_TYPE_VERTEX,
415 RTC_BUFFER_TYPE_VERTEX,
420 assert(verts_buffer);
422 for (
size_t i = (
size_t)0; i < num_verts; ++i) {
423 verts_buffer[i].
x =
verts[i].x;
424 verts_buffer[i].
y =
verts[i].y;
425 verts_buffer[i].
z =
verts[i].z;
437void pack_motion_verts(
size_t num_curves,
440 const float *curve_radius,
443 for (
size_t j = 0; j < num_curves; ++j) {
447 for (; k < c.
num_keys + 1; ++k, ++fk) {
448 rtc_verts[k].x =
verts[fk].x;
449 rtc_verts[k].y =
verts[fk].y;
450 rtc_verts[k].z =
verts[fk].z;
451 rtc_verts[k].w = curve_radius[fk];
454 rtc_verts[0] = rtc_verts[1];
455 rtc_verts[k] = rtc_verts[k - 1];
460void BVHEmbree::set_curve_vertex_buffer(RTCGeometry geom_id,
const Hair *hair,
const bool update)
463 size_t num_motion_steps = 1;
464 if (hair->has_motion_blur()) {
467 num_motion_steps = hair->get_motion_steps();
471 const size_t num_curves = hair->num_curves();
473 for (
size_t j = 0; j < num_curves; ++j) {
479 size_t num_keys_embree = num_keys;
480 num_keys_embree += num_curves * 2;
483 const int t_mid = (num_motion_steps - 1) / 2;
484 const float *curve_radius = &hair->get_curve_radius()[0];
485 for (
int t = 0; t < num_motion_steps; ++t) {
490 float4 *rtc_verts = (
update) ? (float4 *)rtcGetGeometryBufferData(
491 geom_id, RTC_BUFFER_TYPE_VERTEX, t) :
492 (
float4 *)rtcSetNewGeometryBuffer(geom_id,
493 RTC_BUFFER_TYPE_VERTEX,
501 const size_t num_curves = hair->num_curves();
502 if (t == t_mid || attr_mP ==
NULL) {
504 pack_motion_verts<float3>(num_curves, hair,
verts, curve_radius, rtc_verts);
507 int t_ = (t > t_mid) ? (t - 1) : t;
509 pack_motion_verts<float4>(num_curves, hair,
verts, curve_radius, rtc_verts);
514 rtcUpdateGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t);
519void BVHEmbree::set_point_vertex_buffer(RTCGeometry geom_id,
524 size_t num_motion_steps = 1;
528 num_motion_steps = pointcloud->get_motion_steps();
532 const size_t num_points = pointcloud->
num_points();
535 const int t_mid = (num_motion_steps - 1) / 2;
536 const float *radius = pointcloud->get_radius().data();
537 for (
int t = 0; t < num_motion_steps; ++t) {
542 float4 *rtc_verts = (
update) ? (float4 *)rtcGetGeometryBufferData(
543 geom_id, RTC_BUFFER_TYPE_VERTEX, t) :
544 (
float4 *)rtcSetNewGeometryBuffer(geom_id,
545 RTC_BUFFER_TYPE_VERTEX,
553 if (t == t_mid || attr_mP ==
NULL) {
555 const float3 *
verts = pointcloud->get_points().data();
556 for (
size_t j = 0; j < num_points; ++j) {
557 rtc_verts[j].x =
verts[j].x;
558 rtc_verts[j].y =
verts[j].y;
559 rtc_verts[j].z =
verts[j].z;
560 rtc_verts[j].w = radius[j];
565 int t_ = (t > t_mid) ? (t - 1) : t;
567 memcpy(rtc_verts,
verts,
sizeof(float4) * num_points);
572 rtcUpdateGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t);
577void BVHEmbree::add_points(
const Object *ob,
const PointCloud *pointcloud,
int i)
582 size_t num_motion_steps = 1;
586 num_motion_steps = pointcloud->get_motion_steps();
590 enum RTCGeometryType type = RTC_GEOMETRY_TYPE_SPHERE_POINT;
592 RTCGeometry geom_id = rtcNewGeometry(rtc_device, type);
594 rtcSetGeometryBuildQuality(geom_id, build_quality);
595 rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
597 set_point_vertex_buffer(geom_id, pointcloud,
false);
599 rtcSetGeometryUserData(geom_id, (
void *)prim_offset);
601# if EMBREE_MAJOR_VERSION >= 4
602 rtcSetGeometryEnableFilterFunctionFromArguments(geom_id,
true);
608 rtcCommitGeometry(geom_id);
609 rtcAttachGeometryByID(scene, geom_id, i * 2);
610 rtcReleaseGeometry(geom_id);
613void BVHEmbree::add_curves(
const Object *ob,
const Hair *hair,
int i)
615 size_t prim_offset = hair->curve_segment_offset;
618 size_t num_motion_steps = 1;
619 if (hair->has_motion_blur()) {
622 num_motion_steps = hair->get_motion_steps();
626 assert(num_motion_steps <= RTC_MAX_TIME_STEP_COUNT);
627 num_motion_steps =
min(num_motion_steps, (
size_t)RTC_MAX_TIME_STEP_COUNT);
629 const size_t num_curves = hair->num_curves();
630 size_t num_segments = 0;
631 for (
size_t j = 0; j < num_curves; ++j) {
637 enum RTCGeometryType type = (hair->curve_shape ==
CURVE_RIBBON ?
638 RTC_GEOMETRY_TYPE_FLAT_CATMULL_ROM_CURVE :
639 RTC_GEOMETRY_TYPE_ROUND_CATMULL_ROM_CURVE);
641 RTCGeometry geom_id = rtcNewGeometry(rtc_device, type);
642 rtcSetGeometryTessellationRate(geom_id,
params.curve_subdivisions + 1);
643 unsigned *rtc_indices = (
unsigned *)rtcSetNewGeometryBuffer(
644 geom_id, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT,
sizeof(
int), num_segments);
645 size_t rtc_index = 0;
646 for (
size_t j = 0; j < num_curves; ++j) {
649 rtc_indices[rtc_index] = c.
first_key + k;
651 rtc_indices[rtc_index] += j * 2;
657 rtcSetGeometryBuildQuality(geom_id, build_quality);
658 rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
660 set_curve_vertex_buffer(geom_id, hair,
false);
662 rtcSetGeometryUserData(geom_id, (
void *)prim_offset);
664# if EMBREE_MAJOR_VERSION >= 4
665 rtcSetGeometryEnableFilterFunctionFromArguments(geom_id,
true);
673 rtcSetGeometryOccludedFilterFunction(geom_id,
678 rtcCommitGeometry(geom_id);
679 rtcAttachGeometryByID(scene, geom_id, i * 2 + 1);
680 rtcReleaseGeometry(geom_id);
683void BVHEmbree::refit(
Progress &progress)
688 unsigned geom_id = 0;
689 foreach (
Object *ob, objects) {
690 if (!
params.top_level || (ob->
is_traceable() && !ob->get_geometry()->is_instanced())) {
691 Geometry *geom = ob->get_geometry();
694 Mesh *mesh =
static_cast<Mesh *
>(geom);
695 if (mesh->num_triangles() > 0) {
696 RTCGeometry geom = rtcGetGeometry(scene, geom_id);
697 set_tri_vertex_buffer(geom, mesh,
true);
698 rtcSetGeometryUserData(geom, (
void *)mesh->prim_offset);
699 rtcCommitGeometry(geom);
703 Hair *hair =
static_cast<Hair *
>(geom);
704 if (hair->num_curves() > 0) {
705 RTCGeometry geom = rtcGetGeometry(scene, geom_id + 1);
706 set_curve_vertex_buffer(geom, hair,
true);
707 rtcSetGeometryUserData(geom, (
void *)hair->curve_segment_offset);
708 rtcCommitGeometry(geom);
714 RTCGeometry geom = rtcGetGeometry(scene, geom_id);
715 set_point_vertex_buffer(geom, pointcloud,
true);
716 rtcCommitGeometry(geom);
723 rtcCommitScene(scene);
ATOMIC_INLINE size_t atomic_add_and_fetch_z(size_t *p, size_t x)
ATOMIC_INLINE size_t atomic_sub_and_fetch_z(size_t *p, size_t x)
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Attribute * find(ustring name) const
static const uint MAX_MOTION_STEPS
bool has_motion_blur() const
void set_substatus(const string &substatus_)
void mem_free(size_t size)
void mem_alloc(size_t size)
#define CCL_NAMESPACE_END
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
ccl_device_forceinline void kernel_embree_filter_occluded_func(const RTCFilterFunctionNArguments *args)
#define kernel_embree_filter_intersection_func
ccl_device void kernel_embree_filter_occluded_func_backface_cull(const RTCFilterFunctionNArguments *args)
ccl_device void kernel_embree_filter_func_backface_cull(const RTCFilterFunctionNArguments *args)
@ ATTR_STD_MOTION_VERTEX_POSITION
void add_curves(bke::CurvesGeometry &curves, const Span< int > new_sizes)
T step(const T &edge, const T &value)
VecBase< float, 4 > float4
static void update(bNodeTree *ntree)
#define SIMD_SET_FLUSH_TO_ZERO
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
static const uint MAX_MOTION_STEPS
bool is_traceable() const
uint visibility_for_tracing() const
size_t num_points() const
CCL_NAMESPACE_BEGIN double time_dt()