26 #include <QtConcurrentMap>
27 #include <QtConcurrentRun>
50 mStatus = RenderingLayers;
52 mLabelingEngineV2.reset();
57 mLabelingEngineV2->setMapSettings(
mSettings );
61 mLayerJobs =
prepareJobs(
nullptr, mLabelingEngineV2.get() );
65 QgsDebugMsgLevel( QStringLiteral(
"QThreadPool max thread count is %1" ).arg( QThreadPool::globalInstance()->maxThreadCount() ), 2 );
69 connect( &mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererParallelJob::renderLayersFinished );
71 mFuture = QtConcurrent::map( mLayerJobs, renderLayerStatic );
72 mFutureWatcher.setFuture( mFuture );
80 QgsDebugMsgLevel( QStringLiteral(
"PARALLEL cancel at status %1" ).arg( mStatus ), 2 );
82 mLabelJob.context.setRenderingStopped(
true );
83 for ( LayerRenderJobs::iterator it = mLayerJobs.begin(); it != mLayerJobs.end(); ++it )
85 it->context.setRenderingStopped(
true );
86 if ( it->renderer && it->renderer->feedback() )
87 it->renderer->feedback()->cancel();
90 if ( mStatus == RenderingLayers )
92 disconnect( &mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererParallelJob::renderLayersFinished );
94 mFutureWatcher.waitForFinished();
96 renderLayersFinished();
99 if ( mStatus == RenderingLabels )
101 disconnect( &mLabelingFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererParallelJob::renderingFinished );
103 mLabelingFutureWatcher.waitForFinished();
108 if ( mStatus == RenderingSecondPass )
110 disconnect( &mSecondPassFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererParallelJob::renderLayersSecondPassFinished );
112 mSecondPassFutureWatcher.waitForFinished();
114 renderLayersSecondPassFinished();
117 Q_ASSERT( mStatus == Idle );
125 QgsDebugMsgLevel( QStringLiteral(
"PARALLEL cancel at status %1" ).arg( mStatus ), 2 );
127 mLabelJob.context.setRenderingStopped(
true );
128 for ( LayerRenderJobs::iterator it = mLayerJobs.begin(); it != mLayerJobs.end(); ++it )
130 it->context.setRenderingStopped(
true );
131 if ( it->renderer && it->renderer->feedback() )
132 it->renderer->feedback()->cancel();
135 if ( mStatus == RenderingLayers )
137 disconnect( &mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererParallelJob::renderLayersFinished );
138 connect( &mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererParallelJob::renderingFinished );
147 if ( mStatus == RenderingLayers )
149 disconnect( &mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererParallelJob::renderLayersFinished );
154 mFutureWatcher.waitForFinished();
156 QgsDebugMsgLevel( QStringLiteral(
"waitForFinished (1): %1 ms" ).arg( t.elapsed() / 1000.0 ), 2 );
158 renderLayersFinished();
161 if ( mStatus == RenderingLabels )
163 disconnect( &mLabelingFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererParallelJob::renderingFinished );
168 mLabelingFutureWatcher.waitForFinished();
170 QgsDebugMsgLevel( QStringLiteral(
"waitForFinished (2): %1 ms" ).arg( t.elapsed() / 1000.0 ), 2 );
175 if ( mStatus == RenderingSecondPass )
177 disconnect( &mSecondPassFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererParallelJob::renderLayersSecondPassFinished );
182 mSecondPassFutureWatcher.waitForFinished();
184 QgsDebugMsg( QStringLiteral(
"waitForFinished (1): %1 ms" ).arg( t.elapsed() / 1000.0 ) );
186 renderLayersSecondPassFinished();
189 Q_ASSERT( mStatus == Idle );
194 return mStatus != Idle;
199 return mLabelJob.cached;
204 if ( mLabelingEngineV2 )
205 return mLabelingEngineV2->takeResults();
212 if ( mStatus == RenderingLayers )
218 void QgsMapRendererParallelJob::renderLayersFinished()
220 Q_ASSERT( mStatus == RenderingLayers );
222 LayerRenderJobs::const_iterator it = mLayerJobs.constBegin();
223 for ( ; it != mLayerJobs.constEnd(); ++it )
225 if ( !it->errors.isEmpty() )
227 mErrors.append( Error( it->layer->id(), it->errors.join(
',' ) ) );
232 if ( mSecondPassLayerJobs.isEmpty() )
241 mStatus = RenderingLabels;
243 connect( &mLabelingFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererParallelJob::renderingFinished );
246 mLabelingFuture = QtConcurrent::run( renderLabelsStatic,
this );
247 mLabelingFutureWatcher.setFuture( mLabelingFuture );
256 #define DEBUG_RENDERING 0
258 void QgsMapRendererParallelJob::renderingFinished()
262 for ( LayerRenderJob &job : mLayerJobs )
266 job.img->save( QString(
"/tmp/first_pass_%1.png" ).arg( i ) );
268 if ( job.maskPass.image )
270 job.maskPass.image->save( QString(
"/tmp/first_pass_%1_mask.png" ).arg( i ) );
276 mLabelJob.img->save( QString(
"/tmp/labels.png" ) );
278 if ( mLabelJob.maskImage )
280 mLabelJob.maskImage->save( QString(
"/tmp/labels_mask.png" ) );
283 if ( ! mSecondPassLayerJobs.isEmpty() )
285 mStatus = RenderingSecondPass;
287 mSecondPassFuture = QtConcurrent::map( mSecondPassLayerJobs, renderLayerStatic );
288 mSecondPassFutureWatcher.setFuture( mSecondPassFuture );
289 connect( &mSecondPassFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererParallelJob::renderLayersSecondPassFinished );
309 void QgsMapRendererParallelJob::renderLayersSecondPassFinished()
334 void QgsMapRendererParallelJob::renderLayerStatic( LayerRenderJob &job )
336 if ( job.context.renderingStopped() )
345 job.imageInitialized =
true;
350 QgsDebugMsgLevel( QStringLiteral(
"job %1 start (layer %2)" ).arg(
reinterpret_cast< quint64
>( &job ), 0, 16 ).arg( job.layerId ), 2 );
353 job.renderer->render();
360 catch ( std::exception &e )
363 QgsDebugMsg(
"Caught unhandled std::exception: " + QString::fromLatin1( e.what() ) );
367 QgsDebugMsg( QStringLiteral(
"Caught unhandled unknown exception" ) );
370 job.errors = job.renderer->errors();
371 job.renderingTime += t.elapsed();
372 QgsDebugMsgLevel( QStringLiteral(
"job %1 end [%2 ms] (layer %3)" ).arg(
reinterpret_cast< quint64
>( &job ), 0, 16 ).arg( job.renderingTime ).arg( job.layerId ), 2 );
378 LabelRenderJob &job =
self->mLabelJob;
382 QElapsedTimer labelTime;
389 painter.begin( job.img );
393 painter.begin( &self->mFinalImage );
399 drawLabeling( job.context, self->mLabelingEngineV2.get(), &painter );
406 catch ( std::exception &e )
409 QgsDebugMsg(
"Caught unhandled std::exception: " + QString::fromLatin1( e.what() ) );
413 QgsDebugMsg( QStringLiteral(
"Caught unhandled unknown exception" ) );
418 job.renderingTime = labelTime.elapsed();
420 job.participatingLayers = _qgis_listRawToQPointer( self->mLabelingEngineV2->participatingLayers() );
423 self->mFinalImage =
composeImage( self->mSettings, self->mLayerJobs, self->mLabelJob );