Skip to content
Permalink
Browse files

Merge pull request #5789 from nyalldawson/render_jobs

[Rendering] Only render in preview jobs layers that are fast enough
  • Loading branch information
nyalldawson committed Dec 5, 2017
2 parents b26c14e + 38cca6c commit b0a36e9bb147ecf0b61b73b9d48348c6fe78aad5
@@ -241,6 +241,8 @@ const double DEFAULT_LINE_WIDTH;
const double DEFAULT_SEGMENT_EPSILON;




typedef unsigned long long qgssize;


@@ -380,6 +380,7 @@ Current time stamp of data source
.. versionadded:: 3.0
%End


signals:

void fullExtentCalculated();
@@ -137,10 +137,12 @@ List of errors that happened during the rendering job - available when the rende

int renderingTime() const;
%Docstring
Find out how long it took to finish the job (in milliseconds)
Returns the total time it took to finish the job (in milliseconds).
.. seealso:: perLayerRenderingTime()
:rtype: int
%End


const QgsMapSettings &mapSettings() const;
%Docstring
Return map settings with which this job was started.
@@ -179,6 +181,7 @@ emitted when asynchronous rendering is finished (or canceled).




};


@@ -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<QString, QString> QgsStringMap SIP_SKIP;

/**
@@ -42,3 +42,7 @@ void QgsDataProvider::setListening( bool isListening )
Q_UNUSED( isListening );
}

bool QgsDataProvider::renderInPreview( const PreviewContext &context )
{
return context.lastRenderingTimeMs <= context.maxRenderingTimeMs;
}
@@ -461,6 +461,37 @@ class CORE_EXPORT QgsDataProvider : public QObject
*/
virtual void setListening( bool isListening );

#ifndef SIP_RUN

/**
* Stores settings related to the context in which a preview job runs.
* \note Not available in Python bindings
* \since QGIS 3.0
*/
struct PreviewContext
{
//! Previous rendering time for the layer, in ms
double lastRenderingTimeMs = -1;

//! Default maximum allowable render time, in ms
double maxRenderingTimeMs = MAXIMUM_LAYER_PREVIEW_TIME_MS;
};
#endif

/**
* Returns whether the layer must be rendered in preview jobs.
*
* The \a context argument gives useful information which can be used
* to determine whether the layer should be rendered or not.
*
* The base implementation returns true if lastRenderingTimeMs <= maxRenderingTimeMs.
*
* \since QGIS 3.0
*
* \note not available in Python bindings
*/
virtual bool renderInPreview( const QgsDataProvider::PreviewContext &context ); // SIP_SKIP

signals:

/**
@@ -64,6 +64,17 @@ void QgsMapRendererJob::setCache( QgsMapRendererCache *cache )
mCache = cache;
}

QHash<QgsMapLayer *, int> QgsMapRendererJob::perLayerRenderingTime() const
{
QHash<QgsMapLayer *, int> result;
for ( auto it = mPerLayerRenderingTime.constBegin(); it != mPerLayerRenderingTime.constEnd(); ++it )
{
if ( it.key() )
result.insert( it.key(), it.value() );
}
return result;
}

const QgsMapSettings &QgsMapRendererJob::mapSettings() const
{
return mSettings;
@@ -412,8 +423,10 @@ void QgsMapRendererJob::cleanupJobs( LayerRenderJobs &jobs )
delete job.renderer;
job.renderer = nullptr;
}
}

if ( job.layer )
mPerLayerRenderingTime.insert( job.layer, job.renderingTime );
}

jobs.clear();
}
@@ -199,9 +199,19 @@ class CORE_EXPORT QgsMapRendererJob : public QObject
*/
void setCache( QgsMapRendererCache *cache );

//! Find out how long it took to finish the job (in milliseconds)
/**
* Returns the total time it took to finish the job (in milliseconds).
* \see perLayerRenderingTime()
*/
int renderingTime() const { return mRenderingTime; }

/**
* Returns the render time (in ms) per layer.
* \note Not available in Python bindings.
* \since QGIS 3.0
*/
QHash< QgsMapLayer *, int > perLayerRenderingTime() const SIP_SKIP;

/**
* Return map settings with which this job was started.
* \returns A QgsMapSettings instance with render settings
@@ -239,6 +249,9 @@ class CORE_EXPORT QgsMapRendererJob : public QObject

int mRenderingTime = 0;

//! Render time (in ms) per layer, by layer ID
QHash< QgsWeakMapLayerPointer, int > mPerLayerRenderingTime;

/**
* Prepares the cache for storing the result of labeling. Returns false if
* the render cannot use cached labels and should not cache the result.
@@ -66,7 +66,6 @@ email : sherman at mrcc.com
#include "qgsmapthemecollection.h"
#include <cmath>


/**
* \ingroup gui
* Deprecated to be deleted, stuff from here should be moved elsewhere.
@@ -612,6 +611,13 @@ void QgsMapCanvas::rendererJobFinished()
p.end();

mMap->setContent( img, imageRect( img, mSettings ) );

mLastLayerRenderTime.clear();
const auto times = mJob->perLayerRenderingTime();
for ( auto it = times.constBegin(); it != times.constEnd(); ++it )
{
mLastLayerRenderTime.insert( it.key()->id(), it.value() );
}
if ( mUsePreviewJobs )
startPreviewJobs();
}
@@ -633,6 +639,13 @@ void QgsMapCanvas::previewJobFinished()
{
mMap->addPreviewImage( job->renderedImage(), job->mapSettings().extent() );
mPreviewJobs.removeAll( job );

int number = job->property( "number" ).toInt();
if ( number < 8 )
{
startPreviewJob( number + 1 );
}

delete job;
}
}
@@ -2269,15 +2282,29 @@ void QgsMapCanvas::startPreviewJob( int number )
jobSettings.setFlag( QgsMapSettings::DrawLabeling, false );
jobSettings.setFlag( QgsMapSettings::RenderPreviewJob, true );

// truncate preview layers to fast layers
const QList<QgsMapLayer *> layers = jobSettings.layers();
QList< QgsMapLayer * > previewLayers;
QgsDataProvider::PreviewContext context;
context.maxRenderingTimeMs = MAXIMUM_LAYER_PREVIEW_TIME_MS;
for ( QgsMapLayer *layer : layers )
{
context.lastRenderingTimeMs = mLastLayerRenderTime.value( layer->id(), 0 );
if ( !layer->dataProvider()->renderInPreview( context ) )
{
QgsDebugMsgLevel( QString( "Layer %1 not rendered because it does not match the renderInPreview criterion %2" ).arg( layer->id() ).arg( mLastLayerRenderTime.value( layer->id() ) ), 3 );
continue;
}

previewLayers << layer;
}
jobSettings.setLayers( previewLayers );

QgsMapRendererQImageJob *job = new QgsMapRendererSequentialJob( jobSettings );
job->setProperty( "number", number );
mPreviewJobs.append( job );
connect( job, &QgsMapRendererJob::finished, this, &QgsMapCanvas::previewJobFinished );
job->start();

if ( number < 8 )
{
schedulePreviewJob( number + 1 );
}
}

void QgsMapCanvas::stopPreviewJobs()
@@ -2299,7 +2326,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, [ = ]()
{
@@ -1000,6 +1000,8 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView

bool mUsePreviewJobs = false;

QHash< QString, int > mLastLayerRenderTime;

/**
* Force a resize of the map canvas item
* \since QGIS 2.16
@@ -3199,18 +3199,25 @@ QString QgsWmsProvider::lastErrorFormat()
QString QgsWmsProvider::name() const
{
return WMS_KEY;
} // QgsWmsProvider::name()
}


QString QgsWmsProvider::description() const
{
return WMS_DESCRIPTION;
} // QgsWmsProvider::description()
}

void QgsWmsProvider::reloadData()
{
}

bool QgsWmsProvider::renderInPreview( const QgsDataProvider::PreviewContext &context )
{
if ( mSettings.mTiled || mSettings.mXyz )
return true;

return QgsRasterDataProvider::renderInPreview( context );
}

QVector<QgsWmsSupportedFormat> QgsWmsProvider::supportedFormats()
{
@@ -208,6 +208,7 @@ class QgsWmsProvider : public QgsRasterDataProvider
QString name() const override;
QString description() const override;
virtual void reloadData() override;
bool renderInPreview( const QgsDataProvider::PreviewContext &context ) override;

static QVector<QgsWmsSupportedFormat> supportedFormats();

0 comments on commit b0a36e9

Please sign in to comment.
You can’t perform that action at this time.