comparison layer/Colour3DPlotRenderer.cpp @ 1090:c8c747783110 spectrogram-minor-refactor

Cut over to using the renderer (though it's very incomplete) and fix some cache problems and pointer lifetime misunderstandings
author Chris Cannam
date Tue, 05 Jul 2016 17:48:26 +0100
parents db976e9f385a
children 8a815776151c
comparison
equal deleted inserted replaced
1089:c8683d94442a 1090:c8c747783110
26 #include <vector> 26 #include <vector>
27 27
28 using namespace std; 28 using namespace std;
29 29
30 Colour3DPlotRenderer::RenderResult 30 Colour3DPlotRenderer::RenderResult
31 Colour3DPlotRenderer::render(QPainter &paint, QRect rect) 31 Colour3DPlotRenderer::render(LayerGeometryProvider *v, QPainter &paint, QRect rect)
32 { 32 {
33 return render(paint, rect, false); 33 return render(v, paint, rect, false);
34 } 34 }
35 35
36 Colour3DPlotRenderer::RenderResult 36 Colour3DPlotRenderer::RenderResult
37 Colour3DPlotRenderer::renderTimeConstrained(QPainter &paint, QRect rect) 37 Colour3DPlotRenderer::renderTimeConstrained(LayerGeometryProvider *v,
38 QPainter &paint, QRect rect)
38 { 39 {
39 return render(paint, rect, true); 40 return render(v, paint, rect, true);
40 } 41 }
41 42
42 Colour3DPlotRenderer::RenderResult 43 Colour3DPlotRenderer::RenderResult
43 Colour3DPlotRenderer::render(QPainter &paint, QRect rect, bool timeConstrained) 44 Colour3DPlotRenderer::render(LayerGeometryProvider *v,
45 QPainter &paint, QRect rect, bool timeConstrained)
44 { 46 {
45 LayerGeometryProvider *v = m_sources.geometryProvider;
46 if (!v) {
47 throw std::logic_error("no LayerGeometryProvider provided");
48 }
49
50 sv_frame_t startFrame = v->getStartFrame(); 47 sv_frame_t startFrame = v->getStartFrame();
51 48
52 int x0 = v->getXForViewX(rect.x()); 49 int x0 = v->getXForViewX(rect.x());
53 int x1 = v->getXForViewX(rect.x() + rect.width()); 50 int x1 = v->getXForViewX(rect.x() + rect.width());
54 if (x0 < 0) x0 = 0; 51 if (x0 < 0) x0 = 0;
55 if (x1 > v->getPaintWidth()) x1 = v->getPaintWidth(); 52 if (x1 > v->getPaintWidth()) x1 = v->getPaintWidth();
56 53
57 m_cache.resize(v->getPaintSize()); 54 m_cache.resize(v->getPaintSize());
58 m_cache.setZoomLevel(v->getZoomLevel()); 55 m_cache.setZoomLevel(v->getZoomLevel());
59 56
57 cerr << "cache start " << m_cache.getStartFrame()
58 << " view start " << startFrame
59 << " valid left " << m_cache.getValidLeft()
60 << " valid right " << m_cache.getValidRight()
61 << " x0 " << x0
62 << " x1 " << x1
63 << endl;
64
65
60 if (m_cache.isValid()) { // some part of the cache is valid 66 if (m_cache.isValid()) { // some part of the cache is valid
61 67
62 if (v->getXForFrame(m_cache.getStartFrame()) == 68 if (v->getXForFrame(m_cache.getStartFrame()) ==
63 v->getXForFrame(startFrame) && 69 v->getXForFrame(startFrame) &&
64 m_cache.getValidLeft() <= x0 && 70 m_cache.getValidLeft() <= x0 &&
65 m_cache.getValidRight() >= x1) { 71 m_cache.getValidRight() >= x1) {
66 72
73 cerr << "cache hit" << endl;
74
67 // cache is valid for the complete requested area 75 // cache is valid for the complete requested area
68 paint.drawImage(rect, m_cache.getImage(), rect); 76 paint.drawImage(rect, m_cache.getImage(), rect);
69 return { rect, {} }; 77 return { rect, {} };
70 78
71 } else { 79 } else {
80 cerr << "cache partial hit" << endl;
81
72 // cache doesn't begin at the right frame or doesn't 82 // cache doesn't begin at the right frame or doesn't
73 // contain the complete view, but might be scrollable or 83 // contain the complete view, but might be scrollable or
74 // partially usable 84 // partially usable
75 m_cache.scrollTo(startFrame); 85 m_cache.scrollTo(v, startFrame);
76 86
77 // if we are not time-constrained, then we want to paint 87 // if we are not time-constrained, then we want to paint
78 // the whole area in one go; we don't return a partial 88 // the whole area in one go; we don't return a partial
79 // paint. To avoid providing the more complex logic to 89 // paint. To avoid providing the more complex logic to
80 // handle painting discontiguous areas, if the only valid 90 // handle painting discontiguous areas, if the only valid
85 m_cache.getValidRight() < x1) { 95 m_cache.getValidRight() < x1) {
86 m_cache.invalidate(); 96 m_cache.invalidate();
87 } 97 }
88 } 98 }
89 } 99 }
100 } else {
101 // cache completely invalid
102 m_cache.setStartFrame(startFrame);
90 } 103 }
91 104
92 bool rightToLeft = false; 105 bool rightToLeft = false;
93 106
94 if (!m_cache.isValid() && timeConstrained) { 107 if (!m_cache.isValid() && timeConstrained) {
102 x0 = int(x1 * 0.3); 115 x0 = int(x1 * 0.3);
103 } 116 }
104 } 117 }
105 118
106 if (m_cache.isValid()) { 119 if (m_cache.isValid()) {
120 cerr << "cache somewhat valid" << endl;
121
107 // When rendering only a part of the cache, we need to make 122 // When rendering only a part of the cache, we need to make
108 // sure that the part we're rendering is adjacent to (or 123 // sure that the part we're rendering is adjacent to (or
109 // overlapping) a valid area of cache, if we have one. The 124 // overlapping) a valid area of cache, if we have one. The
110 // alternative is to ditch the valid area of cache and render 125 // alternative is to ditch the valid area of cache and render
111 // only the requested area, but that's risky because this can 126 // only the requested area, but that's risky because this can
123 // sub-regions of our target region in right-to-left order in 138 // sub-regions of our target region in right-to-left order in
124 // order to ensure contiguity 139 // order to ensure contiguity
125 rightToLeft = isLeftOfValidArea; 140 rightToLeft = isLeftOfValidArea;
126 } 141 }
127 142
128 renderToCache(x0, x1 - x0, rightToLeft, timeConstrained); 143 renderToCache(v, x0, x1 - x0, rightToLeft, timeConstrained);
129 144
130 QRect pr = rect & m_cache.getValidArea(); 145 QRect pr = rect & m_cache.getValidArea();
131 paint.drawImage(pr.x(), pr.y(), m_cache.getImage(), 146 paint.drawImage(pr.x(), pr.y(), m_cache.getImage(),
132 pr.x(), pr.y(), pr.width(), pr.height()); 147 pr.x(), pr.y(), pr.width(), pr.height());
133 148
159 174
160 //!!! should we own the Dense3DModelPeakCache here? or should it persist 175 //!!! should we own the Dense3DModelPeakCache here? or should it persist
161 } 176 }
162 177
163 void 178 void
164 Colour3DPlotRenderer::renderToCache(int x0, int repaintWidth, 179 Colour3DPlotRenderer::renderToCache(LayerGeometryProvider *v,
180 int x0, int repaintWidth,
165 bool rightToLeft, bool timeConstrained) 181 bool rightToLeft, bool timeConstrained)
166 { 182 {
167 // Draw to the draw buffer, and then scale-copy from there. 183 // Draw to the draw buffer, and then scale-copy from there.
168 184
169 DenseThreeDimensionalModel *model = m_sources.source; 185 DenseThreeDimensionalModel *model = m_sources.source;
170 if (!model || !model->isOK() || !model->isReady()) { 186 if (!model || !model->isOK() || !model->isReady()) {
171 throw std::logic_error("no source model provided, or model not ready"); 187 throw std::logic_error("no source model provided, or model not ready");
172 } 188 }
173
174 LayerGeometryProvider *v = m_sources.geometryProvider; // already checked
175 189
176 // The draw buffer contains a fragment at either our pixel 190 // The draw buffer contains a fragment at either our pixel
177 // resolution (if there is more than one time-bin per pixel) or 191 // resolution (if there is more than one time-bin per pixel) or
178 // time-bin resolution (if a time-bin spans more than one pixel). 192 // time-bin resolution (if a time-bin spans more than one pixel).
179 // We need to ensure that it starts and ends at points where a 193 // We need to ensure that it starts and ends at points where a
249 // case because it means we're well zoomed in 263 // case because it means we're well zoomed in
250 timeConstrained = false; 264 timeConstrained = false;
251 265
252 } else { 266 } else {
253 for (int x = 0; x < drawWidth; ++x) { 267 for (int x = 0; x < drawWidth; ++x) {
254 sv_frame_t f0 = v->getFrameForX(x); 268 sv_frame_t f0 = v->getFrameForX(x0 + x);
255 double s0 = double(f0 - model->getStartFrame()) / binResolution; 269 double s0 = double(f0 - model->getStartFrame()) / binResolution;
256 binforx[x] = int(s0 + 0.0001); 270 binforx[x] = int(s0 + 0.0001);
257 } 271 }
258 272
259 if (m_sources.peaks) { // peaks cache exists 273 if (m_sources.peaks) { // peaks cache exists
267 } 281 }
268 } 282 }
269 } 283 }
270 284
271 for (int y = 0; y < h; ++y) { 285 for (int y = 0; y < h; ++y) {
272 binfory[y] = 286 binfory[y] = m_sources.verticalBinLayer->getBinForY(v, h - y - 1);
273 m_sources.verticalBinLayer->getBinForY(m_sources.geometryProvider, y);
274 } 287 }
275 288
276 int attainedWidth = renderDrawBuffer(repaintWidth, 289 int attainedWidth = renderDrawBuffer(repaintWidth,
277 h, 290 h,
278 binforx, 291 binforx,
332 m_cache.drawImage(paintedLeft, attainedWidth, 345 m_cache.drawImage(paintedLeft, attainedWidth,
333 m_drawBuffer, 346 m_drawBuffer,
334 paintedLeft - x0, attainedWidth); 347 paintedLeft - x0, attainedWidth);
335 } 348 }
336 } 349 }
337
338 350
339 int 351 int
340 Colour3DPlotRenderer::renderDrawBuffer(int w, int h, 352 Colour3DPlotRenderer::renderDrawBuffer(int w, int h,
341 const vector<int> &binforx, 353 const vector<int> &binforx,
342 const vector<double> &binfory, 354 const vector<double> &binfory,
414 // get column -> scale -> record extents -> 426 // get column -> scale -> record extents ->
415 // normalise -> peak pick -> apply display gain -> 427 // normalise -> peak pick -> apply display gain ->
416 // distribute/interpolate 428 // distribute/interpolate
417 429
418 ColumnOp::Column fullColumn = sourceModel->getColumn(sx); 430 ColumnOp::Column fullColumn = sourceModel->getColumn(sx);
431
432 cerr << "x " << x << ", sx " << sx << ", col height " << fullColumn.size()
433 << ", minbin " << minbin << ", maxbin " << maxbin << endl;
434
419 ColumnOp::Column column = 435 ColumnOp::Column column =
420 vector<float>(fullColumn.data() + minbin, 436 vector<float>(fullColumn.data() + minbin,
421 fullColumn.data() + maxbin + 1); 437 fullColumn.data() + maxbin + 1);
422 438
423 //!!! fft scale if (m_colourScale != PhaseColourScale) { 439 //!!! fft scale if (m_colourScale != PhaseColourScale) {