123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- // Copyright 2009-2021 Intel Corporation
- // SPDX-License-Identifier: Apache-2.0
- #pragma once
- #include "heuristic_binning.h"
- namespace embree
- {
- namespace isa
- {
- /*! Performs standard object binning */
- template<typename PrimRef, size_t BINS>
- struct UnalignedHeuristicArrayBinningSAH
- {
- typedef BinSplit<BINS> Split;
- typedef BinInfoT<BINS,PrimRef,BBox3fa> Binner;
- typedef range<size_t> Set;
- __forceinline UnalignedHeuristicArrayBinningSAH () // FIXME: required?
- : scene(nullptr), prims(nullptr) {}
-
- /*! remember prim array */
- __forceinline UnalignedHeuristicArrayBinningSAH (Scene* scene, PrimRef* prims)
- : scene(scene), prims(prims) {}
- const LinearSpace3fa computeAlignedSpace(const range<size_t>& set)
- {
- Vec3fa axis(0,0,1);
- uint64_t bestGeomPrimID = -1;
- /*! find curve with minimum ID that defines valid direction */
- for (size_t i=set.begin(); i<set.end(); i++)
- {
- const unsigned int geomID = prims[i].geomID();
- const unsigned int primID = prims[i].primID();
- const uint64_t geomprimID = prims[i].ID64();
- if (geomprimID >= bestGeomPrimID) continue;
- const Vec3fa axis1 = scene->get(geomID)->computeDirection(primID);
- if (sqr_length(axis1) > 1E-18f) {
- axis = normalize(axis1);
- bestGeomPrimID = geomprimID;
- }
- }
- return frame(axis).transposed();
- }
-
- const PrimInfo computePrimInfo(const range<size_t>& set, const LinearSpace3fa& space)
- {
- auto computeBounds = [&](const range<size_t>& r) -> CentGeomBBox3fa
- {
- CentGeomBBox3fa bounds(empty);
- for (size_t i=r.begin(); i<r.end(); i++) {
- Geometry* mesh = scene->get(prims[i].geomID());
- bounds.extend(mesh->vbounds(space,prims[i].primID()));
- }
- return bounds;
- };
-
- const CentGeomBBox3fa bounds = parallel_reduce(set.begin(), set.end(), size_t(1024), size_t(4096),
- CentGeomBBox3fa(empty), computeBounds, CentGeomBBox3fa::merge2);
- return PrimInfo(set.begin(),set.end(),bounds);
- }
- struct BinBoundsAndCenter
- {
- __forceinline BinBoundsAndCenter(Scene* scene, const LinearSpace3fa& space)
- : scene(scene), space(space) {}
-
- /*! returns center for binning */
- __forceinline Vec3fa binCenter(const PrimRef& ref) const
- {
- Geometry* mesh = (Geometry*) scene->get(ref.geomID());
- BBox3fa bounds = mesh->vbounds(space,ref.primID());
- return embree::center2(bounds);
- }
-
- /*! returns bounds and centroid used for binning */
- __forceinline void binBoundsAndCenter(const PrimRef& ref, BBox3fa& bounds_o, Vec3fa& center_o) const
- {
- Geometry* mesh = (Geometry*) scene->get(ref.geomID());
- BBox3fa bounds = mesh->vbounds(space,ref.primID());
- bounds_o = bounds;
- center_o = embree::center2(bounds);
- }
- private:
- Scene* scene;
- const LinearSpace3fa space;
- };
-
- /*! finds the best split */
- __forceinline const Split find(const PrimInfoRange& pinfo, const size_t logBlockSize, const LinearSpace3fa& space)
- {
- if (likely(pinfo.size() < 10000))
- return find_template<false>(pinfo,logBlockSize,space);
- else
- return find_template<true>(pinfo,logBlockSize,space);
- }
- /*! finds the best split */
- template<bool parallel>
- const Split find_template(const PrimInfoRange& set, const size_t logBlockSize, const LinearSpace3fa& space)
- {
- Binner binner(empty);
- const BinMapping<BINS> mapping(set);
- BinBoundsAndCenter binBoundsAndCenter(scene,space);
- bin_serial_or_parallel<parallel>(binner,prims,set.begin(),set.end(),size_t(4096),mapping,binBoundsAndCenter);
- return binner.best(mapping,logBlockSize);
- }
-
- /*! array partitioning */
- __forceinline void split(const Split& split, const LinearSpace3fa& space, const Set& set, PrimInfoRange& lset, PrimInfoRange& rset)
- {
- if (likely(set.size() < 10000))
- split_template<false>(split,space,set,lset,rset);
- else
- split_template<true>(split,space,set,lset,rset);
- }
- /*! array partitioning */
- template<bool parallel>
- __forceinline void split_template(const Split& split, const LinearSpace3fa& space, const Set& set, PrimInfoRange& lset, PrimInfoRange& rset)
- {
- if (!split.valid()) {
- deterministic_order(set);
- return splitFallback(set,lset,rset);
- }
-
- const size_t begin = set.begin();
- const size_t end = set.end();
- CentGeomBBox3fa local_left(empty);
- CentGeomBBox3fa local_right(empty);
- const int splitPos = split.pos;
- const int splitDim = split.dim;
- BinBoundsAndCenter binBoundsAndCenter(scene,space);
- size_t center = 0;
- if (likely(set.size() < 10000))
- center = serial_partitioning(prims,begin,end,local_left,local_right,
- [&] (const PrimRef& ref) { return split.mapping.bin_unsafe(ref,binBoundsAndCenter)[splitDim] < splitPos; },
- [] (CentGeomBBox3fa& pinfo,const PrimRef& ref) { pinfo.extend_center2(ref); });
- else
- center = parallel_partitioning(prims,begin,end,EmptyTy(),local_left,local_right,
- [&] (const PrimRef& ref) { return split.mapping.bin_unsafe(ref,binBoundsAndCenter)[splitDim] < splitPos; },
- [] (CentGeomBBox3fa& pinfo,const PrimRef& ref) { pinfo.extend_center2(ref); },
- [] (CentGeomBBox3fa& pinfo0,const CentGeomBBox3fa& pinfo1) { pinfo0.merge(pinfo1); },
- 128);
-
- new (&lset) PrimInfoRange(begin,center,local_left);
- new (&rset) PrimInfoRange(center,end,local_right);
- assert(area(lset.geomBounds) >= 0.0f);
- assert(area(rset.geomBounds) >= 0.0f);
- }
-
- void deterministic_order(const range<size_t>& set)
- {
- /* required as parallel partition destroys original primitive order */
- std::sort(&prims[set.begin()],&prims[set.end()]);
- }
-
- void splitFallback(const range<size_t>& set, PrimInfoRange& lset, PrimInfoRange& rset)
- {
- const size_t begin = set.begin();
- const size_t end = set.end();
- const size_t center = (begin + end)/2;
-
- CentGeomBBox3fa left(empty);
- for (size_t i=begin; i<center; i++)
- left.extend_center2(prims[i]);
- new (&lset) PrimInfoRange(begin,center,left);
-
- CentGeomBBox3fa right(empty);
- for (size_t i=center; i<end; i++)
- right.extend_center2(prims[i]);
- new (&rset) PrimInfoRange(center,end,right);
- }
-
- private:
- Scene* const scene;
- PrimRef* const prims;
- };
- /*! Performs standard object binning */
- template<typename PrimRefMB, size_t BINS>
- struct UnalignedHeuristicArrayBinningMB
- {
- typedef BinSplit<BINS> Split;
- typedef typename PrimRefMB::BBox BBox;
- typedef BinInfoT<BINS,PrimRefMB,BBox> ObjectBinner;
-
- static const size_t PARALLEL_THRESHOLD = 3 * 1024;
- static const size_t PARALLEL_FIND_BLOCK_SIZE = 1024;
- static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 128;
- UnalignedHeuristicArrayBinningMB(Scene* scene)
- : scene(scene) {}
- const LinearSpace3fa computeAlignedSpaceMB(Scene* scene, const SetMB& set)
- {
- Vec3fa axis0(0,0,1);
- uint64_t bestGeomPrimID = -1;
- /*! find curve with minimum ID that defines valid direction */
- for (size_t i=set.begin(); i<set.end(); i++)
- {
- const PrimRefMB& prim = (*set.prims)[i];
- const unsigned int geomID = prim.geomID();
- const unsigned int primID = prim.primID();
- const uint64_t geomprimID = prim.ID64();
- if (geomprimID >= bestGeomPrimID) continue;
-
- const Geometry* mesh = scene->get(geomID);
- const range<int> tbounds = mesh->timeSegmentRange(set.time_range);
- if (tbounds.size() == 0) continue;
- const size_t t = (tbounds.begin()+tbounds.end())/2;
- const Vec3fa axis1 = mesh->computeDirection(primID,t);
- if (sqr_length(axis1) > 1E-18f) {
- axis0 = normalize(axis1);
- bestGeomPrimID = geomprimID;
- }
- }
- return frame(axis0).transposed();
- }
- struct BinBoundsAndCenter
- {
- __forceinline BinBoundsAndCenter(Scene* scene, BBox1f time_range, const LinearSpace3fa& space)
- : scene(scene), time_range(time_range), space(space) {}
-
- /*! returns center for binning */
- template<typename PrimRef>
- __forceinline Vec3fa binCenter(const PrimRef& ref) const
- {
- Geometry* mesh = scene->get(ref.geomID());
- LBBox3fa lbounds = mesh->vlinearBounds(space,ref.primID(),time_range);
- return center2(lbounds.interpolate(0.5f));
- }
- /*! returns bounds and centroid used for binning */
- __noinline void binBoundsAndCenter (const PrimRefMB& ref, BBox3fa& bounds_o, Vec3fa& center_o) const // __noinline is workaround for ICC16 bug under MacOSX
- {
- Geometry* mesh = scene->get(ref.geomID());
- LBBox3fa lbounds = mesh->vlinearBounds(space,ref.primID(),time_range);
- bounds_o = lbounds.interpolate(0.5f);
- center_o = center2(bounds_o);
- }
- /*! returns bounds and centroid used for binning */
- __noinline void binBoundsAndCenter (const PrimRefMB& ref, LBBox3fa& bounds_o, Vec3fa& center_o) const // __noinline is workaround for ICC16 bug under MacOSX
- {
- Geometry* mesh = scene->get(ref.geomID());
- LBBox3fa lbounds = mesh->vlinearBounds(space,ref.primID(),time_range);
- bounds_o = lbounds;
- center_o = center2(lbounds.interpolate(0.5f));
- }
-
- private:
- Scene* scene;
- BBox1f time_range;
- const LinearSpace3fa space;
- };
- /*! finds the best split */
- const Split find(const SetMB& set, const size_t logBlockSize, const LinearSpace3fa& space)
- {
- BinBoundsAndCenter binBoundsAndCenter(scene,set.time_range,space);
- ObjectBinner binner(empty);
- const BinMapping<BINS> mapping(set.size(),set.centBounds);
- bin_parallel(binner,set.prims->data(),set.begin(),set.end(),PARALLEL_FIND_BLOCK_SIZE,PARALLEL_THRESHOLD,mapping,binBoundsAndCenter);
- Split osplit = binner.best(mapping,logBlockSize);
- osplit.sah *= set.time_range.size();
- if (!osplit.valid()) osplit.data = Split::SPLIT_FALLBACK; // use fallback split
- return osplit;
- }
-
- /*! array partitioning */
- __forceinline void split(const Split& split, const LinearSpace3fa& space, const SetMB& set, SetMB& lset, SetMB& rset)
- {
- BinBoundsAndCenter binBoundsAndCenter(scene,set.time_range,space);
- const size_t begin = set.begin();
- const size_t end = set.end();
- PrimInfoMB left = empty;
- PrimInfoMB right = empty;
- const vint4 vSplitPos(split.pos);
- const vbool4 vSplitMask(1 << split.dim);
- auto isLeft = [&] (const PrimRefMB &ref) { return any(((vint4)split.mapping.bin_unsafe(ref,binBoundsAndCenter) < vSplitPos) & vSplitMask); };
- auto reduction = [] (PrimInfoMB& pinfo, const PrimRefMB& ref) { pinfo.add_primref(ref); };
- auto reduction2 = [] (PrimInfoMB& pinfo0,const PrimInfoMB& pinfo1) { pinfo0.merge(pinfo1); };
- size_t center = parallel_partitioning(set.prims->data(),begin,end,EmptyTy(),left,right,isLeft,reduction,reduction2,PARALLEL_PARTITION_BLOCK_SIZE,PARALLEL_THRESHOLD);
- new (&lset) SetMB(left,set.prims,range<size_t>(begin,center),set.time_range);
- new (&rset) SetMB(right,set.prims,range<size_t>(center,end ),set.time_range);
- }
- private:
- Scene* scene;
- };
- }
- }
|