Revision control
++ // Copyright 2009-2021 Intel Corporation
++ // SPDX-License-Identifier: Apache-2.0
++
++ #include "grid_soa.h"
++
++ namespace embree
++ {
++ namespace isa
++ {
++ GridSOA::GridSOA(const SubdivPatch1Base* patches, unsigned time_steps,
++ const unsigned x0, const unsigned x1, const unsigned y0, const unsigned y1, const unsigned swidth, const unsigned sheight,
++ const SubdivMesh* const geom, const size_t gridOffset, const size_t gridBytes, BBox3fa* bounds_o)
++ : troot(BVH4::emptyNode),
++ time_steps(time_steps), width(x1-x0+1), height(y1-y0+1), dim_offset(width*height),
++ _geomID(patches->geomID()), _primID(patches->primID()),
++ gridOffset(unsigned(gridOffset)), gridBytes(unsigned(gridBytes)), rootOffset(unsigned(gridOffset+time_steps*gridBytes))
++ {
++ /* the generate loops need padded arrays, thus first store into these temporary arrays */
++ unsigned temp_size = width*height+VSIZEX;
++ dynamic_large_stack_array(float,local_grid_u,temp_size,32*32*sizeof(float));
++ dynamic_large_stack_array(float,local_grid_v,temp_size,32*32*sizeof(float));
++ dynamic_large_stack_array(float,local_grid_x,temp_size,32*32*sizeof(float));
++ dynamic_large_stack_array(float,local_grid_y,temp_size,32*32*sizeof(float));
++ dynamic_large_stack_array(float,local_grid_z,temp_size,32*32*sizeof(float));
++ dynamic_large_stack_array(int,local_grid_uv,temp_size,32*32*sizeof(int));
++
++ /* first create the grids for each time step */
++ for (size_t t=0; t<time_steps; t++)
++ {
++ /* compute vertex grid (+displacement) */
++ evalGrid(patches[t],x0,x1,y0,y1,swidth,sheight,
++ local_grid_x,local_grid_y,local_grid_z,local_grid_u,local_grid_v,geom);
++
++ /* encode UVs */
++ for (unsigned i=0; i<dim_offset; i+=VSIZEX) {
++ const vintx iu = (vintx) clamp(vfloatx::load(&local_grid_u[i])*(0x10000/8.0f), vfloatx(0.0f), vfloatx(0xFFFF));
++ const vintx iv = (vintx) clamp(vfloatx::load(&local_grid_v[i])*(0x10000/8.0f), vfloatx(0.0f), vfloatx(0xFFFF));
++ vintx::storeu(&local_grid_uv[i], (iv << 16) | iu);
++ }
++
++ /* copy temporary data to compact grid */
++ float* const grid_x = (float*)(gridData(t) + 0*dim_offset);
++ float* const grid_y = (float*)(gridData(t) + 1*dim_offset);
++ float* const grid_z = (float*)(gridData(t) + 2*dim_offset);
++ int * const grid_uv = (int* )(gridData(t) + 3*dim_offset);
++
++ for (size_t i=0; i<width*height; i++)
++ {
++ grid_x[i] = local_grid_x[i];
++ grid_y[i] = local_grid_y[i];
++ grid_z[i] = local_grid_z[i];
++ grid_uv[i] = local_grid_uv[i];
++ }
++ }
++
++ /* create normal BVH when no motion blur is active */
++ if (time_steps == 1)
++ root(0) = buildBVH(bounds_o).first;
++
++ /* otherwise build MBlur BVH */
++ else {
++ BBox3fa gbounds[RTC_MAX_TIME_STEP_COUNT];
++ troot = buildMSMBlurBVH(make_range(0,int(time_steps-1)),gbounds).first;
++
++ if (bounds_o)
++ for (size_t i=0; i<time_steps; i++)
++ bounds_o[i] = gbounds[i];
++ }
++ }
++
++ size_t GridSOA::getBVHBytes(const GridRange& range, const size_t nodeBytes, const size_t leafBytes)
++ {
++ if (range.hasLeafSize())
++ return leafBytes;
++
++ __aligned(64) GridRange r[4];
++ const size_t children = range.splitIntoSubRanges(r);
++
++ size_t bytes = nodeBytes;
++ for (size_t i=0; i<children; i++)
++ bytes += getBVHBytes(r[i],nodeBytes,leafBytes);
++ return bytes;
++ }
++
++ size_t GridSOA::getTemporalBVHBytes(const range<int> time_range, const size_t nodeBytes)
++ {
++ if (time_range.size() <= 1)
++ return 0;
++
++ size_t bytes = nodeBytes;
++ for (int i=0; i<4; i++) {
++ const int begin = time_range.begin() + (i+0)*time_range.size()/4;
++ const int end = time_range.begin() + (i+1)*time_range.size()/4;
++ bytes += getTemporalBVHBytes(make_range(begin,end),nodeBytes);
++ }
++ return bytes;
++ }
++
++ std::pair<BVH4::NodeRef,BBox3fa> GridSOA::buildBVH(const GridRange& range, size_t& allocator)
++ {
++ /*! create leaf node */
++ if (unlikely(range.hasLeafSize()))
++ {
++ /* we store index of first subgrid vertex as leaf node */
++ BVH4::NodeRef curNode = BVH4::encodeTypedLeaf(encodeLeaf(range.u_start,range.v_start),0);
++
++ /* return bounding box */
++ return std::make_pair(curNode,calculateBounds(0,range));
++ }
++
++ /* create internal node */
++ else
++ {
++ /* allocate new bvh4 node */
++ BVH4::AABBNode* node = (BVH4::AABBNode *)&bvhData()[allocator];
++ allocator += sizeof(BVH4::AABBNode);
++ node->clear();
++
++ /* split range */
++ GridRange r[4];
++ const unsigned children = range.splitIntoSubRanges(r);
++
++ /* recurse into subtrees */
++ BBox3fa bounds( empty );
++ for (unsigned i=0; i<children; i++)
++ {
++ std::pair<BVH4::NodeRef,BBox3fa> node_bounds = buildBVH(r[i], allocator);
++ node->set(i,node_bounds.first,node_bounds.second);
++ bounds.extend(node_bounds.second);
++ }
++ assert(is_finite(bounds));
++ return std::make_pair(BVH4::encodeNode(node),bounds);
++ }
++ }
++
++ std::pair<BVH4::NodeRef,BBox3fa> GridSOA::buildBVH(BBox3fa* bounds_o)
++ {
++ size_t allocator = 0;
++ GridRange range(0,width-1,0,height-1);
++ std::pair<BVH4::NodeRef,BBox3fa> root_bounds = buildBVH(range,allocator);
++ if (bounds_o) *bounds_o = root_bounds.second;
++ assert(allocator == gridOffset);
++ return root_bounds;
++ }
++
++ std::pair<BVH4::NodeRef,LBBox3fa> GridSOA::buildMBlurBVH(size_t time, const GridRange& range, size_t& allocator)
++ {
++ /*! create leaf node */
++ if (unlikely(range.hasLeafSize()))
++ {
++ /* we store index of first subgrid vertex as leaf node */
++ BVH4::NodeRef curNode = BVH4::encodeTypedLeaf(encodeLeaf(range.u_start,range.v_start),0);
++
++ /* return bounding box */
++ const BBox3fa b0 = calculateBounds(time+0,range);
++ const BBox3fa b1 = calculateBounds(time+1,range);
++ return std::make_pair(curNode,LBBox3fa(b0,b1));
++ }
++
++ /* create internal node */
++ else
++ {
++ /* allocate new bvh4 node */
++ BVH4::AABBNodeMB* node = (BVH4::AABBNodeMB *)&bvhData()[allocator];
++ allocator += sizeof(BVH4::AABBNodeMB);
++ node->clear();
++
++ /* split range */
++ GridRange r[4];
++ const unsigned children = range.splitIntoSubRanges(r);
++
++ /* recurse into subtrees */
++ LBBox3fa bounds(empty);
++ for (unsigned i=0; i<children; i++)
++ {
++ const BBox1f time_range(float(time+0)/float(time_steps-1),
++ float(time+1)/float(time_steps-1));
++ std::pair<BVH4::NodeRef,LBBox3fa> node_bounds = buildMBlurBVH(time, r[i], allocator);
++ node->setRef(i,node_bounds.first);
++ node->setBounds(i,node_bounds.second.global(time_range));
++ bounds.extend(node_bounds.second);
++ }
++ assert(is_finite(bounds.bounds0));
++ assert(is_finite(bounds.bounds1));
++
++ return std::make_pair(BVH4::encodeNode(node),bounds);
++ }
++ }
++
++ std::pair<BVH4::NodeRef,LBBox3fa> GridSOA::buildMSMBlurBVH(const range<int> time_range, size_t& allocator, BBox3fa* bounds_o)
++ {
++ assert(time_range.size() > 0);
++ if (time_range.size() == 1)
++ {
++ size_t t = time_range.begin();
++ GridRange range(0,width-1,0,height-1);
++ std::pair<BVH4::NodeRef,LBBox3fa> root_bounds = buildMBlurBVH(t,range,allocator);
++ root(t) = root_bounds.first;
++ bounds_o[t+0] = root_bounds.second.bounds0;
++ bounds_o[t+1] = root_bounds.second.bounds1;
++ return root_bounds;
++ }
++
++ /* allocate new bvh4 node */
++ BVH4::AABBNodeMB4D* node = (BVH4::AABBNodeMB4D*)&bvhData()[allocator];
++ allocator += sizeof(BVH4::AABBNodeMB4D);
++ node->clear();
++
++ for (int i=0, j=0; i<4; i++)
++ {
++ const int begin = time_range.begin() + (i+0)*time_range.size()/4;
++ const int end = time_range.begin() + (i+1)*time_range.size()/4;
++ if (end-begin <= 0) continue;
++ std::pair<BVH4::NodeRef,LBBox3fa> node_bounds = buildMSMBlurBVH(make_range(begin,end),allocator,bounds_o);
++ const float t0 = float(begin)/float(time_steps-1);
++ const float t1 = float(end )/float(time_steps-1);
++ BVH4::NodeRecordMB4D nodeRecord;
++ nodeRecord.ref = node_bounds.first;
++ nodeRecord.lbounds = node_bounds.second;
++ nodeRecord.dt = BBox1f(t0, t1);
++ node->set(j,nodeRecord);
++ j++;
++ }
++
++ const LBBox3fa lbounds = LBBox3fa([&] ( int i ) { return bounds_o[i]; }, time_range, time_steps-1);
++ return std::make_pair(BVH4::encodeNode(node),lbounds);
++ }
++
++ std::pair<BVH4::NodeRef,LBBox3fa> GridSOA::buildMSMBlurBVH(const range<int> time_range, BBox3fa* bounds_o)
++ {
++ size_t allocator = 0;
++ std::pair<BVH4::NodeRef,LBBox3fa> root = buildMSMBlurBVH(time_range,allocator,bounds_o);
++ assert(allocator == gridOffset);
++ return root;
++ }
++ }
++ }