1 /*
2  * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
3  * and code copyright 2009-2012 Intel Corporation
4  *
5  * Modifications Copyright 2011-2013, Blender Foundation.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 #if BVH_FEATURE(BVH_HAIR)
21 #  define NODE_INTERSECT bvh_node_intersect
22 #else
23 #  define NODE_INTERSECT bvh_aligned_node_intersect
24 #endif
25 
26 /* This is a template BVH traversal function, where various features can be
27  * enabled/disabled. This way we can compile optimized versions for each case
28  * without new features slowing things down.
29  *
30  * BVH_HAIR: hair curve rendering
31  * BVH_MOTION: motion blur rendering
32  */
33 
34 #ifndef __KERNEL_GPU__
35 ccl_device
36 #else
37 ccl_device_inline
38 #endif
BVH_FUNCTION_FULL_NAME(BVH)39     bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
40                                      const Ray *ray,
41                                      Intersection *isect_array,
42                                      const uint visibility,
43                                      const uint max_hits,
44                                      uint *num_hits)
45 {
46   /* todo:
47    * - likely and unlikely for if() statements
48    * - test restrict attribute for pointers
49    */
50 
51   /* traversal stack in CUDA thread-local memory */
52   int traversal_stack[BVH_STACK_SIZE];
53   traversal_stack[0] = ENTRYPOINT_SENTINEL;
54 
55   /* traversal variables in registers */
56   int stack_ptr = 0;
57   int node_addr = kernel_data.bvh.root;
58 
59   /* ray parameters in registers */
60   const float tmax = ray->t;
61   float3 P = ray->P;
62   float3 dir = bvh_clamp_direction(ray->D);
63   float3 idir = bvh_inverse_direction(dir);
64   int object = OBJECT_NONE;
65   float isect_t = tmax;
66 
67 #if BVH_FEATURE(BVH_MOTION)
68   Transform ob_itfm;
69 #endif
70 
71   int num_hits_in_instance = 0;
72 
73   *num_hits = 0;
74   isect_array->t = tmax;
75 
76   /* traversal loop */
77   do {
78     do {
79       /* traverse internal nodes */
80       while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
81         int node_addr_child1, traverse_mask;
82         float dist[2];
83         float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
84 
85         traverse_mask = NODE_INTERSECT(kg,
86                                        P,
87 #if BVH_FEATURE(BVH_HAIR)
88                                        dir,
89 #endif
90                                        idir,
91                                        isect_t,
92                                        node_addr,
93                                        visibility,
94                                        dist);
95 
96         node_addr = __float_as_int(cnodes.z);
97         node_addr_child1 = __float_as_int(cnodes.w);
98 
99         if (traverse_mask == 3) {
100           /* Both children were intersected, push the farther one. */
101           bool is_closest_child1 = (dist[1] < dist[0]);
102           if (is_closest_child1) {
103             int tmp = node_addr;
104             node_addr = node_addr_child1;
105             node_addr_child1 = tmp;
106           }
107 
108           ++stack_ptr;
109           kernel_assert(stack_ptr < BVH_STACK_SIZE);
110           traversal_stack[stack_ptr] = node_addr_child1;
111         }
112         else {
113           /* One child was intersected. */
114           if (traverse_mask == 2) {
115             node_addr = node_addr_child1;
116           }
117           else if (traverse_mask == 0) {
118             /* Neither child was intersected. */
119             node_addr = traversal_stack[stack_ptr];
120             --stack_ptr;
121           }
122         }
123       }
124 
125       /* if node is leaf, fetch triangle list */
126       if (node_addr < 0) {
127         float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr - 1));
128         int prim_addr = __float_as_int(leaf.x);
129 
130         if (prim_addr >= 0) {
131           const int prim_addr2 = __float_as_int(leaf.y);
132           const uint type = __float_as_int(leaf.w);
133           const uint p_type = type & PRIMITIVE_ALL;
134 
135           /* pop */
136           node_addr = traversal_stack[stack_ptr];
137           --stack_ptr;
138 
139           /* primitive intersection */
140           while (prim_addr < prim_addr2) {
141             kernel_assert((kernel_tex_fetch(__prim_type, prim_addr) & PRIMITIVE_ALL) == p_type);
142             bool hit;
143 
144             /* todo: specialized intersect functions which don't fill in
145              * isect unless needed and check SD_HAS_TRANSPARENT_SHADOW?
146              * might give a few % performance improvement */
147 
148             switch (p_type) {
149               case PRIMITIVE_TRIANGLE: {
150                 hit = triangle_intersect(kg, isect_array, P, dir, visibility, object, prim_addr);
151                 break;
152               }
153 #if BVH_FEATURE(BVH_MOTION)
154               case PRIMITIVE_MOTION_TRIANGLE: {
155                 hit = motion_triangle_intersect(
156                     kg, isect_array, P, dir, ray->time, visibility, object, prim_addr);
157                 break;
158               }
159 #endif
160 #if BVH_FEATURE(BVH_HAIR)
161               case PRIMITIVE_CURVE_THICK:
162               case PRIMITIVE_MOTION_CURVE_THICK:
163               case PRIMITIVE_CURVE_RIBBON:
164               case PRIMITIVE_MOTION_CURVE_RIBBON: {
165                 const uint curve_type = kernel_tex_fetch(__prim_type, prim_addr);
166                 hit = curve_intersect(
167                     kg, isect_array, P, dir, visibility, object, prim_addr, ray->time, curve_type);
168                 break;
169               }
170 #endif
171               default: {
172                 hit = false;
173                 break;
174               }
175             }
176 
177             /* shadow ray early termination */
178             if (hit) {
179               /* detect if this surface has a shader with transparent shadows */
180 
181               /* todo: optimize so primitive visibility flag indicates if
182                * the primitive has a transparent shadow shader? */
183               int prim = kernel_tex_fetch(__prim_index, isect_array->prim);
184               int shader = 0;
185 
186 #ifdef __HAIR__
187               if (kernel_tex_fetch(__prim_type, isect_array->prim) & PRIMITIVE_ALL_TRIANGLE)
188 #endif
189               {
190                 shader = kernel_tex_fetch(__tri_shader, prim);
191               }
192 #ifdef __HAIR__
193               else {
194                 float4 str = kernel_tex_fetch(__curves, prim);
195                 shader = __float_as_int(str.z);
196               }
197 #endif
198               int flag = kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags;
199 
200               /* if no transparent shadows, all light is blocked */
201               if (!(flag & SD_HAS_TRANSPARENT_SHADOW)) {
202                 return true;
203               }
204               /* if maximum number of hits reached, block all light */
205               else if (*num_hits == max_hits) {
206                 return true;
207               }
208 
209               /* move on to next entry in intersections array */
210               isect_array++;
211               (*num_hits)++;
212               num_hits_in_instance++;
213 
214               isect_array->t = isect_t;
215             }
216 
217             prim_addr++;
218           }
219         }
220         else {
221           /* instance push */
222           object = kernel_tex_fetch(__prim_object, -prim_addr - 1);
223 
224 #if BVH_FEATURE(BVH_MOTION)
225           isect_t = bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, isect_t, &ob_itfm);
226 #else
227           isect_t = bvh_instance_push(kg, object, ray, &P, &dir, &idir, isect_t);
228 #endif
229 
230           num_hits_in_instance = 0;
231           isect_array->t = isect_t;
232 
233           ++stack_ptr;
234           kernel_assert(stack_ptr < BVH_STACK_SIZE);
235           traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
236 
237           node_addr = kernel_tex_fetch(__object_node, object);
238         }
239       }
240     } while (node_addr != ENTRYPOINT_SENTINEL);
241 
242     if (stack_ptr >= 0) {
243       kernel_assert(object != OBJECT_NONE);
244 
245       /* Instance pop. */
246       if (num_hits_in_instance) {
247         float t_fac;
248 
249 #if BVH_FEATURE(BVH_MOTION)
250         bvh_instance_motion_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac, &ob_itfm);
251 #else
252         bvh_instance_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac);
253 #endif
254 
255         /* scale isect->t to adjust for instancing */
256         for (int i = 0; i < num_hits_in_instance; i++) {
257           (isect_array - i - 1)->t *= t_fac;
258         }
259       }
260       else {
261 #if BVH_FEATURE(BVH_MOTION)
262         bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, FLT_MAX, &ob_itfm);
263 #else
264         bvh_instance_pop(kg, object, ray, &P, &dir, &idir, FLT_MAX);
265 #endif
266       }
267 
268       isect_t = tmax;
269       isect_array->t = isect_t;
270 
271       object = OBJECT_NONE;
272       node_addr = traversal_stack[stack_ptr];
273       --stack_ptr;
274     }
275   } while (node_addr != ENTRYPOINT_SENTINEL);
276 
277   return false;
278 }
279 
BVH_FUNCTION_NAME(KernelGlobals * kg,const Ray * ray,Intersection * isect_array,const uint visibility,const uint max_hits,uint * num_hits)280 ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg,
281                                          const Ray *ray,
282                                          Intersection *isect_array,
283                                          const uint visibility,
284                                          const uint max_hits,
285                                          uint *num_hits)
286 {
287   return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, isect_array, visibility, max_hits, num_hits);
288 }
289 
290 #undef BVH_FUNCTION_NAME
291 #undef BVH_FUNCTION_FEATURES
292 #undef NODE_INTERSECT
293