Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions tomviz/TransformUtils.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,15 @@ static pipeline::DeferredLinkInfo appendTransformAtPortDeferred(
deferred.linksToRestore.append({ targetPort, sinkInput });
pip->removeLink(m.link);
pip->createLink(m.newOut, sinkInput);
// removeLink() reset this terminal sink/group's visualization. Re-show it
// (the VTK objects still hold the last data) so the downstream module
// stays on screen while the dialog is open. Nothing clears it again until
// the not-yet-run transform produces output and the sink swaps it in
// directly, so it also stays visible all through execution. Mirrors the
// restorePresentation() the dialog's cancel path performs.
if (auto* node = sinkInput->node()) {
node->restorePresentation();
}
}
return deferred;
}
Expand Down
29 changes: 27 additions & 2 deletions tomviz/pipeline/data/VolumeData.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@
#include <vtkSMTransferFunctionManager.h>
#include <vtkSMTransferFunctionProxy.h>

#include <QCoreApplication>
#include <QJsonArray>
#include <QMetaObject>
#include <QThread>

#include <array>

Expand Down Expand Up @@ -70,9 +73,31 @@ VolumeData::~VolumeData()
// unique, counter-based name. The proxy manager holds its own reference,
// so dropping our vtkSmartPointer isn't enough — without this unregister
// the proxy lives until app exit and every load/reset cycle adds another.
if (m_colorMap) {
if (!m_colorMap) {
return;
}

// UnRegisterProxy mutates the ParaView session proxy manager, which is
// not thread-safe and must run on the GUI thread. A VolumeData is a port
// payload whose lifetime is governed by shared_ptr refcounting, and the
// pipeline executor can drop the last ref on the worker thread (inflight
// eviction, clearHandle, the OnDisk deleter) — destroying us there.
// Touching the proxy manager off the GUI thread races
// pqServerManagerObserver / pqServerManagerModel and crashes in
// onProxyRegistered. Marshal the unregister to the GUI thread; the proxy
// manager's own reference keeps the captured proxy alive until the queued
// call runs.
vtkSmartPointer<vtkSMProxy> proxy = m_colorMap;
auto unregister = [proxy]() {
vtkNew<vtkSMParaViewPipelineController> controller;
controller->UnRegisterProxy(m_colorMap);
controller->UnRegisterProxy(proxy);
};

auto* app = QCoreApplication::instance();
if (!app || QThread::currentThread() == app->thread()) {
unregister();
} else {
QMetaObject::invokeMethod(app, unregister, Qt::QueuedConnection);
}
}

Expand Down
Loading