From 32d10334751982eaefe414fe432afbde4bdcd591 Mon Sep 17 00:00:00 2001 From: lbgos <285507185+lbgos@users.noreply.github.com> Date: Tue, 13 Oct 2026 01:48:21 +0300 Subject: [PATCH] Halve LSH lookup memory and align public key-loader rows --- .../drivers/rift_s/rift_s_world_matcher.hpp | 25 +++++++++++-------- tests/tests_rift_s_world_matcher.cpp | 5 +++- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/xrt/drivers/rift_s/rift_s_world_matcher.hpp b/src/xrt/drivers/rift_s/rift_s_world_matcher.hpp index 105cf3d4a..88b746e3b 100644 --- a/src/xrt/drivers/rift_s/rift_s_world_matcher.hpp +++ b/src/xrt/drivers/rift_s/rift_s_world_matcher.hpp @@ -40,7 +40,7 @@ struct RiftSOrbHamming : cvflann::HammingLUT class RiftSOrbIndex { public: - explicit RiftSOrbIndex(const cv::Mat &descriptors) : train(descriptors) + explicit RiftSOrbIndex(const cv::Mat &descriptors) : train(descriptors.clone()) { cvflann::Matrix dataset(train.data, train.rows, train.cols, train.step); masks.push_back(0); @@ -54,7 +54,7 @@ public: table.hash.add(dataset); table.buckets.resize(size_t(1) << 20); table.present.resize(size_t(1) << 14); - table.candidates.reserve(train.rows); + table.candidates.reserve(size_t(train.rows) * 2); for (int row = 0; row < train.rows; ++row) { auto key = table.hash.getKey(train.ptr(row)); auto bit = uint64_t(1) << (key & 63); @@ -62,7 +62,8 @@ public: continue; table.present[key >> 6] |= bit; const auto &bucket = *table.hash.getBucketFromKey(key); - table.buckets[key] = {uint32_t(table.candidates.size()), uint32_t(bucket.size())}; + table.buckets[key] = uint32_t(table.candidates.size()); + table.candidates.push_back(uint32_t(bucket.size())); table.candidates.insert(table.candidates.end(), bucket.begin(), bucket.end()); } } @@ -86,8 +87,9 @@ public: auto probe = key ^ mask; if (!(table.present[probe >> 6] & (uint64_t(1) << (probe & 63)))) continue; - const auto range = table.buckets[probe]; - for (uint32_t at = range.start; at < range.start + range.count; ++at) { + auto start = table.buckets[probe]; + auto end = start + 1 + table.candidates[start]; + for (uint32_t at = start + 1; at < end; ++at) { auto candidate = table.candidates[at]; result.addPoint( distance(query, train.ptr(candidate), 32), @@ -109,11 +111,7 @@ private: struct Table { cvflann::lsh::LshTable hash; - struct Range - { - uint32_t start = 0, count = 0; - }; - std::vector buckets; + std::vector buckets; std::vector present; std::vector candidates; }; @@ -150,7 +148,12 @@ public: { #if (defined(__x86_64__) || defined(__i386__)) && defined(__GNUC__) if (fast) { - fast->knnMatch(descriptors, nearest, count); + // OpenCV hashes rows through size_t loads. A packed aligned copy + // keeps sliced or unaligned callers out of that loader. + cv::Mat queries = descriptors; + if (!queries.isContinuous() || reinterpret_cast(queries.data) % alignof(size_t)) + queries = descriptors.clone(); + fast->knnMatch(queries, nearest, count); return; } #endif diff --git a/tests/tests_rift_s_world_matcher.cpp b/tests/tests_rift_s_world_matcher.cpp index bf256012f..3d8acca04 100644 --- a/tests/tests_rift_s_world_matcher.cpp +++ b/tests/tests_rift_s_world_matcher.cpp @@ -28,7 +28,10 @@ TEST_CASE("Native room descriptor distance preserves BF and LSH neighbor identit reference->add(std::vector{train}); reference->train(); cvflann::seed_random(seed); - RiftSWorldMatcher native(train); + cv::Mat padded_train(train.rows, 35, CV_8U); + cv::Mat sliced_train = padded_train.colRange(1, 33); + train.copyTo(sliced_train); + RiftSWorldMatcher native(sliced_train); // Non-contiguous rows must retain query indices and neighbor order. cv::Mat padded(queries.rows, 35, CV_8U); cv::Mat sliced = padded.colRange(1, 33);