use std::set instead of vector for original_brushes since we need them implicitly sorted and no dupes

parallelize PruneNodes_R and CalcTreeBounds_r
This commit is contained in:
Jonathan 2022-08-01 13:19:50 -04:00
parent 26a18d5cc3
commit 755a9e65ca
6 changed files with 36 additions and 44 deletions

View File

@ -24,34 +24,6 @@
#include <vector>
#include <list>
template<class T>
void sort_and_remove_duplicates(T &v)
{
std::sort(v.begin(), v.end());
auto last = std::unique(v.begin(), v.end());
v.erase(last, v.end());
}
template<class E>
std::vector<E> concat(const std::vector<E> &a, const std::vector<E> &b)
{
std::vector<E> result;
result.reserve(a.size() + b.size());
std::copy(a.begin(), a.end(), std::back_inserter(result));
std::copy(b.begin(), b.end(), std::back_inserter(result));
return result;
}
template<class E>
std::vector<E> make_vector(E e)
{
std::vector<E> result;
result.push_back(std::move(e));
return result;
}
template<class E>
std::list<E> make_list(E e)
{

View File

@ -605,9 +605,16 @@ namespace qv
// there is a node_t structure for every node and leaf in the bsp tree
#include <set>
struct bspbrush_t;
struct side_t;
struct bspbrush_t_less
{
bool operator()(const bspbrush_t *a, const bspbrush_t *b) const;
};
struct node_t
{
// both leafs and nodes
@ -627,7 +634,7 @@ struct node_t
// information for leafs
contentflags_t contents; // leaf nodes (0 for decision nodes)
std::vector<bspbrush_t *> original_brushes;
std::set<bspbrush_t *, bspbrush_t_less> original_brushes;
std::vector<face_t *> markfaces; // leaf nodes only, point to node faces
portal_t *portals;
int visleafnum; // -1 = solid

View File

@ -28,6 +28,11 @@
#include <qbsp/map.hh>
#include <qbsp/qbsp.hh>
bool bspbrush_t_less::operator()(const bspbrush_t *a, const bspbrush_t *b) const
{
return a->file_order < b->file_order;
}
const maptexinfo_t &side_t::get_texinfo() const
{
return map.mtexinfos[this->texinfo];

View File

@ -408,7 +408,7 @@ static void LeafNode(node_t *leafnode, std::vector<std::unique_ptr<bspbrush_t>>
}
for (auto &brush : brushes) {
Q_assert(brush->original != nullptr);
leafnode->original_brushes.push_back(brush->original);
leafnode->original_brushes.insert(brush->original);
}
qbsp_options.target_game->count_contents_in_stats(leafnode->contents, *stats.leafstats);

View File

@ -392,11 +392,12 @@ static void CalcTreeBounds_r(tree_t *tree, node_t *node)
return;
}
CalcTreeBounds_r(tree, node->children[0].get());
CalcTreeBounds_r(tree, node->children[1].get());
tbb::task_group g;
g.run([&]() { CalcTreeBounds_r(tree, node->children[0].get()); });
g.run([&]() { CalcTreeBounds_r(tree, node->children[1].get()); });
g.wait();
node->bounds = node->children[0]->bounds;
node->bounds += node->children[1]->bounds;
node->bounds = node->children[0]->bounds + node->children[1]->bounds;
if (node->bounds.mins()[0] >= node->bounds.maxs()[0]) {
logging::print("WARNING: node without a volume\n");
@ -406,8 +407,8 @@ static void CalcTreeBounds_r(tree_t *tree, node_t *node)
node->bounds = {node->parent->bounds.mins(), node->parent->bounds.mins()};
}
for (int i = 0; i < 3; i++) {
if (fabs(node->bounds.mins()[i]) > qbsp_options.worldextent.value()) {
for (auto &v : node->bounds.mins()) {
if (fabs(v) > qbsp_options.worldextent.value()) {
logging::print("WARNING: node with unbounded volume\n");
break;
}
@ -517,6 +518,8 @@ void MakeTreePortals(tree_t *tree)
MakePortalsFromBuildportals(tree, std::move(buildportals));
logging::header("CalcTreeBounds");
CalcTreeBounds_r(tree, tree->headnode.get());
logging::print(logging::flag::STAT, " {:8} tiny portals\n", stats.c_tinyportals);

View File

@ -25,6 +25,7 @@
#include <qbsp/qbsp.hh>
#include <qbsp/brush.hh>
#include <qbsp/portals.hh>
#include <tbb/task_group.h>
//============================================================================
@ -62,14 +63,15 @@ void FreeTreePortals(tree_t *tree)
static void ConvertNodeToLeaf(node_t *node, const contentflags_t &contents)
{
// merge the children's brush lists
node->original_brushes = concat(node->children[0]->original_brushes, node->children[1]->original_brushes);
sort_and_remove_duplicates(node->original_brushes);
node->original_brushes = node->children[0]->original_brushes;
node->original_brushes.insert(node->children[1]->original_brushes.begin(), node->children[1]->original_brushes.end());
node->is_leaf = true;
for (int i = 0; i < 2; ++i) {
node->children[i] = nullptr;
for (auto &child : node->children) {
child = nullptr;
}
node->facelist.clear();
node->contents = contents;
@ -77,14 +79,16 @@ static void ConvertNodeToLeaf(node_t *node, const contentflags_t &contents)
Q_assert(node->markfaces.empty());
}
static void PruneNodes_R(node_t *node, int &count_pruned)
static void PruneNodes_R(node_t *node, std::atomic_int32_t &count_pruned)
{
if (node->is_leaf) {
return;
}
PruneNodes_R(node->children[0].get(), count_pruned);
PruneNodes_R(node->children[1].get(), count_pruned);
tbb::task_group g;
g.run([&]() { PruneNodes_R(node->children[0].get(), count_pruned); });
g.run([&]() { PruneNodes_R(node->children[1].get(), count_pruned); });
g.wait();
if (node->children[0]->is_leaf && node->children[0]->contents.is_any_solid(qbsp_options.target_game) &&
node->children[1]->is_leaf && node->children[1]->contents.is_any_solid(qbsp_options.target_game)) {
@ -109,7 +113,8 @@ void PruneNodes(node_t *node)
{
logging::funcheader();
int count_pruned = 0;
std::atomic_int32_t count_pruned = 0;
PruneNodes_R(node, count_pruned);
logging::print(logging::flag::STAT, " {:8} pruned nodes\n", count_pruned);