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 }