1// Copyright 2009-2021 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5
6#include "grid_soa.h"
7#include "../common/ray.h"
8#include "triangle_intersector_pluecker.h"
9
10namespace embree
11{
12 namespace isa
13 {
14 template<int K>
15 struct MapUV0
16 {
17 const float* const grid_uv;
18 size_t ofs00, ofs01, ofs10, ofs11;
19
20 __forceinline MapUV0(const float* const grid_uv, size_t ofs00, size_t ofs01, size_t ofs10, size_t ofs11)
21 : grid_uv(grid_uv), ofs00(ofs00), ofs01(ofs01), ofs10(ofs10), ofs11(ofs11) {}
22
23 __forceinline void operator() (vfloat<K>& u, vfloat<K>& v, Vec3vf<K>& Ng) const {
24 const vfloat<K> uv00(grid_uv[ofs00]);
25 const vfloat<K> uv01(grid_uv[ofs01]);
26 const vfloat<K> uv10(grid_uv[ofs10]);
27 const vfloat<K> uv11(grid_uv[ofs11]);
28 const Vec2vf<K> uv0 = GridSOA::decodeUV(uv00);
29 const Vec2vf<K> uv1 = GridSOA::decodeUV(uv01);
30 const Vec2vf<K> uv2 = GridSOA::decodeUV(uv10);
31 const Vec2vf<K> uv = madd(u,uv1,madd(v,uv2,(1.0f-u-v)*uv0));
32 u = uv[0]; v = uv[1];
33 }
34 };
35
36 template<int K>
37 struct MapUV1
38 {
39 const float* const grid_uv;
40 size_t ofs00, ofs01, ofs10, ofs11;
41
42 __forceinline MapUV1(const float* const grid_uv, size_t ofs00, size_t ofs01, size_t ofs10, size_t ofs11)
43 : grid_uv(grid_uv), ofs00(ofs00), ofs01(ofs01), ofs10(ofs10), ofs11(ofs11) {}
44
45 __forceinline void operator() (vfloat<K>& u, vfloat<K>& v, Vec3vf<K>& Ng) const {
46 const vfloat<K> uv00(grid_uv[ofs00]);
47 const vfloat<K> uv01(grid_uv[ofs01]);
48 const vfloat<K> uv10(grid_uv[ofs10]);
49 const vfloat<K> uv11(grid_uv[ofs11]);
50 const Vec2vf<K> uv0 = GridSOA::decodeUV(uv10);
51 const Vec2vf<K> uv1 = GridSOA::decodeUV(uv01);
52 const Vec2vf<K> uv2 = GridSOA::decodeUV(uv11);
53 const Vec2vf<K> uv = madd(u,uv1,madd(v,uv2,(1.0f-u-v)*uv0));
54 u = uv[0]; v = uv[1];
55 }
56 };
57
58 template<int K>
59 class GridSOAIntersectorK
60 {
61 public:
62 typedef void Primitive;
63
64 class Precalculations
65 {
66#if defined(__AVX__)
67 static const int M = 8;
68#else
69 static const int M = 4;
70#endif
71
72 public:
73 __forceinline Precalculations (const vbool<K>& valid, const RayK<K>& ray)
74 : grid(nullptr), intersector(valid,ray) {}
75
76 public:
77 GridSOA* grid;
78 PlueckerIntersectorK<M,K> intersector; // FIXME: use quad intersector
79 };
80
81 /*! Intersect a ray with the primitive. */
82 static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
83 {
84 const size_t dim_offset = pre.grid->dim_offset;
85 const size_t line_offset = pre.grid->width;
86 const float* const grid_x = pre.grid->decodeLeaf(0,prim);
87 const float* const grid_y = grid_x + 1 * dim_offset;
88 const float* const grid_z = grid_x + 2 * dim_offset;
89 const float* const grid_uv = grid_x + 3 * dim_offset;
90
91 const size_t max_x = pre.grid->width == 2 ? 1 : 2;
92 const size_t max_y = pre.grid->height == 2 ? 1 : 2;
93 for (size_t y=0; y<max_y; y++)
94 {
95 for (size_t x=0; x<max_x; x++)
96 {
97 const size_t ofs00 = (y+0)*line_offset+(x+0);
98 const size_t ofs01 = (y+0)*line_offset+(x+1);
99 const size_t ofs10 = (y+1)*line_offset+(x+0);
100 const size_t ofs11 = (y+1)*line_offset+(x+1);
101 const Vec3vf<K> p00(grid_x[ofs00],grid_y[ofs00],grid_z[ofs00]);
102 const Vec3vf<K> p01(grid_x[ofs01],grid_y[ofs01],grid_z[ofs01]);
103 const Vec3vf<K> p10(grid_x[ofs10],grid_y[ofs10],grid_z[ofs10]);
104 const Vec3vf<K> p11(grid_x[ofs11],grid_y[ofs11],grid_z[ofs11]);
105
106 pre.intersector.intersectK(valid_i,ray,p00,p01,p10,MapUV0<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),IntersectKEpilogMU<1,K,true>(ray,context,pre.grid->geomID(),pre.grid->primID()));
107 pre.intersector.intersectK(valid_i,ray,p10,p01,p11,MapUV1<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),IntersectKEpilogMU<1,K,true>(ray,context,pre.grid->geomID(),pre.grid->primID()));
108 }
109 }
110 }
111
112 /*! Test if the ray is occluded by the primitive */
113 static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
114 {
115 const size_t dim_offset = pre.grid->dim_offset;
116 const size_t line_offset = pre.grid->width;
117 const float* const grid_x = pre.grid->decodeLeaf(0,prim);
118 const float* const grid_y = grid_x + 1 * dim_offset;
119 const float* const grid_z = grid_x + 2 * dim_offset;
120 const float* const grid_uv = grid_x + 3 * dim_offset;
121
122 vbool<K> valid = valid_i;
123 const size_t max_x = pre.grid->width == 2 ? 1 : 2;
124 const size_t max_y = pre.grid->height == 2 ? 1 : 2;
125 for (size_t y=0; y<max_y; y++)
126 {
127 for (size_t x=0; x<max_x; x++)
128 {
129 const size_t ofs00 = (y+0)*line_offset+(x+0);
130 const size_t ofs01 = (y+0)*line_offset+(x+1);
131 const size_t ofs10 = (y+1)*line_offset+(x+0);
132 const size_t ofs11 = (y+1)*line_offset+(x+1);
133 const Vec3vf<K> p00(grid_x[ofs00],grid_y[ofs00],grid_z[ofs00]);
134 const Vec3vf<K> p01(grid_x[ofs01],grid_y[ofs01],grid_z[ofs01]);
135 const Vec3vf<K> p10(grid_x[ofs10],grid_y[ofs10],grid_z[ofs10]);
136 const Vec3vf<K> p11(grid_x[ofs11],grid_y[ofs11],grid_z[ofs11]);
137
138 pre.intersector.intersectK(valid,ray,p00,p01,p10,MapUV0<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),OccludedKEpilogMU<1,K,true>(valid,ray,context,pre.grid->geomID(),pre.grid->primID()));
139 if (none(valid)) break;
140 pre.intersector.intersectK(valid,ray,p10,p01,p11,MapUV1<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),OccludedKEpilogMU<1,K,true>(valid,ray,context,pre.grid->geomID(),pre.grid->primID()));
141 if (none(valid)) break;
142 }
143 }
144 return !valid;
145 }
146
147 template<typename Loader>
148 static __forceinline void intersect(RayHitK<K>& ray, size_t k,
149 IntersectContext* context,
150 const float* const grid_x,
151 const size_t line_offset,
152 const size_t lines,
153 Precalculations& pre)
154 {
155 typedef typename Loader::vfloat vfloat;
156 const size_t dim_offset = pre.grid->dim_offset;
157 const float* const grid_y = grid_x + 1 * dim_offset;
158 const float* const grid_z = grid_x + 2 * dim_offset;
159 const float* const grid_uv = grid_x + 3 * dim_offset;
160 Vec3<vfloat> v0, v1, v2; Loader::gather(grid_x,grid_y,grid_z,line_offset,lines,v0,v1,v2);
161 pre.intersector.intersect(ray,k,v0,v1,v2,GridSOA::MapUV<Loader>(grid_uv,line_offset,lines),Intersect1KEpilogMU<Loader::M,K,true>(ray,k,context,pre.grid->geomID(),pre.grid->primID()));
162 };
163
164 template<typename Loader>
165 static __forceinline bool occluded(RayK<K>& ray, size_t k,
166 IntersectContext* context,
167 const float* const grid_x,
168 const size_t line_offset,
169 const size_t lines,
170 Precalculations& pre)
171 {
172 typedef typename Loader::vfloat vfloat;
173 const size_t dim_offset = pre.grid->dim_offset;
174 const float* const grid_y = grid_x + 1 * dim_offset;
175 const float* const grid_z = grid_x + 2 * dim_offset;
176 const float* const grid_uv = grid_x + 3 * dim_offset;
177 Vec3<vfloat> v0, v1, v2; Loader::gather(grid_x,grid_y,grid_z,line_offset,lines,v0,v1,v2);
178 return pre.intersector.intersect(ray,k,v0,v1,v2,GridSOA::MapUV<Loader>(grid_uv,line_offset,lines),Occluded1KEpilogMU<Loader::M,K,true>(ray,k,context,pre.grid->geomID(),pre.grid->primID()));
179 }
180
181 /*! Intersect a ray with the primitive. */
182 static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
183 {
184 const size_t line_offset = pre.grid->width;
185 const size_t lines = pre.grid->height;
186 const float* const grid_x = pre.grid->decodeLeaf(0,prim);
187#if defined(__AVX__)
188 intersect<GridSOA::Gather3x3>( ray, k, context, grid_x, line_offset, lines, pre);
189#else
190 intersect<GridSOA::Gather2x3>(ray, k, context, grid_x , line_offset, lines, pre);
191 if (likely(lines > 2))
192 intersect<GridSOA::Gather2x3>(ray, k, context, grid_x+line_offset, line_offset, lines, pre);
193#endif
194 }
195
196 /*! Test if the ray is occluded by the primitive */
197 static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
198 {
199 const size_t line_offset = pre.grid->width;
200 const size_t lines = pre.grid->height;
201 const float* const grid_x = pre.grid->decodeLeaf(0,prim);
202
203#if defined(__AVX__)
204 return occluded<GridSOA::Gather3x3>( ray, k, context, grid_x, line_offset, lines, pre);
205#else
206 if (occluded<GridSOA::Gather2x3>(ray, k, context, grid_x , line_offset, lines, pre)) return true;
207 if (likely(lines > 2))
208 if (occluded<GridSOA::Gather2x3>(ray, k, context, grid_x+line_offset, line_offset, lines, pre)) return true;
209#endif
210 return false;
211 }
212 };
213
214 template<int K>
215 class GridSOAMBIntersectorK
216 {
217 public:
218 typedef void Primitive;
219 typedef typename GridSOAIntersectorK<K>::Precalculations Precalculations;
220
221 /*! Intersect a ray with the primitive. */
222 static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
223 {
224 vfloat<K> vftime;
225 vint<K> vitime = getTimeSegment<K>(ray.time(), vfloat<K>((float)(pre.grid->time_steps-1)), vftime);
226
227 vbool<K> valid1 = valid_i;
228 while (any(valid1)) {
229 const size_t j = bsf(movemask(valid1));
230 const int itime = vitime[j];
231 const vbool<K> valid2 = valid1 & (itime == vitime);
232 valid1 = valid1 & !valid2;
233 intersect(valid2,pre,ray,vftime,itime,context,prim,lazy_node);
234 }
235 }
236
237 /*! Intersect a ray with the primitive. */
238 static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, const vfloat<K>& ftime, int itime, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
239 {
240 const size_t grid_offset = pre.grid->gridBytes >> 2;
241 const size_t dim_offset = pre.grid->dim_offset;
242 const size_t line_offset = pre.grid->width;
243 const float* const grid_x = pre.grid->decodeLeaf(itime,prim);
244 const float* const grid_y = grid_x + 1 * dim_offset;
245 const float* const grid_z = grid_x + 2 * dim_offset;
246 const float* const grid_uv = grid_x + 3 * dim_offset;
247
248 const size_t max_x = pre.grid->width == 2 ? 1 : 2;
249 const size_t max_y = pre.grid->height == 2 ? 1 : 2;
250 for (size_t y=0; y<max_y; y++)
251 {
252 for (size_t x=0; x<max_x; x++)
253 {
254 size_t ofs00 = (y+0)*line_offset+(x+0);
255 size_t ofs01 = (y+0)*line_offset+(x+1);
256 size_t ofs10 = (y+1)*line_offset+(x+0);
257 size_t ofs11 = (y+1)*line_offset+(x+1);
258 const Vec3vf<K> a00(grid_x[ofs00],grid_y[ofs00],grid_z[ofs00]);
259 const Vec3vf<K> a01(grid_x[ofs01],grid_y[ofs01],grid_z[ofs01]);
260 const Vec3vf<K> a10(grid_x[ofs10],grid_y[ofs10],grid_z[ofs10]);
261 const Vec3vf<K> a11(grid_x[ofs11],grid_y[ofs11],grid_z[ofs11]);
262 ofs00 += grid_offset;
263 ofs01 += grid_offset;
264 ofs10 += grid_offset;
265 ofs11 += grid_offset;
266 const Vec3vf<K> b00(grid_x[ofs00],grid_y[ofs00],grid_z[ofs00]);
267 const Vec3vf<K> b01(grid_x[ofs01],grid_y[ofs01],grid_z[ofs01]);
268 const Vec3vf<K> b10(grid_x[ofs10],grid_y[ofs10],grid_z[ofs10]);
269 const Vec3vf<K> b11(grid_x[ofs11],grid_y[ofs11],grid_z[ofs11]);
270 const Vec3vf<K> p00 = lerp(a00,b00,ftime);
271 const Vec3vf<K> p01 = lerp(a01,b01,ftime);
272 const Vec3vf<K> p10 = lerp(a10,b10,ftime);
273 const Vec3vf<K> p11 = lerp(a11,b11,ftime);
274
275 pre.intersector.intersectK(valid_i,ray,p00,p01,p10,MapUV0<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),IntersectKEpilogMU<1,K,true>(ray,context,pre.grid->geomID(),pre.grid->primID()));
276 pre.intersector.intersectK(valid_i,ray,p10,p01,p11,MapUV1<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),IntersectKEpilogMU<1,K,true>(ray,context,pre.grid->geomID(),pre.grid->primID()));
277 }
278 }
279 }
280
281 /*! Test if the ray is occluded by the primitive */
282 static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
283 {
284 vfloat<K> vftime;
285 vint<K> vitime = getTimeSegment<K>(ray.time(), vfloat<K>((float)(pre.grid->time_steps-1)), vftime);
286
287 vbool<K> valid_o = valid_i;
288 vbool<K> valid1 = valid_i;
289 while (any(valid1)) {
290 const int j = int(bsf(movemask(valid1)));
291 const int itime = vitime[j];
292 const vbool<K> valid2 = valid1 & (itime == vitime);
293 valid1 = valid1 & !valid2;
294 valid_o &= !valid2 | occluded(valid2,pre,ray,vftime,itime,context,prim,lazy_node);
295 }
296 return !valid_o;
297 }
298
299 /*! Test if the ray is occluded by the primitive */
300 static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, const vfloat<K>& ftime, int itime, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
301 {
302 const size_t grid_offset = pre.grid->gridBytes >> 2;
303 const size_t dim_offset = pre.grid->dim_offset;
304 const size_t line_offset = pre.grid->width;
305 const float* const grid_x = pre.grid->decodeLeaf(itime,prim);
306 const float* const grid_y = grid_x + 1 * dim_offset;
307 const float* const grid_z = grid_x + 2 * dim_offset;
308 const float* const grid_uv = grid_x + 3 * dim_offset;
309
310 vbool<K> valid = valid_i;
311 const size_t max_x = pre.grid->width == 2 ? 1 : 2;
312 const size_t max_y = pre.grid->height == 2 ? 1 : 2;
313 for (size_t y=0; y<max_y; y++)
314 {
315 for (size_t x=0; x<max_x; x++)
316 {
317 size_t ofs00 = (y+0)*line_offset+(x+0);
318 size_t ofs01 = (y+0)*line_offset+(x+1);
319 size_t ofs10 = (y+1)*line_offset+(x+0);
320 size_t ofs11 = (y+1)*line_offset+(x+1);
321 const Vec3vf<K> a00(grid_x[ofs00],grid_y[ofs00],grid_z[ofs00]);
322 const Vec3vf<K> a01(grid_x[ofs01],grid_y[ofs01],grid_z[ofs01]);
323 const Vec3vf<K> a10(grid_x[ofs10],grid_y[ofs10],grid_z[ofs10]);
324 const Vec3vf<K> a11(grid_x[ofs11],grid_y[ofs11],grid_z[ofs11]);
325 ofs00 += grid_offset;
326 ofs01 += grid_offset;
327 ofs10 += grid_offset;
328 ofs11 += grid_offset;
329 const Vec3vf<K> b00(grid_x[ofs00],grid_y[ofs00],grid_z[ofs00]);
330 const Vec3vf<K> b01(grid_x[ofs01],grid_y[ofs01],grid_z[ofs01]);
331 const Vec3vf<K> b10(grid_x[ofs10],grid_y[ofs10],grid_z[ofs10]);
332 const Vec3vf<K> b11(grid_x[ofs11],grid_y[ofs11],grid_z[ofs11]);
333 const Vec3vf<K> p00 = lerp(a00,b00,ftime);
334 const Vec3vf<K> p01 = lerp(a01,b01,ftime);
335 const Vec3vf<K> p10 = lerp(a10,b10,ftime);
336 const Vec3vf<K> p11 = lerp(a11,b11,ftime);
337
338 pre.intersector.intersectK(valid,ray,p00,p01,p10,MapUV0<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),OccludedKEpilogMU<1,K,true>(valid,ray,context,pre.grid->geomID(),pre.grid->primID()));
339 if (none(valid)) break;
340 pre.intersector.intersectK(valid,ray,p10,p01,p11,MapUV1<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),OccludedKEpilogMU<1,K,true>(valid,ray,context,pre.grid->geomID(),pre.grid->primID()));
341 if (none(valid)) break;
342 }
343 }
344 return valid;
345 }
346
347 template<typename Loader>
348 static __forceinline void intersect(RayHitK<K>& ray, size_t k,
349 const float ftime,
350 IntersectContext* context,
351 const float* const grid_x,
352 const size_t line_offset,
353 const size_t lines,
354 Precalculations& pre)
355 {
356 typedef typename Loader::vfloat vfloat;
357 const size_t grid_offset = pre.grid->gridBytes >> 2;
358 const size_t dim_offset = pre.grid->dim_offset;
359 const float* const grid_y = grid_x + 1 * dim_offset;
360 const float* const grid_z = grid_x + 2 * dim_offset;
361 const float* const grid_uv = grid_x + 3 * dim_offset;
362
363 Vec3<vfloat> a0, a1, a2;
364 Loader::gather(grid_x,grid_y,grid_z,line_offset,lines,a0,a1,a2);
365
366 Vec3<vfloat> b0, b1, b2;
367 Loader::gather(grid_x+grid_offset,grid_y+grid_offset,grid_z+grid_offset,line_offset,lines,b0,b1,b2);
368
369 Vec3<vfloat> v0 = lerp(a0,b0,vfloat(ftime));
370 Vec3<vfloat> v1 = lerp(a1,b1,vfloat(ftime));
371 Vec3<vfloat> v2 = lerp(a2,b2,vfloat(ftime));
372
373 pre.intersector.intersect(ray,k,v0,v1,v2,GridSOA::MapUV<Loader>(grid_uv,line_offset,lines),Intersect1KEpilogMU<Loader::M,K,true>(ray,k,context,pre.grid->geomID(),pre.grid->primID()));
374 };
375
376 template<typename Loader>
377 static __forceinline bool occluded(RayK<K>& ray, size_t k,
378 const float ftime,
379 IntersectContext* context,
380 const float* const grid_x,
381 const size_t line_offset,
382 const size_t lines,
383 Precalculations& pre)
384 {
385 typedef typename Loader::vfloat vfloat;
386 const size_t grid_offset = pre.grid->gridBytes >> 2;
387 const size_t dim_offset = pre.grid->dim_offset;
388 const float* const grid_y = grid_x + 1 * dim_offset;
389 const float* const grid_z = grid_x + 2 * dim_offset;
390 const float* const grid_uv = grid_x + 3 * dim_offset;
391
392 Vec3<vfloat> a0, a1, a2;
393 Loader::gather(grid_x,grid_y,grid_z,line_offset,lines,a0,a1,a2);
394
395 Vec3<vfloat> b0, b1, b2;
396 Loader::gather(grid_x+grid_offset,grid_y+grid_offset,grid_z+grid_offset,line_offset,lines,b0,b1,b2);
397
398 Vec3<vfloat> v0 = lerp(a0,b0,vfloat(ftime));
399 Vec3<vfloat> v1 = lerp(a1,b1,vfloat(ftime));
400 Vec3<vfloat> v2 = lerp(a2,b2,vfloat(ftime));
401
402 return pre.intersector.intersect(ray,k,v0,v1,v2,GridSOA::MapUV<Loader>(grid_uv,line_offset,lines),Occluded1KEpilogMU<Loader::M,K,true>(ray,k,context,pre.grid->geomID(),pre.grid->primID()));
403 }
404
405 /*! Intersect a ray with the primitive. */
406 static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
407 {
408 float ftime;
409 int itime = getTimeSegment(ray.time()[k], float(pre.grid->time_steps-1), ftime);
410
411 const size_t line_offset = pre.grid->width;
412 const size_t lines = pre.grid->height;
413 const float* const grid_x = pre.grid->decodeLeaf(itime,prim);
414
415#if defined(__AVX__)
416 intersect<GridSOA::Gather3x3>( ray, k, ftime, context, grid_x, line_offset, lines, pre);
417#else
418 intersect<GridSOA::Gather2x3>(ray, k, ftime, context, grid_x, line_offset, lines, pre);
419 if (likely(lines > 2))
420 intersect<GridSOA::Gather2x3>(ray, k, ftime, context, grid_x+line_offset, line_offset, lines, pre);
421#endif
422 }
423
424 /*! Test if the ray is occluded by the primitive */
425 static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
426 {
427 float ftime;
428 int itime = getTimeSegment(ray.time()[k], float(pre.grid->time_steps-1), ftime);
429
430 const size_t line_offset = pre.grid->width;
431 const size_t lines = pre.grid->height;
432 const float* const grid_x = pre.grid->decodeLeaf(itime,prim);
433
434#if defined(__AVX__)
435 return occluded<GridSOA::Gather3x3>( ray, k, ftime, context, grid_x, line_offset, lines, pre);
436#else
437 if (occluded<GridSOA::Gather2x3>(ray, k, ftime, context, grid_x, line_offset, lines, pre)) return true;
438 if (likely(lines > 2))
439 if (occluded<GridSOA::Gather2x3>(ray, k, ftime, context, grid_x+line_offset, line_offset, lines, pre)) return true;
440#endif
441 return false;
442 }
443 };
444 }
445}
446