Minor optimizations (#1551)
* avoid using atomics when not needed * fast path for empty boxes and cache query * clarify previous question
This commit is contained in:
@@ -450,6 +450,8 @@ Vec<int> Winding03_(const Manifold::Impl& inP, const Manifold::Impl& inQ,
|
||||
Kernel02<expandP, forward> k02{a, b};
|
||||
auto recorderf = [&](int i, int b) {
|
||||
const auto [s02, z02] = k02(verts[i], b);
|
||||
// note that i is distinct on each thread, and verts contains unique
|
||||
// elements, so this does not require atomics
|
||||
if (std::isfinite(z02)) w03[verts[i]] += s02 * (forward ? 1 : -1);
|
||||
};
|
||||
auto recorder = MakeSimpleRecorder(recorderf);
|
||||
|
||||
+7
-16
@@ -64,17 +64,14 @@ struct DuplicateVerts {
|
||||
}
|
||||
};
|
||||
|
||||
template <bool atomic>
|
||||
struct CountVerts {
|
||||
VecView<Halfedge> halfedges;
|
||||
VecView<int> count;
|
||||
VecView<const int> inclusion;
|
||||
|
||||
void operator()(size_t i) {
|
||||
if (atomic)
|
||||
AtomicAdd(count[i / 3], std::abs(inclusion[halfedges[i].startVert]));
|
||||
else
|
||||
count[i / 3] += std::abs(inclusion[halfedges[i].startVert]);
|
||||
for (size_t j : {0, 1, 2})
|
||||
count[i] += std::abs(inclusion[halfedges[3 * i + j].startVert]);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -117,17 +114,11 @@ std::tuple<Vec<int>, Vec<int>> SizeOutput(
|
||||
auto sidesPerFaceP = sidesPerFacePQ.view(0, inP.NumTri());
|
||||
auto sidesPerFaceQ = sidesPerFacePQ.view(inP.NumTri(), inQ.NumTri());
|
||||
|
||||
if (inP.halfedge_.size() >= 1e5) {
|
||||
for_each(ExecutionPolicy::Par, countAt(0_uz), countAt(inP.halfedge_.size()),
|
||||
CountVerts<true>({inP.halfedge_, sidesPerFaceP, i03}));
|
||||
for_each(ExecutionPolicy::Par, countAt(0_uz), countAt(inQ.halfedge_.size()),
|
||||
CountVerts<true>({inQ.halfedge_, sidesPerFaceQ, i30}));
|
||||
} else {
|
||||
for_each(ExecutionPolicy::Seq, countAt(0_uz), countAt(inP.halfedge_.size()),
|
||||
CountVerts<false>({inP.halfedge_, sidesPerFaceP, i03}));
|
||||
for_each(ExecutionPolicy::Seq, countAt(0_uz), countAt(inQ.halfedge_.size()),
|
||||
CountVerts<false>({inQ.halfedge_, sidesPerFaceQ, i30}));
|
||||
}
|
||||
auto policy = autoPolicy(inP.halfedge_.size());
|
||||
for_each(policy, countAt(0_uz), countAt(inP.halfedge_.size() / 3),
|
||||
CountVerts({inP.halfedge_, sidesPerFaceP, i03}));
|
||||
for_each(policy, countAt(0_uz), countAt(inQ.halfedge_.size() / 3),
|
||||
CountVerts({inQ.halfedge_, sidesPerFaceQ, i30}));
|
||||
|
||||
if (i12.size() >= 1e5) {
|
||||
for_each_n(ExecutionPolicy::Par, countAt(0), i12.size(),
|
||||
|
||||
+12
-4
@@ -168,10 +168,11 @@ struct FindCollision {
|
||||
|
||||
using Local = typename Recorder::Local;
|
||||
|
||||
inline int RecordCollision(int node, const int queryIdx, Local& local) {
|
||||
inline int RecordCollision(std::invoke_result_t<F, const int> query, int node,
|
||||
const int queryIdx, Local& local) {
|
||||
auto box = nodeBBox_[node];
|
||||
if (hasTransform) box = box.Transform(transform);
|
||||
bool overlaps = box.DoesOverlap(f(queryIdx));
|
||||
bool overlaps = box.DoesOverlap(query);
|
||||
if (overlaps && IsLeaf(node)) {
|
||||
int leafIdx = Node2Leaf(node);
|
||||
if (!selfCollision || leafIdx != queryIdx) {
|
||||
@@ -182,6 +183,13 @@ struct FindCollision {
|
||||
}
|
||||
|
||||
void operator()(const int queryIdx) {
|
||||
auto query = f(queryIdx);
|
||||
|
||||
// early exit for empty boxes
|
||||
if constexpr (std::is_same_v<std::remove_cv_t<decltype(query)>, Box>) {
|
||||
if (query.min.x == std::numeric_limits<double>::infinity()) return;
|
||||
}
|
||||
|
||||
// stack cannot overflow because radix tree has max depth 30 (Morton code) +
|
||||
// 32 (index).
|
||||
int stack[64];
|
||||
@@ -194,8 +202,8 @@ struct FindCollision {
|
||||
int child1 = internalChildren_[internal].first;
|
||||
int child2 = internalChildren_[internal].second;
|
||||
|
||||
int traverse1 = RecordCollision(child1, queryIdx, local);
|
||||
int traverse2 = RecordCollision(child2, queryIdx, local);
|
||||
int traverse1 = RecordCollision(query, child1, queryIdx, local);
|
||||
int traverse2 = RecordCollision(query, child2, queryIdx, local);
|
||||
|
||||
if (!traverse1 && !traverse2) {
|
||||
if (top < 0) break; // done
|
||||
|
||||
Reference in New Issue
Block a user