Blender V4.5
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#include <embree4/rtcore_geometry.h>
10#include <embree4/rtcore_ray.h>
11#include <embree4/rtcore_scene.h>
12
13#ifdef __KERNEL_ONEAPI__
16#else
19#endif
20
21#include "kernel/bvh/types.h"
22#include "kernel/bvh/util.h"
23#include "kernel/geom/object.h"
26#include "kernel/sample/lcg.h"
27
29
30#ifdef __KERNEL_ONEAPI__
31using numhit_t = uint16_t;
32#else
33using numhit_t = uint32_t;
34#endif
35
36/* Before Embree 4.4, the so-called Traversable functionality was exposed through Scene API.
37 * So, in order to simplify code between different versions, we are defining the traversable class
38 * and calls for older Embree versions as well. */
39#if RTC_VERSION < 40400
40# define RTCTraversable RTCScene
41# define rtcGetGeometryUserDataFromTraversable rtcGetGeometryUserDataFromScene
42# define rtcTraversableIntersect1 rtcIntersect1
43# define rtcTraversableOccluded1 rtcOccluded1
44#endif
45
46#ifdef __KERNEL_ONEAPI__
47# define CYCLES_EMBREE_USED_FEATURES \
48 (kernel_handler.get_specialization_constant<oneapi_embree_features>())
49#else
50# define CYCLES_EMBREE_USED_FEATURES \
51 (RTCFeatureFlags)(RTC_FEATURE_FLAG_TRIANGLE | RTC_FEATURE_FLAG_INSTANCE | \
52 RTC_FEATURE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS | RTC_FEATURE_FLAG_POINT | \
53 RTC_FEATURE_FLAG_MOTION_BLUR | RTC_FEATURE_FLAG_ROUND_CATMULL_ROM_CURVE | \
54 RTC_FEATURE_FLAG_FLAT_CATMULL_ROM_CURVE)
55#endif
56
57#define EMBREE_IS_HAIR(x) (x & 1)
58
59/* Intersection context. */
60
61struct CCLFirstHitContext : public RTCRayQueryContext {
63 /* For avoiding self intersections */
64 const Ray *ray;
65};
66
78
88
89struct CCLVolumeContext : public RTCRayQueryContext {
91 const Ray *ray;
92#ifdef __VOLUME_RECORD_ALL__
93 numhit_t max_hits;
94#endif
97};
98
99/* Utilities. */
100
102 RTCRay &rtc_ray,
103 const uint visibility)
104{
105 rtc_ray.org_x = ray.P.x;
106 rtc_ray.org_y = ray.P.y;
107 rtc_ray.org_z = ray.P.z;
108 rtc_ray.dir_x = ray.D.x;
109 rtc_ray.dir_y = ray.D.y;
110 rtc_ray.dir_z = ray.D.z;
111 rtc_ray.tnear = ray.tmin;
112 rtc_ray.tfar = ray.tmax;
113 rtc_ray.time = ray.time;
114 rtc_ray.mask = visibility;
115}
116
118 RTCRayHit &rayhit,
119 const uint visibility)
120{
121 kernel_embree_setup_ray(ray, rayhit.ray, visibility);
122 rayhit.hit.geomID = RTC_INVALID_GEOMETRY_ID;
123 rayhit.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
124}
125
127{
128 return (hit->instID[0] != RTC_INVALID_GEOMETRY_ID ? hit->instID[0] : hit->geomID) / 2;
129}
130
132 const RTCHit *hit,
133 const Ray *ray,
134 const intptr_t prim_offset)
135{
136 const int object = kernel_embree_get_hit_object(hit);
137
138 int prim;
139 if ((ray->self.object == object) || (ray->self.light_object == object)) {
140 prim = hit->primID + prim_offset;
141 }
142 else {
143 return false;
144 }
145
146 const bool is_hair = hit->geomID & 1;
147 if (is_hair) {
148 prim = kernel_data_fetch(curve_segments, prim).prim;
149 }
150
151 return intersection_skip_self_shadow(ray->self, object, prim);
152}
153
155 const RTCRay *ray,
156 const RTCHit *hit,
157 Intersection *isect,
158 const intptr_t prim_offset)
159{
160 isect->t = ray->tfar;
161 isect->prim = hit->primID + prim_offset;
163
164 const bool is_hair = hit->geomID & 1;
165 if (is_hair) {
166 const KernelCurveSegment segment = kernel_data_fetch(curve_segments, isect->prim);
167 isect->type = segment.type;
168 isect->prim = segment.prim;
169 isect->u = hit->u;
170 isect->v = hit->v;
171 }
172 else {
173 isect->type = kernel_data_fetch(objects, isect->object).primitive_type;
174 isect->u = hit->u;
175 isect->v = hit->v;
176 }
177}
178
180 const RTCRay *ray,
181 const RTCHit *hit,
182 Intersection *isect)
183{
184 intptr_t prim_offset;
185 if (hit->instID[0] != RTC_INVALID_GEOMETRY_ID) {
187 kernel_data.device_bvh, hit->instID[0]);
188 prim_offset = intptr_t(rtcGetGeometryUserDataFromTraversable(inst_scene, hit->geomID));
189 }
190 else {
191 prim_offset = intptr_t(
192 rtcGetGeometryUserDataFromTraversable(kernel_data.device_bvh, hit->geomID));
193 }
194 kernel_embree_convert_hit(kg, ray, hit, isect, prim_offset);
195}
196
198 const RTCRay *ray,
199 const RTCHit *hit,
200 Intersection *isect,
201 const int object,
202 const intptr_t prim_offset)
203{
204 isect->u = hit->u;
205 isect->v = hit->v;
206 isect->t = ray->tfar;
207 isect->prim = hit->primID + prim_offset;
208 isect->object = object;
209 isect->type = kernel_data_fetch(objects, object).primitive_type;
210}
211
212/* Ray filter functions. */
213
214/* This gets called by Embree at every valid ray/object intersection.
215 * Things like recording subsurface or shadow hits for later evaluation
216 * as well as filtering for volume objects happen here.
217 * Cycles' own BVH does that directly inside the traversal calls. */
219 const RTCFilterFunctionNArguments *args)
220{
221 /* Current implementation in Cycles assumes only single-ray intersection queries. */
222 assert(args->N == 1);
223
224 RTCHit *hit = (RTCHit *)args->hit;
225 CCLFirstHitContext *ctx = (CCLFirstHitContext *)(args->context);
226#ifdef __KERNEL_ONEAPI__
227 KernelGlobalsGPU *kg = nullptr;
228#else
229 const ThreadKernelGlobalsCPU *kg = ctx->kg;
230#endif
231 const Ray *cray = ctx->ray;
232
234 kg, hit, cray, reinterpret_cast<intptr_t>(args->geometryUserPtr)))
235 {
236 *args->valid = 0;
237 return;
238 }
239
240#ifdef __SHADOW_LINKING__
242 *args->valid = 0;
243 return;
244 }
245#endif
246}
247
248/* This gets called by Embree at every valid ray/object intersection.
249 * Things like recording subsurface or shadow hits for later evaluation
250 * as well as filtering for volume objects happen here.
251 * Cycles' own BVH does that directly inside the traversal calls.
252 */
254 const RTCFilterFunctionNArguments *args)
255{
256 /* Current implementation in Cycles assumes only single-ray intersection queries. */
257 assert(args->N == 1);
258
259 const RTCRay *ray = (RTCRay *)args->ray;
260 RTCHit *hit = (RTCHit *)args->hit;
261 CCLShadowContext *ctx = (CCLShadowContext *)(args->context);
262#ifdef __KERNEL_ONEAPI__
263 KernelGlobalsGPU *kg = nullptr;
264#else
265 const ThreadKernelGlobalsCPU *kg = ctx->kg;
266#endif
267 const Ray *cray = ctx->ray;
268
269 Intersection current_isect;
271 kg, ray, hit, &current_isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
272 if (intersection_skip_self_shadow(cray->self, current_isect.object, current_isect.prim)) {
273 *args->valid = 0;
274 return;
275 }
276
277#ifdef __SHADOW_LINKING__
278 if (intersection_skip_shadow_link(kg, cray->self, current_isect.object)) {
279 *args->valid = 0;
280 return;
281 }
282#endif
283
284 /* If no transparent shadows or max number of hits exceeded, all light is blocked. */
285 const int flags = intersection_get_shader_flags(kg, current_isect.prim, current_isect.type);
286 if ((flags & SD_HAS_TRANSPARENT_SHADOW) == 0) {
287 ctx->opaque_hit = true;
288 return;
289 }
290
292 kg, ctx->isect_s, current_isect.object, current_isect.prim, ctx->num_hits))
293 {
294 *args->valid = 0;
295 return;
296 }
297
298 ++ctx->num_hits;
299 if (ctx->num_hits > ctx->max_hits) {
300 ctx->opaque_hit = true;
301 return;
302 }
303
304 /* Always use baked shadow transparency for curves. */
305 if (current_isect.type & PRIMITIVE_CURVE) {
307 kg, current_isect.object, current_isect.prim, current_isect.type, current_isect.u);
308
310 ctx->opaque_hit = true;
311 return;
312 }
313 else {
314 *args->valid = 0;
315 return;
316 }
317 }
318
319 numhit_t isect_index = ctx->num_recorded_hits;
320
321 /* Always increase the number of recorded hits, even beyond the maximum,
322 * so that we can detect this and trace another ray if needed.
323 * More details about the related logic can be found in implementation of
324 * "shadow_intersections_has_remaining" and "integrate_transparent_shadow"
325 * functions. */
326 ++ctx->num_recorded_hits;
327
328 /* This tells Embree to continue tracing. */
329 *args->valid = 0;
330
331 const numhit_t max_record_hits = min(ctx->max_hits, numhit_t(INTEGRATOR_SHADOW_ISECT_SIZE));
332 /* If the maximum number of hits was reached, replace the furthest intersection
333 * with a closer one so we get the N closest intersections. */
334 if (isect_index >= max_record_hits) {
335 /* When recording only N closest hits, max_t will always only decrease.
336 * So let's test if we are already not meeting criteria and can skip max_t recalculation. */
337 if (current_isect.t >= ctx->max_t) {
338 return;
339 }
340
341 float max_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, 0, t);
342 numhit_t max_recorded_hit = numhit_t(0);
343 float second_largest_t = 0.0f;
344
345 for (numhit_t i = numhit_t(1); i < max_record_hits; ++i) {
346 const float isect_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, i, t);
347 if (isect_t > max_t) {
348 second_largest_t = max_t;
349 max_recorded_hit = i;
350 max_t = isect_t;
351 }
352 else if (isect_t > second_largest_t) {
353 second_largest_t = isect_t;
354 }
355 }
356
357 if (isect_index == max_record_hits && current_isect.t >= max_t) {
358 /* `ctx->max_t` was initialized to `ray->tmax` before the index exceeds the limit. Now that
359 * we have looped through the array, we can properly clamp `ctx->max_t`. */
360 ctx->max_t = max_t;
361 return;
362 }
363
364 isect_index = max_recorded_hit;
365
366 /* After replacing `max_t` with `current_isect.t`, the new largest t would be either
367 * `current_isect.t` or the second largest t before. */
368 ctx->max_t = max(second_largest_t, current_isect.t);
369 }
370
371 integrator_state_write_shadow_isect(ctx->isect_s, &current_isect, isect_index);
372}
373
375 const RTCFilterFunctionNArguments *args)
376{
377 /* Current implementation in Cycles assumes only single-ray intersection queries. */
378 assert(args->N == 1);
379
380 const RTCRay *ray = (RTCRay *)args->ray;
381 RTCHit *hit = (RTCHit *)args->hit;
382 CCLLocalContext *ctx = (CCLLocalContext *)(args->context);
383#ifdef __KERNEL_ONEAPI__
384 KernelGlobalsGPU *kg = nullptr;
385#else
386 const ThreadKernelGlobalsCPU *kg = ctx->kg;
387#endif
388 const Ray *cray = ctx->ray;
389
390 /* Check if it's hitting the correct object. */
391 Intersection current_isect;
392 if (ctx->is_sss) {
394 ray,
395 hit,
396 &current_isect,
397 ctx->local_object_id,
398 reinterpret_cast<intptr_t>(args->geometryUserPtr));
399 }
400 else {
402 kg, ray, hit, &current_isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
403 if (ctx->local_object_id != current_isect.object) {
404 /* This tells Embree to continue tracing. */
405 *args->valid = 0;
406 return;
407 }
408 }
409 if (intersection_skip_self_local(cray->self, current_isect.prim)) {
410 *args->valid = 0;
411 return;
412 }
413
414 /* No intersection information requested, just return a hit. */
415 if (ctx->max_hits == 0) {
416 return;
417 }
418
419 /* Ignore curves. */
420 if (EMBREE_IS_HAIR(hit->geomID)) {
421 /* This tells Embree to continue tracing. */
422 *args->valid = 0;
423 return;
424 }
425
426 LocalIntersection *local_isect = ctx->local_isect;
427 int hit_idx = 0;
428
429 if (ctx->lcg_state) {
430 /* See triangle_intersect_subsurface() for the native equivalent. */
431 for (int i = min((int)ctx->max_hits, local_isect->num_hits) - 1; i >= 0; --i) {
432 if (local_isect->hits[i].t == ray->tfar) {
433 /* This tells Embree to continue tracing. */
434 *args->valid = 0;
435 return;
436 }
437 }
438
439 local_isect->num_hits++;
440
441 if (local_isect->num_hits <= ctx->max_hits) {
442 hit_idx = local_isect->num_hits - 1;
443 }
444 else {
445 /* reservoir sampling: if we are at the maximum number of
446 * hits, randomly replace element or skip it */
447 hit_idx = lcg_step_uint(ctx->lcg_state) % local_isect->num_hits;
448
449 if (hit_idx >= ctx->max_hits) {
450 /* This tells Embree to continue tracing. */
451 *args->valid = 0;
452 return;
453 }
454 }
455 }
456 else {
457 /* Record closest intersection only. */
458 if (local_isect->num_hits && current_isect.t > local_isect->hits[0].t) {
459 *args->valid = 0;
460 return;
461 }
462
463 local_isect->num_hits = 1;
464 }
465
466 /* record intersection */
467 local_isect->hits[hit_idx] = current_isect;
468 local_isect->Ng[hit_idx] = normalize(make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z));
469 /* This tells Embree to continue tracing. */
470 *args->valid = 0;
471}
472
474 const RTCFilterFunctionNArguments *args)
475{
476 /* Current implementation in Cycles assumes only single-ray intersection queries. */
477 assert(args->N == 1);
478
479 const RTCRay *ray = (RTCRay *)args->ray;
480 RTCHit *hit = (RTCHit *)args->hit;
481 CCLVolumeContext *ctx = (CCLVolumeContext *)(args->context);
482#ifdef __KERNEL_ONEAPI__
483 KernelGlobalsGPU *kg = nullptr;
484#else
485 const ThreadKernelGlobalsCPU *kg = ctx->kg;
486#endif
487 const Ray *cray = ctx->ray;
488
489#ifdef __VOLUME_RECORD_ALL__
490 /* Append the intersection to the end of the array. */
491 if (ctx->num_hits < ctx->max_hits) {
492#endif
493 Intersection current_isect;
495 kg, ray, hit, &current_isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
496 if (intersection_skip_self(cray->self, current_isect.object, current_isect.prim)) {
497 *args->valid = 0;
498 return;
499 }
500
501 Intersection *isect = &ctx->vol_isect[ctx->num_hits];
502 ++ctx->num_hits;
503 *isect = current_isect;
504 /* Only primitives from volume object. */
505 uint tri_object = isect->object;
506 int object_flag = kernel_data_fetch(object_flag, tri_object);
507 if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
508 --ctx->num_hits;
509#ifndef __VOLUME_RECORD_ALL__
510 /* Without __VOLUME_RECORD_ALL__ we need only a first counted hit, so we will
511 * continue tracing only if a current hit is not counted. */
512 *args->valid = 0;
513#endif
514 }
515#ifdef __VOLUME_RECORD_ALL__
516 /* This tells Embree to continue tracing. */
517 *args->valid = 0;
518 }
519#endif
520}
521
522#ifdef __KERNEL_ONEAPI__
523/* Static wrappers so we can call the callbacks from out side the ONEAPIKernelContext class */
524RTC_SYCL_INDIRECTLY_CALLABLE static void ccl_always_inline
525kernel_embree_filter_intersection_func_static(const RTCFilterFunctionNArguments *args)
526{
527 RTCHit *hit = (RTCHit *)args->hit;
528 CCLFirstHitContext *ctx = (CCLFirstHitContext *)(args->context);
529 ONEAPIKernelContext *context = static_cast<ONEAPIKernelContext *>(ctx->kg);
530 context->kernel_embree_filter_intersection_func_impl(args);
531}
532
533RTC_SYCL_INDIRECTLY_CALLABLE static void ccl_always_inline
534kernel_embree_filter_occluded_shadow_all_func_static(const RTCFilterFunctionNArguments *args)
535{
536 RTCHit *hit = (RTCHit *)args->hit;
537 CCLShadowContext *ctx = (CCLShadowContext *)(args->context);
538 ONEAPIKernelContext *context = static_cast<ONEAPIKernelContext *>(ctx->kg);
539 context->kernel_embree_filter_occluded_shadow_all_func_impl(args);
540}
541
542RTC_SYCL_INDIRECTLY_CALLABLE static void ccl_always_inline
543kernel_embree_filter_occluded_local_func_static(const RTCFilterFunctionNArguments *args)
544{
545 RTCHit *hit = (RTCHit *)args->hit;
546 CCLLocalContext *ctx = (CCLLocalContext *)(args->context);
547 ONEAPIKernelContext *context = static_cast<ONEAPIKernelContext *>(ctx->kg);
548 context->kernel_embree_filter_occluded_local_func_impl(args);
549}
550
551RTC_SYCL_INDIRECTLY_CALLABLE static void ccl_always_inline
552kernel_embree_filter_occluded_volume_all_func_static(const RTCFilterFunctionNArguments *args)
553{
554 RTCHit *hit = (RTCHit *)args->hit;
555 CCLVolumeContext *ctx = (CCLVolumeContext *)(args->context);
556 ONEAPIKernelContext *context = static_cast<ONEAPIKernelContext *>(ctx->kg);
557 context->kernel_embree_filter_occluded_volume_all_func_impl(args);
558}
559
560# define kernel_embree_filter_intersection_func \
561 ONEAPIKernelContext::kernel_embree_filter_intersection_func_static
562# define kernel_embree_filter_occluded_shadow_all_func \
563 ONEAPIKernelContext::kernel_embree_filter_occluded_shadow_all_func_static
564# define kernel_embree_filter_occluded_local_func \
565 ONEAPIKernelContext::kernel_embree_filter_occluded_local_func_static
566# define kernel_embree_filter_occluded_volume_all_func \
567 ONEAPIKernelContext::kernel_embree_filter_occluded_volume_all_func_static
568#else
569# define kernel_embree_filter_intersection_func kernel_embree_filter_intersection_func_impl
570# define kernel_embree_filter_occluded_shadow_all_func \
571 kernel_embree_filter_occluded_shadow_all_func_impl
572# define kernel_embree_filter_occluded_local_func kernel_embree_filter_occluded_local_func_impl
573# define kernel_embree_filter_occluded_volume_all_func \
574 kernel_embree_filter_occluded_volume_all_func_impl
575#endif
576
577/* Scene intersection. */
578
580 const ccl_private Ray *ray,
581 const uint visibility,
583{
584 isect->t = ray->tmax;
586 rtcInitRayQueryContext(&ctx);
587#ifdef __KERNEL_ONEAPI__
588 /* NOTE(sirgienko): Cycles GPU back-ends passes nullptr to KernelGlobals and
589 * uses global device allocation (CUDA, Optix, HIP) or passes all needed data
590 * as a class context (Metal, oneAPI). So we need to pass this context here
591 * in order to have an access to it later in Embree filter functions on GPU. */
592 ctx.kg = (KernelGlobals)this;
593#else
594 ctx.kg = kg;
595#endif
596
597 RTCRayHit ray_hit;
598 ctx.ray = ray;
599 kernel_embree_setup_rayhit(*ray, ray_hit, visibility);
600
601 RTCIntersectArguments args;
602 rtcInitIntersectArguments(&args);
603 args.filter = reinterpret_cast<RTCFilterFunctionN>(kernel_embree_filter_intersection_func);
604 args.feature_mask = CYCLES_EMBREE_USED_FEATURES;
605 args.context = &ctx;
606 rtcTraversableIntersect1(kernel_data.device_bvh, &ray_hit, &args);
607 if (ray_hit.hit.geomID == RTC_INVALID_GEOMETRY_ID ||
608 ray_hit.hit.primID == RTC_INVALID_GEOMETRY_ID)
609 {
610 return false;
611 }
612
613 kernel_embree_convert_hit(kg, &ray_hit.ray, &ray_hit.hit, isect);
614 return true;
615}
616
617#ifdef __BVH_LOCAL__
618ccl_device_intersect bool kernel_embree_intersect_local(KernelGlobals kg,
619 const ccl_private Ray *ray,
620 ccl_private LocalIntersection *local_isect,
621 const int local_object,
622 ccl_private uint *lcg_state,
623 const int max_hits)
624{
625 const bool has_bvh = !(kernel_data_fetch(object_flag, local_object) &
627 CCLLocalContext ctx;
628 rtcInitRayQueryContext(&ctx);
629# ifdef __KERNEL_ONEAPI__
630 /* NOTE(sirgienko): Cycles GPU back-ends passes nullptr to KernelGlobals and
631 * uses global device allocation (CUDA, Optix, HIP) or passes all needed data
632 * as a class context (Metal, oneAPI). So we need to pass this context here
633 * in order to have an access to it later in Embree filter functions on GPU. */
634 ctx.kg = (KernelGlobals)this;
635# else
636 ctx.kg = kg;
637# endif
638 ctx.is_sss = has_bvh;
639 ctx.lcg_state = lcg_state;
640 ctx.max_hits = max_hits;
641 ctx.ray = ray;
642 ctx.local_isect = local_isect;
643 if (local_isect) {
644 local_isect->num_hits = 0;
645 }
646 ctx.local_object_id = local_object;
647 RTCRay rtc_ray;
649
650 RTCOccludedArguments args;
651 rtcInitOccludedArguments(&args);
652 args.filter = reinterpret_cast<RTCFilterFunctionN>(kernel_embree_filter_occluded_local_func);
653 args.feature_mask = CYCLES_EMBREE_USED_FEATURES;
654 args.context = &ctx;
655
656 /* If this object has its own BVH, use it. */
657 if (has_bvh) {
658 float3 P = ray->P;
659 float3 dir = ray->D;
660 float3 idir = ray->D;
661# ifdef __OBJECT_MOTION__
662 bvh_instance_motion_push(kg, local_object, ray, &P, &dir, &idir);
663# else
664 bvh_instance_push(kg, local_object, ray, &P, &dir, &idir);
665# endif
666
667 rtc_ray.org_x = P.x;
668 rtc_ray.org_y = P.y;
669 rtc_ray.org_z = P.z;
670 rtc_ray.dir_x = dir.x;
671 rtc_ray.dir_y = dir.y;
672 rtc_ray.dir_z = dir.z;
673 rtc_ray.tnear = ray->tmin;
674 rtc_ray.tfar = ray->tmax;
676 kernel_data.device_bvh, local_object * 2);
677 kernel_assert(scene);
678 if (scene) {
679 rtcTraversableOccluded1(scene, &rtc_ray, &args);
680 }
681 }
682 else {
683 rtcTraversableOccluded1(kernel_data.device_bvh, &rtc_ray, &args);
684 }
685
686 /* rtcOccluded1 sets tfar to -inf if a hit was found. */
687 return (local_isect && local_isect->num_hits > 0) || (rtc_ray.tfar < 0);
688}
689#endif
690
691#ifdef __SHADOW_RECORD_ALL__
692ccl_device_intersect bool kernel_embree_intersect_shadow_all(KernelGlobals kg,
694 const ccl_private Ray *ray,
695 const uint visibility,
696 const uint max_hits,
697 ccl_private uint *num_recorded_hits,
698 ccl_private float *throughput)
699{
701 rtcInitRayQueryContext(&ctx);
702# ifdef __KERNEL_ONEAPI__
703 /* NOTE(sirgienko): Cycles GPU back-ends passes nullptr to KernelGlobals and
704 * uses global device allocation (CUDA, Optix, HIP) or passes all needed data
705 * as a class context (Metal, oneAPI). So we need to pass this context here
706 * in order to have an access to it later in Embree filter functions on GPU. */
707 ctx.kg = (KernelGlobals)this;
708# else
709 ctx.kg = kg;
710# endif
711 ctx.num_hits = ctx.num_recorded_hits = numhit_t(0);
712 ctx.throughput = 1.0f;
713 ctx.opaque_hit = false;
714 ctx.isect_s = state;
715 ctx.max_hits = numhit_t(max_hits);
716 ctx.max_t = ray->tmax;
717 ctx.ray = ray;
718 RTCRay rtc_ray;
719 kernel_embree_setup_ray(*ray, rtc_ray, visibility);
720 RTCOccludedArguments args;
721 rtcInitOccludedArguments(&args);
722 args.filter = reinterpret_cast<RTCFilterFunctionN>(
724 args.feature_mask = CYCLES_EMBREE_USED_FEATURES;
725 args.context = &ctx;
726 rtcTraversableOccluded1(kernel_data.device_bvh, &rtc_ray, &args);
727
728 *num_recorded_hits = ctx.num_recorded_hits;
729 *throughput = ctx.throughput;
730 return ctx.opaque_hit;
731}
732#endif
733
734#ifdef __VOLUME__
735ccl_device_intersect uint kernel_embree_intersect_volume(KernelGlobals kg,
736 const ccl_private Ray *ray,
739 const uint max_hits,
740# endif
741 const uint visibility)
742{
744 rtcInitRayQueryContext(&ctx);
745# ifdef __KERNEL_ONEAPI__
746 /* NOTE(sirgienko) Cycles GPU back-ends passes nullptr to KernelGlobals and
747 * uses global device allocation (CUDA, Optix, HIP) or passes all needed data
748 * as a class context (Metal, oneAPI). So we need to pass this context here
749 * in order to have an access to it later in Embree filter functions on GPU. */
750 ctx.kg = (KernelGlobals)this;
751# else
752 ctx.kg = kg;
753# endif
754 ctx.vol_isect = isect;
755# ifdef __VOLUME_RECORD_ALL__
756 ctx.max_hits = numhit_t(max_hits);
757# endif
758 ctx.num_hits = numhit_t(0);
759 ctx.ray = ray;
760 RTCRay rtc_ray;
761 kernel_embree_setup_ray(*ray, rtc_ray, visibility);
762 RTCOccludedArguments args;
763 rtcInitOccludedArguments(&args);
764 args.filter = reinterpret_cast<RTCFilterFunctionN>(
766 args.feature_mask = CYCLES_EMBREE_USED_FEATURES;
767 args.context = &ctx;
768 rtcTraversableOccluded1(kernel_data.device_bvh, &rtc_ray, &args);
769 return ctx.num_hits;
770}
771#endif
772
unsigned int uint
ccl_device_forceinline int intersection_get_shader_flags(KernelGlobals kg, const int prim, const int type)
ccl_device_inline bool intersection_skip_shadow_link(KernelGlobals kg, const ccl_ray_data RaySelfPrimitives &self, const int isect_object)
ccl_device_inline bool intersection_skip_self_shadow(const ccl_ray_data RaySelfPrimitives &self, const int object, const int prim)
ccl_device_inline bool intersection_skip_self(const ccl_ray_data RaySelfPrimitives &self, const int object, const int prim)
#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_forceinline bool intersection_skip_shadow_already_recoded(KernelGlobals kg, IntegratorShadowState state, const int object, const int prim, const int num_hits)
ccl_device_inline bool intersection_skip_self_local(const ccl_ray_data RaySelfPrimitives &self, const int prim)
#define kernel_assert(cond)
#define kernel_data
#define ccl_device_forceinline
#define kernel_data_fetch(name, index)
#define ccl_always_inline
#define INTEGRATOR_SHADOW_ISECT_SIZE
#define __VOLUME_RECORD_ALL__
#define ccl_private
const ThreadKernelGlobalsCPU * KernelGlobals
#define ccl_device_inline
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
VecBase< float, D > normalize(VecOp< float, D >) RET
#define assert(assertion)
#define ccl_device_intersect
#define rtcTraversableOccluded1
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_inline void kernel_embree_convert_sss_hit(KernelGlobals kg, const RTCRay *ray, const RTCHit *hit, Intersection *isect, const int object, const intptr_t prim_offset)
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_intersect bool kernel_embree_intersect(KernelGlobals kg, const ccl_private Ray *ray, const uint visibility, ccl_private Intersection *isect)
ccl_device_inline void kernel_embree_setup_rayhit(const Ray &ray, RTCRayHit &rayhit, const uint visibility)
#define kernel_embree_filter_occluded_volume_all_func
#define kernel_embree_filter_intersection_func
#define rtcGetGeometryUserDataFromTraversable
ccl_device_inline int kernel_embree_get_hit_object(const RTCHit *hit)
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)
#define rtcTraversableIntersect1
#define kernel_embree_filter_occluded_local_func
ccl_device_forceinline void kernel_embree_filter_intersection_func_impl(const RTCFilterFunctionNArguments *args)
#define RTCTraversable
#define kernel_embree_filter_occluded_shadow_all_func
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, const int object, const ccl_private Ray *ray, ccl_private float3 *P, ccl_private float3 *dir, ccl_private float3 *idir)
@ SD_HAS_TRANSPARENT_SHADOW
@ PRIMITIVE_CURVE
@ PATH_RAY_ALL_VISIBILITY
@ 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]
int context(const bContext *C, const char *member, bContextDataResult *result)
#define min(a, b)
Definition sort.cc:36
IntegratorShadowStateCPU * 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, const ccl_private Intersection *ccl_restrict isect, const int index)
Definition state_util.h:284
LocalIntersection * local_isect
IntegratorShadowState isect_s
struct Intersection hits[LOCAL_MAX_HITS]
float3 Ng[LOCAL_MAX_HITS]
float tmax
float tmin
float3 P
float time
RaySelfPrimitives self
float3 D
float z
Definition sky_float3.h:27
float y
Definition sky_float3.h:27
float x
Definition sky_float3.h:27
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251