From 997619c9ed2bd1be738bf5af0570ce261b5b7940 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 15 Nov 2017 20:10:08 +0100 Subject: [PATCH] [Rendering] Only render in preview jobs layers that are fast enough This implements the improvements discussed in the mailing list thread https://lists.osgeo.org/pipermail/qgis-developer/2017-November/050524.html to avoid rendering layers in preview jobs that take too much time to render. --- python/core/qgis.sip | 2 ++ python/core/qgsmaplayer.sip | 1 + src/core/qgis.h | 12 ++++++++++++ src/core/qgsdataprovider.cpp | 4 ++++ src/core/qgsdataprovider.h | 15 +++++++++++++++ src/core/qgsmaplayer.h | 20 ++++++++++++++++++++ src/core/qgsmaprenderercustompainterjob.cpp | 4 ++++ src/core/qgsmaprendererjob.cpp | 7 +++++++ src/core/qgsmaprendererparalleljob.cpp | 4 ++++ src/gui/qgsmapcanvas.cpp | 3 +-- 10 files changed, 70 insertions(+), 2 deletions(-) diff --git a/python/core/qgis.sip b/python/core/qgis.sip index 42449b0a279..a97e19ec1aa 100644 --- a/python/core/qgis.sip +++ b/python/core/qgis.sip @@ -241,6 +241,8 @@ const double DEFAULT_LINE_WIDTH; const double DEFAULT_SEGMENT_EPSILON; + + typedef unsigned long long qgssize; diff --git a/python/core/qgsmaplayer.sip b/python/core/qgsmaplayer.sip index 21c119965ff..1bb66131458 100644 --- a/python/core/qgsmaplayer.sip +++ b/python/core/qgsmaplayer.sip @@ -916,6 +916,7 @@ Time stamp of data source in the moment when data/metadata were loaded by provid :rtype: bool %End + public slots: void setMinimumScale( double scale ); diff --git a/src/core/qgis.h b/src/core/qgis.h index 7b954c89c73..50b60ab2da3 100644 --- a/src/core/qgis.h +++ b/src/core/qgis.h @@ -440,6 +440,18 @@ const double DEFAULT_LINE_WIDTH = 0.26; //! Default snapping tolerance for segments const double DEFAULT_SEGMENT_EPSILON = 1e-8; +///@cond PRIVATE +#ifndef SIP_RUN + +//! Delay between the scheduling of 2 preview jobs +const int PREVIEW_JOB_DELAY_MS = 250; + +//! Maximum rendering time for a layer of a preview job +const int MAXIMUM_LAYER_PREVIEW_TIME_MS = 250; +#endif + +///@endcond + typedef QMap QgsStringMap SIP_SKIP; /** diff --git a/src/core/qgsdataprovider.cpp b/src/core/qgsdataprovider.cpp index f660cdcc4d5..6507a27a2fc 100644 --- a/src/core/qgsdataprovider.cpp +++ b/src/core/qgsdataprovider.cpp @@ -42,3 +42,7 @@ void QgsDataProvider::setListening( bool isListening ) Q_UNUSED( isListening ); } +bool QgsDataProvider::renderInPreview( double lastRenderingTimeMS, double maxRenderingTimeMS ) +{ + return lastRenderingTimeMS <= maxRenderingTimeMS; +} diff --git a/src/core/qgsdataprovider.h b/src/core/qgsdataprovider.h index 3ac1a0425d9..0367c51cde1 100644 --- a/src/core/qgsdataprovider.h +++ b/src/core/qgsdataprovider.h @@ -461,6 +461,21 @@ class CORE_EXPORT QgsDataProvider : public QObject */ virtual void setListening( bool isListening ); + /** + * Returns whether the layer must be rendered in preview jobs. + * + * The base implementation returns lastRenderingTimeMS <= maxRenderingTimeMS + * + * \param lastRenderingTimeMS last rendering time in milliseconds. + * \param maxRenderingTimeMS maximum allowed rendering time in milliseconds. + * \returns true if the layer must be rendered. + * + * \since QGIS 3.0 + * + * \note not available in Python bindings + */ + virtual bool renderInPreview( double lastRenderingTimeMS, double maxRenderingTimeMS ); // SIP_SKIP + signals: /** diff --git a/src/core/qgsmaplayer.h b/src/core/qgsmaplayer.h index 5c2aee4ec8f..82b7ede46bc 100644 --- a/src/core/qgsmaplayer.h +++ b/src/core/qgsmaplayer.h @@ -882,6 +882,25 @@ class CORE_EXPORT QgsMapLayer : public QObject */ bool isRefreshOnNotifyEnabled() const { return mIsRefreshOnNofifyEnabled; } +///@cond PRIVATE +#ifndef SIP_RUN + + /** + * Set last rendering time. + * + * \note not available in Python bindings + */ + void setLastRenderingTime( double time ) { mLastRenderingTime = time; } + + /** + * Get last rendering time. + * + * \note not available in Python bindings + */ + double lastRenderingTime() const { return mLastRenderingTime; } +#endif +///@endcond + public slots: /** @@ -1221,6 +1240,7 @@ class CORE_EXPORT QgsMapLayer : public QObject //! Renderer for 3D views QgsAbstract3DRenderer *m3DRenderer = nullptr; + double mLastRenderingTime = 0.0; }; Q_DECLARE_METATYPE( QgsMapLayer * ) diff --git a/src/core/qgsmaprenderercustompainterjob.cpp b/src/core/qgsmaprenderercustompainterjob.cpp index 05da2c8fe26..5415b0ccec8 100644 --- a/src/core/qgsmaprenderercustompainterjob.cpp +++ b/src/core/qgsmaprenderercustompainterjob.cpp @@ -265,6 +265,10 @@ void QgsMapRendererCustomPainterJob::doRender() job.renderer->render(); job.renderingTime = layerTime.elapsed(); + if ( job.layer ) + { + job.layer->setLastRenderingTime( job.renderingTime ); + } } if ( job.img ) diff --git a/src/core/qgsmaprendererjob.cpp b/src/core/qgsmaprendererjob.cpp index 4ddbb60817e..f70a4a2acb3 100644 --- a/src/core/qgsmaprendererjob.cpp +++ b/src/core/qgsmaprendererjob.cpp @@ -242,6 +242,13 @@ LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter *painter, QgsLabelingEn continue; } + if ( ( mSettings.flags() & QgsMapSettings::RenderPreviewJob ) && + !ml->dataProvider()->renderInPreview( ml->lastRenderingTime(), MAXIMUM_LAYER_PREVIEW_TIME_MS ) ) + { + QgsDebugMsgLevel( "Layer not rendered because it does not match the renderInPreview criterion", 3 ); + continue; + } + QgsRectangle r1 = mSettings.visibleExtent(), r2; QgsCoordinateTransform ct; diff --git a/src/core/qgsmaprendererparalleljob.cpp b/src/core/qgsmaprendererparalleljob.cpp index a4fb51bc834..9bf56a3abc4 100644 --- a/src/core/qgsmaprendererparalleljob.cpp +++ b/src/core/qgsmaprendererparalleljob.cpp @@ -270,6 +270,10 @@ void QgsMapRendererParallelJob::renderLayerStatic( LayerRenderJob &job ) QgsDebugMsg( "Caught unhandled unknown exception" ); } job.renderingTime = t.elapsed(); + if ( job.layer ) + { + job.layer->setLastRenderingTime( job.renderingTime ); + } QgsDebugMsgLevel( QString( "job %1 end [%2 ms] (layer %3)" ).arg( reinterpret_cast< quint64 >( &job ), 0, 16 ).arg( job.renderingTime ).arg( job.layer ? job.layer->id() : QString() ), 2 ); } diff --git a/src/gui/qgsmapcanvas.cpp b/src/gui/qgsmapcanvas.cpp index ba753d091f6..249c17f9980 100644 --- a/src/gui/qgsmapcanvas.cpp +++ b/src/gui/qgsmapcanvas.cpp @@ -66,7 +66,6 @@ email : sherman at mrcc.com #include "qgsmapthemecollection.h" #include - /** * \ingroup gui * Deprecated to be deleted, stuff from here should be moved elsewhere. @@ -2299,7 +2298,7 @@ void QgsMapCanvas::stopPreviewJobs() void QgsMapCanvas::schedulePreviewJob( int number ) { mPreviewTimer.setSingleShot( true ); - mPreviewTimer.setInterval( 250 ); + mPreviewTimer.setInterval( PREVIEW_JOB_DELAY_MS ); disconnect( mPreviewTimerConnection ); mPreviewTimerConnection = connect( &mPreviewTimer, &QTimer::timeout, this, [ = ]() {