mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-15 00:02:52 -04:00
Merge pull request #5789 from nyalldawson/render_jobs
[Rendering] Only render in preview jobs layers that are fast enough
This commit is contained in:
commit
b0a36e9bb1
@ -241,6 +241,8 @@ const double DEFAULT_LINE_WIDTH;
|
|||||||
const double DEFAULT_SEGMENT_EPSILON;
|
const double DEFAULT_SEGMENT_EPSILON;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef unsigned long long qgssize;
|
typedef unsigned long long qgssize;
|
||||||
|
|
||||||
|
|
||||||
|
@ -380,6 +380,7 @@ Current time stamp of data source
|
|||||||
.. versionadded:: 3.0
|
.. versionadded:: 3.0
|
||||||
%End
|
%End
|
||||||
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void fullExtentCalculated();
|
void fullExtentCalculated();
|
||||||
|
@ -137,10 +137,12 @@ List of errors that happened during the rendering job - available when the rende
|
|||||||
|
|
||||||
int renderingTime() const;
|
int renderingTime() const;
|
||||||
%Docstring
|
%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
|
:rtype: int
|
||||||
%End
|
%End
|
||||||
|
|
||||||
|
|
||||||
const QgsMapSettings &mapSettings() const;
|
const QgsMapSettings &mapSettings() const;
|
||||||
%Docstring
|
%Docstring
|
||||||
Return map settings with which this job was started.
|
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
|
//! Default snapping tolerance for segments
|
||||||
const double DEFAULT_SEGMENT_EPSILON = 1e-8;
|
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;
|
typedef QMap<QString, QString> QgsStringMap SIP_SKIP;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,3 +42,7 @@ void QgsDataProvider::setListening( bool isListening )
|
|||||||
Q_UNUSED( 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 );
|
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:
|
signals:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -64,6 +64,17 @@ void QgsMapRendererJob::setCache( QgsMapRendererCache *cache )
|
|||||||
mCache = 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
|
const QgsMapSettings &QgsMapRendererJob::mapSettings() const
|
||||||
{
|
{
|
||||||
return mSettings;
|
return mSettings;
|
||||||
@ -412,8 +423,10 @@ void QgsMapRendererJob::cleanupJobs( LayerRenderJobs &jobs )
|
|||||||
delete job.renderer;
|
delete job.renderer;
|
||||||
job.renderer = nullptr;
|
job.renderer = nullptr;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
if ( job.layer )
|
||||||
|
mPerLayerRenderingTime.insert( job.layer, job.renderingTime );
|
||||||
|
}
|
||||||
|
|
||||||
jobs.clear();
|
jobs.clear();
|
||||||
}
|
}
|
||||||
|
@ -199,9 +199,19 @@ class CORE_EXPORT QgsMapRendererJob : public QObject
|
|||||||
*/
|
*/
|
||||||
void setCache( QgsMapRendererCache *cache );
|
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; }
|
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.
|
* Return map settings with which this job was started.
|
||||||
* \returns A QgsMapSettings instance with render settings
|
* \returns A QgsMapSettings instance with render settings
|
||||||
@ -239,6 +249,9 @@ class CORE_EXPORT QgsMapRendererJob : public QObject
|
|||||||
|
|
||||||
int mRenderingTime = 0;
|
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
|
* Prepares the cache for storing the result of labeling. Returns false if
|
||||||
* the render cannot use cached labels and should not cache the result.
|
* 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 "qgsmapthemecollection.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \ingroup gui
|
* \ingroup gui
|
||||||
* Deprecated to be deleted, stuff from here should be moved elsewhere.
|
* Deprecated to be deleted, stuff from here should be moved elsewhere.
|
||||||
@ -612,6 +611,13 @@ void QgsMapCanvas::rendererJobFinished()
|
|||||||
p.end();
|
p.end();
|
||||||
|
|
||||||
mMap->setContent( img, imageRect( img, mSettings ) );
|
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 )
|
if ( mUsePreviewJobs )
|
||||||
startPreviewJobs();
|
startPreviewJobs();
|
||||||
}
|
}
|
||||||
@ -633,6 +639,13 @@ void QgsMapCanvas::previewJobFinished()
|
|||||||
{
|
{
|
||||||
mMap->addPreviewImage( job->renderedImage(), job->mapSettings().extent() );
|
mMap->addPreviewImage( job->renderedImage(), job->mapSettings().extent() );
|
||||||
mPreviewJobs.removeAll( job );
|
mPreviewJobs.removeAll( job );
|
||||||
|
|
||||||
|
int number = job->property( "number" ).toInt();
|
||||||
|
if ( number < 8 )
|
||||||
|
{
|
||||||
|
startPreviewJob( number + 1 );
|
||||||
|
}
|
||||||
|
|
||||||
delete job;
|
delete job;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2269,15 +2282,29 @@ void QgsMapCanvas::startPreviewJob( int number )
|
|||||||
jobSettings.setFlag( QgsMapSettings::DrawLabeling, false );
|
jobSettings.setFlag( QgsMapSettings::DrawLabeling, false );
|
||||||
jobSettings.setFlag( QgsMapSettings::RenderPreviewJob, true );
|
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 );
|
QgsMapRendererQImageJob *job = new QgsMapRendererSequentialJob( jobSettings );
|
||||||
|
job->setProperty( "number", number );
|
||||||
mPreviewJobs.append( job );
|
mPreviewJobs.append( job );
|
||||||
connect( job, &QgsMapRendererJob::finished, this, &QgsMapCanvas::previewJobFinished );
|
connect( job, &QgsMapRendererJob::finished, this, &QgsMapCanvas::previewJobFinished );
|
||||||
job->start();
|
job->start();
|
||||||
|
|
||||||
if ( number < 8 )
|
|
||||||
{
|
|
||||||
schedulePreviewJob( number + 1 );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QgsMapCanvas::stopPreviewJobs()
|
void QgsMapCanvas::stopPreviewJobs()
|
||||||
@ -2299,7 +2326,7 @@ void QgsMapCanvas::stopPreviewJobs()
|
|||||||
void QgsMapCanvas::schedulePreviewJob( int number )
|
void QgsMapCanvas::schedulePreviewJob( int number )
|
||||||
{
|
{
|
||||||
mPreviewTimer.setSingleShot( true );
|
mPreviewTimer.setSingleShot( true );
|
||||||
mPreviewTimer.setInterval( 250 );
|
mPreviewTimer.setInterval( PREVIEW_JOB_DELAY_MS );
|
||||||
disconnect( mPreviewTimerConnection );
|
disconnect( mPreviewTimerConnection );
|
||||||
mPreviewTimerConnection = connect( &mPreviewTimer, &QTimer::timeout, this, [ = ]()
|
mPreviewTimerConnection = connect( &mPreviewTimer, &QTimer::timeout, this, [ = ]()
|
||||||
{
|
{
|
||||||
|
@ -1000,6 +1000,8 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
|
|||||||
|
|
||||||
bool mUsePreviewJobs = false;
|
bool mUsePreviewJobs = false;
|
||||||
|
|
||||||
|
QHash< QString, int > mLastLayerRenderTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Force a resize of the map canvas item
|
* Force a resize of the map canvas item
|
||||||
* \since QGIS 2.16
|
* \since QGIS 2.16
|
||||||
|
@ -3199,18 +3199,25 @@ QString QgsWmsProvider::lastErrorFormat()
|
|||||||
QString QgsWmsProvider::name() const
|
QString QgsWmsProvider::name() const
|
||||||
{
|
{
|
||||||
return WMS_KEY;
|
return WMS_KEY;
|
||||||
} // QgsWmsProvider::name()
|
}
|
||||||
|
|
||||||
|
|
||||||
QString QgsWmsProvider::description() const
|
QString QgsWmsProvider::description() const
|
||||||
{
|
{
|
||||||
return WMS_DESCRIPTION;
|
return WMS_DESCRIPTION;
|
||||||
} // QgsWmsProvider::description()
|
}
|
||||||
|
|
||||||
void QgsWmsProvider::reloadData()
|
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()
|
QVector<QgsWmsSupportedFormat> QgsWmsProvider::supportedFormats()
|
||||||
{
|
{
|
||||||
|
@ -208,6 +208,7 @@ class QgsWmsProvider : public QgsRasterDataProvider
|
|||||||
QString name() const override;
|
QString name() const override;
|
||||||
QString description() const override;
|
QString description() const override;
|
||||||
virtual void reloadData() override;
|
virtual void reloadData() override;
|
||||||
|
bool renderInPreview( const QgsDataProvider::PreviewContext &context ) override;
|
||||||
|
|
||||||
static QVector<QgsWmsSupportedFormat> supportedFormats();
|
static QVector<QgsWmsSupportedFormat> supportedFormats();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user