Revert "qbsp: parallelize solidbsp"

This reverts commit 2ebfa8d780.
This commit is contained in:
Eric Wasylishen 2020-01-29 01:51:31 -07:00
parent 2ebfa8d780
commit f74d85c022
2 changed files with 124 additions and 145 deletions

View File

@ -278,9 +278,6 @@ typedef struct surface_s {
bool has_detail; // 1 if the surface has detail brushes bool has_detail; // 1 if the surface has detail brushes
bool has_struct; // 1 if the surface has non-detail brushes bool has_struct; // 1 if the surface has non-detail brushes
short lmshift; short lmshift;
vec_t metric; // temporary storage used during solidbsp
int splits; // temporary storage used during solidbsp
} surface_t; } surface_t;

View File

@ -20,13 +20,9 @@
*/ */
#include <limits.h> #include <limits.h>
#include <algorithm>
#include <qbsp/qbsp.hh> #include <qbsp/qbsp.hh>
#include "tbb/parallel_for_each.h"
#include "tbb/task_group.h"
int splitnodes; int splitnodes;
static int leaffaces; static int leaffaces;
@ -236,7 +232,7 @@ DivideBounds(const vec3_t mins, const vec3_t maxs, const qbsp_plane_t *split,
* Calculate the split plane metric for axial planes * Calculate the split plane metric for axial planes
*/ */
static vec_t static vec_t
SplitPlaneMetric_Axial(const qbsp_plane_t *p, const vec3_t mins, const vec3_t maxs) SplitPlaneMetric_Axial(const qbsp_plane_t *p, vec3_t mins, vec3_t maxs)
{ {
vec_t value, dist; vec_t value, dist;
int i; int i;
@ -259,7 +255,7 @@ SplitPlaneMetric_Axial(const qbsp_plane_t *p, const vec3_t mins, const vec3_t ma
* Calculate the split plane metric for non-axial planes * Calculate the split plane metric for non-axial planes
*/ */
static vec_t static vec_t
SplitPlaneMetric_NonAxial(const qbsp_plane_t *p, const vec3_t mins, const vec3_t maxs) SplitPlaneMetric_NonAxial(const qbsp_plane_t *p, vec3_t mins, vec3_t maxs)
{ {
vec3_t fmins, fmaxs, bmins, bmaxs; vec3_t fmins, fmaxs, bmins, bmaxs;
vec_t value = 0.0; vec_t value = 0.0;
@ -275,7 +271,7 @@ SplitPlaneMetric_NonAxial(const qbsp_plane_t *p, const vec3_t mins, const vec3_t
} }
static inline vec_t static inline vec_t
SplitPlaneMetric(const qbsp_plane_t *p, const vec3_t mins, const vec3_t maxs) SplitPlaneMetric(const qbsp_plane_t *p, vec3_t mins, vec3_t maxs)
{ {
vec_t value; vec_t value;
@ -295,27 +291,19 @@ The clipping hull BSP doesn't worry about avoiding splits
================== ==================
*/ */
static surface_t * static surface_t *
ChooseMidPlaneFromList(const std::vector<surface_t*>& surfaces, const vec3_t mins, const vec3_t maxs) ChooseMidPlaneFromList(surface_t *surfaces, vec3_t mins, vec3_t maxs)
{ {
// compute the metrics in parallel surface_t *surf, *bestsurface;
tbb::parallel_for_each(surfaces, [mins, maxs](surface_t* surf){ vec_t metric, bestmetric;
surf->metric = VECT_MAX; qbsp_plane_t *plane;
int pass;
if (surf->onnode)
return;
qbsp_plane_t *plane = &map.planes[surf->planenum];
/* calculate the split metric, smaller values are better */
surf->metric = SplitPlaneMetric(plane, mins, maxs);
});
/* pick the plane that splits the least */ /* pick the plane that splits the least */
vec_t bestmetric = VECT_MAX; bestmetric = VECT_MAX;
surface_t *bestsurface = NULL; bestsurface = NULL;
for (int pass = 0; pass < 2; pass++) { for (pass = 0; pass < 2; pass++) {
for (surface_t *surf : surfaces) { for (surf = surfaces; surf; surf = surf->next) {
if (surf->onnode) if (surf->onnode)
continue; continue;
@ -325,20 +313,21 @@ ChooseMidPlaneFromList(const std::vector<surface_t*>& surfaces, const vec3_t min
continue; continue;
/* check for axis aligned surfaces */ /* check for axis aligned surfaces */
qbsp_plane_t *plane = &map.planes[surf->planenum]; plane = &map.planes[surf->planenum];
if (!(plane->type < 3)) if (!(plane->type < 3))
continue; continue;
/* calculate the split metric, smaller values are better */ /* calculate the split metric, smaller values are better */
if (surf->metric < bestmetric) { metric = SplitPlaneMetric(plane, mins, maxs);
bestmetric = surf->metric; if (metric < bestmetric) {
bestmetric = metric;
bestsurface = surf; bestsurface = surf;
} }
} }
if (!bestsurface) { if (!bestsurface) {
/* Choose based on spatial subdivision only */ /* Choose based on spatial subdivision only */
for (surface_t *surf : surfaces) { for (surf = surfaces; surf; surf = surf->next) {
if (surf->onnode) if (surf->onnode)
continue; continue;
@ -347,8 +336,10 @@ ChooseMidPlaneFromList(const std::vector<surface_t*>& surfaces, const vec3_t min
if( !surf->has_struct && !pass ) if( !surf->has_struct && !pass )
continue; continue;
if (surf->metric < bestmetric) { plane = &map.planes[surf->planenum];
bestmetric = surf->metric; metric = SplitPlaneMetric(plane, mins, maxs);
if (metric < bestmetric) {
bestmetric = metric;
bestsurface = surf; bestsurface = surf;
} }
} }
@ -384,35 +375,52 @@ The real BSP hueristic
================== ==================
*/ */
static surface_t * static surface_t *
ChoosePlaneFromList(const std::vector<surface_t*>& surfaces, const vec3_t mins, const vec3_t maxs) ChoosePlaneFromList(surface_t *surfaces, vec3_t mins, vec3_t maxs)
{ {
// compute the splits in parallel int pass, splits, minsplits;
tbb::parallel_for_each(surfaces, [surfaces, mins, maxs](surface_t* surf){ bool hintsplit;
surf->splits = INT_MAX; surface_t *surf, *surf2, *bestsurface;
surf->metric = VECT_MAX; vec_t distribution, bestdistribution;
const qbsp_plane_t *plane, *plane2;
const face_t *face;
/* pick the plane that splits the least */
minsplits = INT_MAX - 1;
bestdistribution = VECT_MAX;
bestsurface = NULL;
/* Two passes - exhaust all non-detail faces before details */
for (pass = 0; pass < 2; pass++) {
for (surf = surfaces; surf; surf = surf->next) {
if (surf->onnode) if (surf->onnode)
return; continue;
/* /*
* Check that the surface has a suitable face for the current pass * Check that the surface has a suitable face for the current pass
* and check whether this is a hint split. * and check whether this is a hint split.
*/ */
bool hintsplit = false; hintsplit = false;
for (const face_t *face = surf->faces; face; face = face->next) { for (face = surf->faces; face; face = face->next) {
if (map.mtexinfos.at(face->texinfo).flags & TEX_HINT) if (map.mtexinfos.at(face->texinfo).flags & TEX_HINT)
hintsplit = true; hintsplit = true;
} }
const qbsp_plane_t *plane = &map.planes[surf->planenum]; if( surf->has_struct && pass )
int splits = 0; continue;
for (surface_t* surf2 : surfaces) { if( !surf->has_struct && !pass )
continue;
plane = &map.planes[surf->planenum];
splits = 0;
for (surf2 = surfaces; surf2; surf2 = surf2->next) {
if (surf2 == surf || surf2->onnode) if (surf2 == surf || surf2->onnode)
continue; continue;
const qbsp_plane_t *plane2 = &map.planes[surf2->planenum]; plane2 = &map.planes[surf2->planenum];
if (plane->type < 3 && plane->type == plane2->type) if (plane->type < 3 && plane->type == plane2->type)
continue; continue;
for (const face_t *face = surf2->faces; face; face = face->next) { for (face = surf2->faces; face; face = face->next) {
const uint64_t flags = map.mtexinfos.at(face->texinfo).flags; const uint64_t flags = map.mtexinfos.at(face->texinfo).flags;
/* Don't penalize for splitting skip faces */ /* Don't penalize for splitting skip faces */
if (flags & TEX_SKIP) if (flags & TEX_SKIP)
@ -424,44 +432,29 @@ ChoosePlaneFromList(const std::vector<surface_t*>& surfaces, const vec3_t mins,
break; break;
} }
splits++; splits++;
if (splits >= minsplits)
break;
} }
} }
if (splits > minsplits)
break;
} }
if (splits > minsplits)
surf->splits = splits;
surf->metric = SplitPlaneMetric(plane, mins, maxs);
});
/* pick the plane that splits the least */
int minsplits = INT_MAX - 1;
vec_t bestdistribution = VECT_MAX;
surface_t* bestsurface = NULL;
/* Two passes - exhaust all non-detail faces before details */
for (int pass = 0; pass < 2; pass++) {
for (surface_t* surf : surfaces) {
if (surf->onnode)
continue; continue;
if( surf->has_struct && pass )
continue;
if( !surf->has_struct && !pass )
continue;
const qbsp_plane_t *plane = &map.planes[surf->planenum];
/* /*
* if equal numbers axial planes win, otherwise decide on spatial * if equal numbers axial planes win, otherwise decide on spatial
* subdivision * subdivision
*/ */
if (surf->splits < minsplits || (surf->splits == minsplits && plane->type < 3)) { if (splits < minsplits || (splits == minsplits && plane->type < 3)) {
if (plane->type < 3) { if (plane->type < 3) {
if (surf->metric > bestdistribution && surf->splits == minsplits) distribution = SplitPlaneMetric(plane, mins, maxs);
if (distribution > bestdistribution && splits == minsplits)
continue; continue;
bestdistribution = surf->metric; bestdistribution = distribution;
} }
/* currently the best! */ /* currently the best! */
minsplits = surf->splits; minsplits = splits;
bestsurface = surf; bestsurface = surf;
} }
} }
@ -486,16 +479,16 @@ returns NULL if the surface list can not be divided any more (a leaf)
================== ==================
*/ */
static surface_t * static surface_t *
SelectPartition(const std::vector<surface_t*>& surfaces) SelectPartition(surface_t *surfaces)
{ {
int i, surfcount; int i, surfcount;
vec3_t mins, maxs; vec3_t mins, maxs;
surface_t *bestsurface; surface_t *surf, *bestsurface;
// count onnode surfaces // count onnode surfaces
surfcount = 0; surfcount = 0;
bestsurface = NULL; bestsurface = NULL;
for (surface_t *surf : surfaces) for (surf = surfaces; surf; surf = surf->next)
if (!surf->onnode) { if (!surf->onnode) {
surfcount++; surfcount++;
bestsurface = surf; bestsurface = surf;
@ -512,7 +505,7 @@ SelectPartition(const std::vector<surface_t*>& surfaces)
mins[i] = VECT_MAX; mins[i] = VECT_MAX;
maxs[i] = -VECT_MAX; maxs[i] = -VECT_MAX;
} }
for (surface_t *surf : surfaces) for (surf = surfaces; surf; surf = surf->next)
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
if (surf->mins[i] < mins[i]) if (surf->mins[i] < mins[i])
mins[i] = surf->mins[i]; mins[i] = surf->mins[i];
@ -617,9 +610,8 @@ DividePlane
================== ==================
*/ */
static void static void
DividePlane(surface_t *in, qbsp_plane_t *split, DividePlane(surface_t *in, qbsp_plane_t *split, surface_t **front,
std::vector<surface_t *>& front, surface_t **back)
std::vector<surface_t *>& back)
{ {
face_t *facet, *next; face_t *facet, *next;
face_t *frontlist, *backlist; face_t *frontlist, *backlist;
@ -628,8 +620,7 @@ DividePlane(surface_t *in, qbsp_plane_t *split,
qbsp_plane_t *inplane; qbsp_plane_t *inplane;
inplane = &map.planes[in->planenum]; inplane = &map.planes[in->planenum];
assert(front.empty()); *front = *back = NULL;
assert(back.empty());
// parallel case is easy // parallel case is easy
if (VectorCompare(inplane->normal, split->normal, EQUAL_EPSILON)) { if (VectorCompare(inplane->normal, split->normal, EQUAL_EPSILON)) {
@ -661,12 +652,12 @@ DividePlane(surface_t *in, qbsp_plane_t *split,
CalcSurfaceInfo(in); CalcSurfaceInfo(in);
if (in->faces) if (in->faces)
front.push_back(in); *front = in;
else else
FreeMem(in, SURFACE, 1); FreeMem(in, SURFACE, 1);
if (newsurf->faces) if (newsurf->faces)
back.push_back(newsurf); *back = newsurf;
else else
FreeMem(newsurf, SURFACE, 1); FreeMem(newsurf, SURFACE, 1);
@ -674,9 +665,9 @@ DividePlane(surface_t *in, qbsp_plane_t *split,
} }
if (inplane->dist > split->dist) if (inplane->dist > split->dist)
front.push_back(in); *front = in;
else else
back.push_back(in); *back = in;
return; return;
} }
// do a real split. may still end up entirely on one side // do a real split. may still end up entirely on one side
@ -699,13 +690,13 @@ DividePlane(surface_t *in, qbsp_plane_t *split,
// if nothing actually got split, just move the in plane // if nothing actually got split, just move the in plane
if (frontlist == NULL) { if (frontlist == NULL) {
back.push_back(in); *back = in;
in->faces = backlist; in->faces = backlist;
return; return;
} }
if (backlist == NULL) { if (backlist == NULL) {
front.push_back(in); *front = in;
in->faces = frontlist; in->faces = frontlist;
return; return;
} }
@ -714,10 +705,10 @@ DividePlane(surface_t *in, qbsp_plane_t *split,
newsurf = (surface_t *)AllocMem(SURFACE, 1, true); newsurf = (surface_t *)AllocMem(SURFACE, 1, true);
*newsurf = *in; *newsurf = *in;
newsurf->faces = backlist; newsurf->faces = backlist;
back.push_back(newsurf); *back = newsurf;
in->faces = frontlist; in->faces = frontlist;
front.push_back(in); *front = in;
// recalc bboxes and flags // recalc bboxes and flags
CalcSurfaceInfo(newsurf); CalcSurfaceInfo(newsurf);
@ -816,9 +807,10 @@ original faces that have some fragment inside this leaf
================== ==================
*/ */
static void static void
LinkConvexFaces(const std::vector<surface_t*>& planelist, node_t *leafnode) LinkConvexFaces(surface_t *planelist, node_t *leafnode)
{ {
face_t *f, *next; face_t *f, *next;
surface_t *surf, *pnext;
int i, count; int i, count;
leafnode->faces = NULL; leafnode->faces = NULL;
@ -826,7 +818,7 @@ LinkConvexFaces(const std::vector<surface_t*>& planelist, node_t *leafnode)
leafnode->planenum = PLANENUM_LEAF; leafnode->planenum = PLANENUM_LEAF;
count = 0; count = 0;
for (surface_t *surf : planelist) { for (surf = planelist; surf; surf = surf->next) {
for (f = surf->faces; f; f = f->next) { for (f = surf->faces; f; f = f->next) {
count++; count++;
@ -888,7 +880,8 @@ LinkConvexFaces(const std::vector<surface_t*>& planelist, node_t *leafnode)
leafnode->markfaces = (face_t **)AllocMem(OTHER, sizeof(face_t *) * (count + 1), true); leafnode->markfaces = (face_t **)AllocMem(OTHER, sizeof(face_t *) * (count + 1), true);
i = 0; i = 0;
for (surface_t *surf : planelist) { for (surf = planelist; surf; surf = pnext) {
pnext = surf->next;
for (f = surf->faces; f; f = next) { for (f = surf->faces; f; f = next) {
next = f->next; next = f->next;
leafnode->markfaces[i] = f->original; leafnode->markfaces[i] = f->original;
@ -947,13 +940,14 @@ PartitionSurfaces
================== ==================
*/ */
static void static void
PartitionSurfaces(std::vector<surface_t*> surfaces, node_t *node) PartitionSurfaces(surface_t *surfaces, node_t *node)
{ {
// split, *next; surface_t *split, *surf, *next;
// surface_t *frontfrag, *backfrag; surface_t *frontlist, *backlist;
surface_t *frontfrag, *backfrag;
qbsp_plane_t *splitplane; qbsp_plane_t *splitplane;
surface_t *split = SelectPartition(surfaces); split = SelectPartition(surfaces);
if (!split) { // this is a leaf node if (!split) { // this is a leaf node
node->planenum = PLANENUM_LEAF; node->planenum = PLANENUM_LEAF;
@ -977,46 +971,35 @@ PartitionSurfaces(std::vector<surface_t*> surfaces, node_t *node)
DivideNodeBounds(node, splitplane); DivideNodeBounds(node, splitplane);
// multiple surfaces, so split all the polysurfaces into front and back lists // multiple surfaces, so split all the polysurfaces into front and back lists
std::vector<surface_t*> frontlist; frontlist = NULL;
std::vector<surface_t*> backlist; backlist = NULL;
for (surface_t *surf : surfaces) { for (surf = surfaces; surf; surf = next) {
// FIXME: these only ever hold 0 or 1 surface each next = surf->next;
std::vector<surface_t*> frontfrag; DividePlane(surf, splitplane, &frontfrag, &backfrag);
std::vector<surface_t*> backfrag; if (frontfrag && backfrag) {
DividePlane(surf, splitplane, frontfrag, backfrag);
if (!frontfrag.empty() && !backfrag.empty()) {
// the plane was split, which may expose oportunities to merge // the plane was split, which may expose oportunities to merge
// adjacent faces into a single face // adjacent faces into a single face
// MergePlaneFaces (frontfrag); // MergePlaneFaces (frontfrag);
// MergePlaneFaces (backfrag); // MergePlaneFaces (backfrag);
} }
if (!frontfrag.empty()) { if (frontfrag) {
if (!frontfrag[0]->faces) if (!frontfrag->faces)
Error("Surface with no faces (%s)", __func__); Error("Surface with no faces (%s)", __func__);
frontlist.push_back(frontfrag[0]); frontfrag->next = frontlist;
frontlist = frontfrag;
} }
if (!backfrag.empty()) { if (backfrag) {
if (!backfrag[0]->faces) if (!backfrag->faces)
Error("Surface with no faces (%s)", __func__); Error("Surface with no faces (%s)", __func__);
backlist.push_back(backfrag[0]); backfrag->next = backlist;
backlist = backfrag;
} }
} }
// Hack to match order of code before moving to std::vector PartitionSurfaces(frontlist, node->children[0]);
std::reverse(frontlist.begin(), frontlist.end()); PartitionSurfaces(backlist, node->children[1]);
std::reverse(backlist.begin(), backlist.end());
// free memory
surfaces.clear();
surfaces.shrink_to_fit();
tbb::task_group g;
g.run([&](){ PartitionSurfaces(std::move(frontlist), node->children[0]); });
g.run([&](){ PartitionSurfaces(std::move(backlist), node->children[1]); });
g.wait();
} }
@ -1079,12 +1062,11 @@ SolidBSP(const mapentity_t *entity, surface_t *surfhead, bool midsplit)
c_illusionary_visblocker = 0; c_illusionary_visblocker = 0;
// count map surfaces; this is used when deciding to switch between midsplit and the expensive partitioning // count map surfaces; this is used when deciding to switch between midsplit and the expensive partitioning
mapsurfaces = 0; mapsurfaces = 0;
std::vector<surface_t*> surfaces_vec;
for (surface_t *surf = surfhead; surf; surf = surf->next) { for (surface_t *surf = surfhead; surf; surf = surf->next) {
mapsurfaces++; mapsurfaces++;
surfaces_vec.push_back(surf);
} }
PartitionSurfaces(std::move(surfaces_vec), headnode);
PartitionSurfaces(surfhead, headnode);
Message(msgStat, "%8d split nodes", splitnodes); Message(msgStat, "%8d split nodes", splitnodes);
Message(msgStat, "%8d solid leafs", c_solid); Message(msgStat, "%8d solid leafs", c_solid);