1 /*
2 * Copyright (c) 2017 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include "KisDabRenderingJob.h"
20
21 #include <QElapsedTimer>
22
23 #include <KisRunnableStrokeJobsInterface.h>
24 #include <KisRunnableStrokeJobData.h>
25
26 #include "KisDabCacheUtils.h"
27 #include "KisDabRenderingQueue.h"
28
29 #include <tool/strokes/FreehandStrokeRunnableJobDataWithUpdate.h>
30
31
KisDabRenderingJob()32 KisDabRenderingJob::KisDabRenderingJob()
33 {
34 }
35
KisDabRenderingJob(int _seqNo,KisDabCacheUtils::DabGenerationInfo _generationInfo,KisDabRenderingJob::JobType _type)36 KisDabRenderingJob::KisDabRenderingJob(int _seqNo, KisDabCacheUtils::DabGenerationInfo _generationInfo, KisDabRenderingJob::JobType _type)
37 : seqNo(_seqNo),
38 generationInfo(_generationInfo),
39 type(_type)
40 {
41 }
42
KisDabRenderingJob(const KisDabRenderingJob & rhs)43 KisDabRenderingJob::KisDabRenderingJob(const KisDabRenderingJob &rhs)
44 : seqNo(rhs.seqNo),
45 generationInfo(rhs.generationInfo),
46 type(rhs.type),
47 originalDevice(rhs.originalDevice),
48 postprocessedDevice(rhs.postprocessedDevice),
49 status(rhs.status),
50 opacity(rhs.opacity),
51 flow(rhs.flow)
52 {
53 }
54
operator =(const KisDabRenderingJob & rhs)55 KisDabRenderingJob &KisDabRenderingJob::operator=(const KisDabRenderingJob &rhs)
56 {
57 seqNo = rhs.seqNo;
58 generationInfo = rhs.generationInfo;
59 type = rhs.type;
60 originalDevice = rhs.originalDevice;
61 postprocessedDevice = rhs.postprocessedDevice;
62 status = rhs.status;
63 opacity = rhs.opacity;
64 flow = rhs.flow;
65
66 return *this;
67 }
68
dstDabOffset() const69 QPoint KisDabRenderingJob::dstDabOffset() const
70 {
71 /// Recenter generated low-res dab around the center
72 /// of the idel theoretical dab rect
73 const QPoint p1 = generationInfo.dstDabRect.topLeft();
74 const QPoint s1 = QPoint(generationInfo.dstDabRect.width(),
75 generationInfo.dstDabRect.height());
76 const QPoint s2 = QPoint(postprocessedDevice->bounds().width(),
77 postprocessedDevice->bounds().height());
78 return p1 + (s1 - s2) / 2;
79 }
80
81
82
KisDabRenderingJobRunner(KisDabRenderingJobSP job,KisDabRenderingQueue * parentQueue,KisRunnableStrokeJobsInterface * runnableJobsInterface)83 KisDabRenderingJobRunner::KisDabRenderingJobRunner(KisDabRenderingJobSP job,
84 KisDabRenderingQueue *parentQueue,
85 KisRunnableStrokeJobsInterface *runnableJobsInterface)
86 : m_job(job),
87 m_parentQueue(parentQueue),
88 m_runnableJobsInterface(runnableJobsInterface)
89 {
90 }
91
~KisDabRenderingJobRunner()92 KisDabRenderingJobRunner::~KisDabRenderingJobRunner()
93 {
94 }
95
executeOneJob(KisDabRenderingJob * job,KisDabCacheUtils::DabRenderingResources * resources,KisDabRenderingQueue * parentQueue)96 int KisDabRenderingJobRunner::executeOneJob(KisDabRenderingJob *job,
97 KisDabCacheUtils::DabRenderingResources *resources,
98 KisDabRenderingQueue *parentQueue)
99 {
100 using namespace KisDabCacheUtils;
101
102 KIS_SAFE_ASSERT_RECOVER_NOOP(job->type == KisDabRenderingJob::Dab ||
103 job->type == KisDabRenderingJob::Postprocess);
104
105 QElapsedTimer executionTime;
106 executionTime.start();
107
108 resources->syncResourcesToSeqNo(job->seqNo, job->generationInfo.info);
109
110 if (job->type == KisDabRenderingJob::Dab) {
111 // TODO: thing about better interface for the reverse queue link
112 job->originalDevice = parentQueue->fetchCachedPaintDevce();
113
114 generateDab(job->generationInfo, resources, &job->originalDevice);
115 }
116
117 // by now the original device should be already prepared
118 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(job->originalDevice, 0);
119
120 if (job->type == KisDabRenderingJob::Dab ||
121 job->type == KisDabRenderingJob::Postprocess) {
122
123 if (job->generationInfo.needsPostprocessing) {
124 // TODO: cache postprocessed device
125
126 if (!job->postprocessedDevice ||
127 *job->originalDevice->colorSpace() != *job->postprocessedDevice->colorSpace()) {
128
129 job->postprocessedDevice = parentQueue->fetchCachedPaintDevce();
130 *job->postprocessedDevice = *job->originalDevice;
131 } else {
132 *job->postprocessedDevice = *job->originalDevice;
133 }
134
135 postProcessDab(job->postprocessedDevice,
136 job->generationInfo.dstDabRect.topLeft(),
137 job->generationInfo.info,
138 resources);
139 } else {
140 job->postprocessedDevice = job->originalDevice;
141 }
142 }
143
144 return executionTime.nsecsElapsed() / 1000;
145 }
146
run()147 void KisDabRenderingJobRunner::run()
148 {
149 int executionTime = 0;
150
151 KisDabCacheUtils::DabRenderingResources *resources = m_parentQueue->fetchResourcesFromCache();
152
153 executionTime = executeOneJob(m_job.data(), resources, m_parentQueue);
154 QList<KisDabRenderingJobSP> jobs = m_parentQueue->notifyJobFinished(m_job->seqNo, executionTime);
155
156 while (!jobs.isEmpty()) {
157 QVector<KisRunnableStrokeJobData*> dataList;
158
159 // start all-but-the-first jobs asynchronously
160 for (int i = 1; i < jobs.size(); i++) {
161 dataList.append(new FreehandStrokeRunnableJobDataWithUpdate(
162 new KisDabRenderingJobRunner(jobs[i], m_parentQueue, m_runnableJobsInterface),
163 KisStrokeJobData::CONCURRENT));
164 }
165
166 m_runnableJobsInterface->addRunnableJobs(dataList);
167
168
169 // execute the first job in the current thread
170 KisDabRenderingJobSP job = jobs.first();
171 executionTime = executeOneJob(job.data(), resources, m_parentQueue);
172 jobs = m_parentQueue->notifyJobFinished(job->seqNo, executionTime);
173 }
174
175 m_parentQueue->putResourcesToCache(resources);
176 }
177