diff options
-rw-r--r-- | intern/cycles/kernel/CMakeLists.txt | 1 | ||||
-rw-r--r-- | intern/cycles/kernel/kernel_bvh.h | 643 | ||||
-rw-r--r-- | intern/cycles/kernel/kernel_bvh_traversal.h | 239 | ||||
-rw-r--r-- | intern/cycles/kernel/kernel_path.h | 44 | ||||
-rw-r--r-- | intern/cycles/kernel/kernel_subsurface.h | 2 | ||||
-rw-r--r-- | intern/cycles/kernel/kernel_types.h | 5 | ||||
-rw-r--r-- | intern/cycles/render/object.cpp | 20 | ||||
-rw-r--r-- | intern/cycles/render/object.h | 2 |
8 files changed, 404 insertions, 552 deletions
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index fbaba1da094..961349f1095 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -22,6 +22,7 @@ set(SRC_HEADERS kernel.h kernel_accumulate.h kernel_bvh.h + kernel_bvh_traversal.h kernel_camera.h kernel_compat_cpu.h kernel_compat_cuda.h diff --git a/intern/cycles/kernel/kernel_bvh.h b/intern/cycles/kernel/kernel_bvh.h index 8df710052b6..ef5c9100e53 100644 --- a/intern/cycles/kernel/kernel_bvh.h +++ b/intern/cycles/kernel/kernel_bvh.h @@ -750,293 +750,7 @@ __device_inline void bvh_curve_intersect(KernelGlobals *kg, Intersection *isect, } #endif -#ifdef __HAIR__ -__device bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect, uint *lcg_state = NULL, float difl = 0.0f, float extmax = 0.0f) -#else -__device bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect) -#endif -{ - /* traversal stack in CUDA thread-local memory */ - int traversalStack[BVH_STACK_SIZE]; - traversalStack[0] = ENTRYPOINT_SENTINEL; - - /* traversal variables in registers */ - int stackPtr = 0; - int nodeAddr = kernel_data.bvh.root; - - /* ray parameters in registers */ - const float tmax = ray->t; - float3 P = ray->P; - float3 idir = bvh_inverse_direction(ray->D); - int object = ~0; - - isect->t = tmax; - isect->object = ~0; - isect->prim = ~0; - isect->u = 0.0f; - isect->v = 0.0f; - - /* traversal loop */ - do { - do - { - /* traverse internal nodes */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) - { - bool traverseChild0, traverseChild1, closestChild1; - int nodeAddrChild1; - -#ifdef __HAIR__ - bvh_node_intersect(kg, &traverseChild0, &traverseChild1, - &closestChild1, &nodeAddr, &nodeAddrChild1, - P, idir, isect->t, visibility, nodeAddr, difl, extmax); -#else - bvh_node_intersect(kg, &traverseChild0, &traverseChild1, - &closestChild1, &nodeAddr, &nodeAddrChild1, - P, idir, isect->t, visibility, nodeAddr); -#endif - - if(traverseChild0 != traverseChild1) { - /* one child was intersected */ - if(traverseChild1) { - nodeAddr = nodeAddrChild1; - } - } - else { - if(!traverseChild0) { - /* neither child was intersected */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; - } - else { - /* both children were intersected, push the farther one */ - if(closestChild1) { - int tmp = nodeAddr; - nodeAddr = nodeAddrChild1; - nodeAddrChild1 = tmp; - } - - ++stackPtr; - traversalStack[stackPtr] = nodeAddrChild1; - } - } - } - - /* if node is leaf, fetch triangle list */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*BVH_NODE_SIZE+(BVH_NODE_SIZE-1)); - int primAddr = __float_as_int(leaf.x); - -#ifdef __INSTANCING__ - if(primAddr >= 0) { -#endif - int primAddr2 = __float_as_int(leaf.y); - - /* pop */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; - - /* primitive intersection */ - while(primAddr < primAddr2) { - /* intersect ray against primitive */ -#ifdef __HAIR__ - uint segment = kernel_tex_fetch(__prim_segment, primAddr); - if(segment != ~0) { - if(kernel_data.curve_kernel_data.curveflags & CURVE_KN_INTERPOLATE) - bvh_cardinal_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment, lcg_state, difl, extmax); - else - bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment, lcg_state, difl, extmax); - } - else -#endif - bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr); - - /* shadow ray early termination */ - if(visibility == PATH_RAY_SHADOW_OPAQUE && isect->prim != ~0) - return true; - - primAddr++; - } -#ifdef __INSTANCING__ - } - else { - /* instance push */ - object = kernel_tex_fetch(__prim_object, -primAddr-1); - bvh_instance_push(kg, object, ray, &P, &idir, &isect->t, tmax); - - ++stackPtr; - traversalStack[stackPtr] = ENTRYPOINT_SENTINEL; - - nodeAddr = kernel_tex_fetch(__object_node, object); - } -#endif - } - } while(nodeAddr != ENTRYPOINT_SENTINEL); - -#ifdef __INSTANCING__ - if(stackPtr >= 0) { - kernel_assert(object != ~0); - - /* instance pop */ - bvh_instance_pop(kg, object, ray, &P, &idir, &isect->t, tmax); - object = ~0; - nodeAddr = traversalStack[stackPtr]; - --stackPtr; - } -#endif - } while(nodeAddr != ENTRYPOINT_SENTINEL); - - return (isect->prim != ~0); -} - -#ifdef __OBJECT_MOTION__ -__device bool bvh_intersect_motion(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect) -{ - /* traversal stack in CUDA thread-local memory */ - int traversalStack[BVH_STACK_SIZE]; - traversalStack[0] = ENTRYPOINT_SENTINEL; - - /* traversal variables in registers */ - int stackPtr = 0; - int nodeAddr = kernel_data.bvh.root; - - /* ray parameters in registers */ - const float tmax = ray->t; - float3 P = ray->P; - float3 idir = bvh_inverse_direction(ray->D); - int object = ~0; - - Transform ob_tfm; - - isect->t = tmax; - isect->object = ~0; - isect->prim = ~0; - isect->u = 0.0f; - isect->v = 0.0f; - - /* traversal loop */ - do { - do - { - /* traverse internal nodes */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) - { - bool traverseChild0, traverseChild1, closestChild1; - int nodeAddrChild1; - - bvh_node_intersect(kg, &traverseChild0, &traverseChild1, - &closestChild1, &nodeAddr, &nodeAddrChild1, - P, idir, isect->t, visibility, nodeAddr); - - if(traverseChild0 != traverseChild1) { - /* one child was intersected */ - if(traverseChild1) { - nodeAddr = nodeAddrChild1; - } - } - else { - if(!traverseChild0) { - /* neither child was intersected */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; - } - else { - /* both children were intersected, push the farther one */ - if(closestChild1) { - int tmp = nodeAddr; - nodeAddr = nodeAddrChild1; - nodeAddrChild1 = tmp; - } - - ++stackPtr; - traversalStack[stackPtr] = nodeAddrChild1; - } - } - } - - /* if node is leaf, fetch triangle list */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*BVH_NODE_SIZE+(BVH_NODE_SIZE-1)); - int primAddr = __float_as_int(leaf.x); - - if(primAddr >= 0) { - int primAddr2 = __float_as_int(leaf.y); - - /* pop */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; - - /* primitive intersection */ - while(primAddr < primAddr2) { - /* intersect ray against primitive */ -#ifdef __HAIR__ - uint segment = kernel_tex_fetch(__prim_segment, primAddr); - if(segment != ~0) { - if(kernel_data.curve_kernel_data.curveflags & CURVE_KN_INTERPOLATE) - bvh_cardinal_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment); - else - bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment); - } - else -#endif - bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr); - - /* shadow ray early termination */ - if(visibility == PATH_RAY_SHADOW_OPAQUE && isect->prim != ~0) - return true; - - primAddr++; - } - } - else { - /* instance push */ - object = kernel_tex_fetch(__prim_object, -primAddr-1); - bvh_instance_motion_push(kg, object, ray, &P, &idir, &isect->t, &ob_tfm, tmax); - - ++stackPtr; - traversalStack[stackPtr] = ENTRYPOINT_SENTINEL; - - nodeAddr = kernel_tex_fetch(__object_node, object); - } - } - } while(nodeAddr != ENTRYPOINT_SENTINEL); - - if(stackPtr >= 0) { - kernel_assert(object != ~0); - - /* instance pop */ - bvh_instance_motion_pop(kg, object, ray, &P, &idir, &isect->t, &ob_tfm, tmax); - object = ~0; - nodeAddr = traversalStack[stackPtr]; - --stackPtr; - } - } while(nodeAddr != ENTRYPOINT_SENTINEL); - - return (isect->prim != ~0); -} -#endif - -#ifdef __HAIR__ -__device_inline bool scene_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect, uint *lcg_state = NULL, float difl = 0.0f, float extmax = 0.0f) -#else -__device_inline bool scene_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect) -#endif -{ -#ifdef __OBJECT_MOTION__ - if(kernel_data.bvh.have_motion) - return bvh_intersect_motion(kg, ray, visibility, isect); - else -#ifdef __HAIR__ - return bvh_intersect(kg, ray, visibility, isect, lcg_state, difl, extmax); -#else - return bvh_intersect(kg, ray, visibility, isect); -#endif - -#else - return bvh_intersect(kg, ray, visibility, isect); -#endif -} - +#ifdef __SUBSURFACE__ /* Special ray intersection routines for subsurface scattering. In that case we * only want to intersect with primitives in the same object, and if case of * multiple hits we pick a single random primitive as the intersection point. */ @@ -1081,283 +795,154 @@ __device_inline void bvh_triangle_intersect_subsurface(KernelGlobals *kg, Inters } } } +#endif -__device_inline int bvh_intersect_subsurface(KernelGlobals *kg, const Ray *ray, Intersection *isect, int subsurface_object, float subsurface_random) -{ - /* traversal stack in CUDA thread-local memory */ - int traversalStack[BVH_STACK_SIZE]; - traversalStack[0] = ENTRYPOINT_SENTINEL; - - /* traversal variables in registers */ - int stackPtr = 0; - int nodeAddr = kernel_data.bvh.root; +/* BVH intersection function variations */ - /* ray parameters in registers */ - const float tmax = ray->t; - float3 P = ray->P; - float3 idir = bvh_inverse_direction(ray->D); - int object = ~0; - - int num_hits = 0; - - isect->t = tmax; - isect->object = ~0; - isect->prim = ~0; - isect->u = 0.0f; - isect->v = 0.0f; - - /* traversal loop */ - do { - do - { - /* traverse internal nodes */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) - { - bool traverseChild0, traverseChild1, closestChild1; - int nodeAddrChild1; - - bvh_node_intersect(kg, &traverseChild0, &traverseChild1, - &closestChild1, &nodeAddr, &nodeAddrChild1, - P, idir, isect->t, ~0, nodeAddr); - - if(traverseChild0 != traverseChild1) { - /* one child was intersected */ - if(traverseChild1) { - nodeAddr = nodeAddrChild1; - } - } - else { - if(!traverseChild0) { - /* neither child was intersected */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; - } - else { - /* both children were intersected, push the farther one */ - if(closestChild1) { - int tmp = nodeAddr; - nodeAddr = nodeAddrChild1; - nodeAddrChild1 = tmp; - } - - ++stackPtr; - traversalStack[stackPtr] = nodeAddrChild1; - } - } - } +#define BVH_INSTANCING 1 +#define BVH_MOTION 2 +#define BVH_HAIR 4 +#define BVH_HAIR_MINIMUM_WIDTH 8 +#define BVH_SUBSURFACE 16 - /* if node is leaf, fetch triangle list */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*BVH_NODE_SIZE+(BVH_NODE_SIZE-1)); - int primAddr = __float_as_int(leaf.x); +#define BVH_FUNCTION_NAME bvh_intersect +#define BVH_FUNCTION_FEATURES 0 +#include "kernel_bvh_traversal.h" -#ifdef __INSTANCING__ - if(primAddr >= 0) { +#if defined(__INSTANCING__) +#define BVH_FUNCTION_NAME bvh_intersect_instancing +#define BVH_FUNCTION_FEATURES BVH_INSTANCING +#include "kernel_bvh_traversal.h" #endif - int primAddr2 = __float_as_int(leaf.y); - /* pop */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; +#if defined(__HAIR__) +#define BVH_FUNCTION_NAME bvh_intersect_hair +#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH +#include "kernel_bvh_traversal.h" +#endif - /* primitive intersection */ - while(primAddr < primAddr2) { - /* only primitives from the same object */ - uint tri_object = (object == ~0)? kernel_tex_fetch(__prim_object, primAddr): object; +#if defined(__OBJECT_MOTION__) +#define BVH_FUNCTION_NAME bvh_intersect_motion +#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION +#include "kernel_bvh_traversal.h" +#endif - if(tri_object == subsurface_object) { - /* intersect ray against primitive */ -#ifdef __HAIR__ - uint segment = kernel_tex_fetch(__prim_segment, primAddr); - if(segment == ~0) /* ignore hair for sss */ +#if defined(__HAIR__) && defined(__OBJECT_MOTION__) +#define BVH_FUNCTION_NAME bvh_intersect_hair_motion +#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH|BVH_MOTION +#include "kernel_bvh_traversal.h" #endif - bvh_triangle_intersect_subsurface(kg, isect, P, idir, object, primAddr, tmax, &num_hits, subsurface_random); - } - primAddr++; - } -#ifdef __INSTANCING__ - } - else { - /* instance push */ - if(subsurface_object == kernel_tex_fetch(__prim_object, -primAddr-1)) { - object = subsurface_object; - bvh_instance_push(kg, object, ray, &P, &idir, &isect->t, tmax); - - ++stackPtr; - traversalStack[stackPtr] = ENTRYPOINT_SENTINEL; - - nodeAddr = kernel_tex_fetch(__object_node, object); - } - else { - /* pop */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; - } - } +#if defined(__SUBSURFACE__) +#define BVH_FUNCTION_NAME bvh_intersect_subsurface +#define BVH_FUNCTION_FEATURES BVH_SUBSURFACE +#include "kernel_bvh_traversal.h" #endif - } - } while(nodeAddr != ENTRYPOINT_SENTINEL); -#ifdef __INSTANCING__ - if(stackPtr >= 0) { - kernel_assert(object != ~0); - - /* instance pop */ - bvh_instance_pop(kg, object, ray, &P, &idir, &isect->t, tmax); - object = ~0; - nodeAddr = traversalStack[stackPtr]; - --stackPtr; - } +#if defined(__SUBSURFACE__) && defined(__INSTANCING__) +#define BVH_FUNCTION_NAME bvh_intersect_subsurface_instancing +#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_SUBSURFACE +#include "kernel_bvh_traversal.h" #endif - } while(nodeAddr != ENTRYPOINT_SENTINEL); - return num_hits; -} +#if defined(__SUBSURFACE__) && defined(__HAIR__) +#define BVH_FUNCTION_NAME bvh_intersect_subsurface_hair +#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_SUBSURFACE|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH +#include "kernel_bvh_traversal.h" +#endif -#ifdef __OBJECT_MOTION__ -__device bool bvh_intersect_motion_subsurface(KernelGlobals *kg, const Ray *ray, Intersection *isect, int subsurface_object, float subsurface_random) -{ - /* traversal stack in CUDA thread-local memory */ - int traversalStack[BVH_STACK_SIZE]; - traversalStack[0] = ENTRYPOINT_SENTINEL; +#if defined(__SUBSURFACE__) && defined(__OBJECT_MOTION__) +#define BVH_FUNCTION_NAME bvh_intersect_subsurface_motion +#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_SUBSURFACE|BVH_MOTION +#include "kernel_bvh_traversal.h" +#endif - /* traversal variables in registers */ - int stackPtr = 0; - int nodeAddr = kernel_data.bvh.root; +#if defined(__SUBSURFACE__) && defined(__HAIR__) && defined(__OBJECT_MOTION__) +#define BVH_FUNCTION_NAME bvh_intersect_subsurface_hair_motion +#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_SUBSURFACE|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH|BVH_MOTION +#include "kernel_bvh_traversal.h" +#endif - /* ray parameters in registers */ - const float tmax = ray->t; - float3 P = ray->P; - float3 idir = bvh_inverse_direction(ray->D); - int object = ~0; - int num_hits = 0; +#ifdef __HAIR__ +__device_inline bool scene_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect, uint *lcg_state = NULL, float difl = 0.0f, float extmax = 0.0f) +#else +__device_inline bool scene_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect) +#endif +{ +#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, lcg_state, difl, extmax); +#endif /* __HAIR__ */ - Transform ob_tfm; + return bvh_intersect_motion(kg, ray, isect, visibility); + } +#endif /* __OBJECT_MOTION__ */ - isect->t = tmax; - isect->object = ~0; - isect->prim = ~0; - isect->u = 0.0f; - isect->v = 0.0f; +#ifdef __HAIR__ + if(kernel_data.bvh.have_curves) + return bvh_intersect_hair(kg, ray, isect, visibility, lcg_state, difl, extmax); +#endif /* __HAIR__ */ - /* traversal loop */ - do { - do - { - /* traverse internal nodes */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) - { - bool traverseChild0, traverseChild1, closestChild1; - int nodeAddrChild1; - - bvh_node_intersect(kg, &traverseChild0, &traverseChild1, - &closestChild1, &nodeAddr, &nodeAddrChild1, - P, idir, isect->t, ~0, nodeAddr); - - if(traverseChild0 != traverseChild1) { - /* one child was intersected */ - if(traverseChild1) { - nodeAddr = nodeAddrChild1; - } - } - else { - if(!traverseChild0) { - /* neither child was intersected */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; - } - else { - /* both children were intersected, push the farther one */ - if(closestChild1) { - int tmp = nodeAddr; - nodeAddr = nodeAddrChild1; - nodeAddrChild1 = tmp; - } - - ++stackPtr; - traversalStack[stackPtr] = nodeAddrChild1; - } - } - } +#ifdef __KERNEL_CPU__ - /* if node is leaf, fetch triangle list */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*BVH_NODE_SIZE+(BVH_NODE_SIZE-1)); - int primAddr = __float_as_int(leaf.x); +#ifdef __INSTANCING__ + if(kernel_data.bvh.have_instancing) + return bvh_intersect_instancing(kg, ray, isect, visibility); +#endif /* __INSTANCING__ */ - if(primAddr >= 0) { - int primAddr2 = __float_as_int(leaf.y); + return bvh_intersect(kg, ray, isect, visibility); +#else /* __KERNEL_CPU__ */ - /* pop */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; +#ifdef __INSTANCING__ + return bvh_intersect_instancing(kg, ray, isect, visibility); +#else + return bvh_intersect(kg, ray, isect, visibility); +#endif /* __INSTANCING__ */ - /* primitive intersection */ - while(primAddr < primAddr2) { - /* only primitives from the same object */ - uint tri_object = (object == ~0)? kernel_tex_fetch(__prim_object, primAddr): object; +#endif /* __KERNEL_CPU__ */ +} - if(tri_object == subsurface_object) { - /* intersect ray against primitive */ +#ifdef __SUBSURFACE__ +__device_inline int scene_intersect_subsurface(KernelGlobals *kg, const Ray *ray, Intersection *isect, int subsurface_object, float subsurface_random) +{ +#ifdef __OBJECT_MOTION__ + if(kernel_data.bvh.have_motion) { #ifdef __HAIR__ - uint segment = kernel_tex_fetch(__prim_segment, primAddr); - if(segment == ~0) /* ignore hair for sss */ -#endif - bvh_triangle_intersect_subsurface(kg, isect, P, idir, object, primAddr, tmax, &num_hits, subsurface_random); - } + if(kernel_data.bvh.have_curves) + return bvh_intersect_subsurface_hair_motion(kg, ray, isect, subsurface_object, subsurface_random); +#endif /* __HAIR__ */ - primAddr++; - } - } - else { - /* instance push */ - if(subsurface_object == kernel_tex_fetch(__prim_object, -primAddr-1)) { - object = subsurface_object; - object = kernel_tex_fetch(__prim_object, -primAddr-1); - bvh_instance_motion_push(kg, object, ray, &P, &idir, &isect->t, &ob_tfm, tmax); - - ++stackPtr; - traversalStack[stackPtr] = ENTRYPOINT_SENTINEL; - - nodeAddr = kernel_tex_fetch(__object_node, object); - } - else { - /* pop */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; - } - } - } - } while(nodeAddr != ENTRYPOINT_SENTINEL); + return bvh_intersect_subsurface_motion(kg, ray, isect, subsurface_object, subsurface_random); + } +#endif /* __OBJECT_MOTION__ */ - if(stackPtr >= 0) { - kernel_assert(object != ~0); +#ifdef __HAIR__ + if(kernel_data.bvh.have_curves) + return bvh_intersect_subsurface_hair(kg, ray, isect, subsurface_object, subsurface_random); +#endif /* __HAIR__ */ - /* instance pop */ - bvh_instance_motion_pop(kg, object, ray, &P, &idir, &isect->t, &ob_tfm, tmax); - object = ~0; - nodeAddr = traversalStack[stackPtr]; - --stackPtr; - } - } while(nodeAddr != ENTRYPOINT_SENTINEL); +#ifdef __KERNEL_CPU__ - return num_hits; -} -#endif +#ifdef __INSTANCING__ + if(kernel_data.bvh.have_instancing) + return bvh_intersect_subsurface_instancing(kg, ray, isect, subsurface_object, subsurface_random); +#endif /* __INSTANCING__ */ -__device_inline int scene_intersect_subsurface(KernelGlobals *kg, const Ray *ray, Intersection *isect, int subsurface_object, float subsurface_random) -{ -#ifdef __OBJECT_MOTION__ - if(kernel_data.bvh.have_motion) - return bvh_intersect_motion_subsurface(kg, ray, isect, subsurface_object, subsurface_random); - else - return bvh_intersect_subsurface(kg, ray, isect, subsurface_object, subsurface_random); + return bvh_intersect_subsurface(kg, ray, isect, subsurface_object, subsurface_random); +#else /* __KERNEL_CPU__ */ + +#ifdef __INSTANCING__ + return bvh_intersect_subsurface_instancing(kg, ray, isect, subsurface_object, subsurface_random); #else return bvh_intersect_subsurface(kg, ray, isect, subsurface_object, subsurface_random); -#endif +#endif /* __INSTANCING__ */ + +#endif /* __KERNEL_CPU__ */ } +#endif /* Ray offset to avoid self intersection */ diff --git a/intern/cycles/kernel/kernel_bvh_traversal.h b/intern/cycles/kernel/kernel_bvh_traversal.h new file mode 100644 index 00000000000..7e69c06a8ca --- /dev/null +++ b/intern/cycles/kernel/kernel_bvh_traversal.h @@ -0,0 +1,239 @@ +/* + * Adapted from code Copyright 2009-2010 NVIDIA Corporation + * Modifications Copyright 2011, Blender Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* 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_INSTANCING: object instancing + * BVH_HAIR: hair curve rendering + * BVH_HAIR_MINIMUM_WIDTH: hair curve rendering with minimum width + * BVH_SUBSURFACE: subsurface same object, random triangle intersection + * BVH_MOTION: motion blur rendering + * + */ + +#define FEATURE(f) (((BVH_FUNCTION_FEATURES) & (f)) != 0) + +__device bool BVH_FUNCTION_NAME +(KernelGlobals *kg, const Ray *ray, Intersection *isect +#if FEATURE(BVH_SUBSURFACE) +, int subsurface_object, float subsurface_random +#else +, const uint visibility +#endif +#if FEATURE(BVH_HAIR_MINIMUM_WIDTH) && !FEATURE(BVH_SUBSURFACE) +, uint *lcg_state = NULL, float difl = 0.0f, float extmax = 0.0f +#endif +) +{ + /* traversal stack in CUDA thread-local memory */ + int traversalStack[BVH_STACK_SIZE]; + traversalStack[0] = ENTRYPOINT_SENTINEL; + + /* traversal variables in registers */ + int stackPtr = 0; + int nodeAddr = kernel_data.bvh.root; + + /* ray parameters in registers */ + const float tmax = ray->t; + float3 P = ray->P; + float3 idir = bvh_inverse_direction(ray->D); + int object = ~0; + +#if FEATURE(BVH_SUBSURFACE) + const uint visibility = ~0; + int num_hits = 0; +#endif + +#if FEATURE(BVH_MOTION) + Transform ob_tfm; +#endif + + isect->t = tmax; + isect->object = ~0; + isect->prim = ~0; + isect->u = 0.0f; + isect->v = 0.0f; + + /* traversal loop */ + do { + do + { + /* traverse internal nodes */ + while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) + { + bool traverseChild0, traverseChild1, closestChild1; + int nodeAddrChild1; + +#if FEATURE(BVH_HAIR_MINIMUM_WIDTH) && !FEATURE(BVH_SUBSURFACE) + bvh_node_intersect(kg, &traverseChild0, &traverseChild1, + &closestChild1, &nodeAddr, &nodeAddrChild1, + P, idir, isect->t, visibility, nodeAddr, difl, extmax); +#else + bvh_node_intersect(kg, &traverseChild0, &traverseChild1, + &closestChild1, &nodeAddr, &nodeAddrChild1, + P, idir, isect->t, visibility, nodeAddr); +#endif + + if(traverseChild0 != traverseChild1) { + /* one child was intersected */ + if(traverseChild1) { + nodeAddr = nodeAddrChild1; + } + } + else { + if(!traverseChild0) { + /* neither child was intersected */ + nodeAddr = traversalStack[stackPtr]; + --stackPtr; + } + else { + /* both children were intersected, push the farther one */ + if(closestChild1) { + int tmp = nodeAddr; + nodeAddr = nodeAddrChild1; + nodeAddrChild1 = tmp; + } + + ++stackPtr; + traversalStack[stackPtr] = nodeAddrChild1; + } + } + } + + /* if node is leaf, fetch triangle list */ + if(nodeAddr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*BVH_NODE_SIZE+(BVH_NODE_SIZE-1)); + int primAddr = __float_as_int(leaf.x); + +#if FEATURE(BVH_INSTANCING) + if(primAddr >= 0) { +#endif + int primAddr2 = __float_as_int(leaf.y); + + /* pop */ + nodeAddr = traversalStack[stackPtr]; + --stackPtr; + + /* primitive intersection */ + while(primAddr < primAddr2) { +#if FEATURE(BVH_SUBSURFACE) + /* only primitives from the same object */ + uint tri_object = (object == ~0)? kernel_tex_fetch(__prim_object, primAddr): object; + + if(tri_object == subsurface_object) { +#endif + + /* intersect ray against primitive */ +#if FEATURE(BVH_HAIR) + uint segment = kernel_tex_fetch(__prim_segment, primAddr); +#if !FEATURE(BVH_SUBSURFACE) + if(segment != ~0) { + if(kernel_data.curve_kernel_data.curveflags & CURVE_KN_INTERPOLATE) +#if FEATURE(BVH_HAIR_MINIMUM_WIDTH) + bvh_cardinal_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment, lcg_state, difl, extmax); + else + bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment, lcg_state, difl, extmax); +#else + bvh_cardinal_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment); + else + bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment); +#endif + } + else +#endif +#endif +#if FEATURE(BVH_SUBSURFACE) +#if FEATURE(BVH_HAIR) + if(segment == ~0) +#endif + bvh_triangle_intersect_subsurface(kg, isect, P, idir, object, primAddr, tmax, &num_hits, subsurface_random); + + } +#else + bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr); + + /* shadow ray early termination */ + if(visibility == PATH_RAY_SHADOW_OPAQUE && isect->prim != ~0) + return true; +#endif + + primAddr++; + } + } +#if FEATURE(BVH_INSTANCING) + else { + /* instance push */ +#if FEATURE(BVH_SUBSURFACE) + if(subsurface_object == kernel_tex_fetch(__prim_object, -primAddr-1)) { + object = subsurface_object; +#else + object = kernel_tex_fetch(__prim_object, -primAddr-1); +#endif + +#if FEATURE(BVH_MOTION) + bvh_instance_motion_push(kg, object, ray, &P, &idir, &isect->t, &ob_tfm, tmax); +#else + bvh_instance_push(kg, object, ray, &P, &idir, &isect->t, tmax); +#endif + + ++stackPtr; + traversalStack[stackPtr] = ENTRYPOINT_SENTINEL; + + nodeAddr = kernel_tex_fetch(__object_node, object); +#if FEATURE(BVH_SUBSURFACE) + } + else { + /* pop */ + nodeAddr = traversalStack[stackPtr]; + --stackPtr; + } +#endif + } + } +#endif + } while(nodeAddr != ENTRYPOINT_SENTINEL); + +#if FEATURE(BVH_INSTANCING) + if(stackPtr >= 0) { + kernel_assert(object != ~0); + + /* instance pop */ +#if FEATURE(BVH_MOTION) + bvh_instance_motion_pop(kg, object, ray, &P, &idir, &isect->t, &ob_tfm, tmax); +#else + bvh_instance_pop(kg, object, ray, &P, &idir, &isect->t, tmax); +#endif + object = ~0; + nodeAddr = traversalStack[stackPtr]; + --stackPtr; + } +#endif + } while(nodeAddr != ENTRYPOINT_SENTINEL); + +#if FEATURE(BVH_SUBSURAFACE) + return (num_hits != 0); +#else + return (isect->prim != ~0); +#endif +} + +#undef FEATURE +#undef BVH_FUNCTION_NAME +#undef BVH_FUNCTION_FEATURES + diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 30abf0c8eb6..956125078d9 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -251,14 +251,19 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample, uint visibility = path_state_ray_visibility(kg, &state); #ifdef __HAIR__ - float difl = 0.0f; - if((kernel_data.cam.resolution == 1) && (state.flag & PATH_RAY_CAMERA)) { - float3 pixdiff = ray.dD.dx + ray.dD.dy; - /*pixdiff = pixdiff - dot(pixdiff, ray.D)*ray.D;*/ - difl = kernel_data.curve_kernel_data.minimum_width * len(pixdiff) * 0.5f; + float difl = 0.0f, extmax = 0.0f; + uint lcg_state = 0; + + if(kernel_data.bvh.have_curves) { + if((kernel_data.cam.resolution == 1) && (state.flag & PATH_RAY_CAMERA)) { + float3 pixdiff = ray.dD.dx + ray.dD.dy; + /*pixdiff = pixdiff - dot(pixdiff, ray.D)*ray.D;*/ + difl = kernel_data.curve_kernel_data.minimum_width * len(pixdiff) * 0.5f; + } + + extmax = kernel_data.curve_kernel_data.maximum_width; + lcg_state = lcg_init(*rng + rng_offset + sample*0x51633e2d); } - float extmax = kernel_data.curve_kernel_data.maximum_width; - uint lcg_state = lcg_init(*rng + rng_offset + sample); bool hit = scene_intersect(kg, &ray, visibility, &isect, &lcg_state, difl, extmax); #else @@ -376,7 +381,7 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample, /* do bssrdf scatter step if we picked a bssrdf closure */ if(sc) { - uint lcg_state = lcg_init(*rng + rng_offset + sample); + uint lcg_state = lcg_init(*rng + rng_offset + sample*0x68bc21eb); subsurface_scatter_step(kg, &sd, state.flag, sc, &lcg_state, false); } } @@ -600,7 +605,7 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray /* do bssrdf scatter step if we picked a bssrdf closure */ if(sc) { - uint lcg_state = lcg_init(*rng + rng_offset + sample); + uint lcg_state = lcg_init(*rng + rng_offset + sample*0x68bc21eb); subsurface_scatter_step(kg, &sd, state.flag, sc, &lcg_state, false); } } @@ -922,14 +927,19 @@ __device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sam uint visibility = path_state_ray_visibility(kg, &state); #ifdef __HAIR__ - float difl = 0.0f; - if((kernel_data.cam.resolution == 1) && (state.flag & PATH_RAY_CAMERA)) { - float3 pixdiff = ray.dD.dx + ray.dD.dy; - /*pixdiff = pixdiff - dot(pixdiff, ray.D)*ray.D;*/ - difl = kernel_data.curve_kernel_data.minimum_width * len(pixdiff) * 0.5f; + float difl = 0.0f, extmax = 0.0f; + uint lcg_state = 0; + + if(kernel_data.bvh.have_curves) { + if((kernel_data.cam.resolution == 1) && (state.flag & PATH_RAY_CAMERA)) { + float3 pixdiff = ray.dD.dx + ray.dD.dy; + /*pixdiff = pixdiff - dot(pixdiff, ray.D)*ray.D;*/ + difl = kernel_data.curve_kernel_data.minimum_width * len(pixdiff) * 0.5f; + } + + extmax = kernel_data.curve_kernel_data.maximum_width; + lcg_state = lcg_init(*rng + rng_offset + sample*0x51633e2d); } - float extmax = kernel_data.curve_kernel_data.maximum_width; - uint lcg_state = lcg_init(*rng + rng_offset + sample); if(!scene_intersect(kg, &ray, visibility, &isect, &lcg_state, difl, extmax)) { #else @@ -1015,7 +1025,7 @@ __device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sam continue; /* set up random number generator */ - uint lcg_state = lcg_init(*rng + rng_offset + sample); + uint lcg_state = lcg_init(*rng + rng_offset + sample*0x68bc21eb); int num_samples = kernel_data.integrator.subsurface_samples; float num_samples_inv = 1.0f/num_samples; diff --git a/intern/cycles/kernel/kernel_subsurface.h b/intern/cycles/kernel/kernel_subsurface.h index 5fef9965c7f..f503c488a34 100644 --- a/intern/cycles/kernel/kernel_subsurface.h +++ b/intern/cycles/kernel/kernel_subsurface.h @@ -210,7 +210,7 @@ __device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd, int sta /* intersect with the same object. if multiple intersections are * found it will randomly pick one of them */ Intersection isect; - if(scene_intersect_subsurface(kg, &ray, &isect, sd->object, u6) == 0) + if(!scene_intersect_subsurface(kg, &ray, &isect, sd->object, u6)) continue; /* setup new shading point */ diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index d07bd4dc1c8..c8268dfea06 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -713,7 +713,10 @@ typedef struct KernelBVH { int root; int attributes_map_stride; int have_motion; - int pad2; + int have_curves; + int have_instancing; + + int pad1, pad2, pad3; } KernelBVH; typedef enum CurveFlag { diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index 17008b7a7f3..1a2780995e3 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -156,6 +156,7 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene map<Mesh*, float> surface_area_map; Scene::MotionType need_motion = scene->need_motion(device->info.advanced_shading); bool have_motion = false; + bool have_curves = false; objects = dscene->objects.resize(OBJECT_SIZE*scene->objects.size()); if(need_motion == Scene::MOTION_PASS) @@ -176,7 +177,7 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene float surface_area = 0.0f; float pass_id = ob->pass_id; float random_number = (float)ob->random_id * (1.0f/(float)0xFFFFFFFF); - + if(transform_uniform_scale(tfm, uniform_scale)) { map<Mesh*, float>::iterator it = surface_area_map.find(mesh); @@ -282,6 +283,10 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene flag |= SD_HOLDOUT_MASK; object_flag[i] = flag; + /* have curves */ + if(mesh->curves.size()) + have_curves = true; + i++; if(progress.get_cancel()) return; @@ -292,6 +297,8 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene device->tex_alloc("__objects_vector", dscene->objects_vector); dscene->data.bvh.have_motion = have_motion; + dscene->data.bvh.have_curves = have_curves; + dscene->data.bvh.have_instancing = true; } void ObjectManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) @@ -319,7 +326,7 @@ void ObjectManager::device_update(Device *device, DeviceScene *dscene, Scene *sc /* todo: do before to support getting object level coords? */ if(scene->params.bvh_type == SceneParams::BVH_STATIC) { progress.set_status("Updating Objects", "Applying Static Transformations"); - apply_static_transforms(scene, object_flag, progress); + apply_static_transforms(dscene, scene, object_flag, progress); } /* allocate object flag */ @@ -338,7 +345,7 @@ void ObjectManager::device_free(Device *device, DeviceScene *dscene) dscene->object_flag.clear(); } -void ObjectManager::apply_static_transforms(Scene *scene, uint *object_flag, Progress& progress) +void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, uint *object_flag, Progress& progress) { /* todo: normals and displacement should be done before applying transform! */ /* todo: create objects/meshes in right order! */ @@ -352,6 +359,7 @@ void ObjectManager::apply_static_transforms(Scene *scene, uint *object_flag, Pro bool motion_blur = false; #endif int i = 0; + bool have_instancing = false; foreach(Object *object, scene->objects) { map<Mesh*, int>::iterator it = mesh_users.find(object->mesh); @@ -377,10 +385,16 @@ void ObjectManager::apply_static_transforms(Scene *scene, uint *object_flag, Pro object_flag[i] |= SD_TRANSFORM_APPLIED; } + else + have_instancing = true; } + else + have_instancing = true; i++; } + + dscene->data.bvh.have_instancing = have_instancing; } void ObjectManager::tag_update(Scene *scene) diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h index 9ba500ca4d6..b3ab0e93b5c 100644 --- a/intern/cycles/render/object.h +++ b/intern/cycles/render/object.h @@ -79,7 +79,7 @@ public: void tag_update(Scene *scene); - void apply_static_transforms(Scene *scene, uint *object_flag, Progress& progress); + void apply_static_transforms(DeviceScene *dscene, Scene *scene, uint *object_flag, Progress& progress); }; CCL_NAMESPACE_END |