| 1 | // Copyright 2009-2021 Intel Corporation | 
| 2 | // SPDX-License-Identifier: Apache-2.0 | 
| 3 |  | 
| 4 | #pragma once | 
| 5 |  | 
| 6 | #include "bvh.h" | 
| 7 | #include <sstream> | 
| 8 |  | 
| 9 | namespace embree | 
| 10 | { | 
| 11 |   template<int N> | 
| 12 |   class BVHNStatistics | 
| 13 |   { | 
| 14 |     typedef BVHN<N> BVH; | 
| 15 |     typedef typename BVH::AABBNode AABBNode; | 
| 16 |     typedef typename BVH::OBBNode OBBNode; | 
| 17 |     typedef typename BVH::AABBNodeMB AABBNodeMB; | 
| 18 |     typedef typename BVH::AABBNodeMB4D AABBNodeMB4D; | 
| 19 |     typedef typename BVH::OBBNodeMB OBBNodeMB; | 
| 20 |     typedef typename BVH::QuantizedNode QuantizedNode; | 
| 21 |  | 
| 22 |     typedef typename BVH::NodeRef NodeRef; | 
| 23 |  | 
| 24 |     struct Statistics  | 
| 25 |     { | 
| 26 |       template<typename Node> | 
| 27 |         struct NodeStat | 
| 28 |       { | 
| 29 |         NodeStat ( double nodeSAH = 0, | 
| 30 |                    size_t numNodes = 0,  | 
| 31 |                    size_t numChildren = 0) | 
| 32 |         : nodeSAH(nodeSAH), | 
| 33 |           numNodes(numNodes),  | 
| 34 |           numChildren(numChildren) {} | 
| 35 |          | 
| 36 |         double sah(BVH* bvh) const { | 
| 37 |           return nodeSAH/bvh->getLinearBounds().expectedHalfArea(); | 
| 38 |         } | 
| 39 |  | 
| 40 |         size_t bytes() const { | 
| 41 |           return numNodes*sizeof(Node); | 
| 42 |         } | 
| 43 |  | 
| 44 |         size_t size() const { | 
| 45 |           return numNodes; | 
| 46 |         } | 
| 47 |  | 
| 48 |         double fillRateNom () const { return double(numChildren);  } | 
| 49 |         double fillRateDen () const { return double(numNodes*N);  } | 
| 50 |         double fillRate    () const { return fillRateNom()/fillRateDen(); } | 
| 51 |  | 
| 52 |         __forceinline friend NodeStat operator+ ( const NodeStat& a, const NodeStat& b) | 
| 53 |         { | 
| 54 |           return NodeStat(a.nodeSAH + b.nodeSAH, | 
| 55 |                           a.numNodes+b.numNodes, | 
| 56 |                           a.numChildren+b.numChildren); | 
| 57 |         } | 
| 58 |  | 
| 59 |         std::string toString(BVH* bvh, double sahTotal, size_t bytesTotal) const | 
| 60 |         { | 
| 61 |           std::ostringstream stream; | 
| 62 |           stream.setf(fmtfl: std::ios::fixed, mask: std::ios::floatfield); | 
| 63 |           stream << "sah = "  << std::setw(7) << std::setprecision(3) << sah(bvh); | 
| 64 |           stream << " ("  << std::setw(6) << std::setprecision(2) << 100.0*sah(bvh)/sahTotal << "%), " ;           | 
| 65 |           stream << "#bytes = "  << std::setw(7) << std::setprecision(2) << bytes()/1E6  << " MB " ; | 
| 66 |           stream << "("  << std::setw(6) << std::setprecision(2) << 100.0*double(bytes())/double(bytesTotal) << "%), " ; | 
| 67 |           stream << "#nodes = "  << std::setw(7) << numNodes << " ("  << std::setw(6) << std::setprecision(2) << 100.0*fillRate() << "% filled), " ; | 
| 68 |           stream << "#bytes/prim = "  << std::setw(6) << std::setprecision(2) << double(bytes())/double(bvh->numPrimitives); | 
| 69 |           return stream.str(); | 
| 70 |         } | 
| 71 |  | 
| 72 |       public: | 
| 73 |         double nodeSAH; | 
| 74 |         size_t numNodes; | 
| 75 |         size_t numChildren; | 
| 76 |       }; | 
| 77 |  | 
| 78 |       struct LeafStat | 
| 79 |       { | 
| 80 |         static const int NHIST = 8; | 
| 81 |  | 
| 82 |         LeafStat ( double leafSAH = 0.0f,  | 
| 83 |                    size_t numLeaves = 0, | 
| 84 |                    size_t numPrimsActive = 0, | 
| 85 |                    size_t numPrimsTotal = 0, | 
| 86 |                    size_t numPrimBlocks = 0, | 
| 87 |                    size_t numBytes = 0) | 
| 88 |         : leafSAH(leafSAH), | 
| 89 |           numLeaves(numLeaves), | 
| 90 |           numPrimsActive(numPrimsActive), | 
| 91 |           numPrimsTotal(numPrimsTotal), | 
| 92 |           numPrimBlocks(numPrimBlocks), | 
| 93 |           numBytes(numBytes) | 
| 94 |         { | 
| 95 |           for (size_t i=0; i<NHIST; i++) | 
| 96 |             numPrimBlocksHistogram[i] = 0; | 
| 97 |         } | 
| 98 |  | 
| 99 |         double sah(BVH* bvh) const { | 
| 100 |           return leafSAH/bvh->getLinearBounds().expectedHalfArea(); | 
| 101 |         } | 
| 102 |  | 
| 103 |         size_t bytes(BVH* bvh) const { | 
| 104 |           return numBytes; | 
| 105 |         } | 
| 106 |  | 
| 107 |         size_t size() const { | 
| 108 |           return numLeaves; | 
| 109 |         } | 
| 110 |  | 
| 111 |         double fillRateNom (BVH* bvh) const { return double(numPrimsActive);  } | 
| 112 |         double fillRateDen (BVH* bvh) const { return double(numPrimsTotal);  } | 
| 113 |         double fillRate    (BVH* bvh) const { return fillRateNom(bvh)/fillRateDen(bvh); } | 
| 114 |  | 
| 115 |         __forceinline friend LeafStat operator+ ( const LeafStat& a, const LeafStat& b) | 
| 116 |         { | 
| 117 |           LeafStat stat(a.leafSAH + b.leafSAH, | 
| 118 |                         a.numLeaves+b.numLeaves, | 
| 119 |                         a.numPrimsActive+b.numPrimsActive, | 
| 120 |                         a.numPrimsTotal+b.numPrimsTotal, | 
| 121 |                         a.numPrimBlocks+b.numPrimBlocks, | 
| 122 |                         a.numBytes+b.numBytes); | 
| 123 |           for (size_t i=0; i<NHIST; i++) { | 
| 124 |             stat.numPrimBlocksHistogram[i] += a.numPrimBlocksHistogram[i]; | 
| 125 |             stat.numPrimBlocksHistogram[i] += b.numPrimBlocksHistogram[i]; | 
| 126 |           } | 
| 127 |           return stat; | 
| 128 |         } | 
| 129 |  | 
| 130 |         std::string toString(BVH* bvh, double sahTotal, size_t bytesTotal) const | 
| 131 |         { | 
| 132 |           std::ostringstream stream; | 
| 133 |           stream.setf(fmtfl: std::ios::fixed, mask: std::ios::floatfield); | 
| 134 |           stream << "sah = "  << std::setw(7) << std::setprecision(3) << sah(bvh); | 
| 135 |           stream << " ("  << std::setw(6) << std::setprecision(2) << 100.0*sah(bvh)/sahTotal << "%), " ; | 
| 136 |           stream << "#bytes = "  << std::setw(7) << std::setprecision(2) << double(bytes(bvh))/1E6  << " MB " ; | 
| 137 |           stream << "("  << std::setw(6) << std::setprecision(2) << 100.0*double(bytes(bvh))/double(bytesTotal) << "%), " ; | 
| 138 |           stream << "#nodes = "  << std::setw(7) << numLeaves << " ("  << std::setw(6) << std::setprecision(2) << 100.0*fillRate(bvh) << "% filled), " ; | 
| 139 |           stream << "#bytes/prim = "  << std::setw(6) << std::setprecision(2) << double(bytes(bvh))/double(bvh->numPrimitives); | 
| 140 |           return stream.str(); | 
| 141 |         } | 
| 142 |  | 
| 143 |         std::string histToString() const | 
| 144 |         { | 
| 145 |           std::ostringstream stream; | 
| 146 |           stream.setf(fmtfl: std::ios::fixed, mask: std::ios::floatfield); | 
| 147 |           for (size_t i=0; i<NHIST; i++) | 
| 148 |             stream << std::setw(6) << std::setprecision(2) << 100.0f*float(numPrimBlocksHistogram[i])/float(numLeaves) << "% " ; | 
| 149 |           return stream.str(); | 
| 150 |         } | 
| 151 |       | 
| 152 |       public: | 
| 153 |         double leafSAH;                    //!< SAH of the leaves only | 
| 154 |         size_t numLeaves;                  //!< Number of leaf nodes. | 
| 155 |         size_t numPrimsActive;             //!< Number of active primitives ( | 
| 156 |         size_t numPrimsTotal;              //!< Number of active and inactive primitives | 
| 157 |         size_t numPrimBlocks;              //!< Number of primitive blocks. | 
| 158 |         size_t numBytes;                   //!< Number of bytes of leaves. | 
| 159 |         size_t numPrimBlocksHistogram[8]; | 
| 160 |       }; | 
| 161 |  | 
| 162 |     public: | 
| 163 |       Statistics (size_t depth = 0, | 
| 164 |                   LeafStat statLeaf = LeafStat(), | 
| 165 |                   NodeStat<AABBNode> statAABBNodes = NodeStat<AABBNode>(), | 
| 166 |                   NodeStat<OBBNode> statOBBNodes = NodeStat<OBBNode>(), | 
| 167 |                   NodeStat<AABBNodeMB> statAABBNodesMB = NodeStat<AABBNodeMB>(), | 
| 168 |                   NodeStat<AABBNodeMB4D> statAABBNodesMB4D = NodeStat<AABBNodeMB4D>(), | 
| 169 |                   NodeStat<OBBNodeMB> statOBBNodesMB = NodeStat<OBBNodeMB>(), | 
| 170 |                   NodeStat<QuantizedNode> statQuantizedNodes = NodeStat<QuantizedNode>()) | 
| 171 |  | 
| 172 |       : depth(depth),  | 
| 173 |         statLeaf(statLeaf), | 
| 174 |         statAABBNodes(statAABBNodes), | 
| 175 |         statOBBNodes(statOBBNodes), | 
| 176 |         statAABBNodesMB(statAABBNodesMB), | 
| 177 |         statAABBNodesMB4D(statAABBNodesMB4D), | 
| 178 |         statOBBNodesMB(statOBBNodesMB), | 
| 179 |         statQuantizedNodes(statQuantizedNodes) {} | 
| 180 |  | 
| 181 |       double sah(BVH* bvh) const  | 
| 182 |       { | 
| 183 |         return statLeaf.sah(bvh) + | 
| 184 |           statAABBNodes.sah(bvh) +  | 
| 185 |           statOBBNodes.sah(bvh) +  | 
| 186 |           statAABBNodesMB.sah(bvh) +  | 
| 187 |           statAABBNodesMB4D.sah(bvh) +  | 
| 188 |           statOBBNodesMB.sah(bvh) +  | 
| 189 |           statQuantizedNodes.sah(bvh); | 
| 190 |       } | 
| 191 |        | 
| 192 |       size_t bytes(BVH* bvh) const { | 
| 193 |         return statLeaf.bytes(bvh) + | 
| 194 |           statAABBNodes.bytes() +  | 
| 195 |           statOBBNodes.bytes() +  | 
| 196 |           statAABBNodesMB.bytes() +  | 
| 197 |           statAABBNodesMB4D.bytes() +  | 
| 198 |           statOBBNodesMB.bytes() +  | 
| 199 |           statQuantizedNodes.bytes(); | 
| 200 |       } | 
| 201 |  | 
| 202 |       size_t size() const  | 
| 203 |       { | 
| 204 |         return statLeaf.size() + | 
| 205 |           statAABBNodes.size() +  | 
| 206 |           statOBBNodes.size() +  | 
| 207 |           statAABBNodesMB.size() +  | 
| 208 |           statAABBNodesMB4D.size() +  | 
| 209 |           statOBBNodesMB.size() +  | 
| 210 |           statQuantizedNodes.size(); | 
| 211 |       } | 
| 212 |  | 
| 213 |       double fillRate (BVH* bvh) const  | 
| 214 |       { | 
| 215 |         double nom = statLeaf.fillRateNom(bvh) + | 
| 216 |           statAABBNodes.fillRateNom() +  | 
| 217 |           statOBBNodes.fillRateNom() +  | 
| 218 |           statAABBNodesMB.fillRateNom() +  | 
| 219 |           statAABBNodesMB4D.fillRateNom() +  | 
| 220 |           statOBBNodesMB.fillRateNom() +  | 
| 221 |           statQuantizedNodes.fillRateNom(); | 
| 222 |         double den = statLeaf.fillRateDen(bvh) + | 
| 223 |           statAABBNodes.fillRateDen() +  | 
| 224 |           statOBBNodes.fillRateDen() +  | 
| 225 |           statAABBNodesMB.fillRateDen() +  | 
| 226 |           statAABBNodesMB4D.fillRateDen() +  | 
| 227 |           statOBBNodesMB.fillRateDen() +  | 
| 228 |           statQuantizedNodes.fillRateDen(); | 
| 229 |         return nom/den; | 
| 230 |       } | 
| 231 |  | 
| 232 |       friend Statistics operator+ ( const Statistics& a, const Statistics& b ) | 
| 233 |       { | 
| 234 |         return Statistics(max(a.depth,b.depth), | 
| 235 |                           a.statLeaf + b.statLeaf, | 
| 236 |                           a.statAABBNodes + b.statAABBNodes, | 
| 237 |                           a.statOBBNodes + b.statOBBNodes, | 
| 238 |                           a.statAABBNodesMB + b.statAABBNodesMB, | 
| 239 |                           a.statAABBNodesMB4D + b.statAABBNodesMB4D, | 
| 240 |                           a.statOBBNodesMB + b.statOBBNodesMB, | 
| 241 |                           a.statQuantizedNodes + b.statQuantizedNodes); | 
| 242 |       } | 
| 243 |  | 
| 244 |       static Statistics add ( const Statistics& a, const Statistics& b ) { | 
| 245 |         return a+b; | 
| 246 |       } | 
| 247 |  | 
| 248 |     public: | 
| 249 |       size_t depth; | 
| 250 |       LeafStat statLeaf; | 
| 251 |       NodeStat<AABBNode> statAABBNodes; | 
| 252 |       NodeStat<OBBNode> statOBBNodes; | 
| 253 |       NodeStat<AABBNodeMB> statAABBNodesMB; | 
| 254 |       NodeStat<AABBNodeMB4D> statAABBNodesMB4D; | 
| 255 |       NodeStat<OBBNodeMB> statOBBNodesMB; | 
| 256 |       NodeStat<QuantizedNode> statQuantizedNodes; | 
| 257 |     }; | 
| 258 |  | 
| 259 |   public: | 
| 260 |  | 
| 261 |     /* Constructor gathers statistics. */ | 
| 262 |     BVHNStatistics (BVH* bvh); | 
| 263 |  | 
| 264 |     /*! Convert statistics into a string */ | 
| 265 |     std::string str(); | 
| 266 |  | 
| 267 |     double sah() const {  | 
| 268 |       return stat.sah(bvh);  | 
| 269 |     } | 
| 270 |  | 
| 271 |     size_t bytesUsed() const { | 
| 272 |       return stat.bytes(bvh); | 
| 273 |     } | 
| 274 |  | 
| 275 |   private: | 
| 276 |     Statistics statistics(NodeRef node, const double A, const BBox1f dt); | 
| 277 |  | 
| 278 |   private: | 
| 279 |     BVH* bvh; | 
| 280 |     Statistics stat; | 
| 281 |   }; | 
| 282 |  | 
| 283 |   typedef BVHNStatistics<4> BVH4Statistics; | 
| 284 |   typedef BVHNStatistics<8> BVH8Statistics; | 
| 285 | } | 
| 286 |  |