Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/bvh/qbvh_traversal_all.h
- This file was moved from intern/cycles/kernel/bvh/qbvh_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. | ||||
| */ | */ | ||||
| /* 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 | ||||
| * | |||||
| */ | */ | ||||
| #if BVH_FEATURE(BVH_HAIR) | #if BVH_FEATURE(BVH_HAIR) | ||||
| # define NODE_INTERSECT qbvh_node_intersect | # define NODE_INTERSECT qbvh_node_intersect | ||||
| #else | #else | ||||
| # define NODE_INTERSECT qbvh_aligned_node_intersect | # define NODE_INTERSECT qbvh_aligned_node_intersect | ||||
| #endif | #endif | ||||
| ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, | ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(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(sergey): | /* TODO(sergey): | ||||
| * - Test if pushing distance on the stack helps. | * - Test if pushing distance on the stack helps. | ||||
| * - Likely and unlikely for if() statements. | * - Likely and unlikely for if() statements. | ||||
| * - Test restrict attribute for pointers. | * - Test ccl_restrict attribute for pointers. | ||||
| */ | */ | ||||
| /* Traversal stack in CUDA thread-local memory. */ | /* Traversal stack in CUDA thread-local memory. */ | ||||
| QBVHStackItem traversal_stack[BVH_QSTACK_SIZE]; | QBVHStackItem traversal_stack[BVH_QSTACK_SIZE]; | ||||
| traversal_stack[0].addr = ENTRYPOINT_SENTINEL; | traversal_stack[0].addr = ENTRYPOINT_SENTINEL; | ||||
| /* Traversal variables in registers. */ | /* Traversal variables in registers. */ | ||||
| int stack_ptr = 0; | int stack_ptr = 0; | ||||
| int node_addr = kernel_data.bvh.root; | int node_addr = kernel_data.bvh.root; | ||||
| /* Ray parameters in registers. */ | /* Ray parameters in registers. */ | ||||
| const float tmax = ray->t; | const float tmax = ray->t; | ||||
| float3 P = ray->P; | float3 P = ray->P; | ||||
| float3 dir = bvh_clamp_direction(ray->D); | float3 dir = bvh_clamp_direction(ray->D); | ||||
| float3 idir = bvh_inverse_direction(dir); | float3 idir = bvh_inverse_direction(dir); | ||||
| int object = OBJECT_NONE; | int object = OBJECT_NONE; | ||||
| float isect_t = tmax; | float isect_t = tmax; | ||||
| #if BVH_FEATURE(BVH_MOTION) | #if BVH_FEATURE(BVH_MOTION) | ||||
| Transform ob_itfm; | Transform ob_itfm; | ||||
| #endif | #endif | ||||
| uint num_hits = 0; | *num_hits = 0; | ||||
| isect_array->t = tmax; | isect_array->t = tmax; | ||||
| #ifndef __KERNEL_SSE41__ | #ifndef __KERNEL_SSE41__ | ||||
| if(!isfinite(P.x)) { | if(!isfinite(P.x)) { | ||||
| return 0; | return false; | ||||
| } | } | ||||
| #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 | ||||
| ssef tnear(0.0f), tfar(isect_t); | ssef tnear(0.0f), tfar(isect_t); | ||||
| ▲ Show 20 Lines • Show All 156 Lines • ▼ Show 20 Lines | #endif | ||||
| node_addr = traversal_stack[stack_ptr].addr; | node_addr = traversal_stack[stack_ptr].addr; | ||||
| --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)); | ||||
| #ifdef __VISIBILITY_FLAG__ | |||||
| if((__float_as_uint(leaf.z) & visibility) == 0) { | if((__float_as_uint(leaf.z) & visibility) == 0) { | ||||
| /* Pop. */ | /* Pop. */ | ||||
| node_addr = traversal_stack[stack_ptr].addr; | node_addr = traversal_stack[stack_ptr].addr; | ||||
| --stack_ptr; | --stack_ptr; | ||||
| continue; | continue; | ||||
| } | } | ||||
| #endif | |||||
| 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 | ||||
| int prim_addr2 = __float_as_int(leaf.y); | int prim_addr2 = __float_as_int(leaf.y); | ||||
| const uint type = __float_as_int(leaf.w); | const uint type = __float_as_int(leaf.w); | ||||
| const uint p_type = type & PRIMITIVE_ALL; | const uint p_type = type & PRIMITIVE_ALL; | ||||
| bool hit; | |||||
| /* Pop. */ | /* Pop. */ | ||||
| node_addr = traversal_stack[stack_ptr].addr; | node_addr = traversal_stack[stack_ptr].addr; | ||||
| --stack_ptr; | --stack_ptr; | ||||
| /* Primitive intersection. */ | /* Primitive intersection. */ | ||||
| switch(p_type) { | while(prim_addr < prim_addr2) { | ||||
| case PRIMITIVE_TRIANGLE: { | |||||
| 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. */ | if(BVH_SKIP_PRIMITIVE_INTERSECTION) { | ||||
| uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; | prim_addr++; | ||||
| int object_flag = kernel_tex_fetch(__object_flag, tri_object); | |||||
| if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { | |||||
| continue; | continue; | ||||
| } | } | ||||
| /* Intersect ray against primitive. */ | bool hit; | ||||
| hit = triangle_intersect(kg, &isect_precalc, isect_array, P, visibility, object, prim_addr); | switch(p_type) { | ||||
| if(hit) { | case PRIMITIVE_TRIANGLE: { | ||||
| /* Move on to next entry in intersections array. */ | hit = triangle_intersect(kg, | ||||
| isect_array++; | &isect_precalc, | ||||
| num_hits++; | isect_array, | ||||
| #if BVH_FEATURE(BVH_INSTANCING) | P, | ||||
| num_hits_in_instance++; | visibility, | ||||
| #endif | object, | ||||
| isect_array->t = isect_t; | prim_addr); | ||||
| if(num_hits == max_hits) { | break; | ||||
| #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)); | case PRIMITIVE_MOTION_TRIANGLE: { | ||||
| # else | hit = motion_triangle_intersect(kg, | ||||
| Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM); | isect_array, | ||||
| float t_fac = 1.0f / len(transform_direction(&itfm, dir)); | P, | ||||
| # endif | dir, | ||||
| for(int i = 0; i < num_hits_in_instance; i++) { | ray->time, | ||||
| (isect_array-i-1)->t *= t_fac; | visibility, | ||||
| object, | |||||
| prim_addr); | |||||
| break; | |||||
| } | } | ||||
| #endif /* BVH_FEATURE(BVH_INSTANCING) */ | #endif | ||||
| return num_hits; | #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; | break; | ||||
| } | } | ||||
| #if BVH_FEATURE(BVH_MOTION) | |||||
| case PRIMITIVE_MOTION_TRIANGLE: { | |||||
| 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; | |||||
| } | } | ||||
| /* Intersect ray against primitive. */ | |||||
| hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, visibility, object, prim_addr); | |||||
| 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 true; | ||||
| } | |||||
| } | |||||
| } | } | ||||
| break; | #endif /* BVH_RESCALE_ON_OVERFLOW */ | ||||
| isect_array->t = isect_t; | |||||
| } | } | ||||
| #endif | /* Move to intersection of the next primitive */ | ||||
| prim_addr++; | |||||
| } | } | ||||
| } | } | ||||
| #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 | ||||
| if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } | if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } | ||||
| if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } | if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } | ||||
| if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } | if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } | ||||
| tfar = ssef(isect_t); | tfar = ssef(isect_t); | ||||
| idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); | |||||
| # if BVH_FEATURE(BVH_HAIR) | # if BVH_FEATURE(BVH_HAIR) | ||||
| dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); | dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); | ||||
| # endif | # endif | ||||
| idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); | |||||
| # ifdef __KERNEL_AVX2__ | # ifdef __KERNEL_AVX2__ | ||||
| P_idir = P*idir; | P_idir = P*idir; | ||||
| P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); | P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); | ||||
| # endif | # endif | ||||
| # if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) | # if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) | ||||
| org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); | org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); | ||||
| # endif | # endif | ||||
| ▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | # endif | ||||
| object = OBJECT_NONE; | object = OBJECT_NONE; | ||||
| node_addr = traversal_stack[stack_ptr].addr; | node_addr = traversal_stack[stack_ptr].addr; | ||||
| --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; | ||||
| } | } | ||||
| #undef NODE_INTERSECT | #undef NODE_INTERSECT | ||||