Skip to content

Commit 96cf4de

Browse files
committed
Process Cost Updates in batches to prevent locking the VertexBuffer over and over again
1 parent 696d75f commit 96cf4de

3 files changed

Lines changed: 178 additions & 53 deletions

File tree

rviz_mesh_tools_plugins/include/rviz_mesh_tools_plugins/MeshDisplay.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
#include <message_filters/cache.h>
8686

8787
#include <rviz_mesh_tools_plugins/RVizMessageFilter.hpp>
88+
#include <rviz_mesh_tools_plugins/ThreadSaveQueue.hpp>
8889

8990
#include <rviz_rendering/mesh_loader.hpp>
9091

@@ -156,6 +157,9 @@ class MeshDisplay : public rviz_common::Display
156157

157158
/**
158159
* @brief Periodically called from rviz
160+
*
161+
* @param wall_dt Time since last update in NANOSECONDS (rviz doc says seconds)
162+
* @param ros_dt Same as wall_dt but in ROS Time also NANOSECONDS
159163
*/
160164
void update(float wall_dt, float ros_dt) override;
161165

@@ -376,6 +380,11 @@ private Q_SLOTS:
376380
*/
377381
void vertexCostsUpdateCallback(const mesh_msgs::msg::MeshVertexCostsSparseStamped::ConstSharedPtr& update);
378382

383+
/**
384+
* @brief Apply all cached vertex cost updates
385+
*/
386+
void applyCachedCostUpdates();
387+
379388
/**
380389
* @brief Requests vertex colors from the specified service
381390
* @param uuid Mesh UUID
@@ -439,6 +448,11 @@ private Q_SLOTS:
439448
/// Cache for vertex costs updates
440449
std::shared_ptr<message_filters::Cache<mesh_msgs::msg::MeshVertexCostsSparseStamped>> m_costsUpdateMsgCache;
441450

451+
/// Cache for batching cost updates
452+
ThreadSafeQueue<mesh_msgs::msg::MeshVertexCostsSparseStamped::ConstSharedPtr> m_costsUpdateCache;
453+
float m_timeSinceLastUpdateApply;
454+
455+
442456
/// Counter for the received messages
443457
uint32_t m_messagesReceived;
444458
/// Uuid of the last received message
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#pragma once
2+
3+
#include <queue>
4+
#include <mutex>
5+
6+
namespace rviz_mesh_tools_plugins
7+
{
8+
9+
10+
template <typename T>
11+
class ThreadSafeQueue: protected std::queue<T>
12+
{
13+
public:
14+
T pop()
15+
{
16+
std::lock_guard lock(mutex_);
17+
T elem = this->std::queue<T>::front();
18+
this->std::queue<T>::pop();
19+
return elem;
20+
}
21+
22+
std::vector<T> popAll()
23+
{
24+
std::lock_guard lock(mutex_);
25+
std::vector<T> data;
26+
data.reserve(this->size());
27+
28+
while(!this->empty())
29+
{
30+
data.push_back(this->std::queue<T>::front());
31+
this->std::queue<T>::pop();
32+
}
33+
return data;
34+
}
35+
36+
void push(const T& elem)
37+
{
38+
std::lock_guard lock(mutex_);
39+
this->std::queue<T>::push(elem);
40+
}
41+
42+
private:
43+
std::mutex mutex_;
44+
};
45+
46+
} // namespace rviz_mesh_tools_plugins

rviz_mesh_tools_plugins/src/MeshDisplay.cpp

Lines changed: 118 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@
8282
#include "rclcpp/executor.hpp"
8383
#include "rmw/validate_full_topic_name.h"
8484

85+
#include <lvr2/attrmaps/AttrMaps.hpp>
86+
8587

8688
using namespace std::chrono_literals;
8789
using std::placeholders::_1;
@@ -102,6 +104,7 @@ namespace rviz_mesh_tools_plugins
102104
MeshDisplay::MeshDisplay()
103105
: rviz_common::Display()
104106
, m_ignoreMsgs(false)
107+
, m_timeSinceLastUpdateApply(0.0)
105108
, m_meshQos(rclcpp::QoS(1).transient_local())
106109
, m_vertexColorsQos(rclcpp::QoS(5))
107110
, m_vertexCostsQos(rclcpp::QoS(5))
@@ -310,9 +313,18 @@ void MeshDisplay::onInitialize()
310313

311314
void MeshDisplay::update(float wall_dt, float ros_dt)
312315
{
313-
(void) wall_dt;
314316
(void) ros_dt;
315317

318+
if (m_timeSinceLastUpdateApply >= 1.0e9)
319+
{
320+
this->applyCachedCostUpdates();
321+
m_timeSinceLastUpdateApply = 0.0;
322+
}
323+
else
324+
{
325+
m_timeSinceLastUpdateApply += wall_dt;
326+
}
327+
316328
this->transformMesh();
317329
}
318330

@@ -1107,74 +1119,127 @@ void MeshDisplay::vertexCostsUpdateCallback(
11071119
return;
11081120
}
11091121

1110-
// Vertex cost have to be applied to the cached layer
1111-
auto result = m_costCache.find(update->type);
1112-
// Unknown layer
1113-
if (result == m_costCache.end())
1114-
{
1115-
//TODO: We could create an empty layer
1116-
return;
1117-
}
1122+
this->m_costsUpdateCache.push(update);
1123+
}
1124+
1125+
void MeshDisplay::applyCachedCostUpdates()
1126+
{
1127+
1128+
const auto updates = m_costsUpdateCache.popAll();
1129+
1130+
RCLCPP_DEBUG(rclcpp::get_logger("rviz_mesh_tools_plugins"), "Processing %lu updates", updates.size());
11181131

1119-
// Update data in the cache
1120-
const auto& data = update->mesh_vertex_costs;
1121-
for (size_t i = 0; i < data.vertices.size(); i++)
1132+
// Space to combine updates per layer
1133+
std::map<std::string, lvr2::SparseVertexMap<float>> combined;
1134+
1135+
for (const auto& update: updates)
11221136
{
1123-
result->second[data.vertices[i]] = data.costs[i];
1137+
// Vertex cost have to be applied to the cached layer
1138+
auto result = combined.find(update->type);
1139+
// Unknown layer
1140+
if (result == combined.end())
1141+
{
1142+
result = combined.insert({update->type, lvr2::SparseVertexMap<float>()}).first;
1143+
}
1144+
1145+
// Update data in the cache
1146+
const auto& data = update->mesh_vertex_costs;
1147+
for (size_t i = 0; i < data.vertices.size(); i++)
1148+
{
1149+
result->second.insert(lvr2::VertexHandle(data.vertices[i]), data.costs[i]);
1150+
}
11241151
}
11251152

1126-
// Update the mesh if we updated the current visual
1127-
if (update->type == m_selectVertexCostMap->getStdString())
1153+
for (const auto& [type, update]: combined)
11281154
{
1129-
if (m_costUseCustomLimits->getBool())
1155+
// Vertex cost have to be applied to the cached layer
1156+
auto result = m_costCache.find(type);
1157+
// Unknown layer
1158+
if (result == m_costCache.end())
11301159
{
1131-
if (m_costCache.count(m_selectVertexCostMap->getStdString()) != 0)
1132-
{
1133-
std::shared_ptr<MeshVisual> visual = getLatestVisual();
1134-
if (visual)
1135-
{
1136-
visual->updateVertexCosts(
1137-
data.vertices,
1138-
data.costs,
1139-
m_costColorType->getOptionInt(),
1140-
m_costLowerLimit->getFloat(),
1141-
m_costUpperLimit->getFloat()
1142-
);
1143-
}
1144-
}
1160+
//TODO: We could create an empty layer
1161+
return;
11451162
}
1146-
else
1163+
1164+
// Update data in the cache
1165+
for (lvr2::VertexHandle v: update)
1166+
{
1167+
result->second[v.idx()] = update[v];
1168+
}
1169+
1170+
// Update the mesh if we updated the current visual
1171+
if (type == m_selectVertexCostMap->getStdString())
11471172
{
1148-
if (m_costCache.count(m_selectVertexCostMap->getStdString()) != 0)
1173+
if (m_costUseCustomLimits->getBool())
11491174
{
1150-
// The correct way is the get the limits from the whole layer
1151-
// TODO: Cache this with the layer itself
1152-
float maxCost = std::numeric_limits<float>::min();
1153-
float minCost = std::numeric_limits<float>::max();
1154-
for (float cost : result->second)
1175+
if (m_costCache.count(m_selectVertexCostMap->getStdString()) != 0)
11551176
{
1156-
if (std::isfinite(cost) && cost > maxCost)
1157-
maxCost = cost;
1158-
if (std::isfinite(cost) && cost < minCost)
1159-
minCost = cost;
1177+
std::shared_ptr<MeshVisual> visual = getLatestVisual();
1178+
if (visual)
1179+
{
1180+
std::vector<uint32_t> vertices;
1181+
std::vector<float> costs;
1182+
vertices.reserve(update.numValues());
1183+
costs.reserve(update.numValues());
1184+
for (lvr2::VertexHandle v: update)
1185+
{
1186+
vertices.push_back(v.idx());
1187+
costs.push_back(update[v]);
1188+
}
1189+
1190+
visual->updateVertexCosts(
1191+
vertices,
1192+
costs,
1193+
m_costColorType->getOptionInt(),
1194+
m_costLowerLimit->getFloat(),
1195+
m_costUpperLimit->getFloat()
1196+
);
1197+
}
11601198
}
1161-
1162-
1163-
std::shared_ptr<MeshVisual> visual = getLatestVisual();
1164-
if (visual)
1199+
}
1200+
else
1201+
{
1202+
if (m_costCache.count(m_selectVertexCostMap->getStdString()) != 0)
11651203
{
1166-
visual->updateVertexCosts(
1167-
data.vertices,
1168-
data.costs,
1169-
m_costColorType->getOptionInt(),
1170-
minCost,
1171-
maxCost
1172-
);
1204+
// The correct way is the get the limits from the whole layer
1205+
// TODO: Cache this with the layer itself
1206+
float maxCost = std::numeric_limits<float>::min();
1207+
float minCost = std::numeric_limits<float>::max();
1208+
for (float cost : result->second)
1209+
{
1210+
if (std::isfinite(cost) && cost > maxCost)
1211+
maxCost = cost;
1212+
if (std::isfinite(cost) && cost < minCost)
1213+
minCost = cost;
1214+
}
1215+
1216+
1217+
std::shared_ptr<MeshVisual> visual = getLatestVisual();
1218+
if (visual)
1219+
{
1220+
std::vector<uint32_t> vertices;
1221+
std::vector<float> costs;
1222+
vertices.reserve(update.numValues());
1223+
costs.reserve(update.numValues());
1224+
for (lvr2::VertexHandle v: update)
1225+
{
1226+
vertices.push_back(v.idx());
1227+
costs.push_back(update[v]);
1228+
}
1229+
visual->updateVertexCosts(
1230+
vertices,
1231+
costs,
1232+
m_costColorType->getOptionInt(),
1233+
minCost,
1234+
maxCost
1235+
);
1236+
}
11731237
}
11741238
}
1239+
updateMeshMaterial();
11751240
}
1176-
updateMeshMaterial();
11771241
}
1242+
11781243
}
11791244

11801245
void MeshDisplay::requestVertexColors(std::string uuid)

0 commit comments

Comments
 (0)