use a reader/writer-esque lock (shared_mutex) instead of exclusive-only recursive lock to speed up plane stuff

This commit is contained in:
Jonathan 2022-07-24 19:05:28 -04:00
parent f8babef4e1
commit 4e3739c751
12 changed files with 70 additions and 88 deletions

View File

@ -33,6 +33,7 @@
#include <unordered_map>
#include <list>
#include <mutex>
#include <shared_mutex>
struct bspbrush_t;
@ -125,7 +126,7 @@ struct maptexdata_t
#include <common/imglib.hh>
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);
}

View File

@ -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<mutex> lck{bouncelights_lock};
bouncelight_t &l = bouncelights.emplace_back();
const int lastBounceLightIndex = static_cast<int>(bouncelights.size()) - 1;
bouncelightsByFacenum[Face_GetNum(bsp, face)].push_back(lastBounceLightIndex);
return l;
}
static void AddBounceLight(const qvec3d &pos, const std::unordered_map<int, qvec3d> &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<int, qvec
}
Q_assert(area > 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<int, qvec
} else if (light_options.visapprox.value() == visapprox_t::RAYS) {
l.bounds = EstimateVisibleBoundsAtPoint(pos);
}
unique_lock<mutex> lck{bouncelights_lock};
bouncelights.push_back(l);
const int lastBounceLightIndex = static_cast<int>(bouncelights.size()) - 1;
bouncelightsByFacenum[Face_GetNum(bsp, face)].push_back(lastBounceLightIndex);
}
const std::vector<bouncelight_t> &BounceLights()

View File

@ -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];

View File

@ -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<std::unique_ptr<bspbrush_t>> SplitBrush(std::unique_ptr<bspbrush_t> 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<std::unique_ptr<bspbrush_t>> result;

View File

@ -290,8 +290,7 @@ static void AddMarksurfaces_r(face_t *face, std::unique_ptr<face_t> 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) {

View File

@ -42,7 +42,7 @@
#include <common/qvec.hh>
mapdata_t map;
std::recursive_mutex map_planes_lock;
std::shared_mutex map_planes_lock;
const std::optional<img::texture_meta> &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<std::unique_ptr<bspbrush_t>> &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);

View File

@ -98,8 +98,7 @@ static std::unique_ptr<face_t> 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;

View File

@ -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) {

View File

@ -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<winding_t> 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<winding_t> 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

View File

@ -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<winding_t> w;

View File

@ -315,8 +315,6 @@ against axial bounding boxes
*/
static std::vector<std::tuple<size_t, const side_t *>> AddBrushBevels(const bspbrush_t &b)
{
const auto lock = std::lock_guard(map_planes_lock);
// add already-present planes
std::vector<std::tuple<size_t, const side_t *>> planes;
@ -324,7 +322,7 @@ static std::vector<std::tuple<size_t, const side_t *>> 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<std::tuple<size_t, const side_t *>> 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<std::unique_ptr<bspbrush_t>> &brushes)
{
const auto lock = std::lock_guard(map_planes_lock);
std::shared_lock lock(map_planes_lock);
bspxbrushes_permodel permodel{1, modelnum};

View File

@ -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())