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