Mercurial > hg > svgui
changeset 1212:a1ee3108d1d3 3.0-integration
Make the colour 3d plot renderer able to support more than one level of peak cache; introduce a second "peak" cache for the spectrogram layer that actually has a 1-1 column relationship with the underlying FFT model, and use it in addition to the existing peak cache if memory is plentiful. Makes spectrograms appear much faster in many common situations.
| author | Chris Cannam |
|---|---|
| date | Thu, 05 Jan 2017 14:02:54 +0000 |
| parents | 7a19738b9762 |
| children | 34df6ff25472 |
| files | layer/Colour3DPlotLayer.cpp layer/Colour3DPlotRenderer.cpp layer/Colour3DPlotRenderer.h layer/SpectrogramLayer.cpp layer/SpectrogramLayer.h |
| diffstat | 5 files changed, 95 insertions(+), 37 deletions(-) [+] |
line wrap: on
line diff
--- a/layer/Colour3DPlotLayer.cpp Thu Jan 05 11:10:57 2017 +0000 +++ b/layer/Colour3DPlotLayer.cpp Thu Jan 05 14:02:54 2017 +0000 @@ -1036,7 +1036,7 @@ sources.verticalBinLayer = this; sources.fft = 0; sources.source = m_model; - sources.peakCache = getPeakCache(); + sources.peakCaches.push_back(getPeakCache()); ColourScale::Parameters cparams; cparams.colourMap = m_colourMap;
--- a/layer/Colour3DPlotRenderer.cpp Thu Jan 05 11:10:57 2017 +0000 +++ b/layer/Colour3DPlotRenderer.cpp Thu Jan 05 14:02:54 2017 +0000 @@ -287,7 +287,7 @@ ColumnOp::Column Colour3DPlotRenderer::getColumn(int sx, int minbin, int nbins, - bool usePeakCache) const + int peakCacheIndex) const { Profiler profiler("Colour3DPlotRenderer::getColumn"); @@ -309,10 +309,12 @@ fullColumn.data() + minbin + nbins); } else { - + ColumnOp::Column fullColumn = - (usePeakCache ? m_sources.peakCache : m_sources.source)-> - getColumn(sx); + (peakCacheIndex >= 0 ? + m_sources.peakCaches[peakCacheIndex] : + m_sources.source) + ->getColumn(sx); column = vector<float>(fullColumn.data() + minbin, fullColumn.data() + minbin + nbins); @@ -508,8 +510,6 @@ vector<int> binforx(repaintWidth); vector<double> binfory(h); - bool usePeakCache = false; - int binsPerPeak = 1; int zoomLevel = v->getZoomLevel(); int binResolution = model->getResolution(); @@ -519,20 +519,29 @@ binforx[x] = int(s0 + 0.0001); } - if (m_sources.peakCache) { - binsPerPeak = m_sources.peakCache->getColumnsPerPeak(); - usePeakCache = (zoomLevel >= binResolution * binsPerPeak); - if (m_params.colourScale.getScale() == - ColourScaleType::Phase) { - usePeakCache = false; + int peakCacheIndex = -1; + int binsPerPeak = -1; + + if (m_params.colourScale.getScale() != ColourScaleType::Phase) { + for (int ix = 0; in_range_for(m_sources.peakCaches, ix); ++ix) { + int bpp = m_sources.peakCaches[ix]->getColumnsPerPeak(); + int equivZoom = binResolution * bpp; + if (zoomLevel >= equivZoom) { + // this peak cache would work, though it might not be best + if (bpp > binsPerPeak) { + // ok, it's better than the best one we've found so far + peakCacheIndex = ix; + binsPerPeak = bpp; + } + } } } SVDEBUG << "[PIX] zoomLevel = " << zoomLevel << ", binResolution " << binResolution << ", binsPerPeak " << binsPerPeak - << ", peak cache " << m_sources.peakCache - << ", usePeakCache = " << usePeakCache + << ", peakCacheIndex " << peakCacheIndex + << ", peakCaches " << m_sources.peakCaches.size() << endl; for (int y = 0; y < h; ++y) { @@ -555,7 +564,7 @@ h, binforx, binfory, - usePeakCache, + peakCacheIndex, rightToLeft, timeConstrained); } @@ -720,7 +729,7 @@ h, binforx, binfory, - false, + -1, false, false); @@ -730,9 +739,9 @@ int scaledRight = v->getXForFrame(rightBoundaryFrame); #ifdef DEBUG_COLOUR_PLOT_REPAINT - cerr << "scaling draw buffer from width " << m_drawBuffer.width() - << " to " << (scaledRight - scaledLeft) << " (nb drawBufferWidth = " - << drawBufferWidth << ")" << endl; + SVDEBUG << "scaling draw buffer from width " << m_drawBuffer.width() + << " to " << (scaledRight - scaledLeft) << " (nb drawBufferWidth = " + << drawBufferWidth << ")" << endl; #endif QImage scaled = scaleDrawBufferImage @@ -783,13 +792,13 @@ Colour3DPlotRenderer::renderDrawBuffer(int w, int h, const vector<int> &binforx, const vector<double> &binfory, - bool usePeakCache, + int peakCacheIndex, bool rightToLeft, bool timeConstrained) { // Callers must have checked that the appropriate subset of // Sources data members are set for the supplied flags (e.g. that - // peakCache model exists if usePeakCache) + // peakCache corresponding to peakCacheIndex exists) RenderTimer timer(timeConstrained ? RenderTimer::FastRender : @@ -799,13 +808,13 @@ int divisor = 1; const DenseThreeDimensionalModel *sourceModel = m_sources.source; - if (usePeakCache) { - divisor = m_sources.peakCache->getColumnsPerPeak(); - sourceModel = m_sources.peakCache; + if (peakCacheIndex >= 0) { + divisor = m_sources.peakCaches[peakCacheIndex]->getColumnsPerPeak(); + sourceModel = m_sources.peakCaches[peakCacheIndex]; } SVDEBUG << "renderDrawBuffer: w = " << w << ", h = " << h - << ", usePeakCache = " << usePeakCache << " (divisor = " + << ", peakCacheIndex = " << peakCacheIndex << " (divisor = " << divisor << "), rightToLeft = " << rightToLeft << ", timeConstrained = " << timeConstrained << endl; SVDEBUG << "renderDrawBuffer: normalization = " << int(m_params.normalization) @@ -887,7 +896,7 @@ // this does the first three: ColumnOp::Column column = getColumn(sx, minbin, nbins, - usePeakCache); + peakCacheIndex); magRange.sample(column); @@ -938,7 +947,7 @@ double fractionComplete = double(columnCount) / double(w); if (timer.outOfTime(fractionComplete)) { - cerr << "out of time" << endl; + SVDEBUG << "out of time" << endl; return columnCount; } }
--- a/layer/Colour3DPlotRenderer.h Thu Jan 05 11:10:57 2017 +0000 +++ b/layer/Colour3DPlotRenderer.h Thu Jan 05 14:02:54 2017 +0000 @@ -48,13 +48,13 @@ { public: struct Sources { - Sources() : verticalBinLayer(0), source(0), peakCache(0), fft(0) { } + Sources() : verticalBinLayer(0), source(0), fft(0) { } // These must all outlive this class const VerticalBinLayer *verticalBinLayer; // always const DenseThreeDimensionalModel *source; // always - const Dense3DModelPeakCache *peakCache; // optionally const FFTModel *fft; // optionally + std::vector<Dense3DModelPeakCache *> peakCaches; // zero or more }; struct Parameters { @@ -280,7 +280,7 @@ int renderDrawBuffer(int w, int h, const std::vector<int> &binforx, const std::vector<double> &binfory, - bool usePeakCache, + int peakCacheIndex, // -1 => don't use a peak cache bool rightToLeft, bool timeConstrained); @@ -306,7 +306,7 @@ const; ColumnOp::Column getColumn(int sx, int minbin, int nbins, - bool usePeakCache) const; + int peakCacheIndex) const; // -1 => don't use cache }; #endif
--- a/layer/SpectrogramLayer.cpp Thu Jan 05 11:10:57 2017 +0000 +++ b/layer/SpectrogramLayer.cpp Thu Jan 05 14:02:54 2017 +0000 @@ -25,6 +25,8 @@ #include "base/LogRange.h" #include "base/ColumnOp.h" #include "base/Strings.h" +#include "base/StorageAdviser.h" +#include "base/Exceptions.h" #include "widgets/CommandHistory.h" #include "data/model/Dense3DModelPeakCache.h" @@ -80,6 +82,7 @@ m_haveDetailedScale(false), m_exiting(false), m_fftModel(0), + m_wholeCache(0), m_peakCache(0), m_peakCacheDivisor(8) { @@ -132,6 +135,7 @@ delete m_fftModel; delete m_peakCache; + delete m_wholeCache; } pair<ColourScaleType, double> @@ -743,8 +747,6 @@ recreateFFTModel(); emit layerParametersChanged(); - -// fillCache(); } int @@ -1339,8 +1341,10 @@ emit sliceableModelReplaced(m_fftModel, 0); delete m_fftModel; delete m_peakCache; + delete m_wholeCache; m_fftModel = 0; m_peakCache = 0; + m_wholeCache = 0; return; } @@ -1355,6 +1359,9 @@ delete m_peakCache; m_peakCache = 0; + + delete m_wholeCache; + m_wholeCache = 0; if (!m_fftModel->isOK()) { QMessageBox::critical @@ -1365,14 +1372,53 @@ m_fftModel = 0; return; } - - m_peakCache = new Dense3DModelPeakCache(m_fftModel, m_peakCacheDivisor); + + if (canStoreWholeCache()) { // i.e. if enough memory + m_wholeCache = new Dense3DModelPeakCache(m_fftModel, 1); + m_peakCache = new Dense3DModelPeakCache(m_wholeCache, m_peakCacheDivisor); + } else { + m_peakCache = new Dense3DModelPeakCache(m_fftModel, m_peakCacheDivisor); + } emit sliceableModelReplaced(oldModel, m_fftModel); delete oldModel; } +bool +SpectrogramLayer::canStoreWholeCache() const +{ + if (!m_fftModel) { + return false; // or true, doesn't really matter + } + + size_t sz = + size_t(m_fftModel->getWidth()) * + size_t(m_fftModel->getHeight()) * + sizeof(float); + + try { + SVDEBUG << "Requesting advice from StorageAdviser on whether to create whole-model cache" << endl; + StorageAdviser::Recommendation recommendation = + StorageAdviser::recommend + (StorageAdviser::Criteria(StorageAdviser::SpeedCritical | + StorageAdviser::PrecisionCritical | + StorageAdviser::FrequentLookupLikely), + sz / 1024, sz / 1024); + if ((recommendation & StorageAdviser::UseDisc) || + (recommendation & StorageAdviser::ConserveSpace)) { + SVDEBUG << "Seems inadvisable to create whole-model cache" << endl; + return false; + } else { + SVDEBUG << "Seems fine to create whole-model cache" << endl; + return true; + } + } catch (const InsufficientDiscSpace &) { + SVDEBUG << "Seems like a terrible idea to create whole-model cache" << endl; + return false; + } +} + const Model * SpectrogramLayer::getSliceableModel() const { @@ -1405,7 +1451,8 @@ sources.verticalBinLayer = this; sources.fft = getFFTModel(); sources.source = sources.fft; - sources.peakCache = getPeakCache(); + if (m_peakCache) sources.peakCaches.push_back(m_peakCache); + if (m_wholeCache) sources.peakCaches.push_back(m_wholeCache); ColourScale::Parameters cparams; cparams.colourMap = m_colourMap;
--- a/layer/SpectrogramLayer.h Thu Jan 05 11:10:57 2017 +0000 +++ b/layer/SpectrogramLayer.h Thu Jan 05 14:02:54 2017 +0000 @@ -304,9 +304,11 @@ FFTModel *m_fftModel; FFTModel *getFFTModel() const { return m_fftModel; } + Dense3DModelPeakCache *m_wholeCache; Dense3DModelPeakCache *m_peakCache; Dense3DModelPeakCache *getPeakCache() const { return m_peakCache; } const int m_peakCacheDivisor; + bool canStoreWholeCache() const; void recreateFFTModel(); typedef std::map<int, MagnitudeRange> ViewMagMap; // key is view id
