26 #include <QtConcurrentRun>
31 static void _fixQPictureDPI( QPainter *p )
37 p->scale(
static_cast< double >(
qt_defaultDpiX() ) / p->device()->logicalDpiX(),
38 static_cast< double >(
qt_defaultDpiY() ) / p->device()->logicalDpiY() );
58 #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
63 QPaintDevice *paintDevice = painter->device();
64 const QString errMsg = QStringLiteral(
"pre-set DPI not equal to painter's DPI (%1 vs %2)" )
65 .arg( paintDevice->logicalDpiX() )
68 "Job::startRender()", errMsg.toLatin1().data() );
81 , mRenderSynchronously( false )
89 Q_ASSERT( !mFutureWatcher.isRunning() );
93 void QgsMapRendererCustomPainterJob::startPrivate()
107 QgsDebugMsgLevel( QStringLiteral(
"Preparing list of layer jobs for rendering" ), 5 );
108 QElapsedTimer prepareTime;
113 mLabelingEngineV2.reset();
118 mLabelingEngineV2->setMapSettings(
mSettings );
122 mLayerJobs =
prepareJobs( mPainter, mLabelingEngineV2.get() );
123 mLabelJob =
prepareLabelingJob( mPainter, mLabelingEngineV2.get(), canUseLabelCache );
126 QgsDebugMsgLevel( QStringLiteral(
"Rendering prepared in (seconds): %1" ).arg( prepareTime.elapsed() / 1000.0 ), 4 );
128 if ( mRenderSynchronously )
139 connect( &mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererCustomPainterJob::futureFinished );
141 mFuture = QtConcurrent::run( staticRender,
this );
142 mFutureWatcher.setFuture( mFuture );
155 disconnect( &mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererCustomPainterJob::futureFinished );
161 mFutureWatcher.waitForFinished();
163 QgsDebugMsgLevel( QStringLiteral(
"QPAINER cancel waited %1 ms" ).arg( t.elapsed() / 1000.0 ), 5 );
174 QgsDebugMsg( QStringLiteral(
"QPAINTER not running!" ) );
178 mLabelJob.context.setRenderingStopped(
true );
179 for ( LayerRenderJob &job : mLayerJobs )
181 job.context()->setRenderingStopped(
true );
182 if ( job.renderer && job.renderer->feedback() )
183 job.renderer->feedback()->cancel();
192 disconnect( &mFutureWatcher, &QFutureWatcher<void>::finished,
this, &QgsMapRendererCustomPainterJob::futureFinished );
197 mFutureWatcher.waitForFinished();
199 QgsDebugMsgLevel( QStringLiteral(
"waitForFinished: %1 ms" ).arg( t.elapsed() / 1000.0 ), 4 );
211 return mLabelJob.cached;
216 if ( mLabelingEngineV2 )
217 return mLabelingEngineV2->takeResults();
226 connect( &mFutureWatcher, &QFutureWatcher<void>::finished, &loop, &QEventLoop::quit );
233 mRenderSynchronously =
true;
236 mRenderSynchronously =
false;
241 mRenderSynchronously =
true;
254 mRenderSynchronously =
false;
255 mPrepareOnly =
false;
259 void QgsMapRendererCustomPainterJob::futureFinished()
289 catch ( std::exception &e )
292 QgsDebugMsg(
"Caught unhandled std::exception: " + QString::fromLatin1( e.what() ) );
296 QgsDebugMsg( QStringLiteral(
"Caught unhandled unknown exception" ) );
300 void QgsMapRendererCustomPainterJob::doRender()
302 const bool hasSecondPass = ! mSecondPassLayerJobs.empty();
304 QElapsedTimer renderTime;
307 for ( LayerRenderJob &job : mLayerJobs )
309 if ( job.context()->renderingStopped() )
314 if ( ! hasSecondPass && job.context()->useAdvancedEffects() )
318 mPainter->setCompositionMode( job.blendMode );
323 QElapsedTimer layerTime;
329 job.imageInitialized =
true;
332 job.completed = job.renderer->render();
336 job.renderer->renderContext()->painter()->end();
339 job.renderingTime += layerTime.elapsed();
342 if ( ! hasSecondPass && job.img )
345 mPainter->setOpacity( job.opacity );
346 mPainter->drawImage( 0, 0, *job.img );
347 mPainter->setOpacity( 1.0 );
358 if ( !mLabelJob.cached )
360 QElapsedTimer labelTime;
366 mLabelJob.img->fill( 0 );
367 painter.begin( mLabelJob.img );
368 mLabelJob.context.setPainter( &painter );
369 drawLabeling( mLabelJob.context, mLabelingEngineV2.get(), &painter );
372 else if ( mLabelJob.picture )
375 painter.begin( mLabelJob.picture.get() );
376 mLabelJob.context.setPainter( &painter );
377 drawLabeling( mLabelJob.context, mLabelingEngineV2.get(), &painter );
382 drawLabeling( mLabelJob.context, mLabelingEngineV2.get(), mPainter );
385 mLabelJob.complete =
true;
386 mLabelJob.renderingTime = labelTime.elapsed();
387 mLabelJob.participatingLayers = _qgis_listRawToQPointer( mLabelingEngineV2->participatingLayers() );
391 if ( ! hasSecondPass )
393 if ( mLabelJob.img && mLabelJob.complete )
395 mPainter->setCompositionMode( QPainter::CompositionMode_SourceOver );
396 mPainter->setOpacity( 1.0 );
397 mPainter->drawImage( 0, 0, *mLabelJob.img );
404 for ( LayerRenderJob &job : mSecondPassLayerJobs )
406 if ( job.context()->renderingStopped() )
411 QElapsedTimer layerTime;
417 job.imageInitialized =
true;
420 job.completed = job.renderer->render();
424 job.renderer->renderContext()->painter()->end();
427 job.renderingTime += layerTime.elapsed();
438 mPainter->setCompositionMode( QPainter::CompositionMode_SourceOver );
439 mPainter->setOpacity( 1.0 );
440 mPainter->drawImage( 0, 0, finalImage );
445 for ( LayerRenderJob &job : mLayerJobs )
451 _fixQPictureDPI( mPainter );
452 mPainter->drawPicture( 0, 0, *job.picture );
456 mPainter->drawImage( 0, 0, *job.img );
459 if ( mLabelJob.picture )
462 _fixQPictureDPI( mPainter );
463 mPainter->drawPicture( 0, 0, *mLabelJob.picture );
469 QgsDebugMsgLevel( QStringLiteral(
"Rendering completed in (seconds): %1" ).arg( renderTime.elapsed() / 1000.0 ), 2 );