1// Copyright 2009-2021 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5
6#include "subgrid.h"
7#include "subgrid_intersector_moeller.h"
8#include "subgrid_intersector_pluecker.h"
9
10namespace embree
11{
12 namespace isa
13 {
14
15 // =======================================================================================
16 // =================================== SubGridIntersectors ===============================
17 // =======================================================================================
18
19
20 template<int N, bool filter>
21 struct SubGridIntersector1Moeller
22 {
23 typedef SubGridQBVHN<N> Primitive;
24 typedef SubGridQuadMIntersector1MoellerTrumbore<4,filter> Precalculations;
25
26 static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const SubGrid& subgrid)
27 {
28 STAT3(normal.trav_prims,1,1,1);
29 const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
30 const GridMesh::Grid &g = mesh->grid(subgrid.primID());
31
32 Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
33 pre.intersect(ray,context,v0,v1,v2,v3,g,subgrid);
34 }
35
36 static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const SubGrid& subgrid)
37 {
38 STAT3(shadow.trav_prims,1,1,1);
39 const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
40 const GridMesh::Grid &g = mesh->grid(subgrid.primID());
41
42 Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
43 return pre.occluded(ray,context,v0,v1,v2,v3,g,subgrid);
44 }
45
46 static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const SubGrid& subgrid)
47 {
48 STAT3(point_query.trav_prims,1,1,1);
49 AccelSet* accel = (AccelSet*)context->scene->get(subgrid.geomID());
50 assert(accel);
51 context->geomID = subgrid.geomID();
52 context->primID = subgrid.primID();
53 return accel->pointQuery(query, context);
54 }
55
56 template<bool robust>
57 static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
58 {
59 BVHNQuantizedBaseNodeIntersector1<N,robust> isec1;
60
61 for (size_t i=0;i<num;i++)
62 {
63 vfloat<N> dist;
64 size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
65#if defined(__AVX__)
66 STAT3(normal.trav_hit_boxes[popcnt(mask)],1,1,1);
67#endif
68 while(mask != 0)
69 {
70 const size_t ID = bscf(mask);
71 assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
72
73 if (unlikely(dist[ID] > ray.tfar)) continue;
74 intersect(pre,ray,context,prim[i].subgrid(ID));
75 }
76 }
77 }
78 template<bool robust>
79 static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
80
81 {
82 BVHNQuantizedBaseNodeIntersector1<N,robust> isec1;
83
84 for (size_t i=0;i<num;i++)
85 {
86 vfloat<N> dist;
87 size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
88 while(mask != 0)
89 {
90 const size_t ID = bscf(mask);
91 assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
92
93 if (occluded(pre,ray,context,prim[i].subgrid(ID)))
94 return true;
95 }
96 }
97 return false;
98 }
99
100 static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context, const Primitive* prim, size_t num, const TravPointQuery<N> &tquery, size_t& lazy_node)
101 {
102 bool changed = false;
103 for (size_t i=0;i<num;i++)
104 {
105 vfloat<N> dist;
106 size_t mask;
107 if (likely(context->query_type == POINT_QUERY_TYPE_SPHERE)) {
108 mask = BVHNQuantizedBaseNodePointQuerySphere1<N>::pointQuery(&prim[i].qnode,tquery,dist);
109 } else {
110 mask = BVHNQuantizedBaseNodePointQueryAABB1<N>::pointQuery(&prim[i].qnode,tquery,dist);
111 }
112 while(mask != 0)
113 {
114 const size_t ID = bscf(mask);
115 assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
116 changed |= pointQuery(query, context, prim[i].subgrid(ID));
117 }
118 }
119 return changed;
120 }
121 };
122
123 template<int N, bool filter>
124 struct SubGridIntersector1Pluecker
125 {
126 typedef SubGridQBVHN<N> Primitive;
127 typedef SubGridQuadMIntersector1Pluecker<4,filter> Precalculations;
128
129 static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const SubGrid& subgrid)
130 {
131 STAT3(normal.trav_prims,1,1,1);
132 const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
133 const GridMesh::Grid &g = mesh->grid(subgrid.primID());
134
135 Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
136 pre.intersect(ray,context,v0,v1,v2,v3,g,subgrid);
137 }
138
139 static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const SubGrid& subgrid)
140 {
141 STAT3(shadow.trav_prims,1,1,1);
142 const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
143 const GridMesh::Grid &g = mesh->grid(subgrid.primID());
144
145 Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
146 return pre.occluded(ray,context,v0,v1,v2,v3,g,subgrid);
147 }
148
149 static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const SubGrid& subgrid)
150 {
151 STAT3(point_query.trav_prims,1,1,1);
152 AccelSet* accel = (AccelSet*)context->scene->get(subgrid.geomID());
153 context->geomID = subgrid.geomID();
154 context->primID = subgrid.primID();
155 return accel->pointQuery(query, context);
156 }
157
158 template<bool robust>
159 static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
160 {
161 BVHNQuantizedBaseNodeIntersector1<N,robust> isec1;
162
163 for (size_t i=0;i<num;i++)
164 {
165 vfloat<N> dist;
166 size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
167#if defined(__AVX__)
168 STAT3(normal.trav_hit_boxes[popcnt(mask)],1,1,1);
169#endif
170 while(mask != 0)
171 {
172 const size_t ID = bscf(mask);
173 assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
174
175 if (unlikely(dist[ID] > ray.tfar)) continue;
176 intersect(pre,ray,context,prim[i].subgrid(ID));
177 }
178 }
179 }
180
181 template<bool robust>
182 static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
183 {
184 BVHNQuantizedBaseNodeIntersector1<N,robust> isec1;
185
186 for (size_t i=0;i<num;i++)
187 {
188 vfloat<N> dist;
189 size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
190 while(mask != 0)
191 {
192 const size_t ID = bscf(mask);
193 assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
194
195 if (occluded(pre,ray,context,prim[i].subgrid(ID)))
196 return true;
197 }
198 }
199 return false;
200 }
201
202 static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context, const Primitive* prim, size_t num, const TravPointQuery<N> &tquery, size_t& lazy_node)
203 {
204 bool changed = false;
205 for (size_t i=0;i<num;i++)
206 {
207 vfloat<N> dist;
208 size_t mask;
209 if (likely(context->query_type == POINT_QUERY_TYPE_SPHERE)) {
210 mask = BVHNQuantizedBaseNodePointQuerySphere1<N>::pointQuery(&prim[i].qnode,tquery,dist);
211 } else {
212 mask = BVHNQuantizedBaseNodePointQueryAABB1<N>::pointQuery(&prim[i].qnode,tquery,dist);
213 }
214#if defined(__AVX__)
215 STAT3(point_query.trav_hit_boxes[popcnt(mask)],1,1,1);
216#endif
217 while(mask != 0)
218 {
219 const size_t ID = bscf(mask);
220 assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
221 changed |= pointQuery(query, context, prim[i].subgrid(ID));
222 }
223 }
224 return changed;
225 }
226 };
227
228 template<int N, int K, bool filter>
229 struct SubGridIntersectorKMoeller
230 {
231 typedef SubGridQBVHN<N> Primitive;
232 typedef SubGridQuadMIntersectorKMoellerTrumbore<4,K,filter> Precalculations;
233
234 static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const SubGrid& subgrid)
235 {
236 Vec3fa vtx[16];
237 const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
238 const GridMesh::Grid &g = mesh->grid(subgrid.primID());
239
240 subgrid.gather(vtx,context->scene);
241 for (unsigned int i=0; i<4; i++)
242 {
243 const Vec3vf<K> p0 = vtx[i*4+0];
244 const Vec3vf<K> p1 = vtx[i*4+1];
245 const Vec3vf<K> p2 = vtx[i*4+2];
246 const Vec3vf<K> p3 = vtx[i*4+3];
247 STAT3(normal.trav_prims,1,popcnt(valid_i),K);
248 pre.intersectK(valid_i,ray,p0,p1,p2,p3,g,subgrid,i,IntersectKEpilogM<4,K,filter>(ray,context,subgrid.geomID(),subgrid.primID(),i));
249 }
250 }
251
252 static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const SubGrid& subgrid)
253 {
254 vbool<K> valid0 = valid_i;
255 Vec3fa vtx[16];
256 const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
257 const GridMesh::Grid &g = mesh->grid(subgrid.primID());
258
259 subgrid.gather(vtx,context->scene);
260 for (unsigned int i=0; i<4; i++)
261 {
262 const Vec3vf<K> p0 = vtx[i*4+0];
263 const Vec3vf<K> p1 = vtx[i*4+1];
264 const Vec3vf<K> p2 = vtx[i*4+2];
265 const Vec3vf<K> p3 = vtx[i*4+3];
266 STAT3(shadow.trav_prims,1,popcnt(valid0),K);
267 pre.intersectK(valid0,ray,p0,p1,p2,p3,g,subgrid,i,OccludedKEpilogM<4,K,filter>(valid0,ray,context,subgrid.geomID(),subgrid.primID(),i));
268 if (none(valid0)) break;
269 }
270 return !valid0;
271 }
272
273 static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const SubGrid& subgrid)
274 {
275 STAT3(normal.trav_prims,1,1,1);
276 const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
277 const GridMesh::Grid &g = mesh->grid(subgrid.primID());
278
279 Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
280 pre.intersect1(ray,k,context,v0,v1,v2,v3,g,subgrid);
281 }
282
283 static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const SubGrid& subgrid)
284 {
285 STAT3(shadow.trav_prims,1,1,1);
286 const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
287 const GridMesh::Grid &g = mesh->grid(subgrid.primID());
288 Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
289 return pre.occluded1(ray,k,context,v0,v1,v2,v3,g,subgrid);
290 }
291
292 template<bool robust>
293 static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
294 {
295 BVHNQuantizedBaseNodeIntersectorK<N,K,robust> isecK;
296 for (size_t j=0;j<num;j++)
297 {
298 size_t m_valid = movemask(prim[j].qnode.validMask());
299 vfloat<K> dist;
300 while(m_valid)
301 {
302 const size_t i = bscf(m_valid);
303 if (none(valid & isecK.intersectK(&prim[j].qnode,i,tray,dist))) continue;
304 intersect(valid,pre,ray,context,prim[j].subgrid(i));
305 }
306 }
307 }
308
309 template<bool robust>
310 static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
311 {
312 BVHNQuantizedBaseNodeIntersectorK<N,K,robust> isecK;
313 vbool<K> valid0 = valid;
314 for (size_t j=0;j<num;j++)
315 {
316 size_t m_valid = movemask(prim[j].qnode.validMask());
317 vfloat<K> dist;
318 while(m_valid)
319 {
320 const size_t i = bscf(m_valid);
321 if (none(valid0 & isecK.intersectK(&prim[j].qnode,i,tray,dist))) continue;
322 valid0 &= !occluded(valid0,pre,ray,context,prim[j].subgrid(i));
323 if (none(valid0)) break;
324 }
325 }
326 return !valid0;
327 }
328
329 template<bool robust>
330 static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
331 {
332 BVHNQuantizedBaseNodeIntersector1<N,robust> isec1;
333
334 for (size_t i=0;i<num;i++)
335 {
336 vfloat<N> dist;
337 size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
338 while(mask != 0)
339 {
340 const size_t ID = bscf(mask);
341 assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
342
343 if (unlikely(dist[ID] > ray.tfar[k])) continue;
344 intersect(pre,ray,k,context,prim[i].subgrid(ID));
345 }
346 }
347 }
348
349 template<bool robust>
350 static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
351 {
352 BVHNQuantizedBaseNodeIntersector1<N,robust> isec1;
353
354 for (size_t i=0;i<num;i++)
355 {
356 vfloat<N> dist;
357 size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
358 while(mask != 0)
359 {
360 const size_t ID = bscf(mask);
361 assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
362
363 if (occluded(pre,ray,k,context,prim[i].subgrid(ID)))
364 return true;
365 }
366 }
367 return false;
368 }
369 };
370
371
372 template<int N, int K, bool filter>
373 struct SubGridIntersectorKPluecker
374 {
375 typedef SubGridQBVHN<N> Primitive;
376 typedef SubGridQuadMIntersectorKPluecker<4,K,filter> Precalculations;
377
378 static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const SubGrid& subgrid)
379 {
380 Vec3fa vtx[16];
381 const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
382 const GridMesh::Grid &g = mesh->grid(subgrid.primID());
383
384 subgrid.gather(vtx,context->scene);
385 for (unsigned int i=0; i<4; i++)
386 {
387 const Vec3vf<K> p0 = vtx[i*4+0];
388 const Vec3vf<K> p1 = vtx[i*4+1];
389 const Vec3vf<K> p2 = vtx[i*4+2];
390 const Vec3vf<K> p3 = vtx[i*4+3];
391 STAT3(normal.trav_prims,1,popcnt(valid_i),K);
392 pre.intersectK(valid_i,ray,p0,p1,p2,p3,g,subgrid,i,IntersectKEpilogM<4,K,filter>(ray,context,subgrid.geomID(),subgrid.primID(),i));
393 }
394 }
395
396 static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const SubGrid& subgrid)
397 {
398 vbool<K> valid0 = valid_i;
399 Vec3fa vtx[16];
400 const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
401 const GridMesh::Grid &g = mesh->grid(subgrid.primID());
402
403 subgrid.gather(vtx,context->scene);
404 for (unsigned int i=0; i<4; i++)
405 {
406 const Vec3vf<K> p0 = vtx[i*4+0];
407 const Vec3vf<K> p1 = vtx[i*4+1];
408 const Vec3vf<K> p2 = vtx[i*4+2];
409 const Vec3vf<K> p3 = vtx[i*4+3];
410 STAT3(shadow.trav_prims,1,popcnt(valid0),K);
411 pre.occludedK(valid0,ray,p0,p1,p2,p3,g,subgrid,i,OccludedKEpilogM<4,K,filter>(valid0,ray,context,subgrid.geomID(),subgrid.primID(),i));
412 if (none(valid0)) break;
413 }
414 return !valid0;
415 }
416
417 static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const SubGrid& subgrid)
418 {
419 STAT3(normal.trav_prims,1,1,1);
420 const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
421 const GridMesh::Grid &g = mesh->grid(subgrid.primID());
422
423 Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
424 pre.intersect1(ray,k,context,v0,v1,v2,v3,g,subgrid);
425 }
426
427 static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const SubGrid& subgrid)
428 {
429 STAT3(shadow.trav_prims,1,1,1);
430 const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
431 const GridMesh::Grid &g = mesh->grid(subgrid.primID());
432 Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
433 return pre.occluded1(ray,k,context,v0,v1,v2,v3,g,subgrid);
434 }
435
436 template<bool robust>
437 static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
438 {
439 BVHNQuantizedBaseNodeIntersectorK<N,K,robust> isecK;
440 for (size_t j=0;j<num;j++)
441 {
442 size_t m_valid = movemask(prim[j].qnode.validMask());
443 vfloat<K> dist;
444 while(m_valid)
445 {
446 const size_t i = bscf(m_valid);
447 if (none(valid & isecK.intersectK(&prim[j].qnode,i,tray,dist))) continue;
448 intersect(valid,pre,ray,context,prim[j].subgrid(i));
449 }
450 }
451 }
452
453 template<bool robust>
454 static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
455 {
456 BVHNQuantizedBaseNodeIntersectorK<N,K,robust> isecK;
457 vbool<K> valid0 = valid;
458 for (size_t j=0;j<num;j++)
459 {
460 size_t m_valid = movemask(prim[j].qnode.validMask());
461 vfloat<K> dist;
462 while(m_valid)
463 {
464 const size_t i = bscf(m_valid);
465 if (none(valid0 & isecK.intersectK(&prim[j].qnode,i,tray,dist))) continue;
466 valid0 &= !occluded(valid0,pre,ray,context,prim[j].subgrid(i));
467 if (none(valid0)) break;
468 }
469 }
470 return !valid0;
471 }
472
473 template<bool robust>
474 static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
475 {
476 BVHNQuantizedBaseNodeIntersector1<N,robust> isec1;
477
478 for (size_t i=0;i<num;i++)
479 {
480 vfloat<N> dist;
481 size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
482 while(mask != 0)
483 {
484 const size_t ID = bscf(mask);
485 assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
486
487 if (unlikely(dist[ID] > ray.tfar[k])) continue;
488 intersect(pre,ray,k,context,prim[i].subgrid(ID));
489 }
490 }
491 }
492
493 template<bool robust>
494 static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
495 {
496 BVHNQuantizedBaseNodeIntersector1<N,robust> isec1;
497
498 for (size_t i=0;i<num;i++)
499 {
500 vfloat<N> dist;
501 size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
502 while(mask != 0)
503 {
504 const size_t ID = bscf(mask);
505 assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
506
507 if (occluded(pre,ray,k,context,prim[i].subgrid(ID)))
508 return true;
509 }
510 }
511 return false;
512 }
513 };
514 }
515}
516