Cycles: Simplify code around debug stats in BVH traversing
[blender.git] / intern / cycles / kernel / geom / geom_bvh.h
1 /*
2  * Adapted from code Copyright 2009-2010 NVIDIA Corporation
3  * Modifications Copyright 2011, Blender Foundation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 /* BVH
19  *
20  * Bounding volume hierarchy for ray tracing. We compile different variations
21  * of the same BVH traversal function for faster rendering when some types of
22  * primitives are not needed, using #includes to work around the lack of
23  * C++ templates in OpenCL.
24  *
25  * Originally based on "Understanding the Efficiency of Ray Traversal on GPUs",
26  * the code has been extended and modified to support more primitives and work
27  * with CPU/CUDA/OpenCL. */
28
29 CCL_NAMESPACE_BEGIN
30
31 /* Don't inline intersect functions on GPU, this is faster */
32 #ifdef __KERNEL_GPU__
33 #  define ccl_device_intersect ccl_device_noinline
34 #else
35 #  define ccl_device_intersect ccl_device_inline
36 #endif
37
38 /* BVH intersection function variations */
39
40 #define BVH_INSTANCING                  1
41 #define BVH_MOTION                              2
42 #define BVH_HAIR                                4
43 #define BVH_HAIR_MINIMUM_WIDTH  8
44
45 #define BVH_NAME_JOIN(x,y) x ## _ ## y
46 #define BVH_NAME_EVAL(x,y) BVH_NAME_JOIN(x,y)
47 #define BVH_FUNCTION_FULL_NAME(prefix) BVH_NAME_EVAL(prefix, BVH_FUNCTION_NAME)
48
49 #define BVH_FEATURE(f) (((BVH_FUNCTION_FEATURES) & (f)) != 0)
50
51 /* Debugging heleprs */
52 #ifdef __KERNEL_DEBUG__
53 #  define BVH_DEBUG_INIT() \
54         do { \
55                 isect->num_traversal_steps = 0; \
56                 isect->num_traversed_instances = 0; \
57         } while(0)
58 #  define BVH_DEBUG_NEXT_STEP() \
59         do { \
60                 ++isect->num_traversal_steps; \
61         } while(0)
62 #  define BVH_DEBUG_NEXT_INSTANCE() \
63         do { \
64                 ++isect->num_traversed_instances; \
65         } while(0)
66 #else  /* __KERNEL_DEBUG__ */
67 #  define BVH_DEBUG_INIT()
68 #  define BVH_DEBUG_NEXT_STEP()
69 #  define BVH_DEBUG_NEXT_INSTANCE()
70 #endif  /* __KERNEL_DEBUG__ */
71
72
73 /* Common QBVH functions. */
74 #ifdef __QBVH__
75 #  include "geom_qbvh.h"
76 #endif
77
78 /* Regular BVH traversal */
79
80 #define BVH_FUNCTION_NAME bvh_intersect
81 #define BVH_FUNCTION_FEATURES 0
82 #include "geom_bvh_traversal.h"
83
84 #if defined(__INSTANCING__)
85 #  define BVH_FUNCTION_NAME bvh_intersect_instancing
86 #  define BVH_FUNCTION_FEATURES BVH_INSTANCING
87 #  include "geom_bvh_traversal.h"
88 #endif
89
90 #if defined(__HAIR__)
91 #  define BVH_FUNCTION_NAME bvh_intersect_hair
92 #  define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH
93 #  include "geom_bvh_traversal.h"
94 #endif
95
96 #if defined(__OBJECT_MOTION__)
97 #  define BVH_FUNCTION_NAME bvh_intersect_motion
98 #  define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
99 #  include "geom_bvh_traversal.h"
100 #endif
101
102 #if defined(__HAIR__) && defined(__OBJECT_MOTION__)
103 #  define BVH_FUNCTION_NAME bvh_intersect_hair_motion
104 #  define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH|BVH_MOTION
105 #  include "geom_bvh_traversal.h"
106 #endif
107
108 /* Subsurface scattering BVH traversal */
109
110 #if defined(__SUBSURFACE__)
111 #  define BVH_FUNCTION_NAME bvh_intersect_subsurface
112 #  define BVH_FUNCTION_FEATURES 0
113 #  include "geom_bvh_subsurface.h"
114 #endif
115
116 #if defined(__SUBSURFACE__) && defined(__OBJECT_MOTION__)
117 #  define BVH_FUNCTION_NAME bvh_intersect_subsurface_motion
118 #  define BVH_FUNCTION_FEATURES BVH_MOTION
119 #  include "geom_bvh_subsurface.h"
120 #endif
121
122 /* Volume BVH traversal */
123
124 #if defined(__VOLUME__)
125 #  define BVH_FUNCTION_NAME bvh_intersect_volume
126 #  define BVH_FUNCTION_FEATURES 0
127 #  include "geom_bvh_volume.h"
128 #endif
129
130 #if defined(__VOLUME__) && defined(__INSTANCING__)
131 #  define BVH_FUNCTION_NAME bvh_intersect_volume_instancing
132 #  define BVH_FUNCTION_FEATURES BVH_INSTANCING
133 #  include "geom_bvh_volume.h"
134 #endif
135
136 #if defined(__VOLUME__) && defined(__OBJECT_MOTION__)
137 #  define BVH_FUNCTION_NAME bvh_intersect_volume_motion
138 #  define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
139 #  include "geom_bvh_volume.h"
140 #endif
141
142 /* Record all intersections - Shadow BVH traversal */
143
144 #if defined(__SHADOW_RECORD_ALL__)
145 #  define BVH_FUNCTION_NAME bvh_intersect_shadow_all
146 #  define BVH_FUNCTION_FEATURES 0
147 #  include "geom_bvh_shadow.h"
148 #endif
149
150 #if defined(__SHADOW_RECORD_ALL__) && defined(__INSTANCING__)
151 #  define BVH_FUNCTION_NAME bvh_intersect_shadow_all_instancing
152 #  define BVH_FUNCTION_FEATURES BVH_INSTANCING
153 #  include "geom_bvh_shadow.h"
154 #endif
155
156 #if defined(__SHADOW_RECORD_ALL__) && defined(__HAIR__)
157 #  define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair
158 #  define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR
159 #  include "geom_bvh_shadow.h"
160 #endif
161
162 #if defined(__SHADOW_RECORD_ALL__) && defined(__OBJECT_MOTION__)
163 #  define BVH_FUNCTION_NAME bvh_intersect_shadow_all_motion
164 #  define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
165 #  include "geom_bvh_shadow.h"
166 #endif
167
168 #if defined(__SHADOW_RECORD_ALL__) && defined(__HAIR__) && defined(__OBJECT_MOTION__)
169 #  define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair_motion
170 #  define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_MOTION
171 #  include "geom_bvh_shadow.h"
172 #endif
173
174 /* Record all intersections - Volume BVH traversal  */
175
176 #if defined(__VOLUME_RECORD_ALL__)
177 #  define BVH_FUNCTION_NAME bvh_intersect_volume_all
178 #  define BVH_FUNCTION_FEATURES 0
179 #  include "geom_bvh_volume_all.h"
180 #endif
181
182 #if defined(__VOLUME_RECORD_ALL__) && defined(__INSTANCING__)
183 #  define BVH_FUNCTION_NAME bvh_intersect_volume_all_instancing
184 #  define BVH_FUNCTION_FEATURES BVH_INSTANCING
185 #  include "geom_bvh_volume_all.h"
186 #endif
187
188 #if defined(__VOLUME_RECORD_ALL__) && defined(__OBJECT_MOTION__)
189 #  define BVH_FUNCTION_NAME bvh_intersect_volume_all_motion
190 #  define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
191 #  include "geom_bvh_volume_all.h"
192 #endif
193
194 #undef BVH_FEATURE
195 #undef BVH_NAME_JOIN
196 #undef BVH_NAME_EVAL
197 #undef BVH_FUNCTION_FULL_NAME
198
199 ccl_device_intersect bool scene_intersect(KernelGlobals *kg,
200                                           const Ray *ray,
201                                           const uint visibility,
202                                           Intersection *isect,
203                                           uint *lcg_state,
204                                           float difl,
205                                           float extmax)
206 {
207 #ifdef __OBJECT_MOTION__
208         if(kernel_data.bvh.have_motion) {
209 #  ifdef __HAIR__
210                 if(kernel_data.bvh.have_curves)
211                         return bvh_intersect_hair_motion(kg, ray, isect, visibility, lcg_state, difl, extmax);
212 #  endif /* __HAIR__ */
213
214                 return bvh_intersect_motion(kg, ray, isect, visibility);
215         }
216 #endif /* __OBJECT_MOTION__ */
217
218 #ifdef __HAIR__
219         if(kernel_data.bvh.have_curves)
220                 return bvh_intersect_hair(kg, ray, isect, visibility, lcg_state, difl, extmax);
221 #endif /* __HAIR__ */
222
223 #ifdef __KERNEL_CPU__
224
225 #  ifdef __INSTANCING__
226         if(kernel_data.bvh.have_instancing)
227                 return bvh_intersect_instancing(kg, ray, isect, visibility);
228 #  endif /* __INSTANCING__ */
229
230         return bvh_intersect(kg, ray, isect, visibility);
231 #else /* __KERNEL_CPU__ */
232
233 #  ifdef __INSTANCING__
234         return bvh_intersect_instancing(kg, ray, isect, visibility);
235 #  else
236         return bvh_intersect(kg, ray, isect, visibility);
237 #  endif /* __INSTANCING__ */
238
239 #endif /* __KERNEL_CPU__ */
240 }
241
242 #ifdef __SUBSURFACE__
243 ccl_device_intersect void scene_intersect_subsurface(KernelGlobals *kg,
244                                                      const Ray *ray,
245                                                      SubsurfaceIntersection *ss_isect,
246                                                      int subsurface_object,
247                                                      uint *lcg_state,
248                                                      int max_hits)
249 {
250 #ifdef __OBJECT_MOTION__
251         if(kernel_data.bvh.have_motion) {
252                 return bvh_intersect_subsurface_motion(kg,
253                                                        ray,
254                                                        ss_isect,
255                                                        subsurface_object,
256                                                        lcg_state,
257                                                        max_hits);
258         }
259 #endif /* __OBJECT_MOTION__ */
260         return bvh_intersect_subsurface(kg,
261                                         ray,
262                                         ss_isect,
263                                         subsurface_object,
264                                         lcg_state,
265                                         max_hits);
266 }
267 #endif
268
269 #ifdef __SHADOW_RECORD_ALL__
270 ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals *kg, const Ray *ray, Intersection *isect, uint max_hits, uint *num_hits)
271 {
272 #  ifdef __OBJECT_MOTION__
273         if(kernel_data.bvh.have_motion) {
274 #    ifdef __HAIR__
275                 if(kernel_data.bvh.have_curves)
276                         return bvh_intersect_shadow_all_hair_motion(kg, ray, isect, max_hits, num_hits);
277 #    endif /* __HAIR__ */
278
279                 return bvh_intersect_shadow_all_motion(kg, ray, isect, max_hits, num_hits);
280         }
281 #  endif /* __OBJECT_MOTION__ */
282
283 #  ifdef __HAIR__
284         if(kernel_data.bvh.have_curves)
285                 return bvh_intersect_shadow_all_hair(kg, ray, isect, max_hits, num_hits);
286 #  endif /* __HAIR__ */
287
288 #  ifdef __INSTANCING__
289         if(kernel_data.bvh.have_instancing)
290                 return bvh_intersect_shadow_all_instancing(kg, ray, isect, max_hits, num_hits);
291 #  endif /* __INSTANCING__ */
292
293         return bvh_intersect_shadow_all(kg, ray, isect, max_hits, num_hits);
294 }
295 #endif  /* __SHADOW_RECORD_ALL__ */
296
297 #ifdef __VOLUME__
298 ccl_device_intersect bool scene_intersect_volume(KernelGlobals *kg,
299                                                  const Ray *ray,
300                                                  Intersection *isect,
301                                                  const uint visibility)
302 {
303 #  ifdef __OBJECT_MOTION__
304         if(kernel_data.bvh.have_motion) {
305                 return bvh_intersect_volume_motion(kg, ray, isect, visibility);
306         }
307 #  endif /* __OBJECT_MOTION__ */
308 #  ifdef __KERNEL_CPU__
309 #    ifdef __INSTANCING__
310         if(kernel_data.bvh.have_instancing)
311                 return bvh_intersect_volume_instancing(kg, ray, isect, visibility);
312 #    endif /* __INSTANCING__ */
313         return bvh_intersect_volume(kg, ray, isect, visibility);
314 #  else /* __KERNEL_CPU__ */
315 #    ifdef __INSTANCING__
316         return bvh_intersect_volume_instancing(kg, ray, isect, visibility);
317 #    else
318         return bvh_intersect_volume(kg, ray, isect, visibility);
319 #    endif /* __INSTANCING__ */
320 #  endif /* __KERNEL_CPU__ */
321 }
322 #endif  /* __VOLUME__ */
323
324 #ifdef __VOLUME_RECORD_ALL__
325 ccl_device_intersect uint scene_intersect_volume_all(KernelGlobals *kg,
326                                                      const Ray *ray,
327                                                      Intersection *isect,
328                                                      const uint max_hits,
329                                                      const uint visibility)
330 {
331 #  ifdef __OBJECT_MOTION__
332         if(kernel_data.bvh.have_motion) {
333                 return bvh_intersect_volume_all_motion(kg, ray, isect, max_hits, visibility);
334         }
335 #  endif /* __OBJECT_MOTION__ */
336 #  ifdef __INSTANCING__
337         if(kernel_data.bvh.have_instancing)
338                 return bvh_intersect_volume_all_instancing(kg, ray, isect, max_hits, visibility);
339 #  endif /* __INSTANCING__ */
340         return bvh_intersect_volume_all(kg, ray, isect, max_hits, visibility);
341 }
342 #endif  /* __VOLUME_RECORD_ALL__ */
343
344
345 /* Ray offset to avoid self intersection.
346  *
347  * This function should be used to compute a modified ray start position for
348  * rays leaving from a surface. */
349
350 ccl_device_inline float3 ray_offset(float3 P, float3 Ng)
351 {
352 #ifdef __INTERSECTION_REFINE__
353         const float epsilon_f = 1e-5f;
354         /* ideally this should match epsilon_f, but instancing and motion blur
355          * precision makes it problematic */
356         const float epsilon_test = 1.0f;
357         const int epsilon_i = 32;
358
359         float3 res;
360
361         /* x component */
362         if(fabsf(P.x) < epsilon_test) {
363                 res.x = P.x + Ng.x*epsilon_f;
364         }
365         else {
366                 uint ix = __float_as_uint(P.x);
367                 ix += ((ix ^ __float_as_uint(Ng.x)) >> 31)? -epsilon_i: epsilon_i;
368                 res.x = __uint_as_float(ix);
369         }
370
371         /* y component */
372         if(fabsf(P.y) < epsilon_test) {
373                 res.y = P.y + Ng.y*epsilon_f;
374         }
375         else {
376                 uint iy = __float_as_uint(P.y);
377                 iy += ((iy ^ __float_as_uint(Ng.y)) >> 31)? -epsilon_i: epsilon_i;
378                 res.y = __uint_as_float(iy);
379         }
380
381         /* z component */
382         if(fabsf(P.z) < epsilon_test) {
383                 res.z = P.z + Ng.z*epsilon_f;
384         }
385         else {
386                 uint iz = __float_as_uint(P.z);
387                 iz += ((iz ^ __float_as_uint(Ng.z)) >> 31)? -epsilon_i: epsilon_i;
388                 res.z = __uint_as_float(iz);
389         }
390
391         return res;
392 #else
393         const float epsilon_f = 1e-4f;
394         return P + epsilon_f*Ng;
395 #endif
396 }
397
398 #if defined(__SHADOW_RECORD_ALL__) || defined (__VOLUME_RECORD_ALL__)
399 /* ToDo: Move to another file? */
400 ccl_device int intersections_compare(const void *a, const void *b)
401 {
402         const Intersection *isect_a = (const Intersection*)a;
403         const Intersection *isect_b = (const Intersection*)b;
404
405         if(isect_a->t < isect_b->t)
406                 return -1;
407         else if(isect_a->t > isect_b->t)
408                 return 1;
409         else
410                 return 0;
411 }
412 #endif
413
414 CCL_NAMESPACE_END
415