1// Copyright 2009-2021 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5
6#include "patch.h"
7#include "catmullclark_patch.h"
8#include "bspline_patch.h"
9#include "gregory_patch.h"
10#include "tessellation.h"
11
12namespace embree
13{
14 namespace isa
15 {
16 struct FeatureAdaptiveEvalGrid
17 {
18 typedef CatmullClark1Ring3fa CatmullClarkRing;
19 typedef CatmullClarkPatch3fa CatmullClarkPatch;
20 typedef BilinearPatch3fa BilinearPatch;
21 typedef BSplinePatch3fa BSplinePatch;
22 typedef BezierPatch3fa BezierPatch;
23 typedef GregoryPatch3fa GregoryPatch;
24
25 private:
26 const unsigned x0,x1;
27 const unsigned y0,y1;
28 const unsigned swidth,sheight;
29 const float rcp_swidth, rcp_sheight;
30 float* const Px;
31 float* const Py;
32 float* const Pz;
33 float* const U;
34 float* const V;
35 float* const Nx;
36 float* const Ny;
37 float* const Nz;
38 const unsigned dwidth;
39 //const unsigned dheight;
40 unsigned count;
41
42
43 public:
44 FeatureAdaptiveEvalGrid (const GeneralCatmullClarkPatch3fa& patch, unsigned subPatch,
45 const unsigned x0, const unsigned x1, const unsigned y0, const unsigned y1, const unsigned swidth, const unsigned sheight,
46 float* Px, float* Py, float* Pz, float* U, float* V,
47 float* Nx, float* Ny, float* Nz,
48 const unsigned dwidth, const unsigned dheight)
49 : x0(x0), x1(x1), y0(y0), y1(y1), swidth(swidth), sheight(sheight), rcp_swidth(1.0f/(swidth-1.0f)), rcp_sheight(1.0f/(sheight-1.0f)),
50 Px(Px), Py(Py), Pz(Pz), U(U), V(V), Nx(Nx), Ny(Ny), Nz(Nz), dwidth(dwidth), /*dheight(dheight),*/ count(0)
51 {
52 assert(swidth < (2<<20) && sheight < (2<<20));
53 const BBox2f srange(Vec2f(0.0f,0.0f),Vec2f(float(swidth-1),float(sheight-1)));
54 const BBox2f erange(Vec2f((float)x0,(float)y0),Vec2f((float)x1,(float)y1));
55
56 /* convert into standard quad patch if possible */
57 if (likely(patch.isQuadPatch()))
58 {
59 CatmullClarkPatch3fa qpatch; patch.init(patch&: qpatch);
60 eval(patch: qpatch, srange, erange, depth: 0);
61 assert(count == (x1-x0+1)*(y1-y0+1));
62 return;
63 }
64
65 /* subdivide patch */
66 unsigned N;
67 array_t<CatmullClarkPatch3fa,GeneralCatmullClarkPatch3fa::SIZE> patches;
68 patch.subdivide(patch&: patches,N_o&: N);
69
70 if (N == 4)
71 {
72 const Vec2f c = srange.center();
73 const BBox2f srange0(srange.lower,c);
74 const BBox2f srange1(Vec2f(c.x,srange.lower.y),Vec2f(srange.upper.x,c.y));
75 const BBox2f srange2(c,srange.upper);
76 const BBox2f srange3(Vec2f(srange.lower.x,c.y),Vec2f(c.x,srange.upper.y));
77
78#if PATCH_USE_GREGORY == 2
79 BezierCurve3fa borders[GeneralCatmullClarkPatch3fa::SIZE]; patch.getLimitBorder(borders);
80 BezierCurve3fa border0l,border0r; borders[0].subdivide(border0l,border0r);
81 BezierCurve3fa border1l,border1r; borders[1].subdivide(border1l,border1r);
82 BezierCurve3fa border2l,border2r; borders[2].subdivide(border2l,border2r);
83 BezierCurve3fa border3l,border3r; borders[3].subdivide(border3l,border3r);
84 GeneralCatmullClarkPatch3fa::fix_quad_ring_order(patches);
85 eval(patches[0],srange0,intersect(srange0,erange),1,&border0l,nullptr,nullptr,&border3r);
86 eval(patches[1],srange1,intersect(srange1,erange),1,&border0r,&border1l,nullptr,nullptr);
87 eval(patches[2],srange2,intersect(srange2,erange),1,nullptr,&border1r,&border2l,nullptr);
88 eval(patches[3],srange3,intersect(srange3,erange),1,nullptr,nullptr,&border2r,&border3l);
89#else
90 GeneralCatmullClarkPatch3fa::fix_quad_ring_order(patches);
91 eval(patch: patches[0],srange: srange0,erange: intersect(a: srange0,b: erange),depth: 1);
92 eval(patch: patches[1],srange: srange1,erange: intersect(a: srange1,b: erange),depth: 1);
93 eval(patch: patches[2],srange: srange2,erange: intersect(a: srange2,b: erange),depth: 1);
94 eval(patch: patches[3],srange: srange3,erange: intersect(a: srange3,b: erange),depth: 1);
95#endif
96 }
97 else
98 {
99 assert(subPatch < N);
100
101#if PATCH_USE_GREGORY == 2
102 BezierCurve3fa borders[2]; patch.getLimitBorder(borders,subPatch);
103 BezierCurve3fa border0l,border0r; borders[0].subdivide(border0l,border0r);
104 BezierCurve3fa border2l,border2r; borders[1].subdivide(border2l,border2r);
105 eval(patches[subPatch], srange, erange, 1, &border0l, nullptr, nullptr, &border2r);
106#else
107 eval(patch: patches[subPatch], srange, erange, depth: 1);
108#endif
109
110 }
111 assert(count == (x1-x0+1)*(y1-y0+1));
112 }
113
114 FeatureAdaptiveEvalGrid (const CatmullClarkPatch3fa& patch,
115 const BBox2f& srange, const BBox2f& erange, const unsigned depth,
116 const unsigned x0, const unsigned x1, const unsigned y0, const unsigned y1, const unsigned swidth, const unsigned sheight,
117 float* Px, float* Py, float* Pz, float* U, float* V,
118 float* Nx, float* Ny, float* Nz,
119 const unsigned dwidth, const unsigned dheight)
120 : x0(x0), x1(x1), y0(y0), y1(y1), swidth(swidth), sheight(sheight), rcp_swidth(1.0f/(swidth-1.0f)), rcp_sheight(1.0f/(sheight-1.0f)),
121 Px(Px), Py(Py), Pz(Pz), U(U), V(V), Nx(Nx), Ny(Ny), Nz(Nz), dwidth(dwidth), /*dheight(dheight),*/ count(0)
122 {
123 eval(patch,srange,erange,depth);
124 }
125
126 template<typename Patch>
127 void evalLocalGrid(const Patch& patch, const BBox2f& srange, const int lx0, const int lx1, const int ly0, const int ly1)
128 {
129 const float scale_x = rcp(x: srange.upper.x-srange.lower.x);
130 const float scale_y = rcp(x: srange.upper.y-srange.lower.y);
131 count += (lx1-lx0)*(ly1-ly0);
132
133#if 0
134 for (unsigned iy=ly0; iy<ly1; iy++) {
135 for (unsigned ix=lx0; ix<lx1; ix++) {
136 const float lu = select(ix == swidth -1, float(1.0f), (float(ix)-srange.lower.x)*scale_x);
137 const float lv = select(iy == sheight-1, float(1.0f), (float(iy)-srange.lower.y)*scale_y);
138 const Vec3fa p = patch.eval(lu,lv);
139 const float u = float(ix)*rcp_swidth;
140 const float v = float(iy)*rcp_sheight;
141 const int ofs = (iy-y0)*dwidth+(ix-x0);
142 Px[ofs] = p.x;
143 Py[ofs] = p.y;
144 Pz[ofs] = p.z;
145 U[ofs] = u;
146 V[ofs] = v;
147 }
148 }
149#else
150 foreach2(lx0,lx1,ly0,ly1,[&](const vboolx& valid, const vintx& ix, const vintx& iy) {
151 const vfloatx lu = select(m: ix == swidth -1, t: vfloatx(1.0f), f: (vfloatx(ix)-srange.lower.x)*scale_x);
152 const vfloatx lv = select(m: iy == sheight-1, t: vfloatx(1.0f), f: (vfloatx(iy)-srange.lower.y)*scale_y);
153 const Vec3vfx p = patch.eval(lu,lv);
154 Vec3vfx n = zero;
155 if (unlikely(Nx != nullptr)) n = normalize_safe(patch.normal(lu,lv));
156 const vfloatx u = vfloatx(ix)*rcp_swidth;
157 const vfloatx v = vfloatx(iy)*rcp_sheight;
158 const vintx ofs = (iy-y0)*dwidth+(ix-x0);
159 if (likely(all(valid)) && all(b: iy==iy[0])) {
160 const unsigned ofs2 = ofs[0];
161 vfloatx::storeu(ptr: Px+ofs2,v: p.x);
162 vfloatx::storeu(ptr: Py+ofs2,v: p.y);
163 vfloatx::storeu(ptr: Pz+ofs2,v: p.z);
164 vfloatx::storeu(ptr: U+ofs2,v: u);
165 vfloatx::storeu(ptr: V+ofs2,v);
166 if (unlikely(Nx != nullptr)) {
167 vfloatx::storeu(ptr: Nx+ofs2,v: n.x);
168 vfloatx::storeu(ptr: Ny+ofs2,v: n.y);
169 vfloatx::storeu(ptr: Nz+ofs2,v: n.z);
170 }
171 } else {
172 foreach_unique_index(valid,iy,[&](const vboolx& valid, const int iy0, const int j) {
173 const unsigned ofs2 = ofs[j]-j;
174 vfloatx::storeu(mask: valid,ptr: Px+ofs2,v: p.x);
175 vfloatx::storeu(mask: valid,ptr: Py+ofs2,v: p.y);
176 vfloatx::storeu(mask: valid,ptr: Pz+ofs2,v: p.z);
177 vfloatx::storeu(mask: valid,ptr: U+ofs2,v: u);
178 vfloatx::storeu(mask: valid,ptr: V+ofs2,v);
179 if (unlikely(Nx != nullptr)) {
180 vfloatx::storeu(mask: valid,ptr: Nx+ofs2,v: n.x);
181 vfloatx::storeu(mask: valid,ptr: Ny+ofs2,v: n.y);
182 vfloatx::storeu(mask: valid,ptr: Nz+ofs2,v: n.z);
183 }
184 });
185 }
186 });
187#endif
188 }
189
190 __forceinline bool final(const CatmullClarkPatch3fa& patch, const CatmullClarkRing::Type type, unsigned depth)
191 {
192 const unsigned max_eval_depth = (type & CatmullClarkRing::TYPE_CREASES) ? PATCH_MAX_EVAL_DEPTH_CREASE : PATCH_MAX_EVAL_DEPTH_IRREGULAR;
193//#if PATCH_MIN_RESOLUTION
194// return patch.isFinalResolution(PATCH_MIN_RESOLUTION) || depth>=max_eval_depth;
195//#else
196 return depth>=max_eval_depth;
197//#endif
198 }
199
200 void eval(const CatmullClarkPatch3fa& patch, const BBox2f& srange, const BBox2f& erange, const unsigned depth,
201 const BezierCurve3fa* border0 = nullptr, const BezierCurve3fa* border1 = nullptr, const BezierCurve3fa* border2 = nullptr, const BezierCurve3fa* border3 = nullptr)
202 {
203 if (erange.empty())
204 return;
205
206 int lx0 = (int) ceilf(x: erange.lower.x);
207 int lx1 = (int) ceilf(x: erange.upper.x) + (erange.upper.x == x1 && (srange.lower.x < erange.upper.x || erange.upper.x == 0));
208 int ly0 = (int) ceilf(x: erange.lower.y);
209 int ly1 = (int) ceilf(x: erange.upper.y) + (erange.upper.y == y1 && (srange.lower.y < erange.upper.y || erange.upper.y == 0));
210 if (lx0 >= lx1 || ly0 >= ly1) return;
211
212 CatmullClarkPatch::Type ty = patch.type();
213
214 if (unlikely(final(patch,ty,depth)))
215 {
216 if (ty & CatmullClarkRing::TYPE_REGULAR) {
217 RegularPatch rpatch(patch,border0,border1,border2,border3);
218 evalLocalGrid(patch: rpatch,srange,lx0,lx1,ly0,ly1);
219 return;
220 } else {
221 IrregularFillPatch ipatch(patch,border0,border1,border2,border3);
222 evalLocalGrid(patch: ipatch,srange,lx0,lx1,ly0,ly1);
223 return;
224 }
225 }
226 else if (ty & CatmullClarkRing::TYPE_REGULAR_CREASES) {
227 assert(depth > 0);
228 RegularPatch rpatch(patch,border0,border1,border2,border3);
229 evalLocalGrid(patch: rpatch,srange,lx0,lx1,ly0,ly1);
230 return;
231 }
232#if PATCH_USE_GREGORY == 2
233 else if (ty & CatmullClarkRing::TYPE_GREGORY_CREASES) {
234 assert(depth > 0);
235 GregoryPatch gpatch(patch,border0,border1,border2,border3);
236 evalLocalGrid(gpatch,srange,lx0,lx1,ly0,ly1);
237 }
238#endif
239 else
240 {
241 array_t<CatmullClarkPatch3fa,4> patches;
242 patch.subdivide(patch&: patches);
243
244 const Vec2f c = srange.center();
245 const BBox2f srange0(srange.lower,c);
246 const BBox2f srange1(Vec2f(c.x,srange.lower.y),Vec2f(srange.upper.x,c.y));
247 const BBox2f srange2(c,srange.upper);
248 const BBox2f srange3(Vec2f(srange.lower.x,c.y),Vec2f(c.x,srange.upper.y));
249
250 eval(patch: patches[0],srange: srange0,erange: intersect(a: srange0,b: erange),depth: depth+1);
251 eval(patch: patches[1],srange: srange1,erange: intersect(a: srange1,b: erange),depth: depth+1);
252 eval(patch: patches[2],srange: srange2,erange: intersect(a: srange2,b: erange),depth: depth+1);
253 eval(patch: patches[3],srange: srange3,erange: intersect(a: srange3,b: erange),depth: depth+1);
254 }
255 }
256 };
257
258 template<typename Eval, typename Patch>
259 bool stitch_col(const Patch& patch, int subPatch,
260 const bool right, const unsigned y0, const unsigned y1, const int fine_y, const int coarse_y,
261 float* Px, float* Py, float* Pz, float* U, float* V, float* Nx, float* Ny, float* Nz, const unsigned dx0, const unsigned dwidth, const unsigned dheight)
262 {
263 assert(coarse_y <= fine_y);
264 if (likely(fine_y == coarse_y))
265 return false;
266
267 const unsigned y0s = stitch(x: y0,fine: fine_y,coarse: coarse_y);
268 const unsigned y1s = stitch(x: y1,fine: fine_y,coarse: coarse_y);
269 const unsigned M = y1s-y0s+1 + VSIZEX;
270
271 dynamic_large_stack_array(float,px,M,64*sizeof(float));
272 dynamic_large_stack_array(float,py,M,64*sizeof(float));
273 dynamic_large_stack_array(float,pz,M,64*sizeof(float));
274 dynamic_large_stack_array(float,u,M,64*sizeof(float));
275 dynamic_large_stack_array(float,v,M,64*sizeof(float));
276 dynamic_large_stack_array(float,nx,M,64*sizeof(float));
277 dynamic_large_stack_array(float,ny,M,64*sizeof(float));
278 dynamic_large_stack_array(float,nz,M,64*sizeof(float));
279 const bool has_Nxyz = Nx; assert(!Nx || (Ny && Nz));
280 Eval(patch,subPatch, right,right, y0s,y1s, 2,coarse_y+1, px,py,pz,u,v,
281 has_Nxyz ? (float*)nx : nullptr,has_Nxyz ? (float*)ny : nullptr ,has_Nxyz ? (float*)nz : nullptr, 1,4097);
282
283 for (unsigned y=y0; y<=y1; y++)
284 {
285 const unsigned ys = stitch(x: y,fine: fine_y,coarse: coarse_y)-y0s;
286 Px[(y-y0)*dwidth+dx0] = px[ys];
287 Py[(y-y0)*dwidth+dx0] = py[ys];
288 Pz[(y-y0)*dwidth+dx0] = pz[ys];
289 U [(y-y0)*dwidth+dx0] = u[ys];
290 V [(y-y0)*dwidth+dx0] = v[ys];
291 if (unlikely(has_Nxyz)) {
292 Nx[(y-y0)*dwidth+dx0] = nx[ys];
293 Ny[(y-y0)*dwidth+dx0] = ny[ys];
294 Nz[(y-y0)*dwidth+dx0] = nz[ys];
295 }
296 }
297 return true;
298 }
299
300 template<typename Eval, typename Patch>
301 bool stitch_row(const Patch& patch, int subPatch,
302 const bool bottom, const unsigned x0, const unsigned x1, const int fine_x, const int coarse_x,
303 float* Px, float* Py, float* Pz, float* U, float* V, float* Nx, float* Ny, float* Nz, const unsigned dy0, const unsigned dwidth, const unsigned dheight)
304 {
305 assert(coarse_x <= fine_x);
306 if (likely(fine_x == coarse_x))
307 return false;
308
309 const unsigned x0s = stitch(x: x0,fine: fine_x,coarse: coarse_x);
310 const unsigned x1s = stitch(x: x1,fine: fine_x,coarse: coarse_x);
311 const unsigned M = x1s-x0s+1 + VSIZEX;
312
313 dynamic_large_stack_array(float,px,M,32*sizeof(float));
314 dynamic_large_stack_array(float,py,M,32*sizeof(float));
315 dynamic_large_stack_array(float,pz,M,32*sizeof(float));
316 dynamic_large_stack_array(float,u,M,32*sizeof(float));
317 dynamic_large_stack_array(float,v,M,32*sizeof(float));
318 dynamic_large_stack_array(float,nx,M,32*sizeof(float));
319 dynamic_large_stack_array(float,ny,M,32*sizeof(float));
320 dynamic_large_stack_array(float,nz,M,32*sizeof(float));
321 const bool has_Nxyz = Nx; assert(!Nx || (Ny && Nz));
322 Eval(patch,subPatch, x0s,x1s, bottom,bottom, coarse_x+1,2, px,py,pz,u,v,
323 has_Nxyz ? (float*)nx :nullptr, has_Nxyz ? (float*)ny : nullptr , has_Nxyz ? (float*)nz : nullptr, 4097,1);
324
325 for (unsigned x=x0; x<=x1; x++)
326 {
327 const unsigned xs = stitch(x,fine: fine_x,coarse: coarse_x)-x0s;
328 Px[dy0*dwidth+x-x0] = px[xs];
329 Py[dy0*dwidth+x-x0] = py[xs];
330 Pz[dy0*dwidth+x-x0] = pz[xs];
331 U [dy0*dwidth+x-x0] = u[xs];
332 V [dy0*dwidth+x-x0] = v[xs];
333 if (unlikely(has_Nxyz)) {
334 Nx[dy0*dwidth+x-x0] = nx[xs];
335 Ny[dy0*dwidth+x-x0] = ny[xs];
336 Nz[dy0*dwidth+x-x0] = nz[xs];
337 }
338 }
339 return true;
340 }
341
342 template<typename Eval, typename Patch>
343 void feature_adaptive_eval_grid (const Patch& patch, unsigned subPatch, const float levels[4],
344 const unsigned x0, const unsigned x1, const unsigned y0, const unsigned y1, const unsigned swidth, const unsigned sheight,
345 float* Px, float* Py, float* Pz, float* U, float* V, float* Nx, float* Ny, float* Nz, const unsigned dwidth, const unsigned dheight)
346 {
347 bool sl = false, sr = false, st = false, sb = false;
348 if (levels) {
349 sl = x0 == 0 && stitch_col<Eval,Patch>(patch,subPatch,0,y0,y1,sheight-1,int(levels[3]), Px,Py,Pz,U,V,Nx,Ny,Nz, 0 ,dwidth,dheight);
350 sr = x1 == swidth-1 && stitch_col<Eval,Patch>(patch,subPatch,1,y0,y1,sheight-1,int(levels[1]), Px,Py,Pz,U,V,Nx,Ny,Nz, x1-x0,dwidth,dheight);
351 st = y0 == 0 && stitch_row<Eval,Patch>(patch,subPatch,0,x0,x1,swidth-1,int(levels[0]), Px,Py,Pz,U,V,Nx,Ny,Nz, 0 ,dwidth,dheight);
352 sb = y1 == sheight-1 && stitch_row<Eval,Patch>(patch,subPatch,1,x0,x1,swidth-1,int(levels[2]), Px,Py,Pz,U,V,Nx,Ny,Nz, y1-y0,dwidth,dheight);
353 }
354 const unsigned ofs = st*dwidth+sl;
355 Eval(patch,subPatch,x0+sl,x1-sr,y0+st,y1-sb, swidth,sheight, Px+ofs,Py+ofs,Pz+ofs,U+ofs,V+ofs,Nx?Nx+ofs:nullptr,Ny?Ny+ofs:nullptr,Nz?Nz+ofs:nullptr, dwidth,dheight);
356 }
357 }
358}
359
360

source code of qtquick3d/src/3rdparty/embree/kernels/subdiv/feature_adaptive_eval_grid.h