Blender V4.3
kernel/device/cpu/bvh.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2021-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5/* CPU Embree implementation of ray-scene intersection. */
6
7#pragma once
8
9#if EMBREE_MAJOR_VERSION >= 4
10# include <embree4/rtcore_ray.h>
11# include <embree4/rtcore_scene.h>
12#else
13# include <embree3/rtcore_ray.h>
14# include <embree3/rtcore_scene.h>
15#endif
16
17#ifdef __KERNEL_ONEAPI__
20#else
23#endif
24
25#include "kernel/bvh/types.h"
26#include "kernel/bvh/util.h"
27#include "kernel/geom/object.h"
30#include "kernel/sample/lcg.h"
31
32#include "util/vector.h"
33
35
36#ifdef __KERNEL_ONEAPI__
37using numhit_t = uint16_t;
38#else
40#endif
41
42#ifdef __KERNEL_ONEAPI__
43# define CYCLES_EMBREE_USED_FEATURES \
44 (kernel_handler.get_specialization_constant<oneapi_embree_features>())
45#else
46# define CYCLES_EMBREE_USED_FEATURES \
47 (RTCFeatureFlags)(RTC_FEATURE_FLAG_TRIANGLE | RTC_FEATURE_FLAG_INSTANCE | \
48 RTC_FEATURE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS | RTC_FEATURE_FLAG_POINT | \
49 RTC_FEATURE_FLAG_MOTION_BLUR | RTC_FEATURE_FLAG_ROUND_CATMULL_ROM_CURVE | \
50 RTC_FEATURE_FLAG_FLAT_CATMULL_ROM_CURVE)
51#endif
52
53#define EMBREE_IS_HAIR(x) (x & 1)
54
55#if EMBREE_MAJOR_VERSION < 4
56# define rtcGetGeometryUserDataFromScene(scene, id) \
57 (rtcGetGeometryUserData(rtcGetGeometry(scene, id)))
58#endif
59
60/* Intersection context. */
61
63#if EMBREE_MAJOR_VERSION >= 4
64 : public RTCRayQueryContext
65#endif
66{
68 /* For avoiding self intersections */
69 const Ray *ray;
70};
71
73#if EMBREE_MAJOR_VERSION >= 4
74 : public RTCRayQueryContext
75#endif
76{
77#if EMBREE_MAJOR_VERSION >= 4
79 const Ray *ray;
80#endif
83 float max_t;
88};
89
91#if EMBREE_MAJOR_VERSION >= 4
92 : public RTCRayQueryContext
93#endif
94{
95#if EMBREE_MAJOR_VERSION >= 4
97 const Ray *ray;
98 numhit_t max_hits;
99#endif
103 bool is_sss;
104};
105
107#if EMBREE_MAJOR_VERSION >= 4
108 : public RTCRayQueryContext
109#endif
110{
111#if EMBREE_MAJOR_VERSION >= 4
112 KernelGlobals kg;
113 const Ray *ray;
114# ifdef __VOLUME_RECORD_ALL__
115 numhit_t max_hits;
116# endif
117 numhit_t num_hits;
118#endif
120};
121
122#if EMBREE_MAJOR_VERSION < 4
123struct CCLIntersectContext : public RTCIntersectContext,
124 public CCLFirstHitContext,
125 public CCLShadowContext,
126 public CCLLocalContext,
127 public CCLVolumeContext {
135
137
139 {
140 kg = kg_;
141 type = type_;
142 ray = NULL;
143 max_hits = numhit_t(1);
144 num_hits = numhit_t(0);
146 throughput = 1.0f;
147 opaque_hit = false;
148 isect_s = NULL;
150 local_object_id = -1;
151 lcg_state = NULL;
152 }
153};
154#endif
155
156/* Utilities. */
157
159 RTCRay &rtc_ray,
160 const uint visibility)
161{
162 rtc_ray.org_x = ray.P.x;
163 rtc_ray.org_y = ray.P.y;
164 rtc_ray.org_z = ray.P.z;
165 rtc_ray.dir_x = ray.D.x;
166 rtc_ray.dir_y = ray.D.y;
167 rtc_ray.dir_z = ray.D.z;
168 rtc_ray.tnear = ray.tmin;
169 rtc_ray.tfar = ray.tmax;
170 rtc_ray.time = ray.time;
171 rtc_ray.mask = visibility;
172}
173
175 RTCRayHit &rayhit,
176 const uint visibility)
177{
178 kernel_embree_setup_ray(ray, rayhit.ray, visibility);
179 rayhit.hit.geomID = RTC_INVALID_GEOMETRY_ID;
180 rayhit.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
181}
182
184{
185 return (hit->instID[0] != RTC_INVALID_GEOMETRY_ID ? hit->instID[0] : hit->geomID) / 2;
186}
187
189 const RTCHit *hit,
190 const Ray *ray,
191 const intptr_t prim_offset)
192{
193 const int object = kernel_embree_get_hit_object(hit);
194
195 int prim;
196 if ((ray->self.object == object) || (ray->self.light_object == object)) {
197 prim = hit->primID + prim_offset;
198 }
199 else {
200 return false;
201 }
202
203 const bool is_hair = hit->geomID & 1;
204 if (is_hair) {
205 prim = kernel_data_fetch(curve_segments, prim).prim;
206 }
207
208 return intersection_skip_self_shadow(ray->self, object, prim);
209}
210
212 const RTCRay *ray,
213 const RTCHit *hit,
214 Intersection *isect,
215 const intptr_t prim_offset)
216{
217 isect->t = ray->tfar;
218 isect->prim = hit->primID + prim_offset;
220
221 const bool is_hair = hit->geomID & 1;
222 if (is_hair) {
223 const KernelCurveSegment segment = kernel_data_fetch(curve_segments, isect->prim);
224 isect->type = segment.type;
225 isect->prim = segment.prim;
226 isect->u = hit->u;
227 isect->v = hit->v;
228 }
229 else {
230 isect->type = kernel_data_fetch(objects, isect->object).primitive_type;
231 isect->u = hit->u;
232 isect->v = hit->v;
233 }
234}
235
237 const RTCRay *ray,
238 const RTCHit *hit,
239 Intersection *isect)
240{
241 intptr_t prim_offset;
242 if (hit->instID[0] != RTC_INVALID_GEOMETRY_ID) {
243 RTCScene inst_scene = (RTCScene)rtcGetGeometryUserDataFromScene(kernel_data.device_bvh,
244 hit->instID[0]);
245 prim_offset = intptr_t(rtcGetGeometryUserDataFromScene(inst_scene, hit->geomID));
246 }
247 else {
248 prim_offset = intptr_t(rtcGetGeometryUserDataFromScene(kernel_data.device_bvh, hit->geomID));
249 }
250 kernel_embree_convert_hit(kg, ray, hit, isect, prim_offset);
251}
252
254 const RTCRay *ray,
255 const RTCHit *hit,
256 Intersection *isect,
257 int object,
258 const intptr_t prim_offset)
259{
260 isect->u = hit->u;
261 isect->v = hit->v;
262 isect->t = ray->tfar;
263 isect->prim = hit->primID + prim_offset;
264 isect->object = object;
265 isect->type = kernel_data_fetch(objects, object).primitive_type;
266}
267
268/* Ray filter functions. */
269
270/* This gets called by Embree at every valid ray/object intersection.
271 * Things like recording subsurface or shadow hits for later evaluation
272 * as well as filtering for volume objects happen here.
273 * Cycles' own BVH does that directly inside the traversal calls. */
275 const RTCFilterFunctionNArguments *args)
276{
277 /* Current implementation in Cycles assumes only single-ray intersection queries. */
278 assert(args->N == 1);
279
280 RTCHit *hit = (RTCHit *)args->hit;
281#if EMBREE_MAJOR_VERSION >= 4
282 CCLFirstHitContext *ctx = (CCLFirstHitContext *)(args->context);
283#else
284 CCLIntersectContext *ctx = (CCLIntersectContext *)(args->context);
285#endif
286#ifdef __KERNEL_ONEAPI__
287 KernelGlobalsGPU *kg = nullptr;
288#else
289 const KernelGlobalsCPU *kg = ctx->kg;
290#endif
291 const Ray *cray = ctx->ray;
292
294 kg, hit, cray, reinterpret_cast<intptr_t>(args->geometryUserPtr)))
295 {
296 *args->valid = 0;
297 return;
298 }
299
300#ifdef __SHADOW_LINKING__
302 *args->valid = 0;
303 return;
304 }
305#endif
306}
307
308/* This gets called by Embree at every valid ray/object intersection.
309 * Things like recording subsurface or shadow hits for later evaluation
310 * as well as filtering for volume objects happen here.
311 * Cycles' own BVH does that directly inside the traversal calls.
312 */
314 const RTCFilterFunctionNArguments *args)
315{
316 /* Current implementation in Cycles assumes only single-ray intersection queries. */
317 assert(args->N == 1);
318
319 const RTCRay *ray = (RTCRay *)args->ray;
320 RTCHit *hit = (RTCHit *)args->hit;
321#if EMBREE_MAJOR_VERSION >= 4
322 CCLShadowContext *ctx = (CCLShadowContext *)(args->context);
323#else
324 CCLIntersectContext *ctx = (CCLIntersectContext *)(args->context);
325#endif
326#ifdef __KERNEL_ONEAPI__
327 KernelGlobalsGPU *kg = nullptr;
328#else
329 const KernelGlobalsCPU *kg = ctx->kg;
330#endif
331 const Ray *cray = ctx->ray;
332
333 Intersection current_isect;
335 kg, ray, hit, &current_isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
336 if (intersection_skip_self_shadow(cray->self, current_isect.object, current_isect.prim)) {
337 *args->valid = 0;
338 return;
339 }
340
341#ifdef __SHADOW_LINKING__
342 if (intersection_skip_shadow_link(kg, cray->self, current_isect.object)) {
343 *args->valid = 0;
344 return;
345 }
346#endif
347
348 /* If no transparent shadows or max number of hits exceeded, all light is blocked. */
349 const int flags = intersection_get_shader_flags(kg, current_isect.prim, current_isect.type);
350 if (!(flags & (SD_HAS_TRANSPARENT_SHADOW)) || ctx->num_hits >= ctx->max_hits) {
351 ctx->opaque_hit = true;
352 return;
353 }
354
355 ++ctx->num_hits;
356
357 /* Always use baked shadow transparency for curves. */
358 if (current_isect.type & PRIMITIVE_CURVE) {
360 kg, current_isect.object, current_isect.prim, current_isect.type, current_isect.u);
361
363 ctx->opaque_hit = true;
364 return;
365 }
366 else {
367 *args->valid = 0;
368 return;
369 }
370 }
371
372 numhit_t isect_index = ctx->num_recorded_hits;
373
374 /* Always increase the number of recorded hits, even beyond the maximum,
375 * so that we can detect this and trace another ray if needed.
376 * More details about the related logic can be found in implementation of
377 * "shadow_intersections_has_remaining" and "integrate_transparent_shadow"
378 * functions. */
379 ++ctx->num_recorded_hits;
380
381 /* This tells Embree to continue tracing. */
382 *args->valid = 0;
383
384 const numhit_t max_record_hits = min(ctx->max_hits, numhit_t(INTEGRATOR_SHADOW_ISECT_SIZE));
385 /* If the maximum number of hits was reached, replace the furthest intersection
386 * with a closer one so we get the N closest intersections. */
387 if (isect_index >= max_record_hits) {
388 /* When recording only N closest hits, max_t will always only decrease.
389 * So let's test if we are already not meeting criteria and can skip max_t recalculation. */
390 if (current_isect.t >= ctx->max_t) {
391 return;
392 }
393
394 float max_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, 0, t);
395 numhit_t max_recorded_hit = numhit_t(0);
396 float second_largest_t = 0.0f;
397
398 for (numhit_t i = numhit_t(1); i < max_record_hits; ++i) {
399 const float isect_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, i, t);
400 if (isect_t > max_t) {
401 second_largest_t = max_t;
402 max_recorded_hit = i;
403 max_t = isect_t;
404 }
405 else if (isect_t > second_largest_t) {
406 second_largest_t = isect_t;
407 }
408 }
409
410 if (isect_index == max_record_hits && current_isect.t >= max_t) {
411 /* `ctx->max_t` was initialized to `ray->tmax` before the index exceeds the limit. Now that
412 * we have looped through the array, we can properly clamp `ctx->max_t`. */
413 ctx->max_t = max_t;
414 return;
415 }
416
417 isect_index = max_recorded_hit;
418
419 /* After replacing `max_t` with `current_isect.t`, the new largest t would be either
420 * `current_isect.t` or the second largest t before. */
421 ctx->max_t = max(second_largest_t, current_isect.t);
422 }
423
424 integrator_state_write_shadow_isect(ctx->isect_s, &current_isect, isect_index);
425}
426
428 const RTCFilterFunctionNArguments *args)
429{
430 /* Current implementation in Cycles assumes only single-ray intersection queries. */
431 assert(args->N == 1);
432
433 const RTCRay *ray = (RTCRay *)args->ray;
434 RTCHit *hit = (RTCHit *)args->hit;
435#if EMBREE_MAJOR_VERSION >= 4
436 CCLLocalContext *ctx = (CCLLocalContext *)(args->context);
437#else
438 CCLIntersectContext *ctx = (CCLIntersectContext *)(args->context);
439#endif
440#ifdef __KERNEL_ONEAPI__
441 KernelGlobalsGPU *kg = nullptr;
442#else
443 const KernelGlobalsCPU *kg = ctx->kg;
444#endif
445 const Ray *cray = ctx->ray;
446
447 /* Check if it's hitting the correct object. */
448 Intersection current_isect;
449 if (ctx->is_sss) {
451 ray,
452 hit,
453 &current_isect,
454 ctx->local_object_id,
455 reinterpret_cast<intptr_t>(args->geometryUserPtr));
456 }
457 else {
459 kg, ray, hit, &current_isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
460 if (ctx->local_object_id != current_isect.object) {
461 /* This tells Embree to continue tracing. */
462 *args->valid = 0;
463 return;
464 }
465 }
466 if (intersection_skip_self_local(cray->self, current_isect.prim)) {
467 *args->valid = 0;
468 return;
469 }
470
471 /* No intersection information requested, just return a hit. */
472 if (ctx->max_hits == 0) {
473 return;
474 }
475
476 /* Ignore curves. */
477 if (EMBREE_IS_HAIR(hit->geomID)) {
478 /* This tells Embree to continue tracing. */
479 *args->valid = 0;
480 return;
481 }
482
483 LocalIntersection *local_isect = ctx->local_isect;
484 int hit_idx = 0;
485
486 if (ctx->lcg_state) {
487 /* See triangle_intersect_subsurface() for the native equivalent. */
488 for (int i = min((int)ctx->max_hits, local_isect->num_hits) - 1; i >= 0; --i) {
489 if (local_isect->hits[i].t == ray->tfar) {
490 /* This tells Embree to continue tracing. */
491 *args->valid = 0;
492 return;
493 }
494 }
495
496 local_isect->num_hits++;
497
498 if (local_isect->num_hits <= ctx->max_hits) {
499 hit_idx = local_isect->num_hits - 1;
500 }
501 else {
502 /* reservoir sampling: if we are at the maximum number of
503 * hits, randomly replace element or skip it */
504 hit_idx = lcg_step_uint(ctx->lcg_state) % local_isect->num_hits;
505
506 if (hit_idx >= ctx->max_hits) {
507 /* This tells Embree to continue tracing. */
508 *args->valid = 0;
509 return;
510 }
511 }
512 }
513 else {
514 /* Record closest intersection only. */
515 if (local_isect->num_hits && current_isect.t > local_isect->hits[0].t) {
516 *args->valid = 0;
517 return;
518 }
519
520 local_isect->num_hits = 1;
521 }
522
523 /* record intersection */
524 local_isect->hits[hit_idx] = current_isect;
525 local_isect->Ng[hit_idx] = normalize(make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z));
526 /* This tells Embree to continue tracing. */
527 *args->valid = 0;
528}
529
531 const RTCFilterFunctionNArguments *args)
532{
533 /* Current implementation in Cycles assumes only single-ray intersection queries. */
534 assert(args->N == 1);
535
536 const RTCRay *ray = (RTCRay *)args->ray;
537 RTCHit *hit = (RTCHit *)args->hit;
538#if EMBREE_MAJOR_VERSION >= 4
539 CCLVolumeContext *ctx = (CCLVolumeContext *)(args->context);
540#else
541 CCLIntersectContext *ctx = (CCLIntersectContext *)(args->context);
542#endif
543#ifdef __KERNEL_ONEAPI__
544 KernelGlobalsGPU *kg = nullptr;
545#else
546 const KernelGlobalsCPU *kg = ctx->kg;
547#endif
548 const Ray *cray = ctx->ray;
549
550#ifdef __VOLUME_RECORD_ALL__
551 /* Append the intersection to the end of the array. */
552 if (ctx->num_hits < ctx->max_hits) {
553#endif
554 Intersection current_isect;
556 kg, ray, hit, &current_isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
557 if (intersection_skip_self(cray->self, current_isect.object, current_isect.prim)) {
558 *args->valid = 0;
559 return;
560 }
561
562 Intersection *isect = &ctx->vol_isect[ctx->num_hits];
563 ++ctx->num_hits;
564 *isect = current_isect;
565 /* Only primitives from volume object. */
566 uint tri_object = isect->object;
567 int object_flag = kernel_data_fetch(object_flag, tri_object);
568 if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
569 --ctx->num_hits;
570#ifndef __VOLUME_RECORD_ALL__
571 /* Without __VOLUME_RECORD_ALL__ we need only a first counted hit, so we will
572 * continue tracing only if a current hit is not counted. */
573 *args->valid = 0;
574#endif
575 }
576#ifdef __VOLUME_RECORD_ALL__
577 /* This tells Embree to continue tracing. */
578 *args->valid = 0;
579 }
580#endif
581}
582
583#if EMBREE_MAJOR_VERSION < 4
585 const RTCFilterFunctionNArguments *args)
586{
587 /* Current implementation in Cycles assumes only single-ray intersection queries. */
588 assert(args->N == 1);
589
590 CCLIntersectContext *ctx = (CCLIntersectContext *)(args->context);
591
592 switch (ctx->type) {
595 break;
599 break;
602 break;
603
605 default:
606 /* We should never reach this point, because
607 * REGULAR intersection is handled in intersection filter. */
608 kernel_assert(false);
609 break;
610 }
611}
612
613ccl_device void kernel_embree_filter_func_backface_cull(const RTCFilterFunctionNArguments *args)
614{
615 const RTCRay *ray = (RTCRay *)args->ray;
616 RTCHit *hit = (RTCHit *)args->hit;
617
618 /* Always ignore back-facing intersections. */
619 if (dot(make_float3(ray->dir_x, ray->dir_y, ray->dir_z),
620 make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z)) > 0.0f)
621 {
622 *args->valid = 0;
623 return;
624 }
625
626 CCLIntersectContext *ctx = ((CCLIntersectContext *)args->context);
627 const KernelGlobalsCPU *kg = ctx->kg;
628 const Ray *cray = ctx->ray;
629
631 kg, hit, cray, reinterpret_cast<intptr_t>(args->geometryUserPtr)))
632 {
633 *args->valid = 0;
634 }
635}
636
638 const RTCFilterFunctionNArguments *args)
639{
640 const RTCRay *ray = (RTCRay *)args->ray;
641 RTCHit *hit = (RTCHit *)args->hit;
642
643 /* Always ignore back-facing intersections. */
644 if (dot(make_float3(ray->dir_x, ray->dir_y, ray->dir_z),
645 make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z)) > 0.0f)
646 {
647 *args->valid = 0;
648 return;
649 }
650
652}
653#endif
654
655#ifdef __KERNEL_ONEAPI__
656/* Static wrappers so we can call the callbacks from out side the ONEAPIKernelContext class */
657RTC_SYCL_INDIRECTLY_CALLABLE static void ccl_always_inline
658kernel_embree_filter_intersection_func_static(const RTCFilterFunctionNArguments *args)
659{
660 RTCHit *hit = (RTCHit *)args->hit;
661 CCLFirstHitContext *ctx = (CCLFirstHitContext *)(args->context);
662 ONEAPIKernelContext *context = static_cast<ONEAPIKernelContext *>(ctx->kg);
663 context->kernel_embree_filter_intersection_func_impl(args);
664}
665
666RTC_SYCL_INDIRECTLY_CALLABLE static void ccl_always_inline
667kernel_embree_filter_occluded_shadow_all_func_static(const RTCFilterFunctionNArguments *args)
668{
669 RTCHit *hit = (RTCHit *)args->hit;
670 CCLShadowContext *ctx = (CCLShadowContext *)(args->context);
671 ONEAPIKernelContext *context = static_cast<ONEAPIKernelContext *>(ctx->kg);
672 context->kernel_embree_filter_occluded_shadow_all_func_impl(args);
673}
674
675RTC_SYCL_INDIRECTLY_CALLABLE static void ccl_always_inline
676kernel_embree_filter_occluded_local_func_static(const RTCFilterFunctionNArguments *args)
677{
678 RTCHit *hit = (RTCHit *)args->hit;
679 CCLLocalContext *ctx = (CCLLocalContext *)(args->context);
680 ONEAPIKernelContext *context = static_cast<ONEAPIKernelContext *>(ctx->kg);
681 context->kernel_embree_filter_occluded_local_func_impl(args);
682}
683
684RTC_SYCL_INDIRECTLY_CALLABLE static void ccl_always_inline
685kernel_embree_filter_occluded_volume_all_func_static(const RTCFilterFunctionNArguments *args)
686{
687 RTCHit *hit = (RTCHit *)args->hit;
688 CCLVolumeContext *ctx = (CCLVolumeContext *)(args->context);
689 ONEAPIKernelContext *context = static_cast<ONEAPIKernelContext *>(ctx->kg);
690 context->kernel_embree_filter_occluded_volume_all_func_impl(args);
691}
692
693# define kernel_embree_filter_intersection_func \
694 ONEAPIKernelContext::kernel_embree_filter_intersection_func_static
695# define kernel_embree_filter_occluded_shadow_all_func \
696 ONEAPIKernelContext::kernel_embree_filter_occluded_shadow_all_func_static
697# define kernel_embree_filter_occluded_local_func \
698 ONEAPIKernelContext::kernel_embree_filter_occluded_local_func_static
699# define kernel_embree_filter_occluded_volume_all_func \
700 ONEAPIKernelContext::kernel_embree_filter_occluded_volume_all_func_static
701#else
702# define kernel_embree_filter_intersection_func kernel_embree_filter_intersection_func_impl
703# if EMBREE_MAJOR_VERSION >= 4
704# define kernel_embree_filter_occluded_shadow_all_func \
705 kernel_embree_filter_occluded_shadow_all_func_impl
706# define kernel_embree_filter_occluded_local_func kernel_embree_filter_occluded_local_func_impl
707# define kernel_embree_filter_occluded_volume_all_func \
708 kernel_embree_filter_occluded_volume_all_func_impl
709# endif
710#endif
711
712/* Scene intersection. */
713
715 ccl_private const Ray *ray,
716 const uint visibility,
718{
719 isect->t = ray->tmax;
720#if EMBREE_MAJOR_VERSION >= 4
722 rtcInitRayQueryContext(&ctx);
723# ifdef __KERNEL_ONEAPI__
724 /* NOTE(sirgienko): Cycles GPU back-ends passes NULL to KernelGlobals and
725 * uses global device allocation (CUDA, Optix, HIP) or passes all needed data
726 * as a class context (Metal, oneAPI). So we need to pass this context here
727 * in order to have an access to it later in Embree filter functions on GPU. */
728 ctx.kg = (KernelGlobals)this;
729# else
730 ctx.kg = kg;
731# endif
732#else
734 rtcInitIntersectContext(&ctx);
735#endif
736
737 RTCRayHit ray_hit;
738 ctx.ray = ray;
739 kernel_embree_setup_rayhit(*ray, ray_hit, visibility);
740
741#if EMBREE_MAJOR_VERSION >= 4
742 RTCIntersectArguments args;
743 rtcInitIntersectArguments(&args);
744 args.filter = reinterpret_cast<RTCFilterFunctionN>(kernel_embree_filter_intersection_func);
745 args.feature_mask = CYCLES_EMBREE_USED_FEATURES;
746 args.context = &ctx;
747 rtcIntersect1(kernel_data.device_bvh, &ray_hit, &args);
748#else
749 rtcIntersect1(kernel_data.device_bvh, &ctx, &ray_hit);
750#endif
751 if (ray_hit.hit.geomID == RTC_INVALID_GEOMETRY_ID ||
752 ray_hit.hit.primID == RTC_INVALID_GEOMETRY_ID)
753 {
754 return false;
755 }
756
757 kernel_embree_convert_hit(kg, &ray_hit.ray, &ray_hit.hit, isect);
758 return true;
759}
760
761#ifdef __BVH_LOCAL__
762ccl_device_intersect bool kernel_embree_intersect_local(KernelGlobals kg,
763 ccl_private const Ray *ray,
764 ccl_private LocalIntersection *local_isect,
765 int local_object,
766 ccl_private uint *lcg_state,
767 int max_hits)
768{
769 const bool has_bvh = !(kernel_data_fetch(object_flag, local_object) &
771# if EMBREE_MAJOR_VERSION >= 4
772 CCLLocalContext ctx;
773 rtcInitRayQueryContext(&ctx);
774# ifdef __KERNEL_ONEAPI__
775 /* NOTE(sirgienko): Cycles GPU back-ends passes NULL to KernelGlobals and
776 * uses global device allocation (CUDA, Optix, HIP) or passes all needed data
777 * as a class context (Metal, oneAPI). So we need to pass this context here
778 * in order to have an access to it later in Embree filter functions on GPU. */
779 ctx.kg = (KernelGlobals)this;
780# else
781 ctx.kg = kg;
782# endif
783# else
784 CCLIntersectContext ctx(kg,
786 rtcInitIntersectContext(&ctx);
787# endif
788 ctx.is_sss = has_bvh;
789 ctx.lcg_state = lcg_state;
790 ctx.max_hits = max_hits;
791 ctx.ray = ray;
792 ctx.local_isect = local_isect;
793 if (local_isect) {
794 local_isect->num_hits = 0;
795 }
796 ctx.local_object_id = local_object;
797 RTCRay rtc_ray;
799
800# if EMBREE_MAJOR_VERSION >= 4
801 RTCOccludedArguments args;
802 rtcInitOccludedArguments(&args);
803 args.filter = reinterpret_cast<RTCFilterFunctionN>(kernel_embree_filter_occluded_local_func);
804 args.feature_mask = CYCLES_EMBREE_USED_FEATURES;
805 args.context = &ctx;
806# endif
807
808 /* If this object has its own BVH, use it. */
809 if (has_bvh) {
810 float3 P = ray->P;
811 float3 dir = ray->D;
812 float3 idir = ray->D;
813# ifdef __OBJECT_MOTION__
814 bvh_instance_motion_push(kg, local_object, ray, &P, &dir, &idir);
815# else
816 bvh_instance_push(kg, local_object, ray, &P, &dir, &idir);
817# endif
818
819 rtc_ray.org_x = P.x;
820 rtc_ray.org_y = P.y;
821 rtc_ray.org_z = P.z;
822 rtc_ray.dir_x = dir.x;
823 rtc_ray.dir_y = dir.y;
824 rtc_ray.dir_z = dir.z;
825 rtc_ray.tnear = ray->tmin;
826 rtc_ray.tfar = ray->tmax;
827 RTCScene scene = (RTCScene)rtcGetGeometryUserDataFromScene(kernel_data.device_bvh,
828 local_object * 2);
829 kernel_assert(scene);
830 if (scene) {
831# if EMBREE_MAJOR_VERSION >= 4
832 rtcOccluded1(scene, &rtc_ray, &args);
833# else
834 rtcOccluded1(scene, &ctx, &rtc_ray);
835# endif
836 }
837 }
838 else {
839# if EMBREE_MAJOR_VERSION >= 4
840 rtcOccluded1(kernel_data.device_bvh, &rtc_ray, &args);
841# else
842 rtcOccluded1(kernel_data.device_bvh, &ctx, &rtc_ray);
843# endif
844 }
845
846 /* rtcOccluded1 sets tfar to -inf if a hit was found. */
847 return (local_isect && local_isect->num_hits > 0) || (rtc_ray.tfar < 0);
848}
849#endif
850
851#ifdef __SHADOW_RECORD_ALL__
852ccl_device_intersect bool kernel_embree_intersect_shadow_all(KernelGlobals kg,
854 ccl_private const Ray *ray,
855 uint visibility,
856 uint max_hits,
857 ccl_private uint *num_recorded_hits,
858 ccl_private float *throughput)
859{
860# if EMBREE_MAJOR_VERSION >= 4
862 rtcInitRayQueryContext(&ctx);
863# ifdef __KERNEL_ONEAPI__
864 /* NOTE(sirgienko): Cycles GPU back-ends passes NULL to KernelGlobals and
865 * uses global device allocation (CUDA, Optix, HIP) or passes all needed data
866 * as a class context (Metal, oneAPI). So we need to pass this context here
867 * in order to have an access to it later in Embree filter functions on GPU. */
868 ctx.kg = (KernelGlobals)this;
869# else
870 ctx.kg = kg;
871# endif
872# else
874 rtcInitIntersectContext(&ctx);
875# endif
876 ctx.num_hits = ctx.num_recorded_hits = numhit_t(0);
877 ctx.throughput = 1.0f;
878 ctx.opaque_hit = false;
879 ctx.isect_s = state;
880 ctx.max_hits = numhit_t(max_hits);
881 ctx.max_t = ray->tmax;
882 ctx.ray = ray;
883 RTCRay rtc_ray;
884 kernel_embree_setup_ray(*ray, rtc_ray, visibility);
885# if EMBREE_MAJOR_VERSION >= 4
886 RTCOccludedArguments args;
887 rtcInitOccludedArguments(&args);
888 args.filter = reinterpret_cast<RTCFilterFunctionN>(
889 kernel_embree_filter_occluded_shadow_all_func);
890 args.feature_mask = CYCLES_EMBREE_USED_FEATURES;
891 args.context = &ctx;
892 rtcOccluded1(kernel_data.device_bvh, &rtc_ray, &args);
893# else
894 rtcOccluded1(kernel_data.device_bvh, &ctx, &rtc_ray);
895# endif
896
897 *num_recorded_hits = ctx.num_recorded_hits;
898 *throughput = ctx.throughput;
899 return ctx.opaque_hit;
900}
901#endif
902
903#ifdef __VOLUME__
904ccl_device_intersect uint kernel_embree_intersect_volume(KernelGlobals kg,
905 ccl_private const Ray *ray,
908 const uint max_hits,
909# endif
910 const uint visibility)
911{
912# if EMBREE_MAJOR_VERSION >= 4
914 rtcInitRayQueryContext(&ctx);
915# ifdef __KERNEL_ONEAPI__
916 /* NOTE(sirgienko) Cycles GPU back-ends passes NULL to KernelGlobals and
917 * uses global device allocation (CUDA, Optix, HIP) or passes all needed data
918 * as a class context (Metal, oneAPI). So we need to pass this context here
919 * in order to have an access to it later in Embree filter functions on GPU. */
920 ctx.kg = (KernelGlobals)this;
921# else
922 ctx.kg = kg;
923# endif
924# else
926 rtcInitIntersectContext(&ctx);
927# endif
928 ctx.vol_isect = isect;
929# ifdef __VOLUME_RECORD_ALL__
930 ctx.max_hits = numhit_t(max_hits);
931# endif
932 ctx.num_hits = numhit_t(0);
933 ctx.ray = ray;
934 RTCRay rtc_ray;
935 kernel_embree_setup_ray(*ray, rtc_ray, visibility);
936# if EMBREE_MAJOR_VERSION >= 4
937 RTCOccludedArguments args;
938 rtcInitOccludedArguments(&args);
939 args.filter = reinterpret_cast<RTCFilterFunctionN>(
940 kernel_embree_filter_occluded_volume_all_func);
941 args.feature_mask = CYCLES_EMBREE_USED_FEATURES;
942 args.context = &ctx;
943 rtcOccluded1(kernel_data.device_bvh, &rtc_ray, &args);
944# else
945 rtcOccluded1(kernel_data.device_bvh, &ctx, &rtc_ray);
946# endif
947 return ctx.num_hits;
948}
949#endif
950
unsigned int uint
SIMD_FORCE_INLINE btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition btVector3.h:303
additional_info("compositor_sum_squared_difference_float_shared") .push_constant(Type output_img float dot(value.rgb, luminance_coefficients)") .define("LOAD(value)"
ccl_device_forceinline int intersection_get_shader_flags(KernelGlobals kg, const int prim, const int type)
ccl_device_inline bool intersection_skip_self_local(ccl_ray_data const RaySelfPrimitives &self, const int prim)
ccl_device_inline bool intersection_skip_self(ccl_ray_data const RaySelfPrimitives &self, const int object, const int prim)
ccl_device_inline bool intersection_skip_shadow_link(KernelGlobals kg, ccl_ray_data const RaySelfPrimitives &self, const int isect_object)
#define CURVE_SHADOW_TRANSPARENCY_CUTOFF
ccl_device_inline float intersection_curve_shadow_transparency(KernelGlobals kg, const int object, const int prim, const int type, const float u)
ccl_device_inline bool intersection_skip_self_shadow(ccl_ray_data const RaySelfPrimitives &self, const int object, const int prim)
#define kernel_assert(cond)
#define kernel_data
const KernelGlobalsCPU *ccl_restrict KernelGlobals
#define kernel_data_fetch(name, index)
#define ccl_device_forceinline
#define ccl_device
#define ccl_private
#define ccl_device_inline
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
#define NULL
#define ccl_always_inline
#define ccl_device_intersect
uint32_t numhit_t
ccl_device_inline void kernel_embree_convert_hit(KernelGlobals kg, const RTCRay *ray, const RTCHit *hit, Intersection *isect, const intptr_t prim_offset)
ccl_device_forceinline void kernel_embree_filter_occluded_local_func_impl(const RTCFilterFunctionNArguments *args)
#define CYCLES_EMBREE_USED_FEATURES
ccl_device_forceinline void kernel_embree_filter_occluded_volume_all_func_impl(const RTCFilterFunctionNArguments *args)
ccl_device_forceinline void kernel_embree_filter_occluded_shadow_all_func_impl(const RTCFilterFunctionNArguments *args)
ccl_device_inline void kernel_embree_convert_sss_hit(KernelGlobals kg, const RTCRay *ray, const RTCHit *hit, Intersection *isect, int object, const intptr_t prim_offset)
ccl_device_inline void kernel_embree_setup_rayhit(const Ray &ray, RTCRayHit &rayhit, const uint visibility)
ccl_device_forceinline void kernel_embree_filter_occluded_func(const RTCFilterFunctionNArguments *args)
ccl_device_intersect bool kernel_embree_intersect(KernelGlobals kg, ccl_private const Ray *ray, const uint visibility, ccl_private Intersection *isect)
#define kernel_embree_filter_intersection_func
ccl_device void kernel_embree_filter_occluded_func_backface_cull(const RTCFilterFunctionNArguments *args)
ccl_device_inline int kernel_embree_get_hit_object(const RTCHit *hit)
#define rtcGetGeometryUserDataFromScene(scene, id)
ccl_device_inline bool kernel_embree_is_self_intersection(const KernelGlobals kg, const RTCHit *hit, const Ray *ray, const intptr_t prim_offset)
#define EMBREE_IS_HAIR(x)
ccl_device void kernel_embree_filter_func_backface_cull(const RTCFilterFunctionNArguments *args)
ccl_device_forceinline void kernel_embree_filter_intersection_func_impl(const RTCFilterFunctionNArguments *args)
ccl_device_inline void kernel_embree_setup_ray(const Ray &ray, RTCRay &rtc_ray, const uint visibility)
ccl_device_inline void bvh_instance_push(KernelGlobals kg, int object, ccl_private const Ray *ray, ccl_private float3 *P, ccl_private float3 *dir, ccl_private float3 *idir)
@ SD_HAS_TRANSPARENT_SHADOW
@ PRIMITIVE_CURVE
@ PATH_RAY_ALL_VISIBILITY
#define INTEGRATOR_SHADOW_ISECT_SIZE
#define __VOLUME_RECORD_ALL__
@ SD_OBJECT_HAS_VOLUME
@ SD_OBJECT_TRANSFORM_APPLIED
CCL_NAMESPACE_BEGIN ccl_device uint lcg_step_uint(T rng)
Definition lcg.h:14
static ulong state[N]
#define min(a, b)
Definition sort.c:32
IntegratorShadowStateCPU *ccl_restrict IntegratorShadowState
Definition state.h:230
#define INTEGRATOR_STATE_ARRAY(state, nested_struct, array_index, member)
Definition state.h:238
ccl_device_forceinline void integrator_state_write_shadow_isect(IntegratorShadowState state, ccl_private const Intersection *ccl_restrict isect, const int index)
Definition state_util.h:263
unsigned short uint16_t
Definition stdint.h:79
unsigned int uint32_t
Definition stdint.h:80
_W64 int intptr_t
Definition stdint.h:118
CCLIntersectContext(KernelGlobals kg_, RayType type_)
LocalIntersection * local_isect
IntegratorShadowState isect_s
struct Intersection hits[LOCAL_MAX_HITS]
float3 Ng[LOCAL_MAX_HITS]
RaySelfPrimitives self
float z
Definition sky_float3.h:27
float y
Definition sky_float3.h:27
float x
Definition sky_float3.h:27
float max