Revision control

++ // Copyright 2009-2021 Intel Corporation
++ // SPDX-License-Identifier: Apache-2.0
++
++ #include "subdivpatch1base.h"
++
++ namespace embree
++ {
++ namespace isa
++ {
++ Vec3fa patchEval(const SubdivPatch1Base& patch, const float uu, const float vv)
++ {
++ if (likely(patch.type == SubdivPatch1Base::BEZIER_PATCH))
++ return ((BezierPatch3fa*)patch.patch_v)->eval(uu,vv);
++ else if (likely(patch.type == SubdivPatch1Base::BSPLINE_PATCH))
++ return ((BSplinePatch3fa*)patch.patch_v)->eval(uu,vv);
++ else if (likely(patch.type == SubdivPatch1Base::GREGORY_PATCH))
++ return ((DenseGregoryPatch3fa*)patch.patch_v)->eval(uu,vv);
++ else if (likely(patch.type == SubdivPatch1Base::BILINEAR_PATCH))
++ return ((BilinearPatch3fa*)patch.patch_v)->eval(uu,vv);
++ return Vec3fa( zero );
++ }
++
++ Vec3fa patchNormal(const SubdivPatch1Base& patch, const float uu, const float vv)
++ {
++ if (likely(patch.type == SubdivPatch1Base::BEZIER_PATCH))
++ return ((BezierPatch3fa*)patch.patch_v)->normal(uu,vv);
++ else if (likely(patch.type == SubdivPatch1Base::BSPLINE_PATCH))
++ return ((BSplinePatch3fa*)patch.patch_v)->normal(uu,vv);
++ else if (likely(patch.type == SubdivPatch1Base::GREGORY_PATCH))
++ return ((DenseGregoryPatch3fa*)patch.patch_v)->normal(uu,vv);
++ else if (likely(patch.type == SubdivPatch1Base::BILINEAR_PATCH))
++ return ((BilinearPatch3fa*)patch.patch_v)->normal(uu,vv);
++ return Vec3fa( zero );
++ }
++
++ template<typename simdf>
++ Vec3<simdf> patchEval(const SubdivPatch1Base& patch, const simdf& uu, const simdf& vv)
++ {
++ if (likely(patch.type == SubdivPatch1Base::BEZIER_PATCH))
++ return ((BezierPatch3fa*)patch.patch_v)->eval(uu,vv);
++ else if (likely(patch.type == SubdivPatch1Base::BSPLINE_PATCH))
++ return ((BSplinePatch3fa*)patch.patch_v)->eval(uu,vv);
++ else if (likely(patch.type == SubdivPatch1Base::GREGORY_PATCH))
++ return ((DenseGregoryPatch3fa*)patch.patch_v)->eval(uu,vv);
++ else if (likely(patch.type == SubdivPatch1Base::BILINEAR_PATCH))
++ return ((BilinearPatch3fa*)patch.patch_v)->eval(uu,vv);
++ return Vec3<simdf>( zero );
++ }
++
++ template<typename simdf>
++ Vec3<simdf> patchNormal(const SubdivPatch1Base& patch, const simdf& uu, const simdf& vv)
++ {
++ if (likely(patch.type == SubdivPatch1Base::BEZIER_PATCH))
++ return ((BezierPatch3fa*)patch.patch_v)->normal(uu,vv);
++ else if (likely(patch.type == SubdivPatch1Base::BSPLINE_PATCH))
++ return ((BSplinePatch3fa*)patch.patch_v)->normal(uu,vv);
++ else if (likely(patch.type == SubdivPatch1Base::GREGORY_PATCH))
++ return ((DenseGregoryPatch3fa*)patch.patch_v)->normal(uu,vv);
++ else if (likely(patch.type == SubdivPatch1Base::BILINEAR_PATCH))
++ return ((BilinearPatch3fa*)patch.patch_v)->normal(uu,vv);
++ return Vec3<simdf>( zero );
++ }
++
++ /* eval grid over patch and stich edges when required */
++ void evalGrid(const SubdivPatch1Base& patch,
++ const unsigned x0, const unsigned x1,
++ const unsigned y0, const unsigned y1,
++ const unsigned swidth, const unsigned sheight,
++ float *__restrict__ const grid_x,
++ float *__restrict__ const grid_y,
++ float *__restrict__ const grid_z,
++ float *__restrict__ const grid_u,
++ float *__restrict__ const grid_v,
++ const SubdivMesh* const geom)
++ {
++ const unsigned dwidth = x1-x0+1;
++ const unsigned dheight = y1-y0+1;
++ const unsigned M = dwidth*dheight+VSIZEX;
++ const unsigned grid_size_simd_blocks = (M-1)/VSIZEX;
++
++ if (unlikely(patch.type == SubdivPatch1Base::EVAL_PATCH))
++ {
++ const bool displ = geom->displFunc;
++ const unsigned N = displ ? M : 0;
++ dynamic_large_stack_array(float,grid_Ng_x,N,32*32*sizeof(float));
++ dynamic_large_stack_array(float,grid_Ng_y,N,32*32*sizeof(float));
++ dynamic_large_stack_array(float,grid_Ng_z,N,32*32*sizeof(float));
++
++ if (geom->patch_eval_trees.size())
++ {
++ feature_adaptive_eval_grid<PatchEvalGrid>
++ (geom->patch_eval_trees[geom->numTimeSteps*patch.primID()+patch.time()], patch.subPatch(), patch.needsStitching() ? patch.level : nullptr,
++ x0,x1,y0,y1,swidth,sheight,
++ grid_x,grid_y,grid_z,grid_u,grid_v,
++ displ ? (float*)grid_Ng_x : nullptr, displ ? (float*)grid_Ng_y : nullptr, displ ? (float*)grid_Ng_z : nullptr,
++ dwidth,dheight);
++ }
++ else
++ {
++ GeneralCatmullClarkPatch3fa ccpatch(patch.edge(),geom->getVertexBuffer(patch.time()));
++
++ feature_adaptive_eval_grid<FeatureAdaptiveEvalGrid,GeneralCatmullClarkPatch3fa>
++ (ccpatch, patch.subPatch(), patch.needsStitching() ? patch.level : nullptr,
++ x0,x1,y0,y1,swidth,sheight,
++ grid_x,grid_y,grid_z,grid_u,grid_v,
++ displ ? (float*)grid_Ng_x : nullptr, displ ? (float*)grid_Ng_y : nullptr, displ ? (float*)grid_Ng_z : nullptr,
++ dwidth,dheight);
++ }
++
++ /* convert sub-patch UVs to patch UVs*/
++ const Vec2f uv0 = patch.getUV(0);
++ const Vec2f uv1 = patch.getUV(1);
++ const Vec2f uv2 = patch.getUV(2);
++ const Vec2f uv3 = patch.getUV(3);
++ for (unsigned i=0; i<grid_size_simd_blocks; i++)
++ {
++ const vfloatx u = vfloatx::load(&grid_u[i*VSIZEX]);
++ const vfloatx v = vfloatx::load(&grid_v[i*VSIZEX]);
++ const vfloatx patch_u = lerp2(uv0.x,uv1.x,uv3.x,uv2.x,u,v);
++ const vfloatx patch_v = lerp2(uv0.y,uv1.y,uv3.y,uv2.y,u,v);
++ vfloatx::store(&grid_u[i*VSIZEX],patch_u);
++ vfloatx::store(&grid_v[i*VSIZEX],patch_v);
++ }
++
++ /* call displacement shader */
++ if (unlikely(geom->displFunc)) {
++ RTCDisplacementFunctionNArguments args;
++ args.geometryUserPtr = geom->userPtr;
++ args.geometry = (RTCGeometry)geom;
++ //args.geomID = patch.geomID();
++ args.primID = patch.primID();
++ args.timeStep = patch.time();
++ args.u = grid_u;
++ args.v = grid_v;
++ args.Ng_x = grid_Ng_x;
++ args.Ng_y = grid_Ng_y;
++ args.Ng_z = grid_Ng_z;
++ args.P_x = grid_x;
++ args.P_y = grid_y;
++ args.P_z = grid_z;
++ args.N = dwidth*dheight;
++ geom->displFunc(&args);
++ }
++
++ /* set last elements in u,v array to 1.0f */
++ const float last_u = grid_u[dwidth*dheight-1];
++ const float last_v = grid_v[dwidth*dheight-1];
++ const float last_x = grid_x[dwidth*dheight-1];
++ const float last_y = grid_y[dwidth*dheight-1];
++ const float last_z = grid_z[dwidth*dheight-1];
++ for (unsigned i=dwidth*dheight;i<grid_size_simd_blocks*VSIZEX;i++)
++ {
++ grid_u[i] = last_u;
++ grid_v[i] = last_v;
++ grid_x[i] = last_x;
++ grid_y[i] = last_y;
++ grid_z[i] = last_z;
++ }
++ }
++ else
++ {
++ /* grid_u, grid_v need to be padded as we write with SIMD granularity */
++ gridUVTessellator(patch.level,swidth,sheight,x0,y0,dwidth,dheight,grid_u,grid_v);
++
++ /* set last elements in u,v array to last valid point */
++ const float last_u = grid_u[dwidth*dheight-1];
++ const float last_v = grid_v[dwidth*dheight-1];
++ for (unsigned i=dwidth*dheight;i<grid_size_simd_blocks*VSIZEX;i++) {
++ grid_u[i] = last_u;
++ grid_v[i] = last_v;
++ }
++
++ /* stitch edges if necessary */
++ if (unlikely(patch.needsStitching()))
++ stitchUVGrid(patch.level,swidth,sheight,x0,y0,dwidth,dheight,grid_u,grid_v);
++
++ /* iterates over all grid points */
++ for (unsigned i=0; i<grid_size_simd_blocks; i++)
++ {
++ const vfloatx u = vfloatx::load(&grid_u[i*VSIZEX]);
++ const vfloatx v = vfloatx::load(&grid_v[i*VSIZEX]);
++ Vec3vfx vtx = patchEval(patch,u,v);
++
++ /* evaluate displacement function */
++ if (unlikely(geom->displFunc != nullptr))
++ {
++ const Vec3vfx normal = normalize_safe(patchNormal(patch, u, v));
++ RTCDisplacementFunctionNArguments args;
++ args.geometryUserPtr = geom->userPtr;
++ args.geometry = (RTCGeometry)geom;
++ //args.geomID = patch.geomID();
++ args.primID = patch.primID();
++ args.timeStep = patch.time();
++ args.u = &u[0];
++ args.v = &v[0];
++ args.Ng_x = &normal.x[0];
++ args.Ng_y = &normal.y[0];
++ args.Ng_z = &normal.z[0];
++ args.P_x = &vtx.x[0];
++ args.P_y = &vtx.y[0];
++ args.P_z = &vtx.z[0];
++ args.N = VSIZEX;
++ geom->displFunc(&args);
++ }
++
++ vfloatx::store(&grid_x[i*VSIZEX],vtx.x);
++ vfloatx::store(&grid_y[i*VSIZEX],vtx.y);
++ vfloatx::store(&grid_z[i*VSIZEX],vtx.z);
++ }
++ }
++ }
++
++
++ /* eval grid over patch and stich edges when required */
++ BBox3fa evalGridBounds(const SubdivPatch1Base& patch,
++ const unsigned x0, const unsigned x1,
++ const unsigned y0, const unsigned y1,
++ const unsigned swidth, const unsigned sheight,
++ const SubdivMesh* const geom)
++ {
++ BBox3fa b(empty);
++ const unsigned dwidth = x1-x0+1;
++ const unsigned dheight = y1-y0+1;
++ const unsigned M = dwidth*dheight+VSIZEX;
++ const unsigned grid_size_simd_blocks = (M-1)/VSIZEX;
++ dynamic_large_stack_array(float,grid_u,M,64*64*sizeof(float));
++ dynamic_large_stack_array(float,grid_v,M,64*64*sizeof(float));
++
++ if (unlikely(patch.type == SubdivPatch1Base::EVAL_PATCH))
++ {
++ const bool displ = geom->displFunc;
++ dynamic_large_stack_array(float,grid_x,M,64*64*sizeof(float));
++ dynamic_large_stack_array(float,grid_y,M,64*64*sizeof(float));
++ dynamic_large_stack_array(float,grid_z,M,64*64*sizeof(float));
++ dynamic_large_stack_array(float,grid_Ng_x,displ ? M : 0,64*64*sizeof(float));
++ dynamic_large_stack_array(float,grid_Ng_y,displ ? M : 0,64*64*sizeof(float));
++ dynamic_large_stack_array(float,grid_Ng_z,displ ? M : 0,64*64*sizeof(float));
++
++ if (geom->patch_eval_trees.size())
++ {
++ feature_adaptive_eval_grid<PatchEvalGrid>
++ (geom->patch_eval_trees[geom->numTimeSteps*patch.primID()+patch.time()], patch.subPatch(), patch.needsStitching() ? patch.level : nullptr,
++ x0,x1,y0,y1,swidth,sheight,
++ grid_x,grid_y,grid_z,grid_u,grid_v,
++ displ ? (float*)grid_Ng_x : nullptr, displ ? (float*)grid_Ng_y : nullptr, displ ? (float*)grid_Ng_z : nullptr,
++ dwidth,dheight);
++ }
++ else
++ {
++ GeneralCatmullClarkPatch3fa ccpatch(patch.edge(),geom->getVertexBuffer(patch.time()));
++
++ feature_adaptive_eval_grid <FeatureAdaptiveEvalGrid,GeneralCatmullClarkPatch3fa>
++ (ccpatch, patch.subPatch(), patch.needsStitching() ? patch.level : nullptr,
++ x0,x1,y0,y1,swidth,sheight,
++ grid_x,grid_y,grid_z,grid_u,grid_v,
++ displ ? (float*)grid_Ng_x : nullptr, displ ? (float*)grid_Ng_y : nullptr, displ ? (float*)grid_Ng_z : nullptr,
++ dwidth,dheight);
++ }
++
++ /* call displacement shader */
++ if (unlikely(geom->displFunc))
++ {
++ RTCDisplacementFunctionNArguments args;
++ args.geometryUserPtr = geom->userPtr;
++ args.geometry = (RTCGeometry)geom;
++ //args.geomID = patch.geomID();
++ args.primID = patch.primID();
++ args.timeStep = patch.time();
++ args.u = grid_u;
++ args.v = grid_v;
++ args.Ng_x = grid_Ng_x;
++ args.Ng_y = grid_Ng_y;
++ args.Ng_z = grid_Ng_z;
++ args.P_x = grid_x;
++ args.P_y = grid_y;
++ args.P_z = grid_z;
++ args.N = dwidth*dheight;
++ geom->displFunc(&args);
++ }
++
++ /* set last elements in u,v array to 1.0f */
++ const float last_u = grid_u[dwidth*dheight-1];
++ const float last_v = grid_v[dwidth*dheight-1];
++ const float last_x = grid_x[dwidth*dheight-1];
++ const float last_y = grid_y[dwidth*dheight-1];
++ const float last_z = grid_z[dwidth*dheight-1];
++ for (unsigned i=dwidth*dheight;i<grid_size_simd_blocks*VSIZEX;i++)
++ {
++ grid_u[i] = last_u;
++ grid_v[i] = last_v;
++ grid_x[i] = last_x;
++ grid_y[i] = last_y;
++ grid_z[i] = last_z;
++ }
++
++ vfloatx bounds_min_x = pos_inf;
++ vfloatx bounds_min_y = pos_inf;
++ vfloatx bounds_min_z = pos_inf;
++ vfloatx bounds_max_x = neg_inf;
++ vfloatx bounds_max_y = neg_inf;
++ vfloatx bounds_max_z = neg_inf;
++ for (unsigned i = 0; i<grid_size_simd_blocks; i++)
++ {
++ vfloatx x = vfloatx::loadu(&grid_x[i * VSIZEX]);
++ vfloatx y = vfloatx::loadu(&grid_y[i * VSIZEX]);
++ vfloatx z = vfloatx::loadu(&grid_z[i * VSIZEX]);
++
++ bounds_min_x = min(bounds_min_x,x);
++ bounds_min_y = min(bounds_min_y,y);
++ bounds_min_z = min(bounds_min_z,z);
++
++ bounds_max_x = max(bounds_max_x,x);
++ bounds_max_y = max(bounds_max_y,y);
++ bounds_max_z = max(bounds_max_z,z);
++ }
++
++ b.lower.x = reduce_min(bounds_min_x);
++ b.lower.y = reduce_min(bounds_min_y);
++ b.lower.z = reduce_min(bounds_min_z);
++ b.upper.x = reduce_max(bounds_max_x);
++ b.upper.y = reduce_max(bounds_max_y);
++ b.upper.z = reduce_max(bounds_max_z);
++ //b.lower.a = 0;
++ //b.upper.a = 0;
++ }
++ else
++ {
++ /* grid_u, grid_v need to be padded as we write with SIMD granularity */
++ gridUVTessellator(patch.level,swidth,sheight,x0,y0,dwidth,dheight,grid_u,grid_v);
++
++ /* set last elements in u,v array to last valid point */
++ const float last_u = grid_u[dwidth*dheight-1];
++ const float last_v = grid_v[dwidth*dheight-1];
++ for (unsigned i=dwidth*dheight;i<grid_size_simd_blocks*VSIZEX;i++) {
++ grid_u[i] = last_u;
++ grid_v[i] = last_v;
++ }
++
++ /* stitch edges if necessary */
++ if (unlikely(patch.needsStitching()))
++ stitchUVGrid(patch.level,swidth,sheight,x0,y0,dwidth,dheight,grid_u,grid_v);
++
++ /* iterates over all grid points */
++ Vec3vfx bounds_min;
++ bounds_min[0] = pos_inf;
++ bounds_min[1] = pos_inf;
++ bounds_min[2] = pos_inf;
++
++ Vec3vfx bounds_max;
++ bounds_max[0] = neg_inf;
++ bounds_max[1] = neg_inf;
++ bounds_max[2] = neg_inf;
++
++ for (unsigned i=0; i<grid_size_simd_blocks; i++)
++ {
++ const vfloatx u = vfloatx::load(&grid_u[i*VSIZEX]);
++ const vfloatx v = vfloatx::load(&grid_v[i*VSIZEX]);
++ Vec3vfx vtx = patchEval(patch,u,v);
++
++ /* evaluate displacement function */
++ if (unlikely(geom->displFunc != nullptr))
++ {
++ const Vec3vfx normal = normalize_safe(patchNormal(patch,u,v));
++ RTCDisplacementFunctionNArguments args;
++ args.geometryUserPtr = geom->userPtr;
++ args.geometry = (RTCGeometry)geom;
++ //args.geomID = patch.geomID();
++ args.primID = patch.primID();
++ args.timeStep = patch.time();
++ args.u = &u[0];
++ args.v = &v[0];
++ args.Ng_x = &normal.x[0];
++ args.Ng_y = &normal.y[0];
++ args.Ng_z = &normal.z[0];
++ args.P_x = &vtx.x[0];
++ args.P_y = &vtx.y[0];
++ args.P_z = &vtx.z[0];
++ args.N = VSIZEX;
++ geom->displFunc(&args);
++ }
++
++ bounds_min[0] = min(bounds_min[0],vtx.x);
++ bounds_max[0] = max(bounds_max[0],vtx.x);
++ bounds_min[1] = min(bounds_min[1],vtx.y);
++ bounds_max[1] = max(bounds_max[1],vtx.y);
++ bounds_min[2] = min(bounds_min[2],vtx.z);
++ bounds_max[2] = max(bounds_max[2],vtx.z);
++ }
++
++ b.lower.x = reduce_min(bounds_min[0]);
++ b.lower.y = reduce_min(bounds_min[1]);
++ b.lower.z = reduce_min(bounds_min[2]);
++ b.upper.x = reduce_max(bounds_max[0]);
++ b.upper.y = reduce_max(bounds_max[1]);
++ b.upper.z = reduce_max(bounds_max[2]);
++ //b.lower.a = 0;
++ //b.upper.a = 0;
++ }
++
++ assert( std::isfinite(b.lower.x) );
++ assert( std::isfinite(b.lower.y) );
++ assert( std::isfinite(b.lower.z) );
++
++ assert( std::isfinite(b.upper.x) );
++ assert( std::isfinite(b.upper.y) );
++ assert( std::isfinite(b.upper.z) );
++
++
++ assert(b.lower.x <= b.upper.x);
++ assert(b.lower.y <= b.upper.y);
++ assert(b.lower.z <= b.upper.z);
++ return b;
++ }
++ }
++ }