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
32 changes: 25 additions & 7 deletions tomviz/HistogramWidget.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#include <QMessageBox>
#include <QSettings>
#include <QSignalBlocker>
#include <QTimer>
#include <QToolButton>
#include <QVBoxLayout>

Expand Down Expand Up @@ -315,16 +316,33 @@ void HistogramWidget::onColorFunctionChanged()
// Avoid infinite recursion
return;
}
m_updatingColorFunction = true;

updateLUTProxy();
if (m_LUT) {
m_LUT->Build();
renderViews();
emit colorMapUpdated();
// This slot is wired to the color transfer function's ModifiedEvent, which
// can fire reentrantly from deep inside another mutation of the *same*
// function -- e.g. VolumeData::rescaleColorMap() ->
// vtkSMProxy::UpdateVTKObjects() -> vtkColorTransferFunction::UpdateRange().
// Rebuilding the LUT here (Build() -> SetAnnotations()) while that outer
// mutation is still on the stack corrupts the function's internal arrays and
// crashes in ~vtkVariant. Defer the rebuild to the next event-loop turn so
// it runs after the mutation unwinds; the pending flag coalesces the
// multi-Hz churn from live operator updates.
if (m_colorFunctionUpdatePending) {
return;
}
m_colorFunctionUpdatePending = true;
QTimer::singleShot(0, this, [this]() {
m_colorFunctionUpdatePending = false;
m_updatingColorFunction = true;

updateLUTProxy();
if (m_LUT) {
m_LUT->Build();
renderViews();
emit colorMapUpdated();
}

m_updatingColorFunction = false;
m_updatingColorFunction = false;
});
}

void HistogramWidget::onScalarOpacityFunctionChanged()
Expand Down
4 changes: 4 additions & 0 deletions tomviz/HistogramWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ public slots:
// To prevent infinite recursion...
bool m_updatingColorFunction = false;

// Coalesces the deferred color-function rebuild (see
// onColorFunctionChanged) so reentrant ModifiedEvents don't pile up.
bool m_colorFunctionUpdatePending = false;

static const int m_defaultAutoContrastThreshold = 5000;
int m_currentAutoContrastThreshold = 5000;
};
Expand Down
Loading