Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/bvh/bvh_traversal_all.h
- This file was moved from intern/cycles/kernel/bvh/bvh_volume_all.h.
| /* | /* | ||||
| * Adapted from code Copyright 2009-2010 NVIDIA Corporation, | * Adapted from code Copyright 2009-2010 NVIDIA Corporation, | ||||
| * and code copyright 2009-2012 Intel Corporation | * and code copyright 2009-2012 Intel Corporation | ||||
| * | * | ||||
| * Modifications Copyright 2011-2014, Blender Foundation. | * Modifications Copyright 2011-2016, Blender Foundation. | ||||
| * | * | ||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| * you may not use this file except in compliance with the License. | * you may not use this file except in compliance with the License. | ||||
| * You may obtain a copy of the License at | * You may obtain a copy of the License at | ||||
| * | * | ||||
| * http://www.apache.org/licenses/LICENSE-2.0 | * http://www.apache.org/licenses/LICENSE-2.0 | ||||
| * | * | ||||
| * Unless required by applicable law or agreed to in writing, software | * Unless required by applicable law or agreed to in writing, software | ||||
| * distributed under the License is distributed on an "AS IS" BASIS, | * distributed under the License is distributed on an "AS IS" BASIS, | ||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| * See the License for the specific language governing permissions and | * See the License for the specific language governing permissions and | ||||
| * limitations under the License. | * limitations under the License. | ||||
| */ | */ | ||||
| #ifdef __QBVH__ | #ifdef __QBVH__ | ||||
| # include "qbvh_volume_all.h" | # include "qbvh_traversal_all.h" | ||||
| #endif | #endif | ||||
| #if BVH_FEATURE(BVH_HAIR) | #if BVH_FEATURE(BVH_HAIR) | ||||
| # define NODE_INTERSECT bvh_node_intersect | # define NODE_INTERSECT bvh_node_intersect | ||||
| #else | #else | ||||
| # define NODE_INTERSECT bvh_aligned_node_intersect | # define NODE_INTERSECT bvh_aligned_node_intersect | ||||
| #endif | #endif | ||||
| /* This is a template BVH traversal function for volumes, where | /* This is a template BVH traversal function for cases when it's required | ||||
| * various features can be enabled/disabled. This way we can compile optimized | * to record multiple intersections at a single go. Actual logic about what | ||||
| * versions for each case without new features slowing things down. | * to do when intersection is found is templated via preprocessor definitions. | ||||
| * | |||||
| * Used for things like: | |||||
| * - Record all transparent shadow intersections. | |||||
| * - Record all volume object intersections. | |||||
| * | * | ||||
| * BVH_INSTANCING: object instancing | * BVH_INSTANCING: object instancing | ||||
| * BVH_HAIR: hair curve rendering | |||||
| * BVH_MOTION: motion blur rendering | * BVH_MOTION: motion blur rendering | ||||
| * | |||||
| */ | */ | ||||
| #ifndef __KERNEL_GPU__ | #ifndef __KERNEL_GPU__ | ||||
| ccl_device | ccl_device | ||||
| #else | #else | ||||
| ccl_device_inline | ccl_device_inline | ||||
| #endif | #endif | ||||
| uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, | bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, | ||||
| const Ray *ray, | const Ray *ray, | ||||
| Intersection *isect_array, | Intersection *isect_array, | ||||
| const uint max_hits, | const uint max_hits, | ||||
| const uint visibility) | const uint visibility, | ||||
| uint *num_hits) | |||||
| { | { | ||||
| /* todo: | /* TODO(sergey): | ||||
| * - test if pushing distance on the stack helps (for non shadow rays) | * - test if pushing distance on the stack helps (for non shadow rays) | ||||
| * - separate version for shadow rays | * - separate version for shadow rays | ||||
| * - likely and unlikely for if() statements | * - likely and unlikely for if() statements | ||||
| * - test restrict attribute for pointers | * - test restrict attribute for pointers | ||||
| */ | */ | ||||
| /* traversal stack in CUDA thread-local memory */ | /* traversal stack in CUDA thread-local memory */ | ||||
| int traversal_stack[BVH_STACK_SIZE]; | int traversal_stack[BVH_STACK_SIZE]; | ||||
| Show All 14 Lines | |||||
| #if BVH_FEATURE(BVH_MOTION) | #if BVH_FEATURE(BVH_MOTION) | ||||
| Transform ob_itfm; | Transform ob_itfm; | ||||
| #endif | #endif | ||||
| #if BVH_FEATURE(BVH_INSTANCING) | #if BVH_FEATURE(BVH_INSTANCING) | ||||
| int num_hits_in_instance = 0; | int num_hits_in_instance = 0; | ||||
| #endif | #endif | ||||
| uint num_hits = 0; | *num_hits = 0; | ||||
| isect_array->t = tmax; | isect_array->t = tmax; | ||||
| #if defined(__KERNEL_SSE2__) | #if defined(__KERNEL_SSE2__) | ||||
| const shuffle_swap_t shuf_identity = shuffle_swap_identity(); | const shuffle_swap_t shuf_identity = shuffle_swap_identity(); | ||||
| const shuffle_swap_t shuf_swap = shuffle_swap_swap(); | const shuffle_swap_t shuf_swap = shuffle_swap_swap(); | ||||
| const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000)); | const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000)); | ||||
| ssef Psplat[3], idirsplat[3]; | ssef Psplat[3], idirsplat[3]; | ||||
| Show All 9 Lines | # endif | ||||
| ssef tsplat(0.0f, 0.0f, -isect_t, -isect_t); | ssef tsplat(0.0f, 0.0f, -isect_t, -isect_t); | ||||
| gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); | gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); | ||||
| #endif /* __KERNEL_SSE2__ */ | #endif /* __KERNEL_SSE2__ */ | ||||
| IsectPrecalc isect_precalc; | IsectPrecalc isect_precalc; | ||||
| triangle_intersect_precalc(dir, &isect_precalc); | triangle_intersect_precalc(dir, &isect_precalc); | ||||
| /* traversal loop */ | /* Traversal loop. */ | ||||
| do { | do { | ||||
| do { | do { | ||||
| /* traverse internal nodes */ | /* traverse internal nodes */ | ||||
| while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { | while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { | ||||
| int node_addr_child1, traverse_mask; | int node_addr_child1, traverse_mask; | ||||
| float dist[2]; | float dist[2]; | ||||
| float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); | float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); | ||||
| #if !defined(__KERNEL_SSE2__) | #if !defined(__KERNEL_SSE2__) | ||||
| traverse_mask = NODE_INTERSECT(kg, | traverse_mask = NODE_INTERSECT(kg, | ||||
| P, | P, | ||||
| # if BVH_FEATURE(BVH_HAIR) | # if BVH_FEATURE(BVH_HAIR) | ||||
| dir, | dir, | ||||
| # endif | # endif | ||||
| idir, | idir, | ||||
| isect_t, | isect_t, | ||||
| node_addr, | node_addr, | ||||
| visibility, | visibility, | ||||
| dist); | dist); | ||||
| #else // __KERNEL_SSE2__ | #else /* __KERNEL_SSE2__ */ | ||||
| traverse_mask = NODE_INTERSECT(kg, | traverse_mask = NODE_INTERSECT(kg, | ||||
| P, | P, | ||||
| dir, | dir, | ||||
| # if BVH_FEATURE(BVH_HAIR) | # if BVH_FEATURE(BVH_HAIR) | ||||
| tnear, | tnear, | ||||
| tfar, | tfar, | ||||
| # endif | # endif | ||||
| tsplat, | tsplat, | ||||
| Psplat, | Psplat, | ||||
| idirsplat, | idirsplat, | ||||
| shufflexyz, | shufflexyz, | ||||
| node_addr, | node_addr, | ||||
| visibility, | visibility, | ||||
| dist); | dist); | ||||
| #endif // __KERNEL_SSE2__ | #endif /* __KERNEL_SSE2__ */ | ||||
| node_addr = __float_as_int(cnodes.z); | node_addr = __float_as_int(cnodes.z); | ||||
| node_addr_child1 = __float_as_int(cnodes.w); | node_addr_child1 = __float_as_int(cnodes.w); | ||||
| if(traverse_mask == 3) { | if(traverse_mask == 3) { | ||||
| /* Both children were intersected, push the farther one. */ | /* Both children were intersected, push the farther one. */ | ||||
| bool is_closest_child1 = (dist[1] < dist[0]); | bool is_closest_child1 = (dist[1] < dist[0]); | ||||
| if(is_closest_child1) { | if(is_closest_child1) { | ||||
| Show All 14 Lines | #endif /* __KERNEL_SSE2__ */ | ||||
| else if(traverse_mask == 0) { | else if(traverse_mask == 0) { | ||||
| /* Neither child was intersected. */ | /* Neither child was intersected. */ | ||||
| node_addr = traversal_stack[stack_ptr]; | node_addr = traversal_stack[stack_ptr]; | ||||
| --stack_ptr; | --stack_ptr; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* if node is leaf, fetch triangle list */ | /* If node is leaf, fetch triangle list. */ | ||||
| if(node_addr < 0) { | if(node_addr < 0) { | ||||
| float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); | float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); | ||||
| int prim_addr = __float_as_int(leaf.x); | int prim_addr = __float_as_int(leaf.x); | ||||
| #if BVH_FEATURE(BVH_INSTANCING) | #if BVH_FEATURE(BVH_INSTANCING) | ||||
| if(prim_addr >= 0) { | if(prim_addr >= 0) { | ||||
| #endif | #endif | ||||
| const int prim_addr2 = __float_as_int(leaf.y); | const int prim_addr2 = __float_as_int(leaf.y); | ||||
| const uint type = __float_as_int(leaf.w); | const uint type = __float_as_int(leaf.w); | ||||
| bool hit; | const uint p_type = type & PRIMITIVE_ALL; | ||||
| /* pop */ | /* Pop. */ | ||||
| node_addr = traversal_stack[stack_ptr]; | node_addr = traversal_stack[stack_ptr]; | ||||
| --stack_ptr; | --stack_ptr; | ||||
| /* primitive intersection */ | /* Primitive intersection. */ | ||||
| switch(type & PRIMITIVE_ALL) { | while(prim_addr < prim_addr2) { | ||||
| case PRIMITIVE_TRIANGLE: { | |||||
| /* intersect ray against primitive */ | |||||
| for(; prim_addr < prim_addr2; prim_addr++) { | |||||
| kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); | kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); | ||||
| /* only primitives from volume object */ | bool hit; | ||||
| uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; | if(BVH_SKIP_PRIMITIVE_INTERSECTION) { | ||||
| int object_flag = kernel_tex_fetch(__object_flag, tri_object); | prim_addr++; | ||||
| if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { | |||||
| continue; | continue; | ||||
| } | } | ||||
| switch(p_type) { | |||||
| case PRIMITIVE_TRIANGLE: { | |||||
| hit = triangle_intersect(kg, | hit = triangle_intersect(kg, | ||||
| &isect_precalc, | &isect_precalc, | ||||
| isect_array, | isect_array, | ||||
| P, | P, | ||||
| visibility, | visibility, | ||||
| object, | object, | ||||
| prim_addr); | prim_addr); | ||||
| if(hit) { | |||||
| /* Move on to next entry in intersections array. */ | |||||
| isect_array++; | |||||
| num_hits++; | |||||
| #if BVH_FEATURE(BVH_INSTANCING) | |||||
| num_hits_in_instance++; | |||||
| #endif | |||||
| isect_array->t = isect_t; | |||||
| if(num_hits == max_hits) { | |||||
| #if BVH_FEATURE(BVH_INSTANCING) | |||||
| # if BVH_FEATURE(BVH_MOTION) | |||||
| float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); | |||||
| # else | |||||
| Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM); | |||||
| float t_fac = 1.0f / len(transform_direction(&itfm, dir)); | |||||
| # endif | |||||
| for(int i = 0; i < num_hits_in_instance; i++) { | |||||
| (isect_array-i-1)->t *= t_fac; | |||||
| } | |||||
| #endif /* BVH_FEATURE(BVH_INSTANCING) */ | |||||
| return num_hits; | |||||
| } | |||||
| } | |||||
| } | |||||
| break; | break; | ||||
| } | } | ||||
| #if BVH_FEATURE(BVH_MOTION) | #if BVH_FEATURE(BVH_MOTION) | ||||
| case PRIMITIVE_MOTION_TRIANGLE: { | case PRIMITIVE_MOTION_TRIANGLE: { | ||||
| /* intersect ray against primitive */ | |||||
| for(; prim_addr < prim_addr2; prim_addr++) { | |||||
| kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); | |||||
| /* only primitives from volume object */ | |||||
| uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; | |||||
| int object_flag = kernel_tex_fetch(__object_flag, tri_object); | |||||
| if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { | |||||
| continue; | |||||
| } | |||||
| hit = motion_triangle_intersect(kg, | hit = motion_triangle_intersect(kg, | ||||
| isect_array, | isect_array, | ||||
| P, | P, | ||||
| dir, | dir, | ||||
| ray->time, | ray->time, | ||||
| visibility, | visibility, | ||||
| object, | object, | ||||
| prim_addr); | prim_addr); | ||||
| break; | |||||
| } | |||||
| #endif | |||||
| #if BVH_FEATURE(BVH_HAIR) | |||||
| case PRIMITIVE_CURVE: | |||||
| case PRIMITIVE_MOTION_CURVE: { | |||||
| if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) { | |||||
| hit = bvh_cardinal_curve_intersect(kg, | |||||
| isect_array, | |||||
| P, | |||||
| dir, | |||||
| visibility, | |||||
| object, | |||||
| prim_addr, | |||||
| ray->time, | |||||
| type, | |||||
| NULL, | |||||
| 0, 0); | |||||
| } | |||||
| else { | |||||
| hit = bvh_curve_intersect(kg, | |||||
| isect_array, | |||||
| P, | |||||
| dir, | |||||
| visibility, | |||||
| object, | |||||
| prim_addr, | |||||
| ray->time, | |||||
| type, | |||||
| NULL, | |||||
| 0, 0); | |||||
| } | |||||
| break; | |||||
| } | |||||
| #endif | |||||
| default: { | |||||
| hit = false; | |||||
| break; | |||||
| } | |||||
| } | |||||
| if(hit) { | if(hit) { | ||||
| /* Early ray termination. */ | |||||
| if(BVH_EARLY_RAY_TERMINATION_CONDITION) { | |||||
| return true; | |||||
| } | |||||
| /* Move on to next entry in intersections array. */ | /* Move on to next entry in intersections array. */ | ||||
| isect_array++; | isect_array++; | ||||
| num_hits++; | (*num_hits)++; | ||||
| # if BVH_FEATURE(BVH_INSTANCING) | #if BVH_FEATURE(BVH_INSTANCING) | ||||
| num_hits_in_instance++; | num_hits_in_instance++; | ||||
| # endif | #endif | ||||
| isect_array->t = isect_t; | /* TODO(sergey): Think of a better name for BVH_RESCALE_ON_OVERFLOW. */ | ||||
| if(num_hits == max_hits) { | # if BVH_FEATURE(BVH_RESCALE_ON_OVERFLOW) | ||||
| if(*num_hits == max_hits) { | |||||
| # if BVH_FEATURE(BVH_INSTANCING) | # if BVH_FEATURE(BVH_INSTANCING) | ||||
| # if BVH_FEATURE(BVH_MOTION) | # if BVH_FEATURE(BVH_MOTION) | ||||
| float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); | float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); | ||||
| # else | # else | ||||
| Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM); | Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM); | ||||
| float t_fac = 1.0f / len(transform_direction(&itfm, dir)); | float t_fac = 1.0f / len(transform_direction(&itfm, dir)); | ||||
| # endif | # endif | ||||
| for(int i = 0; i < num_hits_in_instance; i++) { | for(int i = 0; i < num_hits_in_instance; i++) { | ||||
| (isect_array-i-1)->t *= t_fac; | (isect_array-i-1)->t *= t_fac; | ||||
| } | } | ||||
| # endif /* BVH_FEATURE(BVH_INSTANCING) */ | # endif /* BVH_FEATURE(BVH_INSTANCING) */ | ||||
| return num_hits; | return num_hits; | ||||
| } | } | ||||
| #endif /* BVH_RESCALE_ON_OVERFLOW */ | |||||
| isect_array->t = isect_t; | |||||
| } | } | ||||
| } | /* Move to intersection of the next primitive */ | ||||
| break; | prim_addr++; | ||||
| } | |||||
| #endif /* BVH_MOTION */ | |||||
| default: { | |||||
| break; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| #if BVH_FEATURE(BVH_INSTANCING) | #if BVH_FEATURE(BVH_INSTANCING) | ||||
| else { | else { | ||||
| /* instance push */ | /* instance push */ | ||||
| object = kernel_tex_fetch(__prim_object, -prim_addr-1); | object = kernel_tex_fetch(__prim_object, -prim_addr-1); | ||||
| int object_flag = kernel_tex_fetch(__object_flag, object); | if((BVH_OBJECT_PUSH_CONDITION)) { | ||||
| if(object_flag & SD_OBJECT_HAS_VOLUME) { | |||||
| # if BVH_FEATURE(BVH_MOTION) | # if BVH_FEATURE(BVH_MOTION) | ||||
| bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_itfm); | bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_itfm); | ||||
| # else | # else | ||||
| bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect_t); | bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect_t); | ||||
| # endif | # endif | ||||
| triangle_intersect_precalc(dir, &isect_precalc); | triangle_intersect_precalc(dir, &isect_precalc); | ||||
| num_hits_in_instance = 0; | num_hits_in_instance = 0; | ||||
| ▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | # endif | ||||
| object = OBJECT_NONE; | object = OBJECT_NONE; | ||||
| node_addr = traversal_stack[stack_ptr]; | node_addr = traversal_stack[stack_ptr]; | ||||
| --stack_ptr; | --stack_ptr; | ||||
| } | } | ||||
| #endif /* FEATURE(BVH_INSTANCING) */ | #endif /* FEATURE(BVH_INSTANCING) */ | ||||
| } while(node_addr != ENTRYPOINT_SENTINEL); | } while(node_addr != ENTRYPOINT_SENTINEL); | ||||
| return num_hits; | return false; | ||||
| } | } | ||||
| ccl_device_inline uint BVH_FUNCTION_NAME(KernelGlobals *kg, | ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg, | ||||
| const Ray *ray, | const Ray *ray, | ||||
| Intersection *isect_array, | Intersection *isect_array, | ||||
| const uint max_hits, | const uint max_hits, | ||||
| const uint visibility) | const uint visibility, | ||||
| uint *num_hits) | |||||
| { | { | ||||
| #ifdef __QBVH__ | #ifdef __QBVH__ | ||||
| if(kernel_data.bvh.use_qbvh) { | if(kernel_data.bvh.use_qbvh) { | ||||
| return BVH_FUNCTION_FULL_NAME(QBVH)(kg, | return BVH_FUNCTION_FULL_NAME(QBVH)(kg, | ||||
| ray, | ray, | ||||
| isect_array, | isect_array, | ||||
| max_hits, | max_hits, | ||||
| visibility); | visibility, | ||||
| num_hits); | |||||
| } | } | ||||
| else | else | ||||
| #endif | #endif | ||||
| { | { | ||||
| kernel_assert(kernel_data.bvh.use_qbvh == false); | kernel_assert(kernel_data.bvh.use_qbvh == false); | ||||
| return BVH_FUNCTION_FULL_NAME(BVH)(kg, | return BVH_FUNCTION_FULL_NAME(BVH)(kg, | ||||
| ray, | ray, | ||||
| isect_array, | isect_array, | ||||
| max_hits, | max_hits, | ||||
| visibility); | visibility, | ||||
| num_hits); | |||||
| } | } | ||||
| } | } | ||||
| #undef BVH_FUNCTION_NAME | #undef BVH_FUNCTION_NAME | ||||
| #undef BVH_FUNCTION_FEATURES | #undef BVH_FUNCTION_FEATURES | ||||
| #undef NODE_INTERSECT | #undef NODE_INTERSECT | ||||