From 4e3739c751cd42f0f1493e602a11db7c97bfd021 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Sun, 24 Jul 2022 19:05:28 -0400 Subject: [PATCH] use a reader/writer-esque lock (shared_mutex) instead of exclusive-only recursive lock to speed up plane stuff --- include/qbsp/map.hh | 5 ++-- light/bounce.cc | 19 ++++++++----- qbsp/brush.cc | 69 ++++++++++++++++++++++----------------------- qbsp/brushbsp.cc | 18 +++--------- qbsp/faces.cc | 3 +- qbsp/map.cc | 4 +-- qbsp/merge.cc | 3 +- qbsp/outside.cc | 3 +- qbsp/portals.cc | 22 ++++++--------- qbsp/prtfile.cc | 2 +- qbsp/qbsp.cc | 8 ++---- qbsp/writebsp.cc | 2 +- 12 files changed, 70 insertions(+), 88 deletions(-) diff --git a/include/qbsp/map.hh b/include/qbsp/map.hh index ede49321..38cdd8f9 100644 --- a/include/qbsp/map.hh +++ b/include/qbsp/map.hh @@ -33,6 +33,7 @@ #include #include #include +#include struct bspbrush_t; @@ -125,7 +126,7 @@ struct maptexdata_t #include -extern std::recursive_mutex map_planes_lock; +extern std::shared_mutex map_planes_lock; struct hashvert_t { @@ -241,7 +242,7 @@ struct mapdata_t const std::string &texinfoTextureName(int texinfo) const { return miptexTextureName(mtexinfos.at(texinfo).miptex); } inline qbsp_plane_t get_plane(int pnum) { - const auto lock = std::lock_guard(map_planes_lock); + std::shared_lock lock(map_planes_lock); return planes.at(pnum); } diff --git a/light/bounce.cc b/light/bounce.cc index bc4d3e58..c2725042 100644 --- a/light/bounce.cc +++ b/light/bounce.cc @@ -91,6 +91,17 @@ qvec3b Face_LookupTextureColor(const mbsp_t *bsp, const mface_t *face) return {127}; } +inline bouncelight_t &CreateBounceLight(const mface_t *face, const mbsp_t *bsp) +{ + unique_lock lck{bouncelights_lock}; + bouncelight_t &l = bouncelights.emplace_back(); + + const int lastBounceLightIndex = static_cast(bouncelights.size()) - 1; + bouncelightsByFacenum[Face_GetNum(bsp, face)].push_back(lastBounceLightIndex); + + return l; +} + static void AddBounceLight(const qvec3d &pos, const std::unordered_map &colorByStyle, const qvec3d &surfnormal, vec_t area, const mface_t *face, const mbsp_t *bsp) { @@ -101,7 +112,7 @@ static void AddBounceLight(const qvec3d &pos, const std::unordered_map 0); - bouncelight_t l; + bouncelight_t &l = CreateBounceLight(face, bsp); l.poly = GLM_FacePoints(bsp, face); l.poly_edgeplanes = GLM_MakeInwardFacingEdgePlanes(l.poly); l.pos = pos; @@ -124,12 +135,6 @@ static void AddBounceLight(const qvec3d &pos, const std::unordered_map lck{bouncelights_lock}; - bouncelights.push_back(l); - - const int lastBounceLightIndex = static_cast(bouncelights.size()) - 1; - bouncelightsByFacenum[Face_GetNum(bsp, face)].push_back(lastBounceLightIndex); } const std::vector &BounceLights() diff --git a/qbsp/brush.cc b/qbsp/brush.cc index e2937e4b..5f2ae2c2 100644 --- a/qbsp/brush.cc +++ b/qbsp/brush.cc @@ -66,8 +66,7 @@ Face_Plane */ qplane3d Face_Plane(const face_t *face) { - const auto lock = std::lock_guard(map_planes_lock); - const qplane3d &result = map.planes.at(face->planenum); + const qplane3d result = map.get_plane(face->planenum); if (face->planeside) { return -result; @@ -78,8 +77,7 @@ qplane3d Face_Plane(const face_t *face) qplane3d Face_Plane(const side_t *face) { - const auto lock = std::lock_guard(map_planes_lock); - const qplane3d &result = map.planes.at(face->planenum); + const qplane3d result = map.get_plane(face->planenum); if (face->planeside) { return -result; @@ -97,8 +95,7 @@ Note: this will not catch 0 area polygons */ static void CheckFace(side_t *face, const mapface_t &sourceface) { - const auto lock = std::lock_guard(map_planes_lock); - const qbsp_plane_t &plane = map.planes.at(face->planenum); + const qbsp_plane_t plane = map.get_plane(face->planenum); if (face->w.size() < 3) { if (face->w.size() == 2) { @@ -229,38 +226,35 @@ inline int plane_hash_fn(const qplane3d &p) return Q_rint(fabs(p.dist)); } -static void PlaneHash_Add(const qplane3d &p, int index) -{ - const auto lock = std::lock_guard(map_planes_lock); - - const int hash = plane_hash_fn(p); - map.planehash[hash].push_back(index); -} - /* * NewPlane * - Returns a global plane number and the side that will be the front */ static int NewPlane(const qplane3d &plane, planeside_t *side) { - const auto lock = std::lock_guard(map_planes_lock); + size_t index; - vec_t len = qv::length(plane.normal); + { + std::unique_lock lock(map_planes_lock); - if (len < 1 - qbsp_options.epsilon.value() || len > 1 + qbsp_options.epsilon.value()) - FError("invalid normal (vector length {:.4})", len); + vec_t len = qv::length(plane.normal); - size_t index = map.planes.size(); - qbsp_plane_t &added_plane = map.planes.emplace_back(qbsp_plane_t{plane}); + if (len < 1 - qbsp_options.epsilon.value() || len > 1 + qbsp_options.epsilon.value()) + FError("invalid normal (vector length {:.4})", len); - bool out_flipped = NormalizePlane(added_plane, side != nullptr); + index = map.planes.size(); + qbsp_plane_t &added_plane = map.planes.emplace_back(qbsp_plane_t{plane}); - if (side) { - *side = out_flipped ? SIDE_BACK : SIDE_FRONT; + bool out_flipped = NormalizePlane(added_plane, side != nullptr); + + if (side) { + *side = out_flipped ? SIDE_BACK : SIDE_FRONT; + } + + const int hash = plane_hash_fn(added_plane); + map.planehash[hash].push_back(index); } - PlaneHash_Add(added_plane, index); - // add the back side, too FindPlane(-plane, nullptr); @@ -274,20 +268,23 @@ static int NewPlane(const qplane3d &plane, planeside_t *side) */ int FindPlane(const qplane3d &plane, planeside_t *side) { - const auto lock = std::lock_guard(map_planes_lock); + { + std::shared_lock lock(map_planes_lock); - for (int i : map.planehash[plane_hash_fn(plane)]) { - const qbsp_plane_t &p = map.planes.at(i); - if (qv::epsilonEqual(p, plane)) { - if (side) { - *side = SIDE_FRONT; + for (int i : map.planehash[plane_hash_fn(plane)]) { + const qbsp_plane_t &p = map.planes.at(i); + if (qv::epsilonEqual(p, plane)) { + if (side) { + *side = SIDE_FRONT; + } + return i; + } else if (side && qv::epsilonEqual(-p, plane)) { + *side = SIDE_BACK; + return i; } - return i; - } else if (side && qv::epsilonEqual(-p, plane)) { - *side = SIDE_BACK; - return i; } } + return NewPlane(plane, side); } @@ -297,7 +294,7 @@ int FindPlane(const qplane3d &plane, planeside_t *side) */ int FindPositivePlane(int planenum) { - const auto lock = std::lock_guard(map_planes_lock); + std::shared_lock lock(map_planes_lock); const auto &plane = map.planes[planenum]; diff --git a/qbsp/brushbsp.cc b/qbsp/brushbsp.cc index a00c4be6..04f8ffcf 100644 --- a/qbsp/brushbsp.cc +++ b/qbsp/brushbsp.cc @@ -252,13 +252,11 @@ static int QuickTestBrushToPlanenum(const bspbrush_t &brush, int planenum, int * } // box on plane side - const auto lock = std::lock_guard(map_planes_lock); - auto plane = map.planes[planenum]; + auto plane = map.get_plane(planenum); int s = BoxOnPlaneSide(brush.bounds, plane); // if both sides, count the visible faces split - if (s == PSIDE_BOTH) - { + if (s == PSIDE_BOTH) { *numsplits += 3; } @@ -289,11 +287,7 @@ static int TestBrushToPlanenum(const bspbrush_t &brush, int planenum, int *numsp } // box on plane side - qbsp_plane_t plane; - { - const auto lock = std::lock_guard(map_planes_lock); - plane = map.planes[planenum]; - } + qbsp_plane_t plane = map.get_plane(planenum); //int s = SphereOnPlaneSide(brush.sphere_origin, brush.sphere_radius, plane); int s = BoxOnPlaneSide(brush.bounds, plane); @@ -607,11 +601,7 @@ https://github.com/id-Software/Quake-2-Tools/blob/master/bsp/qbsp3/brushbsp.c#L9 */ static twosided> SplitBrush(std::unique_ptr brush, int planenum) { - qplane3d split; - { - const auto lock = std::lock_guard(map_planes_lock); - split = map.planes.at(planenum); - } + qplane3d split = map.get_plane(planenum); twosided> result; diff --git a/qbsp/faces.cc b/qbsp/faces.cc index ed585cb2..b60b8fb2 100644 --- a/qbsp/faces.cc +++ b/qbsp/faces.cc @@ -290,8 +290,7 @@ static void AddMarksurfaces_r(face_t *face, std::unique_ptr face_copy, n return; } - const auto lock = std::lock_guard(map_planes_lock); - const qbsp_plane_t &splitplane = map.planes.at(node->planenum); + const qbsp_plane_t splitplane = map.get_plane(node->planenum); auto [frontFragment, backFragment] = SplitFace(std::move(face_copy), splitplane); if (frontFragment) { diff --git a/qbsp/map.cc b/qbsp/map.cc index 54e64128..f5a5c78d 100644 --- a/qbsp/map.cc +++ b/qbsp/map.cc @@ -42,7 +42,7 @@ #include mapdata_t map; -std::recursive_mutex map_planes_lock; +std::shared_mutex map_planes_lock; const std::optional &mapdata_t::load_image_meta(const std::string_view &name) { @@ -2373,7 +2373,7 @@ from q3map */ void WriteBspBrushMap(const fs::path &name, const std::vector> &list) { - const auto lock = std::lock_guard(map_planes_lock); + std::shared_lock lock(map_planes_lock); logging::print("writing {}\n", name); std::ofstream f(name); diff --git a/qbsp/merge.cc b/qbsp/merge.cc index 8501139f..88d21c62 100644 --- a/qbsp/merge.cc +++ b/qbsp/merge.cc @@ -98,8 +98,7 @@ static std::unique_ptr TryMerge(const face_t *f1, const face_t *f2) // check slope of connected lines // if the slopes are colinear, the point can be removed - const auto lock = std::lock_guard(map_planes_lock); - const auto &plane = map.planes.at(f1->planenum); + auto plane = map.get_plane(f1->planenum); planenormal = plane.normal; if (f1->planeside) planenormal = -planenormal; diff --git a/qbsp/outside.cc b/qbsp/outside.cc index f4653a58..c32dbee7 100644 --- a/qbsp/outside.cc +++ b/qbsp/outside.cc @@ -59,8 +59,7 @@ static node_t *PointInLeaf(node_t *node, const qvec3d &point) return node; } - const auto lock = std::lock_guard(map_planes_lock); - const auto &plane = map.planes.at(node->planenum); + const auto plane = map.get_plane(node->planenum); vec_t dist = plane.distance_to(point); if (dist > 0) { diff --git a/qbsp/portals.cc b/qbsp/portals.cc index 1522592c..87649bd9 100644 --- a/qbsp/portals.cc +++ b/qbsp/portals.cc @@ -218,20 +218,18 @@ BaseWindingForNode Creates a winding from the given node plane, clipped by all parent nodes. ================ */ -#define BASE_WINDING_EPSILON 0.001 -#define SPLIT_WINDING_EPSILON 0.001 +constexpr vec_t BASE_WINDING_EPSILON = 0.001; +constexpr vec_t SPLIT_WINDING_EPSILON = 0.001; std::optional BaseWindingForNode(node_t *node) { - const auto lock = std::lock_guard(map_planes_lock); - auto plane = map.planes.at(node->planenum); + auto plane = map.get_plane(node->planenum); std::optional w = BaseWindingForPlane(plane); // clip by all the parents - for (node_t *np = node->parent; np && w; ) - { - plane = map.planes.at(np->planenum); + for (node_t *np = node->parent; np && w; ) { + plane = map.get_plane(np->planenum); const planeside_t keep = (np->children[0].get() == node) ? SIDE_FRONT : SIDE_BACK; @@ -256,8 +254,6 @@ portals in the node. */ void MakeNodePortal(tree_t *tree, node_t *node, portalstats_t &stats) { - const auto lock = std::lock_guard(map_planes_lock); - auto w = BaseWindingForNode(node); // clip the portal by all the other portals in the node @@ -267,12 +263,12 @@ void MakeNodePortal(tree_t *tree, node_t *node, portalstats_t &stats) if (p->nodes[0] == node) { side = 0; - plane = map.planes.at(p->planenum); + plane = map.get_plane(p->planenum); } else if (p->nodes[1] == node) { side = 1; - plane = -map.planes.at(p->planenum); + plane = -map.get_plane(p->planenum); } else Error("CutNodePortals_r: mislinked portal"); @@ -722,8 +718,6 @@ Finds a brush side to use for texturing the given portal */ static void FindPortalSide(portal_t *p) { - const auto lock = std::lock_guard(map_planes_lock); - // decide which content change is strongest // solid > lava > water, etc contentflags_t viscontents = @@ -734,11 +728,11 @@ static void FindPortalSide(portal_t *p) int planenum = p->onnode->planenum; side_t *bestside = nullptr; float bestdot = 0; + qbsp_plane_t p1 = map.get_plane(p->onnode->planenum); for (int j = 0; j < 2; j++) { node_t *n = p->nodes[j]; - auto p1 = map.planes.at(p->onnode->planenum); // iterate the n->original_brushes vector in reverse order, so later brushes // in the map file order are prioritized diff --git a/qbsp/prtfile.cc b/qbsp/prtfile.cc index c3d20f33..fa077ba4 100644 --- a/qbsp/prtfile.cc +++ b/qbsp/prtfile.cc @@ -49,7 +49,7 @@ static void WriteFloat(std::ofstream &portalFile, vec_t v) static void WritePortals_r(node_t *node, std::ofstream &portalFile, bool clusters) { - const auto lock = std::lock_guard(map_planes_lock); + std::shared_lock lock(map_planes_lock); const portal_t *p, *next; std::optional w; diff --git a/qbsp/qbsp.cc b/qbsp/qbsp.cc index 32785062..18d7d1b6 100644 --- a/qbsp/qbsp.cc +++ b/qbsp/qbsp.cc @@ -315,8 +315,6 @@ against axial bounding boxes */ static std::vector> AddBrushBevels(const bspbrush_t &b) { - const auto lock = std::lock_guard(map_planes_lock); - // add already-present planes std::vector> planes; @@ -324,7 +322,7 @@ static std::vector> AddBrushBevels(const bspb int32_t planenum = f.planenum; if (f.planeside) { - planenum = FindPlane(-map.planes.at(f.planenum), nullptr); + planenum = FindPlane(-map.get_plane(f.planenum), nullptr); } int32_t outputplanenum = ExportMapPlane(planenum); @@ -409,7 +407,7 @@ static std::vector> AddBrushBevels(const bspb // behind this plane, it is a proper edge bevel for (; it != b.sides.end(); it++) { auto &f = *it; - const auto &plane = map.planes.at(f.planenum); + const auto &plane = map.get_plane(f.planenum); qplane3d temp = f.planeside ? -plane : plane; // if this plane has allready been used, skip it @@ -765,7 +763,7 @@ hull sizes static void BSPX_Brushes_AddModel( struct bspxbrushes_s *ctx, int modelnum, std::vector> &brushes) { - const auto lock = std::lock_guard(map_planes_lock); + std::shared_lock lock(map_planes_lock); bspxbrushes_permodel permodel{1, modelnum}; diff --git a/qbsp/writebsp.cc b/qbsp/writebsp.cc index e5aba80c..9dd1f5e8 100644 --- a/qbsp/writebsp.cc +++ b/qbsp/writebsp.cc @@ -37,7 +37,7 @@ using nlohmann::json; */ size_t ExportMapPlane(size_t planenum) { - const auto lock = std::lock_guard(map_planes_lock); + std::shared_lock lock(map_planes_lock); qbsp_plane_t &plane = map.planes.at(planenum); if (plane.outputplanenum.has_value())