diff --git a/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp b/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp index aee1b25a9575be96c945a742b2a453965e45fe80..09132638b89c66675a0723bf8b245d808442a50b 100644 --- a/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp +++ b/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp @@ -31,6 +31,22 @@ using namespace armarx; +struct armarx::ArVizWidgetBatchCallback : IceUtil::Shared +{ + class ArVizWidgetController* this_; + + void onSuccess(armarx::viz::RecordingBatch const& batch) + { + this_->onGetBatchAsync(batch); + } + + void onFailure(Ice::Exception const& ex) + { + ARMARX_WARNING << "Failed to get batch async.\nReason:" + << ex; + } +}; + ArVizWidgetController::ArVizWidgetController() { widget.setupUi(getWidget()); @@ -80,6 +96,13 @@ void ArVizWidgetController::onInitComponent() usingProxy(storageName); } ARMARX_IMPORTANT << "OnInit: " << storageName; + + callbackData = new ArVizWidgetBatchCallback(); + callbackData->this_ = this; + callback = viz::newCallback_StorageInterface_getRecordingBatch( + callbackData, + &ArVizWidgetBatchCallback::onSuccess, + &ArVizWidgetBatchCallback::onFailure); } void armarx::ArVizWidgetController::onExitComponent() @@ -479,18 +502,6 @@ void ArVizWidgetController::selectRecording(const viz::Recording& recording) currentRecording = recording; currentRecordingSelected = true; enableWidgetAccordingToMode(); - - widget.replayRevisionSpinBox->blockSignals(true); - widget.replayRevisionSpinBox->setMinimum(recording.firstRevision); - widget.replayRevisionSpinBox->setMaximum(recording.lastRevision); - widget.replayRevisionSpinBox->setValue(recording.firstRevision); - widget.replayRevisionSpinBox->blockSignals(false); - - widget.replayRevisionSlider->blockSignals(true); - widget.replayRevisionSlider->setMinimum(recording.firstRevision); - widget.replayRevisionSlider->setMaximum(recording.lastRevision); - widget.replayRevisionSlider->setValue(recording.firstRevision); - widget.replayRevisionSlider->blockSignals(false); } void ArVizWidgetController::onReplayStart(bool) @@ -504,6 +515,18 @@ void ArVizWidgetController::onReplayStart(bool) changeMode(ArVizWidgetMode::Replaying); + widget.replayRevisionSpinBox->blockSignals(true); + widget.replayRevisionSpinBox->setMinimum(currentRecording.firstRevision); + widget.replayRevisionSpinBox->setMaximum(currentRecording.lastRevision); + widget.replayRevisionSpinBox->setValue(currentRecording.firstRevision); + widget.replayRevisionSpinBox->blockSignals(false); + + widget.replayRevisionSlider->blockSignals(true); + widget.replayRevisionSlider->setMinimum(currentRecording.firstRevision); + widget.replayRevisionSlider->setMaximum(currentRecording.lastRevision); + widget.replayRevisionSlider->setValue(currentRecording.firstRevision); + widget.replayRevisionSlider->blockSignals(false); + onReplaySliderChanged(widget.replayRevisionSlider->value()); } @@ -541,10 +564,10 @@ long ArVizWidgetController::replayToRevision(long revision) viz::RecordingBatch const& batch = getRecordingBatch(matchingBatchHeader->index); - ARMARX_INFO << "Replaying to revision : " << revision - << "\nGot batch: " << batch.header.firstRevision << " - " << batch.header.lastRevision - << "\nUpdates: " << batch.updates.size() - << "\nInitial state: " << batch.initialState.size(); + ARMARX_VERBOSE << "Replaying to revision : " << revision + << "\nGot batch: " << batch.header.firstRevision << " - " << batch.header.lastRevision + << "\nUpdates: " << batch.updates.size() + << "\nInitial state: " << batch.initialState.size(); auto revisionLess = [](viz::TimestampedLayerUpdate const & lhs, viz::TimestampedLayerUpdate const & rhs) @@ -631,17 +654,49 @@ void ArVizWidgetController::enableWidgetAccordingToMode() } } +void ArVizWidgetController::onGetBatchAsync(const viz::RecordingBatch& batch) +{ + // We received a batch asynchronously ==> Update the cache + ARMARX_INFO << "Received async batch: " << batch.header.index; + std::unique_lock<std::mutex> lock(recordingBatchCacheMutex); + + auto& entry = recordingBatchCache[batch.header.index]; + entry.data = batch; + entry.lastUsed = IceUtil::Time::now(); +} + viz::RecordingBatch const& ArVizWidgetController::getRecordingBatch(long index) { IceUtil::Time now = IceUtil::Time::now(); + + std::unique_lock<std::mutex> lock(recordingBatchCacheMutex); + auto iter = recordingBatchCache.find(index); if (iter != recordingBatchCache.end()) { + // Start prefetching neighbouring batches + bool asyncPrefetchIsRunning = callbackResult && !callbackResult->isCompleted(); + if (!asyncPrefetchIsRunning) + { + if (index + 1 < (long)currentRecording.batchHeaders.size() + && recordingBatchCache.count(index + 1) == 0) + { + callbackResult = storage->begin_getRecordingBatch(currentRecording.id, index + 1, callback); + } + else if (index > 0 && recordingBatchCache.count(index - 1) == 0) + { + callbackResult = storage->begin_getRecordingBatch(currentRecording.id, index - 1, callback); + } + + } + auto& entry = iter->second; entry.lastUsed = now; return entry.data; } + ARMARX_INFO << "Batch #" << index << " is not in the cache. Getting synchronously, blocking GUI..."; + // Entry is not in the cache, we have to get it from ArVizStorage auto& newEntry = recordingBatchCache[index]; newEntry.lastUsed = now; diff --git a/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.h b/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.h index 3c57686177dc4e16297b9e35267cc9d3519d4602..cf6f27efd4c96d3c097c72704ac0dd8e744e3dd9 100644 --- a/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.h +++ b/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.h @@ -45,6 +45,9 @@ namespace armarx Replaying, }; + struct ArVizWidgetBatchCallback; + + /** \page ArmarXGui-GuiPlugins-ArViz ArViz \brief The ArViz allows visualizing ... @@ -106,6 +109,8 @@ namespace armarx void onConnectComponent() override; void onDisconnectComponent() override; + void onGetBatchAsync(viz::RecordingBatch const& batch); + public slots: /* QT slot declarations */ @@ -179,10 +184,15 @@ namespace armarx viz::RecordingBatch const& getRecordingBatch(long index); - std::size_t recordingBatchCacheMaxSize = 3; + std::size_t recordingBatchCacheMaxSize = 5; + std::mutex recordingBatchCacheMutex; std::map<long, TimestampedRecordingBatch> recordingBatchCache; ArVizWidgetMode mode = ArVizWidgetMode::NotConnected; + + IceUtil::Handle<ArVizWidgetBatchCallback> callbackData; + armarx::viz::Callback_StorageInterface_getRecordingBatchPtr callback; + Ice::AsyncResultPtr callbackResult; }; }