1// Copyright 2009-2021 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5
6#include "patch.h"
7#include "feature_adaptive_eval_grid.h"
8
9namespace embree
10{
11 namespace isa
12 {
13 struct PatchEvalGrid
14 {
15 typedef Patch3fa Patch;
16 typedef Patch::Ref Ref;
17 typedef GeneralCatmullClarkPatch3fa GeneralCatmullClarkPatch;
18 typedef CatmullClarkPatch3fa CatmullClarkPatch;
19 typedef BSplinePatch3fa BSplinePatch;
20 typedef BezierPatch3fa BezierPatch;
21 typedef GregoryPatch3fa GregoryPatch;
22 typedef BilinearPatch3fa BilinearPatch;
23
24 private:
25 const unsigned x0,x1;
26 const unsigned y0,y1;
27 const unsigned swidth,sheight;
28 const float rcp_swidth, rcp_sheight;
29 float* const Px;
30 float* const Py;
31 float* const Pz;
32 float* const U;
33 float* const V;
34 float* const Nx;
35 float* const Ny;
36 float* const Nz;
37 const unsigned dwidth,dheight;
38 unsigned count;
39
40 public:
41
42 PatchEvalGrid (Ref patch, unsigned subPatch,
43 const unsigned x0, const unsigned x1, const unsigned y0, const unsigned y1, const unsigned swidth, const unsigned sheight,
44 float* Px, float* Py, float* Pz, float* U, float* V,
45 float* Nx, float* Ny, float* Nz,
46 const unsigned dwidth, const unsigned dheight)
47 : 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)),
48 Px(Px), Py(Py), Pz(Pz), U(U), V(V), Nx(Nx), Ny(Ny), Nz(Nz), dwidth(dwidth), dheight(dheight), count(0)
49 {
50 assert(swidth < (2<<20) && sheight < (2<<20));
51 const BBox2f srange(Vec2f(0.0f,0.0f),Vec2f(float(swidth-1),float(sheight-1)));
52 const BBox2f erange(Vec2f(float(x0),float(y0)),Vec2f((float)x1,(float)y1));
53 bool done MAYBE_UNUSED = eval(This: patch,subPatch,srange,erange);
54 assert(done);
55 assert(count == (x1-x0+1)*(y1-y0+1));
56 }
57
58 template<typename Patch>
59 __forceinline void evalLocalGrid(const Patch* patch, const BBox2f& srange, const int lx0, const int lx1, const int ly0, const int ly1)
60 {
61 const float scale_x = rcp(x: srange.upper.x-srange.lower.x);
62 const float scale_y = rcp(x: srange.upper.y-srange.lower.y);
63 count += (lx1-lx0)*(ly1-ly0);
64
65#if 0
66 for (unsigned iy=ly0; iy<ly1; iy++) {
67 for (unsigned ix=lx0; ix<lx1; ix++) {
68 const float lu = select(ix == swidth -1, float(1.0f), (float(ix)-srange.lower.x)*scale_x);
69 const float lv = select(iy == sheight-1, float(1.0f), (float(iy)-srange.lower.y)*scale_y);
70 const Vec3fa p = patch->patch.eval(lu,lv);
71 const float u = float(ix)*rcp_swidth;
72 const float v = float(iy)*rcp_sheight;
73 const int ofs = (iy-y0)*dwidth+(ix-x0);
74 Px[ofs] = p.x;
75 Py[ofs] = p.y;
76 Pz[ofs] = p.z;
77 U[ofs] = u;
78 V[ofs] = v;
79 }
80 }
81#else
82 foreach2(lx0,lx1,ly0,ly1,[&](const vboolx& valid, const vintx& ix, const vintx& iy) {
83 const vfloatx lu = select(m: ix == swidth -1, t: vfloatx(1.0f), f: (vfloatx(ix)-srange.lower.x)*scale_x);
84 const vfloatx lv = select(m: iy == sheight-1, t: vfloatx(1.0f), f: (vfloatx(iy)-srange.lower.y)*scale_y);
85 const Vec3vfx p = patch->patch.eval(lu,lv);
86 Vec3vfx n = zero;
87 if (unlikely(Nx != nullptr)) n = normalize_safe(patch->patch.normal(lu,lv));
88 const vfloatx u = vfloatx(ix)*rcp_swidth;
89 const vfloatx v = vfloatx(iy)*rcp_sheight;
90 const vintx ofs = (iy-y0)*dwidth+(ix-x0);
91 if (likely(all(valid)) && all(b: iy==iy[0])) {
92 const unsigned ofs2 = ofs[0];
93 vfloatx::storeu(ptr: Px+ofs2,v: p.x);
94 vfloatx::storeu(ptr: Py+ofs2,v: p.y);
95 vfloatx::storeu(ptr: Pz+ofs2,v: p.z);
96 vfloatx::storeu(ptr: U+ofs2,v: u);
97 vfloatx::storeu(ptr: V+ofs2,v);
98 if (unlikely(Nx != nullptr)) {
99 vfloatx::storeu(ptr: Nx+ofs2,v: n.x);
100 vfloatx::storeu(ptr: Ny+ofs2,v: n.y);
101 vfloatx::storeu(ptr: Nz+ofs2,v: n.z);
102 }
103 } else {
104 foreach_unique_index(valid,iy,[&](const vboolx& valid, const int iy0, const int j) {
105 const unsigned ofs2 = ofs[j]-j;
106 vfloatx::storeu(mask: valid,ptr: Px+ofs2,v: p.x);
107 vfloatx::storeu(mask: valid,ptr: Py+ofs2,v: p.y);
108 vfloatx::storeu(mask: valid,ptr: Pz+ofs2,v: p.z);
109 vfloatx::storeu(mask: valid,ptr: U+ofs2,v: u);
110 vfloatx::storeu(mask: valid,ptr: V+ofs2,v);
111 if (unlikely(Nx != nullptr)) {
112 vfloatx::storeu(mask: valid,ptr: Nx+ofs2,v: n.x);
113 vfloatx::storeu(mask: valid,ptr: Ny+ofs2,v: n.y);
114 vfloatx::storeu(mask: valid,ptr: Nz+ofs2,v: n.z);
115 }
116 });
117 }
118 });
119#endif
120 }
121
122 bool eval(Ref This, const BBox2f& srange, const BBox2f& erange, const unsigned depth)
123 {
124 if (erange.empty())
125 return true;
126
127 const int lx0 = (int) ceilf(x: erange.lower.x);
128 const int lx1 = (int) ceilf(x: erange.upper.x) + (erange.upper.x == x1 && (srange.lower.x < erange.upper.x || erange.upper.x == 0));
129 const int ly0 = (int) ceilf(x: erange.lower.y);
130 const int ly1 = (int) ceilf(x: erange.upper.y) + (erange.upper.y == y1 && (srange.lower.y < erange.upper.y || erange.upper.y == 0));
131 if (lx0 >= lx1 || ly0 >= ly1)
132 return true;
133
134 if (!This)
135 return false;
136
137 switch (This.type())
138 {
139 case Patch::BILINEAR_PATCH: {
140 evalLocalGrid(patch: (Patch::BilinearPatch*)This.object(),srange,lx0,lx1,ly0,ly1);
141 return true;
142 }
143 case Patch::BSPLINE_PATCH: {
144 evalLocalGrid(patch: (Patch::BSplinePatch*)This.object(),srange,lx0,lx1,ly0,ly1);
145 return true;
146 }
147 case Patch::BEZIER_PATCH: {
148 evalLocalGrid(patch: (Patch::BezierPatch*)This.object(),srange,lx0,lx1,ly0,ly1);
149 return true;
150 }
151 case Patch::GREGORY_PATCH: {
152 evalLocalGrid(patch: (Patch::GregoryPatch*)This.object(),srange,lx0,lx1,ly0,ly1);
153 return true;
154 }
155 case Patch::SUBDIVIDED_QUAD_PATCH:
156 {
157 const Vec2f c = srange.center();
158 const BBox2f srange0(srange.lower,c);
159 const BBox2f srange1(Vec2f(c.x,srange.lower.y),Vec2f(srange.upper.x,c.y));
160 const BBox2f srange2(c,srange.upper);
161 const BBox2f srange3(Vec2f(srange.lower.x,c.y),Vec2f(c.x,srange.upper.y));
162
163 Patch::SubdividedQuadPatch* patch = (Patch::SubdividedQuadPatch*)This.object();
164 eval(This: patch->child[0],srange: srange0,erange: intersect(a: srange0,b: erange),depth: depth+1);
165 eval(This: patch->child[1],srange: srange1,erange: intersect(a: srange1,b: erange),depth: depth+1);
166 eval(This: patch->child[2],srange: srange2,erange: intersect(a: srange2,b: erange),depth: depth+1);
167 eval(This: patch->child[3],srange: srange3,erange: intersect(a: srange3,b: erange),depth: depth+1);
168 return true;
169 }
170 case Patch::EVAL_PATCH: {
171 CatmullClarkPatch patch; patch.deserialize(ptr: This.object());
172 FeatureAdaptiveEvalGrid(patch,srange,erange,depth,x0,x1,y0,y1,swidth,sheight,Px,Py,Pz,U,V,Nx,Ny,Nz,dwidth,dheight);
173 count += (lx1-lx0)*(ly1-ly0);
174 return true;
175 }
176 default:
177 assert(false);
178 return false;
179 }
180 }
181
182 bool eval(Ref This, unsigned subPatch, const BBox2f& srange, const BBox2f& erange)
183 {
184 if (!This)
185 return false;
186
187 switch (This.type())
188 {
189 case Patch::SUBDIVIDED_GENERAL_PATCH: {
190 Patch::SubdividedGeneralPatch* patch = (Patch::SubdividedGeneralPatch*)This.object();
191 assert(subPatch < patch->N);
192 return eval(This: patch->child[subPatch],srange,erange,depth: 1);
193 }
194 default:
195 assert(subPatch == 0);
196 return eval(This,srange,erange,depth: 0);
197 }
198 }
199 };
200
201 __forceinline unsigned patch_eval_subdivision_count (const HalfEdge* h)
202 {
203 const unsigned N = h->numEdges();
204 if (N == 4) return 1;
205 else return N;
206 }
207
208 template<typename Tessellator>
209 inline void patch_eval_subdivision (const HalfEdge* h, Tessellator tessellator)
210 {
211 const unsigned N = h->numEdges();
212 int neighborSubdiv[GeneralCatmullClarkPatch3fa::SIZE]; // FIXME: use array_t
213 float levels[GeneralCatmullClarkPatch3fa::SIZE];
214 for (unsigned i=0; i<N; i++) {
215 assert(i<GeneralCatmullClarkPatch3fa::SIZE);
216 neighborSubdiv[i] = h->hasOpposite() ? h->opposite()->numEdges() != 4 : 0;
217 levels[i] = h->edge_level;
218 h = h->next();
219 }
220 if (N == 4)
221 {
222 const Vec2f uv[4] = { Vec2f(0.0f,0.0f), Vec2f(1.0f,0.0f), Vec2f(1.0f,1.0f), Vec2f(0.0f,1.0f) };
223 tessellator(uv,neighborSubdiv,levels,0);
224 }
225 else
226 {
227 for (unsigned i=0; i<N; i++)
228 {
229 assert(i<MAX_PATCH_VALENCE);
230 static_assert(MAX_PATCH_VALENCE <= 16, "MAX_PATCH_VALENCE > 16");
231 const int h = (i >> 2) & 3, l = i & 3;
232 const Vec2f subPatchID((float)l,(float)h);
233 const Vec2f uv[4] = { 2.0f*subPatchID + (0.5f+Vec2f(0.0f,0.0f)),
234 2.0f*subPatchID + (0.5f+Vec2f(1.0f,0.0f)),
235 2.0f*subPatchID + (0.5f+Vec2f(1.0f,1.0f)),
236 2.0f*subPatchID + (0.5f+Vec2f(0.0f,1.0f)) };
237 const int neighborSubdiv1[4] = { 0,0,0,0 };
238 const float levels1[4] = { 0.5f*levels[(i+0)%N], 0.5f*levels[(i+0)%N], 0.5f*levels[(i+N-1)%N], 0.5f*levels[(i+N-1)%N] };
239 tessellator(uv,neighborSubdiv1,levels1,i);
240 }
241 }
242 }
243 }
244}
245
246

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