2021-05-20 12:49:33 +02:00
|
|
|
// Copyright 2009-2021 Intel Corporation
|
2020-12-19 14:50:20 +01:00
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "bvh.h"
|
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
namespace embree
|
|
|
|
{
|
|
|
|
template<int N>
|
|
|
|
class BVHNStatistics
|
|
|
|
{
|
|
|
|
typedef BVHN<N> BVH;
|
|
|
|
typedef typename BVH::AABBNode AABBNode;
|
|
|
|
typedef typename BVH::OBBNode OBBNode;
|
|
|
|
typedef typename BVH::AABBNodeMB AABBNodeMB;
|
|
|
|
typedef typename BVH::AABBNodeMB4D AABBNodeMB4D;
|
|
|
|
typedef typename BVH::OBBNodeMB OBBNodeMB;
|
|
|
|
typedef typename BVH::QuantizedNode QuantizedNode;
|
|
|
|
|
|
|
|
typedef typename BVH::NodeRef NodeRef;
|
|
|
|
|
|
|
|
struct Statistics
|
|
|
|
{
|
|
|
|
template<typename Node>
|
|
|
|
struct NodeStat
|
|
|
|
{
|
|
|
|
NodeStat ( double nodeSAH = 0,
|
|
|
|
size_t numNodes = 0,
|
|
|
|
size_t numChildren = 0)
|
|
|
|
: nodeSAH(nodeSAH),
|
|
|
|
numNodes(numNodes),
|
|
|
|
numChildren(numChildren) {}
|
|
|
|
|
|
|
|
double sah(BVH* bvh) const {
|
|
|
|
return nodeSAH/bvh->getLinearBounds().expectedHalfArea();
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t bytes() const {
|
|
|
|
return numNodes*sizeof(Node);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t size() const {
|
|
|
|
return numNodes;
|
|
|
|
}
|
|
|
|
|
|
|
|
double fillRateNom () const { return double(numChildren); }
|
|
|
|
double fillRateDen () const { return double(numNodes*N); }
|
|
|
|
double fillRate () const { return fillRateNom()/fillRateDen(); }
|
|
|
|
|
|
|
|
__forceinline friend NodeStat operator+ ( const NodeStat& a, const NodeStat& b)
|
|
|
|
{
|
|
|
|
return NodeStat(a.nodeSAH + b.nodeSAH,
|
|
|
|
a.numNodes+b.numNodes,
|
|
|
|
a.numChildren+b.numChildren);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string toString(BVH* bvh, double sahTotal, size_t bytesTotal) const
|
|
|
|
{
|
|
|
|
std::ostringstream stream;
|
|
|
|
stream.setf(std::ios::fixed, std::ios::floatfield);
|
|
|
|
stream << "sah = " << std::setw(7) << std::setprecision(3) << sah(bvh);
|
|
|
|
stream << " (" << std::setw(6) << std::setprecision(2) << 100.0*sah(bvh)/sahTotal << "%), ";
|
|
|
|
stream << "#bytes = " << std::setw(7) << std::setprecision(2) << bytes()/1E6 << " MB ";
|
|
|
|
stream << "(" << std::setw(6) << std::setprecision(2) << 100.0*double(bytes())/double(bytesTotal) << "%), ";
|
|
|
|
stream << "#nodes = " << std::setw(7) << numNodes << " (" << std::setw(6) << std::setprecision(2) << 100.0*fillRate() << "% filled), ";
|
|
|
|
stream << "#bytes/prim = " << std::setw(6) << std::setprecision(2) << double(bytes())/double(bvh->numPrimitives);
|
|
|
|
return stream.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
double nodeSAH;
|
|
|
|
size_t numNodes;
|
|
|
|
size_t numChildren;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct LeafStat
|
|
|
|
{
|
|
|
|
static const int NHIST = 8;
|
|
|
|
|
|
|
|
LeafStat ( double leafSAH = 0.0f,
|
|
|
|
size_t numLeaves = 0,
|
|
|
|
size_t numPrimsActive = 0,
|
|
|
|
size_t numPrimsTotal = 0,
|
|
|
|
size_t numPrimBlocks = 0,
|
|
|
|
size_t numBytes = 0)
|
|
|
|
: leafSAH(leafSAH),
|
|
|
|
numLeaves(numLeaves),
|
|
|
|
numPrimsActive(numPrimsActive),
|
|
|
|
numPrimsTotal(numPrimsTotal),
|
|
|
|
numPrimBlocks(numPrimBlocks),
|
|
|
|
numBytes(numBytes)
|
|
|
|
{
|
|
|
|
for (size_t i=0; i<NHIST; i++)
|
|
|
|
numPrimBlocksHistogram[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
double sah(BVH* bvh) const {
|
|
|
|
return leafSAH/bvh->getLinearBounds().expectedHalfArea();
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t bytes(BVH* bvh) const {
|
|
|
|
return numBytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t size() const {
|
|
|
|
return numLeaves;
|
|
|
|
}
|
|
|
|
|
|
|
|
double fillRateNom (BVH* bvh) const { return double(numPrimsActive); }
|
|
|
|
double fillRateDen (BVH* bvh) const { return double(numPrimsTotal); }
|
|
|
|
double fillRate (BVH* bvh) const { return fillRateNom(bvh)/fillRateDen(bvh); }
|
|
|
|
|
|
|
|
__forceinline friend LeafStat operator+ ( const LeafStat& a, const LeafStat& b)
|
|
|
|
{
|
|
|
|
LeafStat stat(a.leafSAH + b.leafSAH,
|
|
|
|
a.numLeaves+b.numLeaves,
|
|
|
|
a.numPrimsActive+b.numPrimsActive,
|
|
|
|
a.numPrimsTotal+b.numPrimsTotal,
|
|
|
|
a.numPrimBlocks+b.numPrimBlocks,
|
|
|
|
a.numBytes+b.numBytes);
|
|
|
|
for (size_t i=0; i<NHIST; i++) {
|
|
|
|
stat.numPrimBlocksHistogram[i] += a.numPrimBlocksHistogram[i];
|
|
|
|
stat.numPrimBlocksHistogram[i] += b.numPrimBlocksHistogram[i];
|
|
|
|
}
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string toString(BVH* bvh, double sahTotal, size_t bytesTotal) const
|
|
|
|
{
|
|
|
|
std::ostringstream stream;
|
|
|
|
stream.setf(std::ios::fixed, std::ios::floatfield);
|
|
|
|
stream << "sah = " << std::setw(7) << std::setprecision(3) << sah(bvh);
|
|
|
|
stream << " (" << std::setw(6) << std::setprecision(2) << 100.0*sah(bvh)/sahTotal << "%), ";
|
|
|
|
stream << "#bytes = " << std::setw(7) << std::setprecision(2) << double(bytes(bvh))/1E6 << " MB ";
|
|
|
|
stream << "(" << std::setw(6) << std::setprecision(2) << 100.0*double(bytes(bvh))/double(bytesTotal) << "%), ";
|
|
|
|
stream << "#nodes = " << std::setw(7) << numLeaves << " (" << std::setw(6) << std::setprecision(2) << 100.0*fillRate(bvh) << "% filled), ";
|
|
|
|
stream << "#bytes/prim = " << std::setw(6) << std::setprecision(2) << double(bytes(bvh))/double(bvh->numPrimitives);
|
|
|
|
return stream.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string histToString() const
|
|
|
|
{
|
|
|
|
std::ostringstream stream;
|
|
|
|
stream.setf(std::ios::fixed, std::ios::floatfield);
|
|
|
|
for (size_t i=0; i<NHIST; i++)
|
|
|
|
stream << std::setw(6) << std::setprecision(2) << 100.0f*float(numPrimBlocksHistogram[i])/float(numLeaves) << "% ";
|
|
|
|
return stream.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
double leafSAH; //!< SAH of the leaves only
|
|
|
|
size_t numLeaves; //!< Number of leaf nodes.
|
|
|
|
size_t numPrimsActive; //!< Number of active primitives (
|
|
|
|
size_t numPrimsTotal; //!< Number of active and inactive primitives
|
|
|
|
size_t numPrimBlocks; //!< Number of primitive blocks.
|
|
|
|
size_t numBytes; //!< Number of bytes of leaves.
|
|
|
|
size_t numPrimBlocksHistogram[8];
|
|
|
|
};
|
|
|
|
|
|
|
|
public:
|
|
|
|
Statistics (size_t depth = 0,
|
|
|
|
LeafStat statLeaf = LeafStat(),
|
|
|
|
NodeStat<AABBNode> statAABBNodes = NodeStat<AABBNode>(),
|
|
|
|
NodeStat<OBBNode> statOBBNodes = NodeStat<OBBNode>(),
|
|
|
|
NodeStat<AABBNodeMB> statAABBNodesMB = NodeStat<AABBNodeMB>(),
|
|
|
|
NodeStat<AABBNodeMB4D> statAABBNodesMB4D = NodeStat<AABBNodeMB4D>(),
|
|
|
|
NodeStat<OBBNodeMB> statOBBNodesMB = NodeStat<OBBNodeMB>(),
|
|
|
|
NodeStat<QuantizedNode> statQuantizedNodes = NodeStat<QuantizedNode>())
|
|
|
|
|
|
|
|
: depth(depth),
|
|
|
|
statLeaf(statLeaf),
|
|
|
|
statAABBNodes(statAABBNodes),
|
|
|
|
statOBBNodes(statOBBNodes),
|
|
|
|
statAABBNodesMB(statAABBNodesMB),
|
|
|
|
statAABBNodesMB4D(statAABBNodesMB4D),
|
|
|
|
statOBBNodesMB(statOBBNodesMB),
|
|
|
|
statQuantizedNodes(statQuantizedNodes) {}
|
|
|
|
|
|
|
|
double sah(BVH* bvh) const
|
|
|
|
{
|
|
|
|
return statLeaf.sah(bvh) +
|
|
|
|
statAABBNodes.sah(bvh) +
|
|
|
|
statOBBNodes.sah(bvh) +
|
|
|
|
statAABBNodesMB.sah(bvh) +
|
|
|
|
statAABBNodesMB4D.sah(bvh) +
|
|
|
|
statOBBNodesMB.sah(bvh) +
|
|
|
|
statQuantizedNodes.sah(bvh);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t bytes(BVH* bvh) const {
|
|
|
|
return statLeaf.bytes(bvh) +
|
|
|
|
statAABBNodes.bytes() +
|
|
|
|
statOBBNodes.bytes() +
|
|
|
|
statAABBNodesMB.bytes() +
|
|
|
|
statAABBNodesMB4D.bytes() +
|
|
|
|
statOBBNodesMB.bytes() +
|
|
|
|
statQuantizedNodes.bytes();
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t size() const
|
|
|
|
{
|
|
|
|
return statLeaf.size() +
|
|
|
|
statAABBNodes.size() +
|
|
|
|
statOBBNodes.size() +
|
|
|
|
statAABBNodesMB.size() +
|
|
|
|
statAABBNodesMB4D.size() +
|
|
|
|
statOBBNodesMB.size() +
|
|
|
|
statQuantizedNodes.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
double fillRate (BVH* bvh) const
|
|
|
|
{
|
|
|
|
double nom = statLeaf.fillRateNom(bvh) +
|
|
|
|
statAABBNodes.fillRateNom() +
|
|
|
|
statOBBNodes.fillRateNom() +
|
|
|
|
statAABBNodesMB.fillRateNom() +
|
|
|
|
statAABBNodesMB4D.fillRateNom() +
|
|
|
|
statOBBNodesMB.fillRateNom() +
|
|
|
|
statQuantizedNodes.fillRateNom();
|
|
|
|
double den = statLeaf.fillRateDen(bvh) +
|
|
|
|
statAABBNodes.fillRateDen() +
|
|
|
|
statOBBNodes.fillRateDen() +
|
|
|
|
statAABBNodesMB.fillRateDen() +
|
|
|
|
statAABBNodesMB4D.fillRateDen() +
|
|
|
|
statOBBNodesMB.fillRateDen() +
|
|
|
|
statQuantizedNodes.fillRateDen();
|
|
|
|
return nom/den;
|
|
|
|
}
|
|
|
|
|
|
|
|
friend Statistics operator+ ( const Statistics& a, const Statistics& b )
|
|
|
|
{
|
|
|
|
return Statistics(max(a.depth,b.depth),
|
|
|
|
a.statLeaf + b.statLeaf,
|
|
|
|
a.statAABBNodes + b.statAABBNodes,
|
|
|
|
a.statOBBNodes + b.statOBBNodes,
|
|
|
|
a.statAABBNodesMB + b.statAABBNodesMB,
|
|
|
|
a.statAABBNodesMB4D + b.statAABBNodesMB4D,
|
|
|
|
a.statOBBNodesMB + b.statOBBNodesMB,
|
|
|
|
a.statQuantizedNodes + b.statQuantizedNodes);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Statistics add ( const Statistics& a, const Statistics& b ) {
|
|
|
|
return a+b;
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
size_t depth;
|
|
|
|
LeafStat statLeaf;
|
|
|
|
NodeStat<AABBNode> statAABBNodes;
|
|
|
|
NodeStat<OBBNode> statOBBNodes;
|
|
|
|
NodeStat<AABBNodeMB> statAABBNodesMB;
|
|
|
|
NodeStat<AABBNodeMB4D> statAABBNodesMB4D;
|
|
|
|
NodeStat<OBBNodeMB> statOBBNodesMB;
|
|
|
|
NodeStat<QuantizedNode> statQuantizedNodes;
|
|
|
|
};
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/* Constructor gathers statistics. */
|
|
|
|
BVHNStatistics (BVH* bvh);
|
|
|
|
|
|
|
|
/*! Convert statistics into a string */
|
|
|
|
std::string str();
|
|
|
|
|
|
|
|
double sah() const {
|
|
|
|
return stat.sah(bvh);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t bytesUsed() const {
|
|
|
|
return stat.bytes(bvh);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Statistics statistics(NodeRef node, const double A, const BBox1f dt);
|
|
|
|
|
|
|
|
private:
|
|
|
|
BVH* bvh;
|
|
|
|
Statistics stat;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef BVHNStatistics<4> BVH4Statistics;
|
|
|
|
typedef BVHNStatistics<8> BVH8Statistics;
|
|
|
|
}
|