Add Chromium-only Blender WebEngine parity work
This commit is contained in:
437
blender-5.2.0/intern/cycles/kernel/bvh/bvh.h
Normal file
437
blender-5.2.0/intern/cycles/kernel/bvh/bvh.h
Normal file
@@ -0,0 +1,437 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/bvh/intersect_filter.h"
|
||||
#include "kernel/bvh/nodes.h"
|
||||
#include "kernel/bvh/types.h"
|
||||
#include "kernel/bvh/util.h"
|
||||
|
||||
#include "kernel/geom/curve_intersect.h"
|
||||
#include "kernel/geom/motion_triangle_intersect.h"
|
||||
#include "kernel/geom/object.h"
|
||||
#include "kernel/geom/point_intersect.h"
|
||||
#include "kernel/geom/triangle_intersect.h"
|
||||
|
||||
/* Device specific acceleration structures for ray tracing. */
|
||||
|
||||
#if defined(__EMBREE__)
|
||||
# include "kernel/device/cpu/bvh.h"
|
||||
# define __BVH2__
|
||||
#elif defined(__KERNEL_METALRT__)
|
||||
# include "kernel/device/metal/bvh.h"
|
||||
#elif defined(__KERNEL_OPTIX__)
|
||||
# include "kernel/device/optix/bvh.h"
|
||||
#elif defined(__KERNEL_HIPRT__)
|
||||
# include "kernel/device/hiprt/bvh.h"
|
||||
#else
|
||||
# define __BVH2__
|
||||
#endif
|
||||
|
||||
#if defined(__KERNEL_ONEAPI__) && defined(WITH_EMBREE_GPU)
|
||||
/* bool is apparently not tested for specialization constants:
|
||||
* https://github.com/intel/llvm/blob/39d1c65272a786b2b13a6f094facfddf9408406d/sycl/test/basic_tests/SYCL-2020-spec-constants.cpp#L25-L27
|
||||
* Instead of adding one more bool specialization constant, we reuse existing embree_features one
|
||||
* and use RTC_FEATURE_FLAG_NONE as value to test for avoiding to call Embree on GPU.
|
||||
*/
|
||||
/* We set it to RTC_FEATURE_FLAG_NONE by default so AoT binaries contain MNE and ray-trace kernels
|
||||
* pre-compiled without Embree.
|
||||
* Changing this default value would require updating the logic in oneapi_load_kernels(). */
|
||||
static constexpr sycl::specialization_id<RTCFeatureFlags> oneapi_embree_features{
|
||||
RTC_FEATURE_FLAG_NONE};
|
||||
# define IF_USING_EMBREE \
|
||||
if (kernel_handler.get_specialization_constant<oneapi_embree_features>() != \
|
||||
RTC_FEATURE_FLAG_NONE)
|
||||
# define IF_NOT_USING_EMBREE \
|
||||
if (kernel_handler.get_specialization_constant<oneapi_embree_features>() == \
|
||||
RTC_FEATURE_FLAG_NONE)
|
||||
#else
|
||||
# define IF_USING_EMBREE
|
||||
# define IF_NOT_USING_EMBREE
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Transparent shadow BVH traversal, recording multiple intersections.
|
||||
*/
|
||||
|
||||
#ifdef __TRANSPARENT_SHADOWS__
|
||||
|
||||
# if defined(__BVH2__)
|
||||
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all
|
||||
# define BVH_FUNCTION_FEATURES BVH_POINTCLOUD
|
||||
# include "kernel/bvh/shadow_all.h"
|
||||
|
||||
# if defined(__HAIR__)
|
||||
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair
|
||||
# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_POINTCLOUD
|
||||
# include "kernel/bvh/shadow_all.h"
|
||||
# endif
|
||||
|
||||
# if defined(__OBJECT_MOTION__)
|
||||
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_motion
|
||||
# define BVH_FUNCTION_FEATURES BVH_MOTION | BVH_POINTCLOUD
|
||||
# include "kernel/bvh/shadow_all.h"
|
||||
# endif
|
||||
|
||||
# if defined(__HAIR__) && defined(__OBJECT_MOTION__)
|
||||
# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair_motion
|
||||
# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_MOTION | BVH_POINTCLOUD
|
||||
# include "kernel/bvh/shadow_all.h"
|
||||
# endif
|
||||
|
||||
ccl_device_inline void scene_intersect_shadow_all_bvh2(
|
||||
KernelGlobals kg,
|
||||
const ccl_private Ray *ccl_restrict ray,
|
||||
ccl_private BVHShadowAllPayload &ccl_restrict payload)
|
||||
{
|
||||
# ifdef __OBJECT_MOTION__
|
||||
if (kernel_data.bvh.have_motion) {
|
||||
# ifdef __HAIR__
|
||||
if (kernel_data.bvh.have_curves) {
|
||||
bvh_intersect_shadow_all_hair_motion(kg, ray, payload);
|
||||
return;
|
||||
}
|
||||
# endif /* __HAIR__ */
|
||||
bvh_intersect_shadow_all_motion(kg, ray, payload);
|
||||
return;
|
||||
}
|
||||
# endif /* __OBJECT_MOTION__ */
|
||||
|
||||
# ifdef __HAIR__
|
||||
if (kernel_data.bvh.have_curves) {
|
||||
bvh_intersect_shadow_all_hair(kg, ray, payload);
|
||||
return;
|
||||
}
|
||||
# endif /* __HAIR__ */
|
||||
bvh_intersect_shadow_all(kg, ray, payload);
|
||||
}
|
||||
# endif /* __BVH2__ */
|
||||
|
||||
ccl_device_intersect void scene_intersect_shadow_all(KernelGlobals kg,
|
||||
IntegratorShadowState state,
|
||||
const ccl_private Ray *ray,
|
||||
const uint visibility,
|
||||
const uint max_transparent_hits,
|
||||
ccl_private uint *num_recorded_hits,
|
||||
ccl_private float *throughput)
|
||||
{
|
||||
# if !defined(__KERNEL_OPTIX__)
|
||||
/* OptiX does not perform well with conditional trace calls, so it handles the validity of the
|
||||
* ray in the scene_intersect_shadow_all_optix(). */
|
||||
if (!intersection_ray_valid(ray)) {
|
||||
*num_recorded_hits = 0;
|
||||
*throughput = 1.0f;
|
||||
return;
|
||||
}
|
||||
# endif
|
||||
|
||||
BVHShadowAllPayload payload;
|
||||
|
||||
/* A bit of a tricky initialization:
|
||||
* - Some backends require extra ray information for custom motion blur intersection.
|
||||
* - Some backends utilize registers to pass commonly accessed data to the trace calls. */
|
||||
# if !defined(__KERNEL_OPTIX__)
|
||||
BVH_PAYLOAD_BASE(payload).ray_self = ray->self;
|
||||
BVH_PAYLOAD_BASE(payload).ray_visibility = visibility;
|
||||
# if defined(__KERNEL_HIPRT__)
|
||||
BVH_PAYLOAD_BASE(payload).ray_time = ray->time;
|
||||
# endif
|
||||
# endif
|
||||
|
||||
payload.state = state;
|
||||
payload.max_transparent_hits = max_transparent_hits;
|
||||
payload.max_record_isect_t = ray->tmax;
|
||||
|
||||
# ifdef __EMBREE__
|
||||
IF_USING_EMBREE
|
||||
{
|
||||
if (kernel_data.device_bvh) {
|
||||
kernel_embree_intersect_shadow_all(kg, ray, payload);
|
||||
*num_recorded_hits = payload.num_recorded_hits;
|
||||
*throughput = payload.throughput;
|
||||
return;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
IF_NOT_USING_EMBREE
|
||||
{
|
||||
# if defined(__BVH2__)
|
||||
scene_intersect_shadow_all_bvh2(kg, ray, payload);
|
||||
# elif defined(__KERNEL_HIPRT__)
|
||||
scene_intersect_shadow_all_hiprt(kg, ray, payload);
|
||||
# elif defined(__KERNEL_METALRT__)
|
||||
scene_intersect_shadow_all_metalrt(ray, payload);
|
||||
# elif defined(__KERNEL_OPTIX__)
|
||||
scene_intersect_shadow_all_optix(ray, visibility, payload);
|
||||
# endif
|
||||
|
||||
*num_recorded_hits = payload.num_recorded_hits;
|
||||
*throughput = payload.throughput;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
kernel_assert(false);
|
||||
}
|
||||
#endif /* __TRANSPARENT_SHADOWS__ */
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
#ifdef __BVH2__
|
||||
|
||||
/* BVH2
|
||||
*
|
||||
* Bounding volume hierarchy for ray tracing, when no native acceleration
|
||||
* structure is available for the device.
|
||||
*
|
||||
* We compile different variations of the same BVH traversal function for
|
||||
* faster rendering when some types of primitives are not needed, using #includes
|
||||
* to work around the lack of C++ templates in OpenCL.
|
||||
*
|
||||
* Originally based on "Understanding the Efficiency of Ray Traversal on GPUs",
|
||||
* the code has been extended and modified to support more primitives and work
|
||||
* with CPU and various GPU kernel languages. */
|
||||
|
||||
/* Regular BVH traversal */
|
||||
|
||||
# define BVH_FUNCTION_NAME bvh_intersect
|
||||
# define BVH_FUNCTION_FEATURES BVH_POINTCLOUD
|
||||
# include "kernel/bvh/traversal.h"
|
||||
|
||||
# if defined(__HAIR__)
|
||||
# define BVH_FUNCTION_NAME bvh_intersect_hair
|
||||
# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_POINTCLOUD
|
||||
# include "kernel/bvh/traversal.h"
|
||||
# endif
|
||||
|
||||
# if defined(__OBJECT_MOTION__)
|
||||
# define BVH_FUNCTION_NAME bvh_intersect_motion
|
||||
# define BVH_FUNCTION_FEATURES BVH_MOTION | BVH_POINTCLOUD
|
||||
# include "kernel/bvh/traversal.h"
|
||||
# endif
|
||||
|
||||
# if defined(__HAIR__) && defined(__OBJECT_MOTION__)
|
||||
# define BVH_FUNCTION_NAME bvh_intersect_hair_motion
|
||||
# define BVH_FUNCTION_FEATURES BVH_HAIR | BVH_MOTION | BVH_POINTCLOUD
|
||||
# include "kernel/bvh/traversal.h"
|
||||
# endif
|
||||
|
||||
ccl_device_intersect bool scene_intersect(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
const uint visibility,
|
||||
ccl_private Intersection *isect)
|
||||
{
|
||||
if (!intersection_ray_valid(ray)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
# ifdef __EMBREE__
|
||||
IF_USING_EMBREE
|
||||
{
|
||||
if (kernel_data.device_bvh) {
|
||||
return kernel_embree_intersect(kg, ray, visibility, isect);
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
IF_NOT_USING_EMBREE
|
||||
{
|
||||
# ifdef __OBJECT_MOTION__
|
||||
if (kernel_data.bvh.have_motion) {
|
||||
# ifdef __HAIR__
|
||||
if (kernel_data.bvh.have_curves) {
|
||||
return bvh_intersect_hair_motion(kg, ray, isect, visibility);
|
||||
}
|
||||
# endif /* __HAIR__ */
|
||||
|
||||
return bvh_intersect_motion(kg, ray, isect, visibility);
|
||||
}
|
||||
# endif /* __OBJECT_MOTION__ */
|
||||
|
||||
# ifdef __HAIR__
|
||||
if (kernel_data.bvh.have_curves) {
|
||||
return bvh_intersect_hair(kg, ray, isect, visibility);
|
||||
}
|
||||
# endif /* __HAIR__ */
|
||||
|
||||
return bvh_intersect(kg, ray, isect, visibility);
|
||||
}
|
||||
|
||||
kernel_assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
ccl_device_intersect bool scene_intersect_shadow(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
const uint visibility)
|
||||
{
|
||||
Intersection isect;
|
||||
return scene_intersect(kg, ray, visibility, &isect);
|
||||
}
|
||||
|
||||
/* Single object BVH traversal, for SSS/AO/bevel. */
|
||||
|
||||
# ifdef __BVH_LOCAL__
|
||||
|
||||
# define BVH_FUNCTION_NAME bvh_intersect_local
|
||||
# define BVH_FUNCTION_FEATURES BVH_HAIR
|
||||
# include "kernel/bvh/local.h"
|
||||
|
||||
# if defined(__OBJECT_MOTION__)
|
||||
# define BVH_FUNCTION_NAME bvh_intersect_local_motion
|
||||
# define BVH_FUNCTION_FEATURES BVH_MOTION | BVH_HAIR
|
||||
# include "kernel/bvh/local.h"
|
||||
# endif
|
||||
|
||||
template<bool single_hit = false>
|
||||
ccl_device_intersect bool scene_intersect_local(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
ccl_private LocalIntersection *local_isect,
|
||||
const int local_object,
|
||||
ccl_private uint *lcg_state,
|
||||
const int max_hits)
|
||||
{
|
||||
if (!intersection_ray_valid(ray)) {
|
||||
if (local_isect) {
|
||||
local_isect->num_hits = 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
# ifdef __EMBREE__
|
||||
IF_USING_EMBREE
|
||||
{
|
||||
if (kernel_data.device_bvh) {
|
||||
return kernel_embree_intersect_local(
|
||||
kg, ray, local_isect, local_object, lcg_state, max_hits);
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
IF_NOT_USING_EMBREE
|
||||
{
|
||||
# ifdef __OBJECT_MOTION__
|
||||
if (kernel_data.bvh.have_motion) {
|
||||
return bvh_intersect_local_motion(kg, ray, local_isect, local_object, lcg_state, max_hits);
|
||||
}
|
||||
# endif /* __OBJECT_MOTION__ */
|
||||
return bvh_intersect_local(kg, ray, local_isect, local_object, lcg_state, max_hits);
|
||||
}
|
||||
|
||||
kernel_assert(false);
|
||||
return false;
|
||||
}
|
||||
# endif
|
||||
|
||||
/* Volume BVH traversal, for initializing or updating the volume stack. */
|
||||
|
||||
# if defined(__VOLUME__) && !defined(__VOLUME_RECORD_ALL__)
|
||||
|
||||
# define BVH_FUNCTION_NAME bvh_intersect_volume
|
||||
# define BVH_FUNCTION_FEATURES BVH_HAIR
|
||||
# include "kernel/bvh/volume.h"
|
||||
|
||||
# if defined(__OBJECT_MOTION__)
|
||||
# define BVH_FUNCTION_NAME bvh_intersect_volume_motion
|
||||
# define BVH_FUNCTION_FEATURES BVH_MOTION | BVH_HAIR
|
||||
# include "kernel/bvh/volume.h"
|
||||
# endif
|
||||
|
||||
ccl_device_intersect bool scene_intersect_volume(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
ccl_private Intersection *isect,
|
||||
const uint visibility)
|
||||
{
|
||||
if (!intersection_ray_valid(ray)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
# ifdef __EMBREE__
|
||||
IF_USING_EMBREE
|
||||
{
|
||||
if (kernel_data.device_bvh) {
|
||||
return kernel_embree_intersect_volume(kg, ray, isect, visibility);
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
IF_NOT_USING_EMBREE
|
||||
{
|
||||
# ifdef __OBJECT_MOTION__
|
||||
if (kernel_data.bvh.have_motion) {
|
||||
return bvh_intersect_volume_motion(kg, ray, isect, visibility);
|
||||
}
|
||||
# endif /* __OBJECT_MOTION__ */
|
||||
|
||||
return bvh_intersect_volume(kg, ray, isect, visibility);
|
||||
}
|
||||
|
||||
kernel_assert(false);
|
||||
return false;
|
||||
}
|
||||
# endif /* defined(__VOLUME__) && !defined(__VOLUME_RECORD_ALL__) */
|
||||
|
||||
/* Volume BVH traversal, for initializing or updating the volume stack.
|
||||
* Variation that records multiple intersections at once. */
|
||||
|
||||
# if defined(__VOLUME__) && defined(__VOLUME_RECORD_ALL__)
|
||||
|
||||
# define BVH_FUNCTION_NAME bvh_intersect_volume_all
|
||||
# define BVH_FUNCTION_FEATURES BVH_HAIR
|
||||
# include "kernel/bvh/volume_all.h"
|
||||
|
||||
# if defined(__OBJECT_MOTION__)
|
||||
# define BVH_FUNCTION_NAME bvh_intersect_volume_all_motion
|
||||
# define BVH_FUNCTION_FEATURES BVH_MOTION | BVH_HAIR
|
||||
# include "kernel/bvh/volume_all.h"
|
||||
# endif
|
||||
|
||||
ccl_device_intersect uint scene_intersect_volume(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
ccl_private Intersection *isect,
|
||||
const uint max_hits,
|
||||
const uint visibility)
|
||||
{
|
||||
if (!intersection_ray_valid(ray)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
# ifdef __EMBREE__
|
||||
IF_USING_EMBREE
|
||||
{
|
||||
if (kernel_data.device_bvh) {
|
||||
return kernel_embree_intersect_volume(kg, ray, isect, max_hits, visibility);
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
IF_NOT_USING_EMBREE
|
||||
{
|
||||
# ifdef __OBJECT_MOTION__
|
||||
if (kernel_data.bvh.have_motion) {
|
||||
return bvh_intersect_volume_all_motion(kg, ray, isect, max_hits, visibility);
|
||||
}
|
||||
# endif /* __OBJECT_MOTION__ */
|
||||
|
||||
return bvh_intersect_volume_all(kg, ray, isect, max_hits, visibility);
|
||||
}
|
||||
|
||||
kernel_assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
# endif /* defined(__VOLUME__) && defined(__VOLUME_RECORD_ALL__) */
|
||||
|
||||
# undef BVH_FEATURE
|
||||
# undef BVH_NAME_JOIN
|
||||
# undef BVH_NAME_EVAL
|
||||
# undef BVH_FUNCTION_FULL_NAME
|
||||
|
||||
#endif /* __BVH2__ */
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
311
blender-5.2.0/intern/cycles/kernel/bvh/intersect_filter.h
Normal file
311
blender-5.2.0/intern/cycles/kernel/bvh/intersect_filter.h
Normal file
@@ -0,0 +1,311 @@
|
||||
/* SPDX-FileCopyrightText: 2026 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/* Intersection and filtering functions for hardware ray-trace style of API.
|
||||
*
|
||||
* Filter functions are invoked for an intersection to give BVH traversal hints whether
|
||||
* traversal is to continue. Returning true from filter functions means the intersection is
|
||||
* filtered (ignored) and the traversal is to continue.
|
||||
*
|
||||
* Note on the template parameters
|
||||
* ===============================
|
||||
*
|
||||
* perform_intersection_tests controls whether checks that are typically are performed during
|
||||
* intersection are to be done in the filter function. Intersection checks that are done by the
|
||||
* hardware do not perform self-intersection and shadow-linking checks: they are done in the
|
||||
* filter function instead. However, if the intersection check uses custom function it performs
|
||||
* these checks early on, so skipping them in the filter function will lead to a better
|
||||
* performance. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/bvh/util.h"
|
||||
#include "kernel/globals.h"
|
||||
#include "kernel/integrator/state.h"
|
||||
#include "kernel/integrator/state_util.h"
|
||||
#include "kernel/types.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
enum IntersectionTest : uint {
|
||||
ISECT_TEST_NONE = 0,
|
||||
|
||||
ISECT_TEST_VISIBILITY_FLAG = (1 << 0),
|
||||
ISECT_TEST_SHADOW_LINKING = (1 << 1),
|
||||
ISECT_TEST_SELF_SHADOW = (1 << 2),
|
||||
|
||||
ISECT_TEST_ALL = (ISECT_TEST_VISIBILITY_FLAG | ISECT_TEST_SHADOW_LINKING |
|
||||
ISECT_TEST_SELF_SHADOW),
|
||||
};
|
||||
|
||||
/* Special tricks to subclass payload.
|
||||
* The issue here is Metal does not support subclassing, but HIP-RT had performance issues with
|
||||
* composition in the past (see !136823). */
|
||||
#if defined(__KERNEL_HIPRT__)
|
||||
# define BVH_PAYLOAD_SUBCLASS(cls, base_cls) struct cls : base_cls
|
||||
# define BVH_PAYLOAD_SUBCLASS_DEFINE(base_cls)
|
||||
# define BVH_PAYLOAD_BASE(obj) (obj)
|
||||
#else
|
||||
# define BVH_PAYLOAD_SUBCLASS(cls, base_cls) struct cls
|
||||
# define BVH_PAYLOAD_SUBCLASS_DEFINE(base_cls) base_cls base;
|
||||
# define BVH_PAYLOAD_BASE(obj) ((obj).base)
|
||||
#endif
|
||||
|
||||
struct BVHPayload {
|
||||
/* In OptiX, self-intersection information and ray visibility are passed via Ray's pointer as
|
||||
* extra payload data. */
|
||||
#if !defined(__KERNEL_OPTIX__)
|
||||
/* Primitives for the self-intersections. */
|
||||
RaySelfPrimitives ray_self;
|
||||
|
||||
/* Ray visibility flags and time. */
|
||||
uint ray_visibility;
|
||||
#endif
|
||||
|
||||
#if defined(__KERNEL_HIPRT__)
|
||||
float ray_time;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* OptiX passes various parameters via registers to the tracing calls. No need to store duplicate
|
||||
* data for OptiX. This will essentially make it so BVHPayload contains data which is strictly
|
||||
* needed for intersection recording and for tracking curve transparency. */
|
||||
#if defined(__KERNEL_OPTIX__)
|
||||
# define BVH_SHADOW_ALL_PAYLOAD_SUBCLASS(cls, base_cls) struct cls
|
||||
# define BVH_SHADOW_ALL_PAYLOAD_SUBCLASS_DEFINE(base_cls)
|
||||
#else
|
||||
# define BVH_SHADOW_ALL_PAYLOAD_SUBCLASS(cls, base_cls) BVH_PAYLOAD_SUBCLASS(cls, base_cls)
|
||||
# define BVH_SHADOW_ALL_PAYLOAD_SUBCLASS_DEFINE(base_cls) BVH_PAYLOAD_SUBCLASS_DEFINE(base_cls)
|
||||
#endif
|
||||
|
||||
BVH_SHADOW_ALL_PAYLOAD_SUBCLASS(BVHShadowAllPayload, BVHPayload)
|
||||
{
|
||||
BVH_SHADOW_ALL_PAYLOAD_SUBCLASS_DEFINE(BVHPayload);
|
||||
|
||||
/* Using uint16_t is slower on HIP, while it is similar performance but potentially lower memory
|
||||
* footprint on other backends. */
|
||||
#if defined(__KERNEL_HIPRT__)
|
||||
using UIntType = uint;
|
||||
#else
|
||||
using UIntType = uint16_t;
|
||||
#endif
|
||||
|
||||
IntegratorShadowState state;
|
||||
|
||||
/* The maximum number of transparent intersections to consider: if there are more intersections
|
||||
* than this value, all light is considered blocked. */
|
||||
UIntType max_transparent_hits;
|
||||
/* The number of transparent intersections tested during BVH traversal. It might be higher than
|
||||
* the number of recorded intersections. */
|
||||
UIntType num_transparent_hits = 0;
|
||||
|
||||
/* Maximum intersection distance t for intersections that are to be recorded.
|
||||
* If intersection's distance exceeds this value, it is not recoded. */
|
||||
float max_record_isect_t;
|
||||
|
||||
/* An index within the shadow_isect array at which the next intersection will be recorded. */
|
||||
UIntType record_isect_index = 0;
|
||||
|
||||
/* The number of intersections that has been attempted to be recorded.
|
||||
* It might be higher than the shadow_isect size, indicating that more invocations of the
|
||||
* intersection kernel are needed. It is different from the num_transparent_hits as it does not
|
||||
* include transparent curve intersections that are handled by accumulating throughput in the
|
||||
* filter function. */
|
||||
UIntType num_recorded_hits = 0;
|
||||
|
||||
/* Accumulated throughput of transparent curve intersections.
|
||||
* Curves are using special optimization by baking their transparency and handling it in the
|
||||
* filter function. */
|
||||
float throughput = 1.0f;
|
||||
};
|
||||
|
||||
/* Filter intersection with possibly transparent surface.
|
||||
*
|
||||
* Designed to be used from the any-hit type of traversal:
|
||||
* - If an opaque surface is hit, returns false, stopping traversal. The scene intersection
|
||||
* function will consider the shadow ray to be blocked.
|
||||
* - If a transparent surface is hit, the intersection is recorded into the shadow_isect array in
|
||||
* the state. The closest N intersections are recorded. */
|
||||
template<uint perform_intersection_tests, uint enabled_primitive_types = PRIMITIVE_ALL>
|
||||
ccl_device_forceinline bool bvh_shadow_all_anyhit_filter(
|
||||
KernelGlobals kg,
|
||||
IntegratorShadowState state,
|
||||
ccl_ray_data BVHShadowAllPayload &ccl_restrict payload,
|
||||
const ccl_ray_data RaySelfPrimitives &ccl_restrict ray_self,
|
||||
const uint ray_visibility,
|
||||
const Intersection isect)
|
||||
|
||||
{
|
||||
#if defined(__VISIBILITY_FLAG__)
|
||||
if constexpr ((perform_intersection_tests & ISECT_TEST_VISIBILITY_FLAG) != 0) {
|
||||
if ((kernel_data_fetch(objects, isect.object).visibility & ray_visibility) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__SHADOW_LINKING__)
|
||||
if constexpr ((perform_intersection_tests & ISECT_TEST_SHADOW_LINKING) != 0) {
|
||||
if (intersection_skip_shadow_link(kg, ray_self, isect.object)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if constexpr ((perform_intersection_tests & ISECT_TEST_SELF_SHADOW) != 0) {
|
||||
if (intersection_skip_self_shadow(ray_self, isect.object, isect.prim)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(__TRANSPARENT_SHADOWS__)
|
||||
/* No transparent shadows in the scene, all light is blocked and we can stop immediately. */
|
||||
payload.throughput = 0.0f;
|
||||
return false;
|
||||
#else
|
||||
/* Detect if this surface has a shader with transparent shadows. */
|
||||
/* TODO: optimize so primitive visibility flag indicates if the primitive has a transparent
|
||||
* shadow shader? */
|
||||
const int shader_flags = intersection_get_shader_flags(kg, isect.prim, isect.type);
|
||||
if ((shader_flags & SD_HAS_TRANSPARENT_SHADOW) == 0) {
|
||||
/* No transparent shadows for the shader, all light is blocked, and we can stop immediately. */
|
||||
payload.throughput = 0.0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Fetch commonly accessed payload data, ensuring that it is used from either register to a
|
||||
* stack, without going to the global memory. */
|
||||
uint num_recorded_hits = payload.num_recorded_hits;
|
||||
|
||||
/* If the intersection is already recorded, ignore it completely: don't update throughput as it
|
||||
* has already been updated. But also don't count it for num_hits as that could result in a
|
||||
* situation when the same ray will be considered transparent when spatial split is off and be
|
||||
* opaque when spatial split is on. Since curves do not record intersections, there is
|
||||
* a possibility for optimization:
|
||||
* - Don't compile this code if the filter is only used for curve primitives.
|
||||
* - Don't run the check if the current intersection comes from the curve, as it will not match
|
||||
* any recorded intersection anyway.
|
||||
*
|
||||
* NOTE: Currently, spatial splits are not used with OptiX, so there is no need to check whether
|
||||
* the intersection has been already recorded. */
|
||||
# if !defined(__KERNEL_OPTIX__)
|
||||
if constexpr ((enabled_primitive_types & (PRIMITIVE_ALL & ~PRIMITIVE_CURVE)) != 0) {
|
||||
if ((isect.type & PRIMITIVE_CURVE) == 0) {
|
||||
if (intersection_skip_shadow_already_recoded(
|
||||
state, isect.object, isect.prim, num_recorded_hits))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
/* Only count transparent bounces, volume bounds bounces are counted when shading. */
|
||||
payload.num_transparent_hits += !(shader_flags & SD_HAS_ONLY_VOLUME);
|
||||
if (payload.num_transparent_hits > payload.max_transparent_hits) {
|
||||
/* The maximum number of intersections has been reached, consider that all light has been
|
||||
* blocked. */
|
||||
payload.throughput = 0.0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
# if defined(__HAIR__)
|
||||
if constexpr ((enabled_primitive_types & PRIMITIVE_CURVE) != 0) {
|
||||
/* Always use baked shadow transparency for curves. */
|
||||
if (isect.type & PRIMITIVE_CURVE) {
|
||||
payload.throughput *= intersection_curve_shadow_transparency(
|
||||
kg, isect.object, isect.prim, isect.type, isect.u);
|
||||
|
||||
if (payload.throughput < CURVE_SHADOW_TRANSPARENCY_CUTOFF) {
|
||||
/* Light attenuated too much through the curve intersections, assume all light is blocked
|
||||
* and do early output. */
|
||||
payload.throughput = 0.0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Don't record the intersection as the throughput has been already modified here.
|
||||
* Simply continue BVH traversal for other intersections. */
|
||||
return true;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
/* If the filter function only handles curves, it is known for the fact that nothing is to be
|
||||
* recorded: curves accumulated baked transparency. Skip this code for a curve-only case. */
|
||||
if constexpr ((enabled_primitive_types & (PRIMITIVE_ALL & ~PRIMITIVE_CURVE)) != 0) {
|
||||
/* Always increase the number of recorded hits, even beyond the maximum, so that we can detect
|
||||
* this and trace another ray if needed. */
|
||||
num_recorded_hits += 1;
|
||||
payload.num_recorded_hits = num_recorded_hits;
|
||||
|
||||
constexpr uint max_record_hits = INTEGRATOR_SHADOW_ISECT_SIZE;
|
||||
if (num_recorded_hits <= max_record_hits || isect.t < payload.max_record_isect_t) {
|
||||
integrator_state_write_shadow_isect(state, &isect, payload.record_isect_index);
|
||||
|
||||
if (num_recorded_hits >= max_record_hits) {
|
||||
/* If the maximum number of hits is reached, find the furthest intersection to replace it
|
||||
* with the next closer one. We want the N closest intersections. */
|
||||
uint record_isect_index = 0;
|
||||
float tmax_hits = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 0, t);
|
||||
for (uint i = 1; i < max_record_hits; ++i) {
|
||||
const float isect_t = INTEGRATOR_STATE_ARRAY(state, shadow_isect, i, t);
|
||||
if (isect_t > tmax_hits) {
|
||||
record_isect_index = i;
|
||||
tmax_hits = isect_t;
|
||||
}
|
||||
}
|
||||
payload.max_record_isect_t = tmax_hits;
|
||||
payload.record_isect_index = record_isect_index;
|
||||
}
|
||||
else {
|
||||
payload.record_isect_index = num_recorded_hits;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Filter intersection to intersections with only primitives with volume shader.
|
||||
*
|
||||
* Expected to be called only on a triangle primitive. The caller is to filter out intersections
|
||||
* with non-triangle primitives.
|
||||
*
|
||||
* Returns false if the primitive is not to be filtered out (accepted), true if the primitive is to
|
||||
* be ignored. */
|
||||
template<bool do_visibility_check = true>
|
||||
ccl_device_forceinline bool bvh_volume_anyhit_triangle_filter(
|
||||
KernelGlobals kg,
|
||||
const int object,
|
||||
const int prim,
|
||||
const ccl_ray_data RaySelfPrimitives &ccl_restrict ray_self,
|
||||
const uint ray_visibility)
|
||||
{
|
||||
#ifdef __VISIBILITY_FLAG__
|
||||
if constexpr (do_visibility_check) {
|
||||
if ((kernel_data_fetch(objects, object).visibility & ray_visibility) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((kernel_data_fetch(object_flag, object) & SD_OBJECT_HAS_VOLUME) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (intersection_skip_self(ray_self, object, prim)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const int shader = kernel_data_fetch(tri_shader, prim);
|
||||
const int shader_flag = kernel_data_fetch(shaders, (shader & SHADER_MASK)).flags;
|
||||
if (!(shader_flag & SD_HAS_VOLUME)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
235
blender-5.2.0/intern/cycles/kernel/bvh/local.h
Normal file
235
blender-5.2.0/intern/cycles/kernel/bvh/local.h
Normal file
@@ -0,0 +1,235 @@
|
||||
/* SPDX-FileCopyrightText: 2009-2010 NVIDIA Corporation
|
||||
* SPDX-FileCopyrightText: 2009-2012 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Adapted from code by Intel & NVIDIA. */
|
||||
|
||||
#if BVH_FEATURE(BVH_HAIR)
|
||||
# define NODE_INTERSECT bvh_node_intersect
|
||||
#else
|
||||
# define NODE_INTERSECT bvh_aligned_node_intersect
|
||||
#endif
|
||||
|
||||
/* This is a template BVH traversal function for finding local intersections
|
||||
* around the shading point, for subsurface scattering and bevel. We disable
|
||||
* various features for performance, and for instanced objects avoid traversing
|
||||
* other parts of the scene.
|
||||
*
|
||||
* BVH_MOTION: motion blur rendering
|
||||
*/
|
||||
|
||||
#ifndef __KERNEL_GPU__
|
||||
ccl_device
|
||||
#else
|
||||
ccl_device_inline
|
||||
#endif
|
||||
bool
|
||||
BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
ccl_private LocalIntersection *local_isect,
|
||||
const int local_object,
|
||||
ccl_private uint *lcg_state,
|
||||
const int max_hits)
|
||||
{
|
||||
/* todo:
|
||||
* - test if pushing distance on the stack helps (for non shadow rays)
|
||||
* - separate version for shadow rays
|
||||
* - likely and unlikely for if() statements
|
||||
* - test restrict attribute for pointers
|
||||
*/
|
||||
|
||||
/* traversal stack in CUDA thread-local memory */
|
||||
int traversal_stack[BVH_STACK_SIZE];
|
||||
traversal_stack[0] = ENTRYPOINT_SENTINEL;
|
||||
|
||||
/* traversal variables in registers */
|
||||
int stack_ptr = 0;
|
||||
int node_addr = kernel_data_fetch(object_node, local_object);
|
||||
|
||||
/* ray parameters in registers */
|
||||
float3 P = ray->P;
|
||||
float3 dir = bvh_clamp_direction(ray->D);
|
||||
float3 idir = bvh_inverse_direction(dir);
|
||||
float tmin = ray->tmin;
|
||||
int object = OBJECT_NONE;
|
||||
float isect_t = ray->tmax;
|
||||
|
||||
if (local_isect != nullptr) {
|
||||
local_isect->num_hits = 0;
|
||||
}
|
||||
kernel_assert((local_isect == nullptr) == (max_hits == 0));
|
||||
|
||||
const uint object_flag = kernel_data_fetch(object_flag, local_object);
|
||||
if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
#if BVH_FEATURE(BVH_MOTION)
|
||||
bvh_instance_motion_push(kg, local_object, ray, &P, &dir, &idir);
|
||||
#else
|
||||
bvh_instance_push(kg, local_object, ray, &P, &dir, &idir);
|
||||
#endif
|
||||
object = local_object;
|
||||
}
|
||||
|
||||
/* traversal loop */
|
||||
do {
|
||||
do {
|
||||
/* traverse internal nodes */
|
||||
while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
|
||||
int node_addr_child1, traverse_mask;
|
||||
float dist[2];
|
||||
float4 cnodes = kernel_data_fetch(bvh_nodes, node_addr + 0);
|
||||
|
||||
traverse_mask = NODE_INTERSECT(kg,
|
||||
P,
|
||||
#if BVH_FEATURE(BVH_HAIR)
|
||||
dir,
|
||||
#endif
|
||||
idir,
|
||||
tmin,
|
||||
isect_t,
|
||||
node_addr,
|
||||
PATH_RAY_VISIBILITY_ALL,
|
||||
dist);
|
||||
|
||||
node_addr = __float_as_int(cnodes.z);
|
||||
node_addr_child1 = __float_as_int(cnodes.w);
|
||||
|
||||
if (traverse_mask == 3) {
|
||||
/* Both children were intersected, push the farther one. */
|
||||
bool is_closest_child1 = (dist[1] < dist[0]);
|
||||
if (is_closest_child1) {
|
||||
int tmp = node_addr;
|
||||
node_addr = node_addr_child1;
|
||||
node_addr_child1 = tmp;
|
||||
}
|
||||
|
||||
++stack_ptr;
|
||||
kernel_assert(stack_ptr < BVH_STACK_SIZE);
|
||||
traversal_stack[stack_ptr] = node_addr_child1;
|
||||
}
|
||||
else {
|
||||
/* One child was intersected. */
|
||||
if (traverse_mask == 2) {
|
||||
node_addr = node_addr_child1;
|
||||
}
|
||||
else if (traverse_mask == 0) {
|
||||
/* Neither child was intersected. */
|
||||
node_addr = traversal_stack[stack_ptr];
|
||||
--stack_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if node is leaf, fetch triangle list */
|
||||
if (node_addr < 0) {
|
||||
float4 leaf = kernel_data_fetch(bvh_leaf_nodes, (-node_addr - 1));
|
||||
int prim_addr = __float_as_int(leaf.x);
|
||||
|
||||
const int prim_addr2 = __float_as_int(leaf.y);
|
||||
const uint type = __float_as_int(leaf.w);
|
||||
|
||||
/* pop */
|
||||
node_addr = traversal_stack[stack_ptr];
|
||||
--stack_ptr;
|
||||
|
||||
/* primitive intersection */
|
||||
switch (type & PRIMITIVE_ALL) {
|
||||
case PRIMITIVE_TRIANGLE: {
|
||||
/* intersect ray against primitive */
|
||||
for (; prim_addr < prim_addr2; prim_addr++) {
|
||||
kernel_assert((kernel_data_fetch(prim_type, prim_addr) & PRIMITIVE_ALL) ==
|
||||
(type & PRIMITIVE_ALL));
|
||||
|
||||
/* Only intersect with matching object, for instanced objects we
|
||||
* already know we are only intersecting the right object. */
|
||||
if (object == OBJECT_NONE) {
|
||||
if (kernel_data_fetch(prim_object, prim_addr) != local_object) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Skip self intersection. */
|
||||
const int prim = kernel_data_fetch(prim_index, prim_addr);
|
||||
if (intersection_skip_self_local(ray->self, prim)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (triangle_intersect_local(kg,
|
||||
local_isect,
|
||||
P,
|
||||
dir,
|
||||
local_object,
|
||||
prim,
|
||||
tmin,
|
||||
isect_t,
|
||||
lcg_state,
|
||||
max_hits))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
#if BVH_FEATURE(BVH_MOTION)
|
||||
case PRIMITIVE_MOTION_TRIANGLE: {
|
||||
/* intersect ray against primitive */
|
||||
for (; prim_addr < prim_addr2; prim_addr++) {
|
||||
kernel_assert((kernel_data_fetch(prim_type, prim_addr) & PRIMITIVE_ALL) ==
|
||||
(type & PRIMITIVE_ALL));
|
||||
|
||||
/* Only intersect with matching object, for instanced objects we
|
||||
* already know we are only intersecting the right object. */
|
||||
if (object == OBJECT_NONE) {
|
||||
if (kernel_data_fetch(prim_object, prim_addr) != local_object) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Skip self intersection. */
|
||||
const int prim = kernel_data_fetch(prim_index, prim_addr);
|
||||
if (intersection_skip_self_local(ray->self, prim)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (motion_triangle_intersect_local(kg,
|
||||
local_isect,
|
||||
P,
|
||||
dir,
|
||||
ray->time,
|
||||
local_object,
|
||||
prim,
|
||||
tmin,
|
||||
isect_t,
|
||||
lcg_state,
|
||||
max_hits))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (node_addr != ENTRYPOINT_SENTINEL);
|
||||
} while (node_addr != ENTRYPOINT_SENTINEL);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
ccl_private LocalIntersection *local_isect,
|
||||
const int local_object,
|
||||
ccl_private uint *lcg_state,
|
||||
const int max_hits)
|
||||
{
|
||||
return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, local_isect, local_object, lcg_state, max_hits);
|
||||
}
|
||||
|
||||
#undef BVH_FUNCTION_NAME
|
||||
#undef BVH_FUNCTION_FEATURES
|
||||
#undef NODE_INTERSECT
|
||||
149
blender-5.2.0/intern/cycles/kernel/bvh/nodes.h
Normal file
149
blender-5.2.0/intern/cycles/kernel/bvh/nodes.h
Normal file
@@ -0,0 +1,149 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "kernel/geom/object.h"
|
||||
#include "kernel/globals.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
// TODO(sergey): Look into avoid use of full Transform and use 3x3 matrix and
|
||||
// 3-vector which might be faster.
|
||||
ccl_device_forceinline Transform bvh_unaligned_node_fetch_space(KernelGlobals kg,
|
||||
const int node_addr,
|
||||
const int child)
|
||||
{
|
||||
Transform space;
|
||||
const int child_addr = node_addr + child * 3;
|
||||
space.x = kernel_data_fetch(bvh_nodes, child_addr + 1);
|
||||
space.y = kernel_data_fetch(bvh_nodes, child_addr + 2);
|
||||
space.z = kernel_data_fetch(bvh_nodes, child_addr + 3);
|
||||
return space;
|
||||
}
|
||||
|
||||
ccl_device_forceinline int bvh_aligned_node_intersect(KernelGlobals kg,
|
||||
const float3 P,
|
||||
const float3 idir,
|
||||
const float tmin,
|
||||
const float tmax,
|
||||
const int node_addr,
|
||||
const uint visibility,
|
||||
float dist[2])
|
||||
{
|
||||
|
||||
/* fetch node data */
|
||||
#ifdef __VISIBILITY_FLAG__
|
||||
float4 cnodes = kernel_data_fetch(bvh_nodes, node_addr + 0);
|
||||
#endif
|
||||
float4 node0 = kernel_data_fetch(bvh_nodes, node_addr + 1);
|
||||
float4 node1 = kernel_data_fetch(bvh_nodes, node_addr + 2);
|
||||
float4 node2 = kernel_data_fetch(bvh_nodes, node_addr + 3);
|
||||
|
||||
/* intersect ray against child nodes */
|
||||
float c0lox = (node0.x - P.x) * idir.x;
|
||||
float c0hix = (node0.z - P.x) * idir.x;
|
||||
float c0loy = (node1.x - P.y) * idir.y;
|
||||
float c0hiy = (node1.z - P.y) * idir.y;
|
||||
float c0loz = (node2.x - P.z) * idir.z;
|
||||
float c0hiz = (node2.z - P.z) * idir.z;
|
||||
float c0min = max4(tmin, min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz));
|
||||
float c0max = min4(tmax, max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz));
|
||||
|
||||
float c1lox = (node0.y - P.x) * idir.x;
|
||||
float c1hix = (node0.w - P.x) * idir.x;
|
||||
float c1loy = (node1.y - P.y) * idir.y;
|
||||
float c1hiy = (node1.w - P.y) * idir.y;
|
||||
float c1loz = (node2.y - P.z) * idir.z;
|
||||
float c1hiz = (node2.w - P.z) * idir.z;
|
||||
float c1min = max4(tmin, min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz));
|
||||
float c1max = min4(tmax, max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz));
|
||||
|
||||
dist[0] = c0min;
|
||||
dist[1] = c1min;
|
||||
|
||||
#ifdef __VISIBILITY_FLAG__
|
||||
/* this visibility test gives a 5% performance hit, how to solve? */
|
||||
return (((c0max >= c0min) && (__float_as_uint(cnodes.x) & visibility)) ? 1 : 0) |
|
||||
(((c1max >= c1min) && (__float_as_uint(cnodes.y) & visibility)) ? 2 : 0);
|
||||
#else
|
||||
return ((c0max >= c0min) ? 1 : 0) | ((c1max >= c1min) ? 2 : 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
ccl_device_forceinline bool bvh_unaligned_node_intersect_child(KernelGlobals kg,
|
||||
const float3 P,
|
||||
const float3 dir,
|
||||
const float tmin,
|
||||
const float tmax,
|
||||
const int node_addr,
|
||||
const int child,
|
||||
float dist[2])
|
||||
{
|
||||
Transform space = bvh_unaligned_node_fetch_space(kg, node_addr, child);
|
||||
float3 aligned_dir = transform_direction(&space, dir);
|
||||
float3 aligned_P = transform_point(&space, P);
|
||||
float3 nrdir = -bvh_inverse_direction(aligned_dir);
|
||||
float3 lower_xyz = aligned_P * nrdir;
|
||||
float3 upper_xyz = lower_xyz - nrdir;
|
||||
const float near_x = min(lower_xyz.x, upper_xyz.x);
|
||||
const float near_y = min(lower_xyz.y, upper_xyz.y);
|
||||
const float near_z = min(lower_xyz.z, upper_xyz.z);
|
||||
const float far_x = max(lower_xyz.x, upper_xyz.x);
|
||||
const float far_y = max(lower_xyz.y, upper_xyz.y);
|
||||
const float far_z = max(lower_xyz.z, upper_xyz.z);
|
||||
const float tnear = max4(tmin, near_x, near_y, near_z);
|
||||
const float tfar = min4(tmax, far_x, far_y, far_z);
|
||||
*dist = tnear;
|
||||
return tnear <= tfar;
|
||||
}
|
||||
|
||||
ccl_device_forceinline int bvh_unaligned_node_intersect(KernelGlobals kg,
|
||||
const float3 P,
|
||||
const float3 dir,
|
||||
const float tmin,
|
||||
const float tmax,
|
||||
const int node_addr,
|
||||
const uint visibility,
|
||||
float dist[2])
|
||||
{
|
||||
int mask = 0;
|
||||
#ifdef __VISIBILITY_FLAG__
|
||||
float4 cnodes = kernel_data_fetch(bvh_nodes, node_addr + 0);
|
||||
#endif
|
||||
if (bvh_unaligned_node_intersect_child(kg, P, dir, tmin, tmax, node_addr, 0, &dist[0])) {
|
||||
#ifdef __VISIBILITY_FLAG__
|
||||
if ((__float_as_uint(cnodes.x) & visibility))
|
||||
#endif
|
||||
{
|
||||
mask |= 1;
|
||||
}
|
||||
}
|
||||
if (bvh_unaligned_node_intersect_child(kg, P, dir, tmin, tmax, node_addr, 1, &dist[1])) {
|
||||
#ifdef __VISIBILITY_FLAG__
|
||||
if ((__float_as_uint(cnodes.y) & visibility))
|
||||
#endif
|
||||
{
|
||||
mask |= 2;
|
||||
}
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
ccl_device_forceinline int bvh_node_intersect(KernelGlobals kg,
|
||||
const float3 P,
|
||||
const float3 dir,
|
||||
const float3 idir,
|
||||
const float tmin,
|
||||
const float tmax,
|
||||
const int node_addr,
|
||||
const uint visibility,
|
||||
float dist[2])
|
||||
{
|
||||
float4 node = kernel_data_fetch(bvh_nodes, node_addr);
|
||||
if (__float_as_uint(node.x) & PATH_RAY_VISIBILITY_NODE_UNALIGNED) {
|
||||
return bvh_unaligned_node_intersect(kg, P, dir, tmin, tmax, node_addr, visibility, dist);
|
||||
}
|
||||
return bvh_aligned_node_intersect(kg, P, idir, tmin, tmax, node_addr, visibility, dist);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
269
blender-5.2.0/intern/cycles/kernel/bvh/shadow_all.h
Normal file
269
blender-5.2.0/intern/cycles/kernel/bvh/shadow_all.h
Normal file
@@ -0,0 +1,269 @@
|
||||
/* SPDX-FileCopyrightText: 2009-2010 NVIDIA Corporation
|
||||
* SPDX-FileCopyrightText: 2009-2012 Intel Corporation
|
||||
* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Adapted code from NVIDIA Corporation. */
|
||||
|
||||
#if BVH_FEATURE(BVH_HAIR)
|
||||
# define NODE_INTERSECT bvh_node_intersect
|
||||
#else
|
||||
# define NODE_INTERSECT bvh_aligned_node_intersect
|
||||
#endif
|
||||
|
||||
/* This is a template BVH traversal function, where various features can be
|
||||
* enabled/disabled. This way we can compile optimized versions for each case
|
||||
* without new features slowing things down.
|
||||
*
|
||||
* BVH_HAIR: hair curve rendering
|
||||
* BVH_POINTCLOUD: point cloud rendering
|
||||
* BVH_MOTION: motion blur rendering
|
||||
*/
|
||||
|
||||
#ifndef __KERNEL_GPU__
|
||||
ccl_device
|
||||
#else
|
||||
ccl_device_inline
|
||||
#endif
|
||||
void
|
||||
BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
|
||||
const ccl_private Ray *ccl_restrict ray,
|
||||
ccl_private BVHShadowAllPayload &ccl_restrict payload)
|
||||
{
|
||||
/* todo:
|
||||
* - likely and unlikely for if() statements
|
||||
* - test restrict attribute for pointers
|
||||
*/
|
||||
|
||||
/* traversal stack in CUDA thread-local memory */
|
||||
int traversal_stack[BVH_STACK_SIZE];
|
||||
traversal_stack[0] = ENTRYPOINT_SENTINEL;
|
||||
|
||||
/* traversal variables in registers */
|
||||
int stack_ptr = 0;
|
||||
int node_addr = kernel_data.bvh.root;
|
||||
|
||||
/* ray parameters in registers */
|
||||
float3 P = ray->P;
|
||||
float3 dir = bvh_clamp_direction(ray->D);
|
||||
float3 idir = bvh_inverse_direction(dir);
|
||||
float tmin = ray->tmin;
|
||||
int object = OBJECT_NONE;
|
||||
|
||||
/* Max distance in world space. May be dynamically reduced when max number of recorded hits is
|
||||
* exceeded and we no longer need to find hits beyond the max distance found. */
|
||||
const float tmax = ray->tmax;
|
||||
|
||||
const uint visibility = payload.base.ray_visibility;
|
||||
|
||||
/* traversal loop */
|
||||
do {
|
||||
do {
|
||||
/* traverse internal nodes */
|
||||
while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
|
||||
int node_addr_child1, traverse_mask;
|
||||
float dist[2];
|
||||
float4 cnodes = kernel_data_fetch(bvh_nodes, node_addr + 0);
|
||||
|
||||
traverse_mask = NODE_INTERSECT(kg,
|
||||
P,
|
||||
#if BVH_FEATURE(BVH_HAIR)
|
||||
dir,
|
||||
#endif
|
||||
idir,
|
||||
tmin,
|
||||
tmax,
|
||||
node_addr,
|
||||
visibility,
|
||||
dist);
|
||||
|
||||
node_addr = __float_as_int(cnodes.z);
|
||||
node_addr_child1 = __float_as_int(cnodes.w);
|
||||
|
||||
if (traverse_mask == 3) {
|
||||
/* Both children were intersected, push the farther one. */
|
||||
bool is_closest_child1 = (dist[1] < dist[0]);
|
||||
if (is_closest_child1) {
|
||||
int tmp = node_addr;
|
||||
node_addr = node_addr_child1;
|
||||
node_addr_child1 = tmp;
|
||||
}
|
||||
|
||||
++stack_ptr;
|
||||
kernel_assert(stack_ptr < BVH_STACK_SIZE);
|
||||
traversal_stack[stack_ptr] = node_addr_child1;
|
||||
}
|
||||
else {
|
||||
/* One child was intersected. */
|
||||
if (traverse_mask == 2) {
|
||||
node_addr = node_addr_child1;
|
||||
}
|
||||
else if (traverse_mask == 0) {
|
||||
/* Neither child was intersected. */
|
||||
node_addr = traversal_stack[stack_ptr];
|
||||
--stack_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if node is leaf, fetch triangle list */
|
||||
if (node_addr < 0) {
|
||||
float4 leaf = kernel_data_fetch(bvh_leaf_nodes, (-node_addr - 1));
|
||||
int prim_addr = __float_as_int(leaf.x);
|
||||
|
||||
if (prim_addr >= 0) {
|
||||
const int prim_addr2 = __float_as_int(leaf.y);
|
||||
const uint type = __float_as_int(leaf.w);
|
||||
|
||||
/* pop */
|
||||
node_addr = traversal_stack[stack_ptr];
|
||||
--stack_ptr;
|
||||
|
||||
/* primitive intersection */
|
||||
for (; prim_addr < prim_addr2; prim_addr++) {
|
||||
kernel_assert((kernel_data_fetch(prim_type, prim_addr) & PRIMITIVE_ALL) ==
|
||||
(type & PRIMITIVE_ALL));
|
||||
bool hit;
|
||||
|
||||
/* todo: specialized intersect functions which don't fill in
|
||||
* isect unless needed and check SD_HAS_TRANSPARENT_SHADOW?
|
||||
* might give a few % performance improvement */
|
||||
Intersection isect ccl_optional_struct_init;
|
||||
|
||||
const int prim_object = (object == OBJECT_NONE) ?
|
||||
kernel_data_fetch(prim_object, prim_addr) :
|
||||
object;
|
||||
const int prim = kernel_data_fetch(prim_index, prim_addr);
|
||||
if (intersection_skip_self_shadow(ray->self, prim_object, prim)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef __SHADOW_LINKING__
|
||||
if (intersection_skip_shadow_link(kg, ray->self, prim_object)) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (type & PRIMITIVE_ALL) {
|
||||
case PRIMITIVE_TRIANGLE: {
|
||||
hit = triangle_intersect(
|
||||
kg, &isect, P, dir, tmin, tmax, visibility, prim_object, prim, prim_addr);
|
||||
break;
|
||||
}
|
||||
#if BVH_FEATURE(BVH_MOTION)
|
||||
case PRIMITIVE_MOTION_TRIANGLE: {
|
||||
hit = motion_triangle_intersect(kg,
|
||||
&isect,
|
||||
P,
|
||||
dir,
|
||||
tmin,
|
||||
tmax,
|
||||
ray->time,
|
||||
visibility,
|
||||
prim_object,
|
||||
prim,
|
||||
prim_addr);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if BVH_FEATURE(BVH_HAIR) && defined(__HAIR__)
|
||||
case PRIMITIVE_CURVE_THICK:
|
||||
case PRIMITIVE_MOTION_CURVE_THICK:
|
||||
case PRIMITIVE_CURVE_RIBBON:
|
||||
case PRIMITIVE_MOTION_CURVE_RIBBON:
|
||||
case PRIMITIVE_CURVE_THICK_LINEAR:
|
||||
case PRIMITIVE_MOTION_CURVE_THICK_LINEAR: {
|
||||
if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
|
||||
const float2 prim_time = kernel_data_fetch(prim_time, prim_addr);
|
||||
if (ray->time < prim_time.x || ray->time > prim_time.y) {
|
||||
hit = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const int curve_type = kernel_data_fetch(prim_type, prim_addr);
|
||||
hit = curve_intersect(
|
||||
kg, &isect, P, dir, tmin, tmax, prim_object, prim, ray->time, curve_type);
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if BVH_FEATURE(BVH_POINTCLOUD) && defined(__POINTCLOUD__)
|
||||
case PRIMITIVE_POINT:
|
||||
case PRIMITIVE_MOTION_POINT: {
|
||||
if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
|
||||
const float2 prim_time = kernel_data_fetch(prim_time, prim_addr);
|
||||
if (ray->time < prim_time.x || ray->time > prim_time.y) {
|
||||
hit = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const int point_type = kernel_data_fetch(prim_type, prim_addr);
|
||||
hit = point_intersect(
|
||||
kg, &isect, P, dir, tmin, tmax, prim_object, prim, ray->time, point_type);
|
||||
break;
|
||||
}
|
||||
#endif /* BVH_FEATURE(BVH_POINTCLOUD) */
|
||||
default: {
|
||||
hit = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hit) {
|
||||
if (!bvh_shadow_all_anyhit_filter<ISECT_TEST_NONE>(kg,
|
||||
payload.state,
|
||||
payload,
|
||||
payload.base.ray_self,
|
||||
payload.base.ray_visibility,
|
||||
isect))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* instance push */
|
||||
object = kernel_data_fetch(prim_object, -prim_addr - 1);
|
||||
|
||||
#if BVH_FEATURE(BVH_MOTION)
|
||||
bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir);
|
||||
#else
|
||||
bvh_instance_push(kg, object, ray, &P, &dir, &idir);
|
||||
#endif
|
||||
|
||||
++stack_ptr;
|
||||
kernel_assert(stack_ptr < BVH_STACK_SIZE);
|
||||
traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
|
||||
|
||||
node_addr = kernel_data_fetch(object_node, object);
|
||||
}
|
||||
}
|
||||
} while (node_addr != ENTRYPOINT_SENTINEL);
|
||||
|
||||
if (stack_ptr >= 0) {
|
||||
kernel_assert(object != OBJECT_NONE);
|
||||
|
||||
/* Instance pop. */
|
||||
bvh_instance_pop(ray, &P, &dir, &idir);
|
||||
|
||||
object = OBJECT_NONE;
|
||||
node_addr = traversal_stack[stack_ptr];
|
||||
--stack_ptr;
|
||||
}
|
||||
} while (node_addr != ENTRYPOINT_SENTINEL);
|
||||
}
|
||||
|
||||
ccl_device_inline void BVH_FUNCTION_NAME(KernelGlobals kg,
|
||||
const ccl_private Ray *ccl_restrict ray,
|
||||
ccl_private BVHShadowAllPayload &ccl_restrict payload)
|
||||
{
|
||||
BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, payload);
|
||||
}
|
||||
|
||||
#undef BVH_FUNCTION_NAME
|
||||
#undef BVH_FUNCTION_FEATURES
|
||||
#undef NODE_INTERSECT
|
||||
273
blender-5.2.0/intern/cycles/kernel/bvh/traversal.h
Normal file
273
blender-5.2.0/intern/cycles/kernel/bvh/traversal.h
Normal file
@@ -0,0 +1,273 @@
|
||||
/* SPDX-FileCopyrightText: 2009-2010 NVIDIA Corporation
|
||||
* SPDX-FileCopyrightText: 2009-2012 Intel Corporation
|
||||
* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Adapted code from NVIDIA Corporation. */
|
||||
|
||||
#if BVH_FEATURE(BVH_HAIR)
|
||||
# define NODE_INTERSECT bvh_node_intersect
|
||||
#else
|
||||
# define NODE_INTERSECT bvh_aligned_node_intersect
|
||||
#endif
|
||||
|
||||
/* This is a template BVH traversal function, where various features can be
|
||||
* enabled/disabled. This way we can compile optimized versions for each case
|
||||
* without new features slowing things down.
|
||||
*
|
||||
* BVH_HAIR: hair curve rendering
|
||||
* BVH_POINTCLOUD: point cloud rendering
|
||||
* BVH_MOTION: motion blur rendering
|
||||
*/
|
||||
|
||||
ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
ccl_private Intersection *isect,
|
||||
const uint visibility)
|
||||
{
|
||||
/* todo:
|
||||
* - test if pushing distance on the stack helps (for non shadow rays)
|
||||
* - separate version for shadow rays
|
||||
* - likely and unlikely for if() statements
|
||||
* - test restrict attribute for pointers
|
||||
*/
|
||||
|
||||
/* traversal stack in CUDA thread-local memory */
|
||||
int traversal_stack[BVH_STACK_SIZE];
|
||||
traversal_stack[0] = ENTRYPOINT_SENTINEL;
|
||||
|
||||
/* traversal variables in registers */
|
||||
int stack_ptr = 0;
|
||||
int node_addr = kernel_data.bvh.root;
|
||||
|
||||
/* ray parameters in registers */
|
||||
float3 P = ray->P;
|
||||
float3 dir = bvh_clamp_direction(ray->D);
|
||||
float3 idir = bvh_inverse_direction(dir);
|
||||
const float tmin = ray->tmin;
|
||||
int object = OBJECT_NONE;
|
||||
|
||||
isect->t = ray->tmax;
|
||||
isect->u = 0.0f;
|
||||
isect->v = 0.0f;
|
||||
isect->prim = PRIM_NONE;
|
||||
isect->object = OBJECT_NONE;
|
||||
|
||||
/* traversal loop */
|
||||
do {
|
||||
do {
|
||||
/* traverse internal nodes */
|
||||
while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
|
||||
int node_addr_child1, traverse_mask;
|
||||
float dist[2];
|
||||
float4 cnodes = kernel_data_fetch(bvh_nodes, node_addr + 0);
|
||||
|
||||
{
|
||||
traverse_mask = NODE_INTERSECT(kg,
|
||||
P,
|
||||
#if BVH_FEATURE(BVH_HAIR)
|
||||
dir,
|
||||
#endif
|
||||
idir,
|
||||
tmin,
|
||||
isect->t,
|
||||
node_addr,
|
||||
visibility,
|
||||
dist);
|
||||
}
|
||||
|
||||
node_addr = __float_as_int(cnodes.z);
|
||||
node_addr_child1 = __float_as_int(cnodes.w);
|
||||
|
||||
if (traverse_mask == 3) {
|
||||
/* Both children were intersected, push the farther one. */
|
||||
bool is_closest_child1 = (dist[1] < dist[0]);
|
||||
if (is_closest_child1) {
|
||||
int tmp = node_addr;
|
||||
node_addr = node_addr_child1;
|
||||
node_addr_child1 = tmp;
|
||||
}
|
||||
|
||||
++stack_ptr;
|
||||
kernel_assert(stack_ptr < BVH_STACK_SIZE);
|
||||
traversal_stack[stack_ptr] = node_addr_child1;
|
||||
}
|
||||
else {
|
||||
/* One child was intersected. */
|
||||
if (traverse_mask == 2) {
|
||||
node_addr = node_addr_child1;
|
||||
}
|
||||
else if (traverse_mask == 0) {
|
||||
/* Neither child was intersected. */
|
||||
node_addr = traversal_stack[stack_ptr];
|
||||
--stack_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if node is leaf, fetch triangle list */
|
||||
if (node_addr < 0) {
|
||||
float4 leaf = kernel_data_fetch(bvh_leaf_nodes, (-node_addr - 1));
|
||||
int prim_addr = __float_as_int(leaf.x);
|
||||
|
||||
if (prim_addr >= 0) {
|
||||
const int prim_addr2 = __float_as_int(leaf.y);
|
||||
const uint type = __float_as_int(leaf.w);
|
||||
|
||||
/* pop */
|
||||
node_addr = traversal_stack[stack_ptr];
|
||||
--stack_ptr;
|
||||
|
||||
/* primitive intersection */
|
||||
for (; prim_addr < prim_addr2; prim_addr++) {
|
||||
|
||||
const int prim_object = (object == OBJECT_NONE) ?
|
||||
kernel_data_fetch(prim_object, prim_addr) :
|
||||
object;
|
||||
const int prim = kernel_data_fetch(prim_index, prim_addr);
|
||||
if (intersection_skip_self_shadow(ray->self, prim_object, prim)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef __SHADOW_LINKING__
|
||||
if (intersection_skip_shadow_link(kg, ray->self, prim_object)) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (type & PRIMITIVE_ALL) {
|
||||
case PRIMITIVE_TRIANGLE: {
|
||||
if (triangle_intersect(kg,
|
||||
isect,
|
||||
P,
|
||||
dir,
|
||||
tmin,
|
||||
isect->t,
|
||||
visibility,
|
||||
prim_object,
|
||||
prim,
|
||||
prim_addr))
|
||||
{
|
||||
/* shadow ray early termination */
|
||||
if (visibility & PATH_RAY_VISIBILITY_SHADOW_OPAQUE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
#if BVH_FEATURE(BVH_MOTION)
|
||||
case PRIMITIVE_MOTION_TRIANGLE: {
|
||||
if (motion_triangle_intersect(kg,
|
||||
isect,
|
||||
P,
|
||||
dir,
|
||||
tmin,
|
||||
isect->t,
|
||||
ray->time,
|
||||
visibility,
|
||||
prim_object,
|
||||
prim,
|
||||
prim_addr))
|
||||
{
|
||||
/* shadow ray early termination */
|
||||
if (visibility & PATH_RAY_VISIBILITY_SHADOW_OPAQUE)
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* BVH_FEATURE(BVH_MOTION) */
|
||||
#if BVH_FEATURE(BVH_HAIR) && defined(__HAIR__)
|
||||
case PRIMITIVE_CURVE_THICK:
|
||||
case PRIMITIVE_MOTION_CURVE_THICK:
|
||||
case PRIMITIVE_CURVE_RIBBON:
|
||||
case PRIMITIVE_MOTION_CURVE_RIBBON:
|
||||
case PRIMITIVE_CURVE_THICK_LINEAR:
|
||||
case PRIMITIVE_MOTION_CURVE_THICK_LINEAR: {
|
||||
if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
|
||||
const float2 prim_time = kernel_data_fetch(prim_time, prim_addr);
|
||||
if (ray->time < prim_time.x || ray->time > prim_time.y) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const int curve_type = kernel_data_fetch(prim_type, prim_addr);
|
||||
const bool hit = curve_intersect(
|
||||
kg, isect, P, dir, tmin, isect->t, prim_object, prim, ray->time, curve_type);
|
||||
if (hit) {
|
||||
/* shadow ray early termination */
|
||||
if (visibility & PATH_RAY_VISIBILITY_SHADOW_OPAQUE)
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* BVH_FEATURE(BVH_HAIR) */
|
||||
#if BVH_FEATURE(BVH_POINTCLOUD) && defined(__POINTCLOUD__)
|
||||
case PRIMITIVE_POINT:
|
||||
case PRIMITIVE_MOTION_POINT: {
|
||||
if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
|
||||
const float2 prim_time = kernel_data_fetch(prim_time, prim_addr);
|
||||
if (ray->time < prim_time.x || ray->time > prim_time.y) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const int point_type = kernel_data_fetch(prim_type, prim_addr);
|
||||
const bool hit = point_intersect(
|
||||
kg, isect, P, dir, tmin, isect->t, prim_object, prim, ray->time, point_type);
|
||||
if (hit) {
|
||||
/* shadow ray early termination */
|
||||
if (visibility & PATH_RAY_VISIBILITY_SHADOW_OPAQUE)
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* BVH_FEATURE(BVH_POINTCLOUD) */
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* instance push */
|
||||
object = kernel_data_fetch(prim_object, -prim_addr - 1);
|
||||
|
||||
#if BVH_FEATURE(BVH_MOTION)
|
||||
bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir);
|
||||
#else
|
||||
bvh_instance_push(kg, object, ray, &P, &dir, &idir);
|
||||
#endif
|
||||
|
||||
++stack_ptr;
|
||||
kernel_assert(stack_ptr < BVH_STACK_SIZE);
|
||||
traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
|
||||
|
||||
node_addr = kernel_data_fetch(object_node, object);
|
||||
}
|
||||
}
|
||||
} while (node_addr != ENTRYPOINT_SENTINEL);
|
||||
|
||||
if (stack_ptr >= 0) {
|
||||
kernel_assert(object != OBJECT_NONE);
|
||||
|
||||
/* instance pop */
|
||||
bvh_instance_pop(ray, &P, &dir, &idir);
|
||||
|
||||
object = OBJECT_NONE;
|
||||
node_addr = traversal_stack[stack_ptr];
|
||||
--stack_ptr;
|
||||
}
|
||||
} while (node_addr != ENTRYPOINT_SENTINEL);
|
||||
|
||||
return (isect->prim != PRIM_NONE);
|
||||
}
|
||||
|
||||
ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
ccl_private Intersection *isect,
|
||||
const uint visibility)
|
||||
{
|
||||
return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, isect, visibility);
|
||||
}
|
||||
|
||||
#undef BVH_FUNCTION_NAME
|
||||
#undef BVH_FUNCTION_FEATURES
|
||||
#undef NODE_INTERSECT
|
||||
33
blender-5.2.0/intern/cycles/kernel/bvh/types.h
Normal file
33
blender-5.2.0/intern/cycles/kernel/bvh/types.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Don't inline intersect functions on GPU, this is faster */
|
||||
#ifdef __KERNEL_GPU__
|
||||
# define ccl_device_intersect ccl_device_forceinline
|
||||
#else
|
||||
# define ccl_device_intersect ccl_device_inline
|
||||
#endif
|
||||
|
||||
/* bottom-most stack entry, indicating the end of traversal */
|
||||
#define ENTRYPOINT_SENTINEL 0x76543210
|
||||
|
||||
/* 64 object BVH + 64 mesh BVH + 64 object node splitting */
|
||||
#define BVH_STACK_SIZE 192
|
||||
/* BVH intersection function variations */
|
||||
|
||||
#define BVH_MOTION 1
|
||||
#define BVH_HAIR 2
|
||||
#define BVH_POINTCLOUD 4
|
||||
|
||||
#define BVH_NAME_JOIN(x, y) x##_##y
|
||||
#define BVH_NAME_EVAL(x, y) BVH_NAME_JOIN(x, y)
|
||||
#define BVH_FUNCTION_FULL_NAME(prefix) BVH_NAME_EVAL(prefix, BVH_FUNCTION_NAME)
|
||||
|
||||
#define BVH_FEATURE(f) (((BVH_FUNCTION_FEATURES) & (f)) != 0)
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
313
blender-5.2.0/intern/cycles/kernel/bvh/util.h
Normal file
313
blender-5.2.0/intern/cycles/kernel/bvh/util.h
Normal file
@@ -0,0 +1,313 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/globals.h"
|
||||
#include "kernel/integrator/state.h"
|
||||
#include "kernel/types.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device_inline bool intersection_ray_valid(const ccl_private Ray *ray)
|
||||
{
|
||||
/* NOTE: Due to some vectorization code non-finite origin point might
|
||||
* cause lots of false-positive intersections which will overflow traversal
|
||||
* stack.
|
||||
* This code is a quick way to perform early output, to avoid crashes in
|
||||
* such cases.
|
||||
* From production scenes so far it seems it's enough to test first element
|
||||
* only.
|
||||
* Scene intersection may also called with empty rays for conditional trace
|
||||
* calls that evaluate to false, so filter those out.
|
||||
*/
|
||||
return isfinite_safe(ray->P.x) && isfinite_safe(ray->D.x) && len_squared(ray->D) != 0.0f &&
|
||||
ray->tmin < FLT_MAX;
|
||||
}
|
||||
|
||||
/* Offset intersection distance by the smallest possible amount, to skip
|
||||
* intersections at this distance. This works in cases where the ray start
|
||||
* position is unchanged and only tmin is updated, since for self
|
||||
* intersection we'll be comparing against the exact same distances.
|
||||
*
|
||||
* Always returns normalized floating point value. */
|
||||
ccl_device_forceinline float intersection_t_offset(const float t)
|
||||
{
|
||||
/* This is a simplified version of `nextafterf(t, FLT_MAX)`, only dealing with
|
||||
* non-negative and finite t. */
|
||||
kernel_assert(t >= 0.0f && isfinite_safe(t));
|
||||
|
||||
/* Special handling of zero, which also includes handling of denormal values:
|
||||
* always return smallest normalized value. If a denormalized zero is returned
|
||||
* it will cause false-positive intersection detection with a distance of 0.
|
||||
*
|
||||
* The check relies on the fact that comparison of denormal values with zero
|
||||
* returns true. */
|
||||
if (t == 0.0f) {
|
||||
/* The exact bit value of this should be 0x1p-126, but hex floating point values notation is
|
||||
* not available in CUDA/OptiX. */
|
||||
return FLT_MIN;
|
||||
}
|
||||
|
||||
const uint32_t bits = __float_as_uint(t) + 1;
|
||||
const float result = __uint_as_float(bits);
|
||||
|
||||
/* Assert that the calculated value is indeed considered to be offset from the
|
||||
* original value. */
|
||||
kernel_assert(result > t);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Ray offset to avoid self intersection.
|
||||
*
|
||||
* This function can be used to compute a modified ray start position for rays
|
||||
* leaving from a surface. This is from:
|
||||
* "A Fast and Robust Method for Avoiding Self-Intersection"
|
||||
* Ray Tracing Gems, chapter 6.
|
||||
*/
|
||||
ccl_device_inline float3 ray_offset(const float3 P, const float3 Ng)
|
||||
{
|
||||
const float int_scale = 256.0f;
|
||||
const int3 of_i = make_int3(
|
||||
(int)(int_scale * Ng.x), (int)(int_scale * Ng.y), (int)(int_scale * Ng.z));
|
||||
|
||||
const float3 p_i = make_float3(
|
||||
__int_as_float(__float_as_int(P.x) + ((P.x < 0) ? -of_i.x : of_i.x)),
|
||||
__int_as_float(__float_as_int(P.y) + ((P.y < 0) ? -of_i.y : of_i.y)),
|
||||
__int_as_float(__float_as_int(P.z) + ((P.z < 0) ? -of_i.z : of_i.z)));
|
||||
const float origin = 1.0f / 32.0f;
|
||||
const float float_scale = 1.0f / 65536.0f;
|
||||
return make_float3(fabsf(P.x) < origin ? P.x + float_scale * Ng.x : p_i.x,
|
||||
fabsf(P.y) < origin ? P.y + float_scale * Ng.y : p_i.y,
|
||||
fabsf(P.z) < origin ? P.z + float_scale * Ng.z : p_i.z);
|
||||
}
|
||||
|
||||
#ifndef __KERNEL_GPU__
|
||||
ccl_device int intersections_compare(const void *a, const void *b)
|
||||
{
|
||||
const Intersection *isect_a = (const Intersection *)a;
|
||||
const Intersection *isect_b = (const Intersection *)b;
|
||||
|
||||
if (isect_a->t < isect_b->t) {
|
||||
return -1;
|
||||
}
|
||||
if (isect_a->t > isect_b->t) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* For subsurface scattering, only sorting a small amount of intersections
|
||||
* so bubble sort is fine for CPU and GPU. */
|
||||
ccl_device_inline void sort_intersections_and_normals(ccl_private Intersection *hits,
|
||||
ccl_private float3 *Ng,
|
||||
uint num_hits)
|
||||
{
|
||||
bool swapped;
|
||||
do {
|
||||
swapped = false;
|
||||
for (uint j = 0; j < num_hits - 1; ++j) {
|
||||
if (hits[j].t > hits[j + 1].t) {
|
||||
Intersection tmp_hit = hits[j];
|
||||
float3 tmp_Ng = Ng[j];
|
||||
hits[j] = hits[j + 1];
|
||||
Ng[j] = Ng[j + 1];
|
||||
hits[j + 1] = tmp_hit;
|
||||
Ng[j + 1] = tmp_Ng;
|
||||
swapped = true;
|
||||
}
|
||||
}
|
||||
--num_hits;
|
||||
} while (swapped);
|
||||
}
|
||||
|
||||
/* Utility to quickly get flags from an intersection. */
|
||||
|
||||
ccl_device_forceinline int intersection_get_shader_flags(KernelGlobals kg,
|
||||
const int prim,
|
||||
const int type)
|
||||
{
|
||||
int shader = 0;
|
||||
|
||||
if (type & PRIMITIVE_TRIANGLE) {
|
||||
shader = kernel_data_fetch(tri_shader, prim);
|
||||
}
|
||||
#ifdef __POINTCLOUD__
|
||||
else if (type & PRIMITIVE_POINT) {
|
||||
shader = kernel_data_fetch(points_shader, prim);
|
||||
}
|
||||
#endif
|
||||
#ifdef __HAIR__
|
||||
else if (type & PRIMITIVE_CURVE) {
|
||||
shader = kernel_data_fetch(curves, prim).shader_id;
|
||||
}
|
||||
#endif
|
||||
|
||||
return kernel_data_fetch(shaders, (shader & SHADER_MASK)).flags;
|
||||
}
|
||||
|
||||
ccl_device_forceinline int intersection_get_shader_from_isect_prim(KernelGlobals kg,
|
||||
const int prim,
|
||||
const int isect_type)
|
||||
{
|
||||
int shader = 0;
|
||||
|
||||
if (isect_type & PRIMITIVE_TRIANGLE) {
|
||||
shader = kernel_data_fetch(tri_shader, prim);
|
||||
}
|
||||
#ifdef __POINTCLOUD__
|
||||
else if (isect_type & PRIMITIVE_POINT) {
|
||||
shader = kernel_data_fetch(points_shader, prim);
|
||||
}
|
||||
#endif
|
||||
#ifdef __HAIR__
|
||||
else if (isect_type & PRIMITIVE_CURVE) {
|
||||
shader = kernel_data_fetch(curves, prim).shader_id;
|
||||
}
|
||||
#endif
|
||||
|
||||
return shader & SHADER_MASK;
|
||||
}
|
||||
|
||||
ccl_device_forceinline int intersection_get_shader(
|
||||
KernelGlobals kg, const ccl_private Intersection *ccl_restrict isect)
|
||||
{
|
||||
return intersection_get_shader_from_isect_prim(kg, isect->prim, isect->type);
|
||||
}
|
||||
|
||||
ccl_device_forceinline uint
|
||||
intersection_get_object_flags(KernelGlobals kg, const ccl_private Intersection *ccl_restrict isect)
|
||||
{
|
||||
return kernel_data_fetch(object_flag, isect->object);
|
||||
}
|
||||
|
||||
/* TODO: find a better (faster) solution for this. Maybe store offset per object for
|
||||
* attributes needed in intersection? */
|
||||
ccl_device_inline int intersection_find_attribute(KernelGlobals kg,
|
||||
const int object,
|
||||
const uint id)
|
||||
{
|
||||
uint attr_offset = kernel_data_fetch(objects, object).attribute_map_offset;
|
||||
AttributeMap attr_map = kernel_data_fetch(attributes_map, attr_offset);
|
||||
|
||||
while (attr_map.id != id) {
|
||||
if (UNLIKELY(attr_map.id == ATTR_STD_NONE)) {
|
||||
if (UNLIKELY(attr_map.element == 0)) {
|
||||
return (int)ATTR_STD_NOT_FOUND;
|
||||
}
|
||||
/* Chain jump to a different part of the table. */
|
||||
attr_offset = attr_map.offset;
|
||||
}
|
||||
else {
|
||||
attr_offset += ATTR_PRIM_TYPES;
|
||||
}
|
||||
attr_map = kernel_data_fetch(attributes_map, attr_offset);
|
||||
}
|
||||
|
||||
/* return result */
|
||||
return (attr_map.element == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : attr_map.offset;
|
||||
}
|
||||
|
||||
/* Transparent Shadows */
|
||||
|
||||
/* Cut-off value to stop transparent shadow tracing when practically opaque. */
|
||||
#define CURVE_SHADOW_TRANSPARENCY_CUTOFF 0.001f
|
||||
|
||||
ccl_device_inline float intersection_curve_shadow_transparency(
|
||||
KernelGlobals kg, const int object, const int prim, const int type, const float u)
|
||||
{
|
||||
/* Find attribute. */
|
||||
const int offset = intersection_find_attribute(kg, object, ATTR_STD_SHADOW_TRANSPARENCY);
|
||||
if (offset == ATTR_STD_NOT_FOUND) {
|
||||
/* If no shadow transparency attribute, assume opaque. */
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/* Interpolate transparency between curve keys. */
|
||||
const KernelCurve kcurve = kernel_data_fetch(curves, prim);
|
||||
const int k0 = kcurve.first_key + PRIMITIVE_UNPACK_SEGMENT(type);
|
||||
const int k1 = k0 + 1;
|
||||
|
||||
const float f0 = kernel_data_fetch(attributes_float, offset + k0);
|
||||
const float f1 = kernel_data_fetch(attributes_float, offset + k1);
|
||||
|
||||
return (1.0f - u) * f0 + u * f1;
|
||||
}
|
||||
|
||||
ccl_device_inline bool intersection_skip_self(const ccl_ray_data RaySelfPrimitives &self,
|
||||
const int object,
|
||||
const int prim)
|
||||
{
|
||||
return (self.prim == prim) && (self.object == object);
|
||||
}
|
||||
|
||||
ccl_device_inline bool intersection_skip_self_shadow(const ccl_ray_data RaySelfPrimitives &self,
|
||||
const int object,
|
||||
const int prim)
|
||||
{
|
||||
return ((self.prim == prim) && (self.object == object)) ||
|
||||
((self.light_prim == prim) && (self.light_object == object));
|
||||
}
|
||||
|
||||
ccl_device_inline bool intersection_skip_self_local(const ccl_ray_data RaySelfPrimitives &self,
|
||||
const int prim)
|
||||
{
|
||||
return (self.prim == prim);
|
||||
}
|
||||
|
||||
#ifdef __SHADOW_LINKING__
|
||||
ccl_device_inline uint64_t
|
||||
ray_get_shadow_set_membership(KernelGlobals kg, const ccl_ray_data RaySelfPrimitives &self)
|
||||
{
|
||||
if (self.light_object != OBJECT_NONE) {
|
||||
return kernel_data_fetch(objects, self.light_object).shadow_set_membership;
|
||||
}
|
||||
|
||||
return LIGHT_LINK_MASK_ALL;
|
||||
}
|
||||
#endif
|
||||
|
||||
ccl_device_inline bool intersection_skip_shadow_link(KernelGlobals kg,
|
||||
const ccl_ray_data RaySelfPrimitives &self,
|
||||
const int isect_object)
|
||||
{
|
||||
#ifdef __SHADOW_LINKING__
|
||||
if (!(kernel_data.kernel_features & KERNEL_FEATURE_SHADOW_LINKING)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint64_t set_membership = ray_get_shadow_set_membership(kg, self);
|
||||
if (set_membership == LIGHT_LINK_MASK_ALL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint blocker_set = kernel_data_fetch(objects, isect_object).blocker_shadow_set;
|
||||
return ((uint64_t(1) << uint64_t(blocker_set)) & set_membership) == 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Check whether an intersection denoted by its object and primitive is to be skipped due to it
|
||||
* being already recoded.
|
||||
* The situation when primitive is already recoded happens when BVH spatial splits are used. */
|
||||
ccl_device_forceinline bool intersection_skip_shadow_already_recoded(IntegratorShadowState state,
|
||||
const int object,
|
||||
const int prim,
|
||||
const uint num_hits)
|
||||
{
|
||||
const uint num_recorded_hits = min(num_hits, INTEGRATOR_SHADOW_ISECT_SIZE);
|
||||
for (uint i = 0; i < num_recorded_hits; ++i) {
|
||||
const int isect_object = INTEGRATOR_STATE_ARRAY(state, shadow_isect, i, object);
|
||||
const int isect_prim = INTEGRATOR_STATE_ARRAY(state, shadow_isect, i, prim);
|
||||
if (object == isect_object && prim == isect_prim) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
235
blender-5.2.0/intern/cycles/kernel/bvh/volume.h
Normal file
235
blender-5.2.0/intern/cycles/kernel/bvh/volume.h
Normal file
@@ -0,0 +1,235 @@
|
||||
/* SPDX-FileCopyrightText: 2009-2010 NVIDIA Corporation
|
||||
* SPDX-FileCopyrightText: 2009-2012 Intel Corporation
|
||||
* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Adapted code from NVIDIA Corporation. */
|
||||
|
||||
#if BVH_FEATURE(BVH_HAIR)
|
||||
# define NODE_INTERSECT bvh_node_intersect
|
||||
#else
|
||||
# define NODE_INTERSECT bvh_aligned_node_intersect
|
||||
#endif
|
||||
|
||||
/* This is a template BVH traversal function for volumes, where
|
||||
* various features can be enabled/disabled. This way we can compile optimized
|
||||
* versions for each case without new features slowing things down.
|
||||
*
|
||||
* BVH_MOTION: motion blur rendering
|
||||
*/
|
||||
|
||||
#ifndef __KERNEL_GPU__
|
||||
ccl_device
|
||||
#else
|
||||
ccl_device_inline
|
||||
#endif
|
||||
bool
|
||||
BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
ccl_private Intersection *isect,
|
||||
const uint visibility)
|
||||
{
|
||||
/* todo:
|
||||
* - test if pushing distance on the stack helps (for non shadow rays)
|
||||
* - separate version for shadow rays
|
||||
* - likely and unlikely for if() statements
|
||||
* - test restrict attribute for pointers
|
||||
*/
|
||||
|
||||
/* traversal stack in CUDA thread-local memory */
|
||||
int traversal_stack[BVH_STACK_SIZE];
|
||||
traversal_stack[0] = ENTRYPOINT_SENTINEL;
|
||||
|
||||
/* traversal variables in registers */
|
||||
int stack_ptr = 0;
|
||||
int node_addr = kernel_data.bvh.root;
|
||||
|
||||
/* ray parameters in registers */
|
||||
float3 P = ray->P;
|
||||
float3 dir = bvh_clamp_direction(ray->D);
|
||||
float3 idir = bvh_inverse_direction(dir);
|
||||
const float tmin = ray->tmin;
|
||||
int object = OBJECT_NONE;
|
||||
|
||||
isect->t = ray->tmax;
|
||||
isect->u = 0.0f;
|
||||
isect->v = 0.0f;
|
||||
isect->prim = PRIM_NONE;
|
||||
isect->object = OBJECT_NONE;
|
||||
|
||||
/* traversal loop */
|
||||
do {
|
||||
do {
|
||||
/* traverse internal nodes */
|
||||
while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
|
||||
int node_addr_child1, traverse_mask;
|
||||
float dist[2];
|
||||
float4 cnodes = kernel_data_fetch(bvh_nodes, node_addr + 0);
|
||||
|
||||
traverse_mask = NODE_INTERSECT(kg,
|
||||
P,
|
||||
#if BVH_FEATURE(BVH_HAIR)
|
||||
dir,
|
||||
#endif
|
||||
idir,
|
||||
tmin,
|
||||
isect->t,
|
||||
node_addr,
|
||||
visibility,
|
||||
dist);
|
||||
|
||||
node_addr = __float_as_int(cnodes.z);
|
||||
node_addr_child1 = __float_as_int(cnodes.w);
|
||||
|
||||
if (traverse_mask == 3) {
|
||||
/* Both children were intersected, push the farther one. */
|
||||
bool is_closest_child1 = (dist[1] < dist[0]);
|
||||
if (is_closest_child1) {
|
||||
int tmp = node_addr;
|
||||
node_addr = node_addr_child1;
|
||||
node_addr_child1 = tmp;
|
||||
}
|
||||
|
||||
++stack_ptr;
|
||||
kernel_assert(stack_ptr < BVH_STACK_SIZE);
|
||||
traversal_stack[stack_ptr] = node_addr_child1;
|
||||
}
|
||||
else {
|
||||
/* One child was intersected. */
|
||||
if (traverse_mask == 2) {
|
||||
node_addr = node_addr_child1;
|
||||
}
|
||||
else if (traverse_mask == 0) {
|
||||
/* Neither child was intersected. */
|
||||
node_addr = traversal_stack[stack_ptr];
|
||||
--stack_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if node is leaf, fetch triangle list */
|
||||
if (node_addr < 0) {
|
||||
float4 leaf = kernel_data_fetch(bvh_leaf_nodes, (-node_addr - 1));
|
||||
int prim_addr = __float_as_int(leaf.x);
|
||||
|
||||
if (prim_addr >= 0) {
|
||||
const int prim_addr2 = __float_as_int(leaf.y);
|
||||
const uint type = __float_as_int(leaf.w);
|
||||
|
||||
/* pop */
|
||||
node_addr = traversal_stack[stack_ptr];
|
||||
--stack_ptr;
|
||||
|
||||
/* primitive intersection */
|
||||
switch (type & PRIMITIVE_ALL) {
|
||||
case PRIMITIVE_TRIANGLE: {
|
||||
/* intersect ray against primitive */
|
||||
for (; prim_addr < prim_addr2; prim_addr++) {
|
||||
kernel_assert((kernel_data_fetch(prim_type, prim_addr) & PRIMITIVE_ALL) ==
|
||||
(type & PRIMITIVE_ALL));
|
||||
/* only primitives from volume object */
|
||||
const int prim_object = (object == OBJECT_NONE) ?
|
||||
kernel_data_fetch(prim_object, prim_addr) :
|
||||
object;
|
||||
const int prim = kernel_data_fetch(prim_index, prim_addr);
|
||||
if (bvh_volume_anyhit_triangle_filter<false>(
|
||||
kg, prim_object, prim, ray->self, visibility))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
triangle_intersect(
|
||||
kg, isect, P, dir, tmin, isect->t, visibility, prim_object, prim, prim_addr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#if BVH_FEATURE(BVH_MOTION)
|
||||
case PRIMITIVE_MOTION_TRIANGLE: {
|
||||
/* intersect ray against primitive */
|
||||
for (; prim_addr < prim_addr2; prim_addr++) {
|
||||
kernel_assert((kernel_data_fetch(prim_type, prim_addr) & PRIMITIVE_ALL) ==
|
||||
(type & PRIMITIVE_ALL));
|
||||
/* only primitives from volume object */
|
||||
const int prim_object = (object == OBJECT_NONE) ?
|
||||
kernel_data_fetch(prim_object, prim_addr) :
|
||||
object;
|
||||
const int prim = kernel_data_fetch(prim_index, prim_addr);
|
||||
if (bvh_volume_anyhit_triangle_filter<false>(
|
||||
kg, prim_object, prim, ray->self, visibility))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
motion_triangle_intersect(kg,
|
||||
isect,
|
||||
P,
|
||||
dir,
|
||||
tmin,
|
||||
isect->t,
|
||||
ray->time,
|
||||
visibility,
|
||||
prim_object,
|
||||
prim,
|
||||
prim_addr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* instance push */
|
||||
object = kernel_data_fetch(prim_object, -prim_addr - 1);
|
||||
uint object_flag = kernel_data_fetch(object_flag, object);
|
||||
if (object_flag & SD_OBJECT_HAS_VOLUME) {
|
||||
#if BVH_FEATURE(BVH_MOTION)
|
||||
bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir);
|
||||
#else
|
||||
bvh_instance_push(kg, object, ray, &P, &dir, &idir);
|
||||
#endif
|
||||
|
||||
++stack_ptr;
|
||||
kernel_assert(stack_ptr < BVH_STACK_SIZE);
|
||||
traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
|
||||
|
||||
node_addr = kernel_data_fetch(object_node, object);
|
||||
}
|
||||
else {
|
||||
/* pop */
|
||||
object = OBJECT_NONE;
|
||||
node_addr = traversal_stack[stack_ptr];
|
||||
--stack_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (node_addr != ENTRYPOINT_SENTINEL);
|
||||
|
||||
if (stack_ptr >= 0) {
|
||||
kernel_assert(object != OBJECT_NONE);
|
||||
|
||||
/* instance pop */
|
||||
bvh_instance_pop(ray, &P, &dir, &idir);
|
||||
|
||||
object = OBJECT_NONE;
|
||||
node_addr = traversal_stack[stack_ptr];
|
||||
--stack_ptr;
|
||||
}
|
||||
} while (node_addr != ENTRYPOINT_SENTINEL);
|
||||
|
||||
return (isect->prim != PRIM_NONE);
|
||||
}
|
||||
|
||||
ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
ccl_private Intersection *isect,
|
||||
const uint visibility)
|
||||
{
|
||||
return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, isect, visibility);
|
||||
}
|
||||
|
||||
#undef BVH_FUNCTION_NAME
|
||||
#undef BVH_FUNCTION_FEATURES
|
||||
#undef NODE_INTERSECT
|
||||
263
blender-5.2.0/intern/cycles/kernel/bvh/volume_all.h
Normal file
263
blender-5.2.0/intern/cycles/kernel/bvh/volume_all.h
Normal file
@@ -0,0 +1,263 @@
|
||||
/* SPDX-FileCopyrightText: 2009-2010 NVIDIA Corporation
|
||||
* SPDX-FileCopyrightText: 2009-2012 Intel Corporation
|
||||
* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Adapted code from NVIDIA Corporation. */
|
||||
|
||||
#if BVH_FEATURE(BVH_HAIR)
|
||||
# define NODE_INTERSECT bvh_node_intersect
|
||||
#else
|
||||
# define NODE_INTERSECT bvh_aligned_node_intersect
|
||||
#endif
|
||||
|
||||
/* This is a template BVH traversal function for volumes, where
|
||||
* various features can be enabled/disabled. This way we can compile optimized
|
||||
* versions for each case without new features slowing things down.
|
||||
*
|
||||
* BVH_MOTION: motion blur rendering
|
||||
*/
|
||||
|
||||
#ifndef __KERNEL_GPU__
|
||||
ccl_device
|
||||
#else
|
||||
ccl_device_inline
|
||||
#endif
|
||||
uint
|
||||
BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
Intersection *isect_array,
|
||||
const uint max_hits,
|
||||
const uint visibility)
|
||||
{
|
||||
/* todo:
|
||||
* - test if pushing distance on the stack helps (for non shadow rays)
|
||||
* - separate version for shadow rays
|
||||
* - likely and unlikely for if() statements
|
||||
* - test restrict attribute for pointers
|
||||
*/
|
||||
|
||||
/* traversal stack in CUDA thread-local memory */
|
||||
int traversal_stack[BVH_STACK_SIZE];
|
||||
traversal_stack[0] = ENTRYPOINT_SENTINEL;
|
||||
|
||||
/* traversal variables in registers */
|
||||
int stack_ptr = 0;
|
||||
int node_addr = kernel_data.bvh.root;
|
||||
|
||||
/* ray parameters in registers */
|
||||
float3 P = ray->P;
|
||||
float3 dir = bvh_clamp_direction(ray->D);
|
||||
float3 idir = bvh_inverse_direction(dir);
|
||||
const float tmin = ray->tmin;
|
||||
int object = OBJECT_NONE;
|
||||
float isect_t = ray->tmax;
|
||||
|
||||
uint num_hits = 0;
|
||||
isect_array->t = ray->tmax;
|
||||
|
||||
/* traversal loop */
|
||||
do {
|
||||
do {
|
||||
/* traverse internal nodes */
|
||||
while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
|
||||
int node_addr_child1, traverse_mask;
|
||||
float dist[2];
|
||||
float4 cnodes = kernel_data_fetch(bvh_nodes, node_addr + 0);
|
||||
|
||||
traverse_mask = NODE_INTERSECT(kg,
|
||||
P,
|
||||
#if BVH_FEATURE(BVH_HAIR)
|
||||
dir,
|
||||
#endif
|
||||
idir,
|
||||
tmin,
|
||||
isect_t,
|
||||
node_addr,
|
||||
visibility,
|
||||
dist);
|
||||
|
||||
node_addr = __float_as_int(cnodes.z);
|
||||
node_addr_child1 = __float_as_int(cnodes.w);
|
||||
|
||||
if (traverse_mask == 3) {
|
||||
/* Both children were intersected, push the farther one. */
|
||||
bool is_closest_child1 = (dist[1] < dist[0]);
|
||||
if (is_closest_child1) {
|
||||
int tmp = node_addr;
|
||||
node_addr = node_addr_child1;
|
||||
node_addr_child1 = tmp;
|
||||
}
|
||||
|
||||
++stack_ptr;
|
||||
kernel_assert(stack_ptr < BVH_STACK_SIZE);
|
||||
traversal_stack[stack_ptr] = node_addr_child1;
|
||||
}
|
||||
else {
|
||||
/* One child was intersected. */
|
||||
if (traverse_mask == 2) {
|
||||
node_addr = node_addr_child1;
|
||||
}
|
||||
else if (traverse_mask == 0) {
|
||||
/* Neither child was intersected. */
|
||||
node_addr = traversal_stack[stack_ptr];
|
||||
--stack_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if node is leaf, fetch triangle list */
|
||||
if (node_addr < 0) {
|
||||
float4 leaf = kernel_data_fetch(bvh_leaf_nodes, (-node_addr - 1));
|
||||
int prim_addr = __float_as_int(leaf.x);
|
||||
|
||||
if (prim_addr >= 0) {
|
||||
const int prim_addr2 = __float_as_int(leaf.y);
|
||||
const uint type = __float_as_int(leaf.w);
|
||||
bool hit;
|
||||
|
||||
/* pop */
|
||||
node_addr = traversal_stack[stack_ptr];
|
||||
--stack_ptr;
|
||||
|
||||
/* primitive intersection */
|
||||
switch (type & PRIMITIVE_ALL) {
|
||||
case PRIMITIVE_TRIANGLE: {
|
||||
/* intersect ray against primitive */
|
||||
for (; prim_addr < prim_addr2; prim_addr++) {
|
||||
kernel_assert((kernel_data_fetch(prim_type, prim_addr) & PRIMITIVE_ALL) ==
|
||||
(type & PRIMITIVE_ALL));
|
||||
/* only primitives from volume object */
|
||||
const int prim_object = (object == OBJECT_NONE) ?
|
||||
kernel_data_fetch(prim_object, prim_addr) :
|
||||
object;
|
||||
const int prim = kernel_data_fetch(prim_index, prim_addr);
|
||||
if (bvh_volume_anyhit_triangle_filter<false>(
|
||||
kg, prim_object, prim, ray->self, visibility))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
hit = triangle_intersect(kg,
|
||||
isect_array,
|
||||
P,
|
||||
dir,
|
||||
tmin,
|
||||
isect_t,
|
||||
visibility,
|
||||
prim_object,
|
||||
prim,
|
||||
prim_addr);
|
||||
if (hit) {
|
||||
/* Move on to next entry in intersections array. */
|
||||
isect_array++;
|
||||
num_hits++;
|
||||
isect_array->t = isect_t;
|
||||
if (num_hits == max_hits) {
|
||||
return num_hits;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
#if BVH_FEATURE(BVH_MOTION)
|
||||
case PRIMITIVE_MOTION_TRIANGLE: {
|
||||
/* intersect ray against primitive */
|
||||
for (; prim_addr < prim_addr2; prim_addr++) {
|
||||
kernel_assert((kernel_data_fetch(prim_type, prim_addr) & PRIMITIVE_ALL) ==
|
||||
(type & PRIMITIVE_ALL));
|
||||
/* only primitives from volume object */
|
||||
const int prim_object = (object == OBJECT_NONE) ?
|
||||
kernel_data_fetch(prim_object, prim_addr) :
|
||||
object;
|
||||
const int prim = kernel_data_fetch(prim_index, prim_addr);
|
||||
if (bvh_volume_anyhit_triangle_filter<false>(
|
||||
kg, prim_object, prim, ray->self, visibility))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
hit = motion_triangle_intersect(kg,
|
||||
isect_array,
|
||||
P,
|
||||
dir,
|
||||
tmin,
|
||||
isect_t,
|
||||
ray->time,
|
||||
visibility,
|
||||
prim_object,
|
||||
prim,
|
||||
prim_addr);
|
||||
if (hit) {
|
||||
/* Move on to next entry in intersections array. */
|
||||
isect_array++;
|
||||
num_hits++;
|
||||
isect_array->t = isect_t;
|
||||
if (num_hits == max_hits) {
|
||||
return num_hits;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* BVH_MOTION */
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* instance push */
|
||||
object = kernel_data_fetch(prim_object, -prim_addr - 1);
|
||||
const uint object_flag = kernel_data_fetch(object_flag, object);
|
||||
if (object_flag & SD_OBJECT_HAS_VOLUME) {
|
||||
#if BVH_FEATURE(BVH_MOTION)
|
||||
bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir);
|
||||
#else
|
||||
bvh_instance_push(kg, object, ray, &P, &dir, &idir);
|
||||
#endif
|
||||
|
||||
isect_array->t = isect_t;
|
||||
|
||||
++stack_ptr;
|
||||
kernel_assert(stack_ptr < BVH_STACK_SIZE);
|
||||
traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
|
||||
|
||||
node_addr = kernel_data_fetch(object_node, object);
|
||||
}
|
||||
else {
|
||||
/* pop */
|
||||
object = OBJECT_NONE;
|
||||
node_addr = traversal_stack[stack_ptr];
|
||||
--stack_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (node_addr != ENTRYPOINT_SENTINEL);
|
||||
|
||||
if (stack_ptr >= 0) {
|
||||
kernel_assert(object != OBJECT_NONE);
|
||||
|
||||
/* Instance pop. */
|
||||
bvh_instance_pop(ray, &P, &dir, &idir);
|
||||
|
||||
object = OBJECT_NONE;
|
||||
node_addr = traversal_stack[stack_ptr];
|
||||
--stack_ptr;
|
||||
}
|
||||
} while (node_addr != ENTRYPOINT_SENTINEL);
|
||||
|
||||
return num_hits;
|
||||
}
|
||||
|
||||
ccl_device_inline uint BVH_FUNCTION_NAME(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
Intersection *isect_array,
|
||||
const uint max_hits,
|
||||
const uint visibility)
|
||||
{
|
||||
return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, isect_array, max_hits, visibility);
|
||||
}
|
||||
|
||||
#undef BVH_FUNCTION_NAME
|
||||
#undef BVH_FUNCTION_FEATURES
|
||||
#undef NODE_INTERSECT
|
||||
Reference in New Issue
Block a user