qbsp: parallelize CSGFaces

This commit is contained in:
Eric Wasylishen 2020-01-28 21:18:08 -07:00
parent e2a5f62f32
commit 1f565d7e7a
3 changed files with 44 additions and 24 deletions

View File

@ -122,6 +122,8 @@ endif (MSVC)
#minimum version that supports unordered_map
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.9)
find_package(TBB REQUIRED)
add_subdirectory(bspinfo)
add_subdirectory(bsputil)
add_subdirectory(light)

View File

@ -4,7 +4,7 @@ project (qbsp CXX)
add_definitions(-DDOUBLEVEC_T)
add_executable(qbsp ${QBSP_SOURCES} main.cc)
target_link_libraries(qbsp ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(qbsp ${CMAKE_THREAD_LIBS_INIT} TBB::tbb)
install(TARGETS qbsp RUNTIME DESTINATION bin)
# test (copied from light/CMakeLists.txt)
@ -22,4 +22,4 @@ set(QBSP_TEST_SOURCE
add_executable(testqbsp EXCLUDE_FROM_ALL ${QBSP_TEST_SOURCE})
add_test(testqbsp testqbsp)
target_link_libraries (testqbsp ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries (testqbsp ${CMAKE_THREAD_LIBS_INIT} TBB::tbb)

View File

@ -22,6 +22,10 @@
#include <qbsp/qbsp.hh>
#include "tbb/mutex.h"
#include "tbb/parallel_do.h"
#include "tbb/parallel_for.h"
/*
NOTES
@ -564,17 +568,8 @@ Returns a list of surfaces containing all of the faces
surface_t *
CSGFaces(const mapentity_t *entity)
{
int i;
const brush_t *brush, *clipbrush;
const face_t *clipface;
face_t *inside, *outside;
bool overwrite, mirror;
surface_t *surfaces;
int progress = 0;
Message(msgProgress, "CSGFaces");
std::map<int, face_t *> planefaces;
csgfaces = brushfaces = csgmergefaces = 0;
#if 0
@ -583,17 +578,33 @@ CSGFaces(const mapentity_t *entity)
logprint(" %s (%s)\n", map.texinfoTextureName(brush->faces->texinfo).c_str(), GetContentsName(brush->contents));
}
#endif
// copy to vector
// TODO: change brush list in mapentity_t to a vector so we can skip this
std::vector<const brush_t*> brushvec;
for (const brush_t* brush = entity->brushes; brush; brush = brush->next) {
brushvec.push_back(brush);
}
// output vector for the parallel_for
std::vector<face_t*> brushvec_outsides;
brushvec_outsides.resize(brushvec.size());
/*
* For each brush, clip away the parts that are inside other brushes.
* Solid brushes override non-solid brushes.
* brush => the brush to be clipped
* clipbrush => the brush we are clipping against
*
* The output of this is a face list for each brush called "outside"
*/
for (brush = entity->brushes; brush; brush = brush->next) {
outside = CopyBrushFaces(brush);
overwrite = false;
clipbrush = entity->brushes;
tbb::parallel_for(static_cast<size_t>(0), brushvec.size(),
[entity, &brushvec, &brushvec_outsides](const size_t i) {
const brush_t* brush = brushvec[i];
face_t *outside = CopyBrushFaces(brush);
bool overwrite = false;
const brush_t *clipbrush = entity->brushes;
for (; clipbrush; clipbrush = clipbrush->next) {
if (brush == clipbrush) {
/* Brushes further down the list overried earlier ones */
@ -632,6 +643,7 @@ CSGFaces(const mapentity_t *entity)
}
/* check bounding box first */
int i;
for (i = 0; i < 3; i++) {
if (brush->mins[i] > clipbrush->maxs[i])
break;
@ -647,11 +659,11 @@ CSGFaces(const mapentity_t *entity)
*/
// divide faces by the planes of the new brush
inside = outside;
face_t *inside = outside;
outside = NULL;
RemoveOutsideFaces(clipbrush, &inside, &outside);
clipface = clipbrush->faces;
const face_t *clipface = clipbrush->faces;
for (; clipface; clipface = clipface->next)
ClipInside(clipface, overwrite, &inside, &outside);
@ -680,18 +692,24 @@ CSGFaces(const mapentity_t *entity)
}
}
// save the result
brushvec_outsides[i] = outside;
});
// Non parallel part:
std::map<int, face_t *> planefaces;
for (size_t i = 0; i < brushvec.size(); ++i) {
const brush_t* brush = brushvec[i];
face_t* outside = brushvec_outsides[i];
/*
* All of the faces left on the outside list are real surface faces
* If the brush is non-solid, mirror faces for the inside view
*/
mirror = options.fContentHack ? true : (brush->contents != CONTENTS_SOLID);
const bool mirror = options.fContentHack ? true : (brush->contents != CONTENTS_SOLID);
SaveFacesToPlaneList(outside, mirror, planefaces);
progress++;
Message(msgPercent, progress, entity->numbrushes);
}
surfaces = BuildSurfaces(planefaces);
surface_t *surfaces = BuildSurfaces(planefaces);
Message(msgStat, "%8d brushfaces", brushfaces);
Message(msgStat, "%8d csgfaces", csgfaces);