diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f08e5e7..5bbc86db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/qbsp/CMakeLists.txt b/qbsp/CMakeLists.txt index a539a35b..bd27eaf2 100644 --- a/qbsp/CMakeLists.txt +++ b/qbsp/CMakeLists.txt @@ -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) diff --git a/qbsp/csg4.cc b/qbsp/csg4.cc index 2bc85d6e..3b0a5d55 100644 --- a/qbsp/csg4.cc +++ b/qbsp/csg4.cc @@ -22,6 +22,10 @@ #include +#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 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 brushvec; + for (const brush_t* brush = entity->brushes; brush; brush = brush->next) { + brushvec.push_back(brush); + } + + // output vector for the parallel_for + std::vector 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(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 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);