Path: blob/master/thirdparty/embree/kernels/builders/heuristic_strand_array.h
9912 views
// Copyright 2009-2021 Intel Corporation1// SPDX-License-Identifier: Apache-2.023#pragma once45#include "priminfo.h"6#include "../../common/algorithms/parallel_reduce.h"7#include "../../common/algorithms/parallel_partition.h"89namespace embree10{11namespace isa12{13/*! Performs standard object binning */14struct HeuristicStrandSplit15{16typedef range<size_t> Set;1718static const size_t PARALLEL_THRESHOLD = 10000;19static const size_t PARALLEL_FIND_BLOCK_SIZE = 4096;20static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 64;2122/*! stores all information to perform some split */23struct Split24{25/*! construct an invalid split by default */26__forceinline Split()27: sah(inf), axis0(zero), axis1(zero) {}2829/*! constructs specified split */30__forceinline Split(const float sah, const Vec3fa& axis0, const Vec3fa& axis1)31: sah(sah), axis0(axis0), axis1(axis1) {}3233/*! calculates standard surface area heuristic for the split */34__forceinline float splitSAH() const { return sah; }3536/*! test if this split is valid */37__forceinline bool valid() const { return sah != float(inf); }3839public:40float sah; //!< SAH cost of the split41Vec3fa axis0, axis1; //!< axis the two strands are aligned into42};4344__forceinline HeuristicStrandSplit () // FIXME: required?45: scene(nullptr), prims(nullptr) {}4647/*! remember prim array */48__forceinline HeuristicStrandSplit (Scene* scene, PrimRef* prims)49: scene(scene), prims(prims) {}5051__forceinline const Vec3fa direction(const PrimRef& prim) {52return scene->get(prim.geomID())->computeDirection(prim.primID());53}5455__forceinline const BBox3fa bounds(const PrimRef& prim) {56return scene->get(prim.geomID())->vbounds(prim.primID());57}5859__forceinline const BBox3fa bounds(const LinearSpace3fa& space, const PrimRef& prim) {60return scene->get(prim.geomID())->vbounds(space,prim.primID());61}6263/*! finds the best split */64const Split find(const range<size_t>& set, size_t logBlockSize)65{66Vec3fa axis0(0,0,1);67uint64_t bestGeomPrimID = -1;6869/* curve with minimum ID determines first axis */70for (size_t i=set.begin(); i<set.end(); i++)71{72const uint64_t geomprimID = prims[i].ID64();73if (geomprimID >= bestGeomPrimID) continue;74const Vec3fa axis = direction(prims[i]);75if (sqr_length(axis) > 1E-18f) {76axis0 = normalize(axis);77bestGeomPrimID = geomprimID;78}79}8081/* find 2nd axis that is most misaligned with first axis and has minimum ID */82float bestCos = 1.0f;83Vec3fa axis1 = axis0;84bestGeomPrimID = -1;85for (size_t i=set.begin(); i<set.end(); i++)86{87const uint64_t geomprimID = prims[i].ID64();88Vec3fa axisi = direction(prims[i]);89float leni = length(axisi);90if (leni == 0.0f) continue;91axisi /= leni;92float cos = abs(dot(axisi,axis0));93if ((cos == bestCos && (geomprimID < bestGeomPrimID)) || cos < bestCos) {94bestCos = cos; axis1 = axisi;95bestGeomPrimID = geomprimID;96}97}9899/* partition the two strands */100size_t lnum = 0, rnum = 0;101BBox3fa lbounds = empty, rbounds = empty;102const LinearSpace3fa space0 = frame(axis0).transposed();103const LinearSpace3fa space1 = frame(axis1).transposed();104105for (size_t i=set.begin(); i<set.end(); i++)106{107PrimRef& prim = prims[i];108const Vec3fa axisi = normalize(direction(prim));109const float cos0 = abs(dot(axisi,axis0));110const float cos1 = abs(dot(axisi,axis1));111112if (cos0 > cos1) { lnum++; lbounds.extend(bounds(space0,prim)); }113else { rnum++; rbounds.extend(bounds(space1,prim)); }114}115116/*! return an invalid split if we do not partition */117if (lnum == 0 || rnum == 0)118return Split(inf,axis0,axis1);119120/*! calculate sah for the split */121const size_t lblocks = (lnum+(1ull<<logBlockSize)-1ull) >> logBlockSize;122const size_t rblocks = (rnum+(1ull<<logBlockSize)-1ull) >> logBlockSize;123const float sah = madd(float(lblocks),halfArea(lbounds),float(rblocks)*halfArea(rbounds));124return Split(sah,axis0,axis1);125}126127/*! array partitioning */128void split(const Split& split, const PrimInfoRange& set, PrimInfoRange& lset, PrimInfoRange& rset)129{130if (!split.valid()) {131deterministic_order(set);132return splitFallback(set,lset,rset);133}134135const size_t begin = set.begin();136const size_t end = set.end();137CentGeomBBox3fa local_left(empty);138CentGeomBBox3fa local_right(empty);139140auto primOnLeftSide = [&] (const PrimRef& prim) -> bool {141const Vec3fa axisi = normalize(direction(prim));142const float cos0 = abs(dot(axisi,split.axis0));143const float cos1 = abs(dot(axisi,split.axis1));144return cos0 > cos1;145};146147auto mergePrimBounds = [this] (CentGeomBBox3fa& pinfo,const PrimRef& ref) {148pinfo.extend(bounds(ref));149};150151size_t center = serial_partitioning(prims,begin,end,local_left,local_right,primOnLeftSide,mergePrimBounds);152153new (&lset) PrimInfoRange(begin,center,local_left);154new (&rset) PrimInfoRange(center,end,local_right);155assert(area(lset.geomBounds) >= 0.0f);156assert(area(rset.geomBounds) >= 0.0f);157}158159void deterministic_order(const Set& set)160{161/* required as parallel partition destroys original primitive order */162std::sort(&prims[set.begin()],&prims[set.end()]);163}164165void splitFallback(const Set& set, PrimInfoRange& lset, PrimInfoRange& rset)166{167const size_t begin = set.begin();168const size_t end = set.end();169const size_t center = (begin + end)/2;170171CentGeomBBox3fa left(empty);172for (size_t i=begin; i<center; i++)173left.extend(bounds(prims[i]));174new (&lset) PrimInfoRange(begin,center,left);175176CentGeomBBox3fa right(empty);177for (size_t i=center; i<end; i++)178right.extend(bounds(prims[i]));179new (&rset) PrimInfoRange(center,end,right);180}181182private:183Scene* const scene;184PrimRef* const prims;185};186}187}188189190