File indexing completed on 2024-05-12 15:58:45

0001 /*
0002  *  SPDX-FileCopyrightText: 2014 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_sync_lod_cache_stroke_strategy.h"
0008 
0009 #include <kis_image.h>
0010 #include <kundo2magicstring.h>
0011 #include "krita_utils.h"
0012 #include "kis_layer_utils.h"
0013 #include "kis_pointer_utils.h"
0014 #include "KisRunnableStrokeJobUtils.h"
0015 
0016 struct KisSyncLodCacheStrokeStrategy::Private
0017 {
0018     KisImageWSP image;
0019 };
0020 
0021 KisSyncLodCacheStrokeStrategy::KisSyncLodCacheStrokeStrategy(KisImageWSP image, bool forgettable)
0022     : KisRunnableBasedStrokeStrategy(QLatin1String("SyncLodCacheStroke"), kundo2_i18n("Instant Preview")),
0023       m_d(new Private)
0024 {
0025     m_d->image = image;
0026 
0027     /**
0028      * We shouldn't start syncing before all the updates are
0029      * done. Otherwise we might get artifacts!
0030      */
0031     enableJob(KisSimpleStrokeStrategy::JOB_INIT, true, KisStrokeJobData::BARRIER, KisStrokeJobData::EXCLUSIVE);
0032     enableJob(KisSimpleStrokeStrategy::JOB_DOSTROKE);
0033 
0034     setRequestsOtherStrokesToEnd(false);
0035     setClearsRedoOnStart(false);
0036     setCanForgetAboutMe(forgettable);
0037 }
0038 
0039 KisSyncLodCacheStrokeStrategy::~KisSyncLodCacheStrokeStrategy()
0040 {
0041 }
0042 
0043 void KisSyncLodCacheStrokeStrategy::initStrokeCallback()
0044 {
0045     QVector<KisStrokeJobData *> jobs;
0046     createJobsData(jobs, m_d->image->root(), m_d->image->currentLevelOfDetail());
0047     addMutatedJobs(jobs);
0048 }
0049 
0050 QList<KisStrokeJobData*> KisSyncLodCacheStrokeStrategy::createJobsData(KisImageWSP /*_image*/)
0051 {
0052     // all the jobs are populates in the init job
0053     return {};
0054 }
0055 
0056 void KisSyncLodCacheStrokeStrategy::createJobsData(QVector<KisStrokeJobData *> &jobs, KisNodeSP imageRoot, int levelOfDetail, KisPaintDeviceList extraDevices)
0057 {
0058     using KisLayerUtils::recursiveApplyNodes;
0059     using KritaUtils::splitRegionIntoPatches;
0060     using KritaUtils::optimalPatchSize;
0061 
0062     using SharedData = QHash<KisPaintDeviceSP, QSharedPointer<KisPaintDevice::LodDataStruct>>;
0063     using SharedDataSP = QSharedPointer<SharedData>;
0064 
0065     SharedDataSP sharedData(new SharedData());
0066 
0067     KisPaintDeviceList deviceList = extraDevices;
0068 
0069     recursiveApplyNodes(imageRoot,
0070         [&deviceList](KisNodeSP node) {
0071              deviceList << node->getLodCapableDevices();
0072         });
0073 
0074     KritaUtils::makeContainerUnique(deviceList);
0075 
0076 
0077     KritaUtils::addJobBarrier(jobs, [sharedData, deviceList, levelOfDetail] () mutable {
0078         Q_FOREACH (KisPaintDeviceSP device, deviceList) {
0079             sharedData->insert(device, toQShared(device->createLodDataStruct(levelOfDetail)));
0080         }
0081     });
0082 
0083     KritaUtils::addJobSequential(jobs, [](){});
0084 
0085     Q_FOREACH (KisPaintDeviceSP device, deviceList) {
0086         KisRegion region = device->regionForLodSyncing();
0087         QVector<QRect> rects = splitRegionIntoPatches(region, optimalPatchSize());
0088 
0089         Q_FOREACH (const QRect &rc, rects) {
0090             KritaUtils::addJobConcurrent(jobs, [sharedData, device, rc] () mutable {
0091                 KIS_ASSERT(sharedData->contains(device));
0092 
0093                 KisPaintDevice::LodDataStruct *data = sharedData->value(device).data();
0094                 device->updateLodDataStruct(data, rc);
0095             });
0096         }
0097     }
0098 
0099     KritaUtils::addJobSequential(jobs, [](){});
0100 
0101     recursiveApplyNodes(imageRoot,
0102         [&jobs](KisNodeSP node) {
0103              KritaUtils::addJobConcurrent(jobs, [node] () mutable {
0104                  node->syncLodCache();
0105              });
0106         });
0107 
0108     KritaUtils::addJobSequential(jobs, [sharedData] () mutable {
0109         auto it = sharedData->begin();
0110         auto end = sharedData->end();
0111 
0112         for (; it != end; ++it) {
0113             KisPaintDeviceSP dev = it.key();
0114             dev->uploadLodDataStruct(it.value().data());
0115         }
0116     });
0117 }