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
9namespace 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(std::ios::fixed, 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(std::ios::fixed, 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(std::ios::fixed, 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