diff view/View.cpp @ 1490:c83504eb2649

Attempt a mechanism for the View to time-align a layer on display using an aligning version of the ViewProxy
author Chris Cannam
date Fri, 02 Aug 2019 16:44:32 +0100
parents c3cc36c014b8
children a2fbcfeb2572
line wrap: on
line diff
--- a/view/View.cpp	Fri Aug 02 16:42:32 2019 +0100
+++ b/view/View.cpp	Fri Aug 02 16:44:32 2019 +0100
@@ -71,6 +71,7 @@
     m_selectionCached(false),
     m_deleting(false),
     m_haveSelectedLayer(false),
+    m_useAligningProxy(false),
     m_manager(nullptr),
     m_propertyContainer(new ViewPropertyContainer(this))
 {
@@ -1349,15 +1350,22 @@
 ModelId
 View::getAligningModel() const
 {
+    ModelId aligning, reference;
+    getAligningAndReferenceModels(aligning, reference);
+    return aligning;
+}
+
+void
+View::getAligningAndReferenceModels(ModelId &aligning,
+                                    ModelId &reference) const
+{
     if (!m_manager ||
         !m_manager->getAlignMode() ||
         m_manager->getPlaybackModel().isNone()) {
-        return {};
+        return;
     }
 
     ModelId anyModel;
-    ModelId alignedModel;
-    ModelId goodModel;
 
     for (auto layer: m_layerStack) {
 
@@ -1371,18 +1379,27 @@
         anyModel = thisId;
 
         if (!model->getAlignmentReference().isNone()) {
-            alignedModel = thisId;
+
             if (layer->isLayerOpaque() ||
                 std::dynamic_pointer_cast
                 <RangeSummarisableTimeValueModel>(model)) {
-                goodModel = thisId;
+
+                aligning = thisId;
+                reference = model->getAlignmentReference();
+                return;
+
+            } else if (aligning.isNone()) {
+                
+                aligning = thisId;
+                reference = model->getAlignmentReference();
             }
         }
     }
 
-    if (!goodModel.isNone()) return goodModel;
-    else if (!alignedModel.isNone()) return alignedModel;
-    else return anyModel;
+    if (aligning.isNone()) {
+        aligning = anyModel;
+        reference = {};
+    }
 }
 
 sv_frame_t
@@ -2132,11 +2149,32 @@
         throw std::logic_error("ERROR: shouldRepaintCache is true, but shouldUseCache is false: this can't lead to the correct result");
     }
 
+    // Create the ViewProxy for geometry provision, using the
+    // device-pixel ratio for pixel-doubled hi-dpi rendering as
+    // appropriate.
+
+    ViewProxy proxy(this, dpratio);
+
+    // Some layers may need an aligning proxy. If a layer's model has
+    // a source model that is the reference model for the aligning
+    // model, and the layer is tagged as to be aligned, then we use an
+    // aligning proxy.
+    
+    ModelId alignmentModelId;
+    ModelId alignmentReferenceId;
+    auto aligningModel = ModelById::get(getAligningModel());
+    if (aligningModel) {
+        alignmentModelId = aligningModel->getAlignment();
+        alignmentReferenceId = aligningModel->getAlignmentReference();
+        SVCERR << "alignmentModelId = " << alignmentModelId << " (reference =  " << alignmentReferenceId << ")" << endl;
+    } else {
+        SVCERR << "no aligningModel" << endl;
+    }
+    ViewProxy aligningProxy(this, dpratio, alignmentModelId);
+    
     // Scrollable (cacheable) items first. If we are repainting the
     // cache, then we paint these to the cache; otherwise straight to
     // the buffer.
-
-    ViewProxy proxy(this, dpratio);
     QRect areaToPaint;
     QPainter paint;
 
@@ -2164,11 +2202,22 @@
         paint.setRenderHint(QPainter::Antialiasing, false);
         paint.save();
 
+        Layer *layer = *i;
+        
+        bool useAligningProxy = false;
+        if (m_useAligningProxy) {
+            if (layer->getModel() == alignmentReferenceId ||
+                layer->getSourceModel() == alignmentReferenceId) {
+                useAligningProxy = true;
+            }
+        }
+
 #ifdef DEBUG_VIEW_WIDGET_PAINT
-        cerr << "Painting scrollable layer " << *i << " using proxy with shouldRepaintCache = " << shouldRepaintCache << ", dpratio = " << dpratio << ", areaToPaint = " << areaToPaint.x() << "," << areaToPaint.y() << " " << areaToPaint.width() << "x" << areaToPaint.height() << endl;
+        cerr << "Painting scrollable layer " << layer << " (model " << layer->getModel() << ", source model " << layer->getSourceModel() << ") with shouldRepaintCache = " << shouldRepaintCache << ", useAligningProxy = " << useAligningProxy << ", dpratio = " << dpratio << ", areaToPaint = " << areaToPaint.x() << "," << areaToPaint.y() << " " << areaToPaint.width() << "x" << areaToPaint.height() << endl;
 #endif
-
-        (*i)->paint(&proxy, paint, areaToPaint);
+        
+        layer->paint(useAligningProxy ? &aligningProxy : &proxy,
+                     paint, areaToPaint);
 
         paint.restore();
     }
@@ -2204,12 +2253,23 @@
         
     for (LayerList::iterator i = nonScrollables.begin(); 
          i != nonScrollables.end(); ++i) {
-
-//        Profiler profiler2("View::paintEvent non-cacheable");
+        
+        Layer *layer = *i;
+        
+        bool useAligningProxy = false;
+        if (m_useAligningProxy) {
+            if (layer->getModel() == alignmentReferenceId ||
+                layer->getSourceModel() == alignmentReferenceId) {
+                useAligningProxy = true;
+            }
+        }
+
 #ifdef DEBUG_VIEW_WIDGET_PAINT
-        cerr << "Painting non-scrollable layer " << *i << " without proxy with shouldRepaintCache = " << shouldRepaintCache << ", dpratio = " << dpratio << ", requestedPaintArea = " << requestedPaintArea.x() << "," << requestedPaintArea.y() << " " << requestedPaintArea.width() << "x" << requestedPaintArea.height() << endl;
+        cerr << "Painting non-scrollable layer " << layer << " (model " << layer->getModel() << ", source model " << layer->getSourceModel() << ") with shouldRepaintCache = " << shouldRepaintCache << ", useAligningProxy = " << useAligningProxy << ", dpratio = " << dpratio << ", requestedPaintArea = " << requestedPaintArea.x() << "," << requestedPaintArea.y() << " " << requestedPaintArea.width() << "x" << requestedPaintArea.height() << endl;
 #endif
-        (*i)->paint(&proxy, paint, requestedPaintArea);
+
+        layer->paint(useAligningProxy ? &aligningProxy : &proxy,
+                     paint, requestedPaintArea);
     }
         
     paint.end();