# HG changeset patch # User Chris Cannam # Date 1483624974 0 # Node ID a1ee3108d1d3ad8431ebae8cb410bf45dbffefb9 # Parent 7a19738b9762f2cbe5a4b39888f33e9afef462ff 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. diff -r 7a19738b9762 -r a1ee3108d1d3 layer/Colour3DPlotLayer.cpp --- 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; diff -r 7a19738b9762 -r a1ee3108d1d3 layer/Colour3DPlotRenderer.cpp --- 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(fullColumn.data() + minbin, fullColumn.data() + minbin + nbins); @@ -508,8 +510,6 @@ vector binforx(repaintWidth); vector 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 &binforx, const vector &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; } } diff -r 7a19738b9762 -r a1ee3108d1d3 layer/Colour3DPlotRenderer.h --- 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 peakCaches; // zero or more }; struct Parameters { @@ -280,7 +280,7 @@ int renderDrawBuffer(int w, int h, const std::vector &binforx, const std::vector &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 diff -r 7a19738b9762 -r a1ee3108d1d3 layer/SpectrogramLayer.cpp --- 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 @@ -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; diff -r 7a19738b9762 -r a1ee3108d1d3 layer/SpectrogramLayer.h --- 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 ViewMagMap; // key is view id