1 // Copyright 2009-2021 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 
4 #pragma once
5 
6 #include "primitive.h"
7 
8 namespace embree
9 {
10   template<int M>
11   struct PointMi
12   {
13     /* Virtual interface to query information about the line segment type */
14     struct Type : public PrimitiveType
15     {
16       const char* name() const;
17       size_t sizeActive(const char* This) const;
18       size_t sizeTotal(const char* This) const;
19       size_t getBytes(const char* This) const;
20     };
21     static Type type;
22 
23    public:
24     /* primitive supports multiple time segments */
25     static const bool singleTimeSegment = false;
26 
27     /* Returns maximum number of stored line segments */
max_sizePointMi28     static __forceinline size_t max_size()
29     {
30       return M;
31     }
32 
33     /* Returns required number of primitive blocks for N line segments */
blocksPointMi34     static __forceinline size_t blocks(size_t N)
35     {
36       return (N + max_size() - 1) / max_size();
37     }
38 
39     /* Returns required number of bytes for N line segments */
bytesPointMi40     static __forceinline size_t bytes(size_t N)
41     {
42       return blocks(N) * sizeof(PointMi);
43     }
44 
45    public:
46     /* Default constructor */
PointMiPointMi47     __forceinline PointMi() {}
48 
49     /* Construction from vertices and IDs */
PointMiPointMi50     __forceinline PointMi(const vuint<M>& geomIDs, const vuint<M>& primIDs, Geometry::GType gtype, uint32_t numPrimitives)
51         : gtype((unsigned char)gtype),
52           numPrimitives(numPrimitives),
53           sharedGeomID(geomIDs[0]),
54           primIDs(primIDs)
55     {
56       assert(all(vuint<M>(geomID()) == geomIDs));
57     }
58 
59     /* Returns a mask that tells which line segments are valid */
validPointMi60     __forceinline vbool<M> valid() const {
61       return vint<M>(step) < vint<M>(numPrimitives);
62     }
63 
64     /* Returns if the specified line segment is valid */
validPointMi65     __forceinline bool valid(const size_t i) const
66     {
67       assert(i < M);
68       return i < numPrimitives;
69     }
70 
71     /* Returns the number of stored line segments */
sizePointMi72     __forceinline size_t size() const {
73       return numPrimitives;
74     }
75 
76     __forceinline unsigned int geomID(unsigned int i = 0) const {
77       return sharedGeomID;
78     }
79 
primIDPointMi80     __forceinline vuint<M>& primID() {
81       return primIDs;
82     }
primIDPointMi83     __forceinline const vuint<M>& primID() const {
84       return primIDs;
85     }
primIDPointMi86     __forceinline unsigned int primID(const size_t i) const {
87       assert(i < M);
88       return primIDs[i];
89     }
90 
91     /* gather the line segments */
92     __forceinline void gather(Vec4vf<M>& p0, const Points* geom) const;
93     __forceinline void gather(Vec4vf<M>& p0, Vec3vf<M>& n0, const Points* geom) const;
94 
95     __forceinline void gatheri(Vec4vf<M>& p0, const Points* geom, const int itime) const;
96     __forceinline void gatheri(Vec4vf<M>& p0, Vec3vf<M>& n0, const Points* geom, const int itime) const;
97 
98     __forceinline void gather(Vec4vf<M>& p0, const Points* geom, float time) const;
99     __forceinline void gather(Vec4vf<M>& p0, Vec3vf<M>& n0, const Points* geom, float time) const;
100 
101     /* Calculate the bounds of the line segments */
102     __forceinline const BBox3fa bounds(const Scene* scene, size_t itime = 0) const
103     {
104       BBox3fa bounds = empty;
105       for (size_t i = 0; i < M && valid(i); i++) {
106         const Points* geom = scene->get<Points>(geomID(i));
107         bounds.extend(geom->bounds(primID(i),itime));
108       }
109       return bounds;
110     }
111 
112     /* Calculate the linear bounds of the primitive */
linearBoundsPointMi113     __forceinline LBBox3fa linearBounds(const Scene* scene, size_t itime) {
114       return LBBox3fa(bounds(scene, itime + 0), bounds(scene, itime + 1));
115     }
116 
linearBoundsPointMi117     __forceinline LBBox3fa linearBounds(const Scene* const scene, size_t itime, size_t numTimeSteps)
118     {
119       LBBox3fa allBounds = empty;
120       for (size_t i = 0; i < M && valid(i); i++) {
121         const Points* geom = scene->get<Points>(geomID(i));
122         allBounds.extend(geom->linearBounds(primID(i), itime, numTimeSteps));
123       }
124       return allBounds;
125     }
126 
linearBoundsPointMi127     __forceinline LBBox3fa linearBounds(const Scene* const scene, const BBox1f time_range)
128     {
129       LBBox3fa allBounds = empty;
130       for (size_t i = 0; i < M && valid(i); i++) {
131         const Points* geom = scene->get<Points>(geomID((unsigned int)i));
132         allBounds.extend(geom->linearBounds(primID(i), time_range));
133       }
134       return allBounds;
135     }
136 
137     /* Fill line segment from line segment list */
138     template<typename PrimRefT>
fillPointMi139     __forceinline void fill(const PrimRefT* prims, size_t& begin, size_t end, Scene* scene)
140     {
141       Geometry::GType gty = scene->get(prims[begin].geomID())->getType();
142       vuint<M> geomID, primID;
143       vuint<M> v0;
144       const PrimRefT* prim = &prims[begin];
145 
146       int numPrimitives = 0;
147       for (size_t i = 0; i < M; i++) {
148         if (begin < end) {
149           geomID[i] = prim->geomID();
150           primID[i] = prim->primID();
151           begin++;
152           numPrimitives++;
153         } else {
154           assert(i);
155           if (i > 0) {
156             geomID[i] = geomID[i - 1];
157             primID[i] = primID[i - 1];
158           }
159         }
160         if (begin < end)
161           prim = &prims[begin];  // FIXME: remove this line
162       }
163       new (this) PointMi(geomID, primID, gty, numPrimitives);  // FIXME: use non temporal store
164     }
165 
166     template<typename BVH, typename Allocator>
createLeafPointMi167     __forceinline static typename BVH::NodeRef createLeaf(BVH* bvh,
168                                                           const PrimRef* prims,
169                                                           const range<size_t>& set,
170                                                           const Allocator& alloc)
171     {
172       size_t start    = set.begin();
173       size_t items    = PointMi::blocks(set.size());
174       size_t numbytes = PointMi::bytes(set.size());
175       PointMi* accel  = (PointMi*)alloc.malloc1(numbytes, M * sizeof(float));
176       for (size_t i = 0; i < items; i++) {
177         accel[i].fill(prims, start, set.end(), bvh->scene);
178       }
179       return bvh->encodeLeaf((char*)accel, items);
180     };
181 
fillMBPointMi182     __forceinline LBBox3fa fillMB(const PrimRef* prims, size_t& begin, size_t end, Scene* scene, size_t itime)
183     {
184       fill(prims, begin, end, scene);
185       return linearBounds(scene, itime);
186     }
187 
fillMBPointMi188     __forceinline LBBox3fa fillMB(
189         const PrimRefMB* prims, size_t& begin, size_t end, Scene* scene, const BBox1f time_range)
190     {
191       fill(prims, begin, end, scene);
192       return linearBounds(scene, time_range);
193     }
194 
195     template<typename BVH, typename SetMB, typename Allocator>
createLeafMBPointMi196     __forceinline static typename BVH::NodeRecordMB4D createLeafMB(BVH* bvh, const SetMB& prims, const Allocator& alloc)
197     {
198       size_t start                     = prims.object_range.begin();
199       size_t end                       = prims.object_range.end();
200       size_t items                     = PointMi::blocks(prims.object_range.size());
201       size_t numbytes                  = PointMi::bytes(prims.object_range.size());
202       PointMi* accel                   = (PointMi*)alloc.malloc1(numbytes, M * sizeof(float));
203       const typename BVH::NodeRef node = bvh->encodeLeaf((char*)accel, items);
204 
205       LBBox3fa bounds = empty;
206       for (size_t i = 0; i < items; i++)
207         bounds.extend(accel[i].fillMB(prims.prims->data(), start, end, bvh->scene, prims.time_range));
208 
209       return typename BVH::NodeRecordMB4D(node, bounds, prims.time_range);
210     };
211 
212     /*! output operator */
213     friend __forceinline embree_ostream operator<<(embree_ostream cout, const PointMi& line)
214     {
215       return cout << "Line" << M << "i {" << line.v0 << ", " << line.geomID() << ", " << line.primID() << "}";
216     }
217 
218    public:
219     unsigned char gtype;
220     unsigned char numPrimitives;
221     unsigned int sharedGeomID;
222 
223    private:
224     vuint<M> primIDs;  // primitive ID
225   };
226 
227   template<>
gather(Vec4vf4 & p0,const Points * geom)228   __forceinline void PointMi<4>::gather(Vec4vf4& p0, const Points* geom) const
229   {
230     const vfloat4 a0   = vfloat4::loadu(geom->vertexPtr(primID(0)));
231     const vfloat4 a1   = vfloat4::loadu(geom->vertexPtr(primID(1)));
232     const vfloat4 a2   = vfloat4::loadu(geom->vertexPtr(primID(2)));
233     const vfloat4 a3   = vfloat4::loadu(geom->vertexPtr(primID(3)));
234     transpose(a0, a1, a2, a3, p0.x, p0.y, p0.z, p0.w);
235   }
236 
237   template<>
gather(Vec4vf4 & p0,Vec3vf4 & n0,const Points * geom)238   __forceinline void PointMi<4>::gather(Vec4vf4& p0, Vec3vf4& n0, const Points* geom) const
239   {
240     const vfloat4 a0   = vfloat4::loadu(geom->vertexPtr(primID(0)));
241     const vfloat4 a1   = vfloat4::loadu(geom->vertexPtr(primID(1)));
242     const vfloat4 a2   = vfloat4::loadu(geom->vertexPtr(primID(2)));
243     const vfloat4 a3   = vfloat4::loadu(geom->vertexPtr(primID(3)));
244     transpose(a0, a1, a2, a3, p0.x, p0.y, p0.z, p0.w);
245     const vfloat4 b0 = vfloat4(geom->normal(primID(0)));
246     const vfloat4 b1 = vfloat4(geom->normal(primID(1)));
247     const vfloat4 b2 = vfloat4(geom->normal(primID(2)));
248     const vfloat4 b3 = vfloat4(geom->normal(primID(3)));
249     transpose(b0, b1, b2, b3, n0.x, n0.y, n0.z);
250   }
251 
252   template<>
gatheri(Vec4vf4 & p0,const Points * geom,const int itime)253   __forceinline void PointMi<4>::gatheri(Vec4vf4& p0, const Points* geom, const int itime) const
254   {
255     const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0), itime));
256     const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1), itime));
257     const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2), itime));
258     const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3), itime));
259     transpose(a0, a1, a2, a3, p0.x, p0.y, p0.z, p0.w);
260   }
261 
262   template<>
gatheri(Vec4vf4 & p0,Vec3vf4 & n0,const Points * geom,const int itime)263   __forceinline void PointMi<4>::gatheri(Vec4vf4& p0, Vec3vf4& n0, const Points* geom, const int itime) const
264   {
265     const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0), itime));
266     const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1), itime));
267     const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2), itime));
268     const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3), itime));
269     transpose(a0, a1, a2, a3, p0.x, p0.y, p0.z, p0.w);
270     const vfloat4 b0 = vfloat4(geom->normal(primID(0), itime));
271     const vfloat4 b1 = vfloat4(geom->normal(primID(1), itime));
272     const vfloat4 b2 = vfloat4(geom->normal(primID(2), itime));
273     const vfloat4 b3 = vfloat4(geom->normal(primID(3), itime));
274     transpose(b0, b1, b2, b3, n0.x, n0.y, n0.z);
275   }
276 
277   template<>
gather(Vec4vf4 & p0,const Points * geom,float time)278   __forceinline void PointMi<4>::gather(Vec4vf4& p0, const Points* geom, float time) const
279   {
280     float ftime;
281     const int itime = geom->timeSegment(time, ftime);
282 
283     Vec4vf4 a0; gatheri(a0, geom, itime);
284     Vec4vf4 b0; gatheri(b0, geom, itime + 1);
285     p0 = lerp(a0, b0, vfloat4(ftime));
286   }
287 
288   template<>
gather(Vec4vf4 & p0,Vec3vf4 & n0,const Points * geom,float time)289   __forceinline void PointMi<4>::gather(Vec4vf4& p0, Vec3vf4& n0, const Points* geom, float time) const
290   {
291     float ftime;
292     const int itime = geom->timeSegment(time, ftime);
293 
294     Vec4vf4 a0, b0;
295     Vec3vf4 norm0, norm1;
296     gatheri(a0, norm0, geom, itime);
297     gatheri(b0, norm1, geom, itime + 1);
298     p0 = lerp(a0, b0, vfloat4(ftime));
299     n0 = lerp(norm0, norm1, vfloat4(ftime));
300   }
301 
302 #if defined(__AVX__)
303 
304   template<>
gather(Vec4vf8 & p0,const Points * geom)305   __forceinline void PointMi<8>::gather(Vec4vf8& p0, const Points* geom) const
306   {
307     const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0)));
308     const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1)));
309     const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2)));
310     const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3)));
311     const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(primID(4)));
312     const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(primID(5)));
313     const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(primID(6)));
314     const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(primID(7)));
315     transpose(a0, a1, a2, a3, a4, a5, a6, a7, p0.x, p0.y, p0.z, p0.w);
316   }
317 
318   template<>
gather(Vec4vf8 & p0,Vec3vf8 & n0,const Points * geom)319   __forceinline void PointMi<8>::gather(Vec4vf8& p0, Vec3vf8& n0, const Points* geom) const
320   {
321     const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0)));
322     const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1)));
323     const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2)));
324     const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3)));
325     const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(primID(4)));
326     const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(primID(5)));
327     const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(primID(6)));
328     const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(primID(7)));
329     transpose(a0, a1, a2, a3, a4, a5, a6, a7, p0.x, p0.y, p0.z, p0.w);
330     const vfloat4 b0 = vfloat4(geom->normal(primID(0)));
331     const vfloat4 b1 = vfloat4(geom->normal(primID(1)));
332     const vfloat4 b2 = vfloat4(geom->normal(primID(2)));
333     const vfloat4 b3 = vfloat4(geom->normal(primID(3)));
334     const vfloat4 b4 = vfloat4(geom->normal(primID(4)));
335     const vfloat4 b5 = vfloat4(geom->normal(primID(5)));
336     const vfloat4 b6 = vfloat4(geom->normal(primID(6)));
337     const vfloat4 b7 = vfloat4(geom->normal(primID(7)));
338     transpose(b0, b1, b2, b3, b4, b5, b6, b7, n0.x, n0.y, n0.z);
339   }
340 
341   template<>
gatheri(Vec4vf8 & p0,const Points * geom,const int itime)342   __forceinline void PointMi<8>::gatheri(Vec4vf8& p0, const Points* geom, const int itime) const
343   {
344     const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0), itime));
345     const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1), itime));
346     const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2), itime));
347     const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3), itime));
348     const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(primID(4), itime));
349     const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(primID(5), itime));
350     const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(primID(6), itime));
351     const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(primID(7), itime));
352     transpose(a0, a1, a2, a3, a4, a5, a6, a7, p0.x, p0.y, p0.z, p0.w);
353   }
354 
355   template<>
gatheri(Vec4vf8 & p0,Vec3vf8 & n0,const Points * geom,const int itime)356   __forceinline void PointMi<8>::gatheri(Vec4vf8& p0, Vec3vf8& n0, const Points* geom, const int itime) const
357   {
358     const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0), itime));
359     const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1), itime));
360     const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2), itime));
361     const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3), itime));
362     const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(primID(4), itime));
363     const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(primID(5), itime));
364     const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(primID(6), itime));
365     const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(primID(7), itime));
366     transpose(a0, a1, a2, a3, a4, a5, a6, a7, p0.x, p0.y, p0.z, p0.w);
367     const vfloat4 b0 = vfloat4(geom->normal(primID(0), itime));
368     const vfloat4 b1 = vfloat4(geom->normal(primID(1), itime));
369     const vfloat4 b2 = vfloat4(geom->normal(primID(2), itime));
370     const vfloat4 b3 = vfloat4(geom->normal(primID(3), itime));
371     const vfloat4 b4 = vfloat4(geom->normal(primID(4), itime));
372     const vfloat4 b5 = vfloat4(geom->normal(primID(5), itime));
373     const vfloat4 b6 = vfloat4(geom->normal(primID(6), itime));
374     const vfloat4 b7 = vfloat4(geom->normal(primID(7), itime));
375     transpose(b0, b1, b2, b3, b4, b5, b6, b7, n0.x, n0.y, n0.z);
376   }
377 
378   template<>
gather(Vec4vf8 & p0,const Points * geom,float time)379   __forceinline void PointMi<8>::gather(Vec4vf8& p0, const Points* geom, float time) const
380   {
381     float ftime;
382     const int itime = geom->timeSegment(time, ftime);
383 
384     Vec4vf8 a0;
385     gatheri(a0, geom, itime);
386     Vec4vf8 b0;
387     gatheri(b0, geom, itime + 1);
388     p0 = lerp(a0, b0, vfloat8(ftime));
389   }
390 
391   template<>
gather(Vec4vf8 & p0,Vec3vf8 & n0,const Points * geom,float time)392   __forceinline void PointMi<8>::gather(Vec4vf8& p0, Vec3vf8& n0, const Points* geom, float time) const
393   {
394     float ftime;
395     const int itime = geom->timeSegment(time, ftime);
396 
397     Vec4vf8 a0, b0;
398     Vec3vf8 norm0, norm1;
399     gatheri(a0, norm0, geom, itime);
400     gatheri(b0, norm1, geom, itime + 1);
401     p0 = lerp(a0, b0, vfloat8(ftime));
402     n0 = lerp(norm0, norm1, vfloat8(ftime));
403   }
404 #endif
405 
406   template<int M>
407   typename PointMi<M>::Type PointMi<M>::type;
408 
409   typedef PointMi<4> Point4i;
410   typedef PointMi<8> Point8i;
411 
412 }  // namespace embree
413