Krita Source Code Documentation
Loading...
Searching...
No Matches
KisConvolutionWorkerFFT< _IteratorFactory_ > Class Template Reference

#include <kis_convolution_worker_fft.h>

+ Inheritance diagram for KisConvolutionWorkerFFT< _IteratorFactory_ >:

Classes

struct  FFTInfo
 

Public Member Functions

void execute (const KisConvolutionKernelSP kernel, const KisPaintDeviceSP src, QPoint srcPos, QPoint dstPos, QSize areaSize, const QRect &dataRect) override
 
void fillCacheFromDevice (KisPaintDeviceSP src, const QRect &rect, const int cacheRowStride, const FFTInfo &info, const QRect &dataRect)
 
 KisConvolutionWorkerFFT (KisPainter *painter, KoUpdater *progress)
 
void limitValue (qreal *value, qreal lowBound, qreal highBound)
 
qreal writeAlphaFromCache (quint8 *dstPtr, const quint32 channel, const FFTInfo &info, double *channelValuePtr, bool *dstValueIsNull)
 
template<bool additionalMultiplierActive>
qreal writeOneChannelFromCache (quint8 *dstPtr, const quint32 channel, const FFTInfo &info, double *channelValuePtr, const qreal additionalMultiplier=0.0)
 
void writeResultToDevice (const QRect &rect, const int cacheRowStride, const int halfKernelWidth, const int halfKernelHeight, const FFTInfo &info, const QRect &dataRect)
 
 ~KisConvolutionWorkerFFT ()
 
- Public Member Functions inherited from KisConvolutionWorker< _IteratorFactory_ >
 KisConvolutionWorker (KisPainter *painter, KoUpdater *progress)
 
virtual ~KisConvolutionWorker ()
 

Private Member Functions

void addToProgress (float amount)
 
void cleanUp ()
 
void fftFillKernelMatrix (const KisConvolutionKernelSP kernel, fftw_complex *m_kernelFFT)
 
void fftLogMatrix (double *channel, const QString &f)
 
void fftMultiply (fftw_complex *channel, fftw_complex *kernel)
 
bool isInterrupted ()
 
void optimumDimensions (quint32 &w, quint32 &h)
 

Private Attributes

QVector< fftw_complex * > m_channelFFT
 
float m_currentProgress {0.0}
 
quint32 m_extraMem {0}
 
quint32 m_fftHeight {0}
 
quint32 m_fftLength {0}
 
quint32 m_fftWidth {0}
 
fftw_complex * m_kernelFFT {0}
 

Additional Inherited Members

- Protected Member Functions inherited from KisConvolutionWorker< _IteratorFactory_ >
QList< KoChannelInfo * > convolvableChannelList (const KisPaintDeviceSP src)
 
- Protected Attributes inherited from KisConvolutionWorker< _IteratorFactory_ >
KisPainterm_painter
 
KoUpdaterm_progress
 

Detailed Description

template<class _IteratorFactory_>
class KisConvolutionWorkerFFT< _IteratorFactory_ >

Definition at line 40 of file kis_convolution_worker_fft.h.

Constructor & Destructor Documentation

◆ KisConvolutionWorkerFFT()

template<class _IteratorFactory_ >
KisConvolutionWorkerFFT< _IteratorFactory_ >::KisConvolutionWorkerFFT ( KisPainter * painter,
KoUpdater * progress )
inline

Definition at line 43 of file kis_convolution_worker_fft.h.

◆ ~KisConvolutionWorkerFFT()

template<class _IteratorFactory_ >
KisConvolutionWorkerFFT< _IteratorFactory_ >::~KisConvolutionWorkerFFT ( )
inline

Definition at line 48 of file kis_convolution_worker_fft.h.

49 {
50 }

Member Function Documentation

◆ addToProgress()

template<class _IteratorFactory_ >
void KisConvolutionWorkerFFT< _IteratorFactory_ >::addToProgress ( float amount)
inlineprivate

◆ cleanUp()

template<class _IteratorFactory_ >
void KisConvolutionWorkerFFT< _IteratorFactory_ >::cleanUp ( )
inlineprivate

Definition at line 534 of file kis_convolution_worker_fft.h.

535 {
536 // free kernel fft data
537 if (m_kernelFFT) {
538 fftw_free(m_kernelFFT);
539 }
540
541 Q_FOREACH (fftw_complex *channel, m_channelFFT) {
542 fftw_free(channel);
543 }
544 m_channelFFT.clear();
545 }
QVector< fftw_complex * > m_channelFFT

References KisConvolutionWorkerFFT< _IteratorFactory_ >::m_channelFFT, and KisConvolutionWorkerFFT< _IteratorFactory_ >::m_kernelFFT.

◆ execute()

template<class _IteratorFactory_ >
void KisConvolutionWorkerFFT< _IteratorFactory_ >::execute ( const KisConvolutionKernelSP kernel,
const KisPaintDeviceSP src,
QPoint srcPos,
QPoint dstPos,
QSize areaSize,
const QRect & dataRect )
inlineoverridevirtual

FIXME: check whether this "optimization" is needed to be uncommented. My tests showed about 30% better performance when the line is commented out (DK).

Implements KisConvolutionWorker< _IteratorFactory_ >.

Definition at line 52 of file kis_convolution_worker_fft.h.

58 {
59 // Make the area we cover as small as possible
60 if (this->m_painter->selection())
61 {
62 QRect r = this->m_painter->selection()->selectedRect().intersected(QRect(srcPos, areaSize));
63 dstPos += r.topLeft() - srcPos;
64 srcPos = r.topLeft();
65 areaSize = r.size();
66 }
67
68 if (areaSize.width() == 0 || areaSize.height() == 0)
69 return;
70
72 if (isInterrupted()) return;
73
74 const quint32 halfKernelWidth = (kernel->width() - 1) / 2;
75 const quint32 halfKernelHeight = (kernel->height() - 1) / 2;
76
77 m_fftWidth = areaSize.width() + 4 * halfKernelWidth;
78 m_fftHeight = areaSize.height() + 2 * halfKernelHeight;
79
85 //optimumDimensions(m_fftWidth, m_fftHeight);
86
88 m_extraMem = (m_fftWidth % 2) ? 1 : 2;
89
90 // create and fill kernel
91 m_kernelFFT = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * m_fftLength);
92 memset(m_kernelFFT, 0, sizeof(fftw_complex) * m_fftLength);
94
95 // find out which channels need convolving
96 QList<KoChannelInfo*> convChannelList = this->convolvableChannelList(src);
97
98 m_channelFFT.resize(convChannelList.count());
99 for (auto i = m_channelFFT.begin(); i != m_channelFFT.end(); ++i) {
100 *i = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * m_fftLength);
101 }
102
103 const double kernelFactor = kernel->factor() ? kernel->factor() : 1;
104 const double fftScale = 1.0 / (m_fftHeight * m_fftWidth) / kernelFactor;
105
106 FFTInfo info (fftScale, convChannelList, kernel, this->m_painter->device()->colorSpace());
107 int cacheRowStride = m_fftWidth + m_extraMem;
108
110 QRect(srcPos.x() - halfKernelWidth,
111 srcPos.y() - halfKernelHeight,
114 cacheRowStride,
115 info, dataRect);
116
117 addToProgress(10);
118 if (isInterrupted()) return;
119
120 // calculate number off fft operations required for progress reporting
121 const float progressPerFFT = (100 - 30) / (double)(convChannelList.count() * 2 + 1);
122
123 // perform FFT
124 fftw_plan fftwPlanForward, fftwPlanBackward;
125
127 fftwPlanForward = fftw_plan_dft_r2c_2d(m_fftHeight, m_fftWidth, (double*)m_kernelFFT, m_kernelFFT, FFTW_ESTIMATE);
128 fftwPlanBackward = fftw_plan_dft_c2r_2d(m_fftHeight, m_fftWidth, m_kernelFFT, (double*)m_kernelFFT, FFTW_ESTIMATE);
130
131 fftw_execute(fftwPlanForward);
132 addToProgress(progressPerFFT);
133 if (isInterrupted()) return;
134
135 for (auto k = m_channelFFT.begin(); k != m_channelFFT.end(); ++k)
136 {
137 fftw_execute_dft_r2c(fftwPlanForward, (double*)(*k), *k);
138 addToProgress(progressPerFFT);
139 if (isInterrupted()) return;
140
142
143 fftw_execute_dft_c2r(fftwPlanBackward, *k, (double*)*k);
144 addToProgress(progressPerFFT);
145 if (isInterrupted()) return;
146 }
147
149 fftw_destroy_plan(fftwPlanForward);
150 fftw_destroy_plan(fftwPlanBackward);
152
153
154 writeResultToDevice(QRect(dstPos.x(), dstPos.y(), areaSize.width(), areaSize.height()),
155 cacheRowStride, halfKernelWidth, halfKernelHeight,
156 info, dataRect);
157
158 addToProgress(20);
159 cleanUp();
160 }
void fillCacheFromDevice(KisPaintDeviceSP src, const QRect &rect, const int cacheRowStride, const FFTInfo &info, const QRect &dataRect)
void fftFillKernelMatrix(const KisConvolutionKernelSP kernel, fftw_complex *m_kernelFFT)
void writeResultToDevice(const QRect &rect, const int cacheRowStride, const int halfKernelWidth, const int halfKernelHeight, const FFTInfo &info, const QRect &dataRect)
void fftMultiply(fftw_complex *channel, fftw_complex *kernel)
QList< KoChannelInfo * > convolvableChannelList(const KisPaintDeviceSP src)
const KoColorSpace * colorSpace() const
KisSelectionSP selection
KisPaintDeviceSP device
QRect selectedRect() const

References KisConvolutionWorkerFFT< _IteratorFactory_ >::addToProgress(), KisConvolutionWorkerFFT< _IteratorFactory_ >::cleanUp(), KisPaintDevice::colorSpace(), KisConvolutionWorker< _IteratorFactory_ >::convolvableChannelList(), KisPainter::device, KisConvolutionKernel::factor, KisConvolutionWorkerFFT< _IteratorFactory_ >::fftFillKernelMatrix(), KisConvolutionWorkerFFT< _IteratorFactory_ >::fftMultiply(), KisConvolutionWorkerFFTLock::fftwMutex, KisConvolutionWorkerFFT< _IteratorFactory_ >::fillCacheFromDevice(), KisConvolutionKernel::height(), KisConvolutionWorkerFFT< _IteratorFactory_ >::isInterrupted(), KisConvolutionWorkerFFT< _IteratorFactory_ >::m_channelFFT, KisConvolutionWorkerFFT< _IteratorFactory_ >::m_extraMem, KisConvolutionWorkerFFT< _IteratorFactory_ >::m_fftHeight, KisConvolutionWorkerFFT< _IteratorFactory_ >::m_fftLength, KisConvolutionWorkerFFT< _IteratorFactory_ >::m_fftWidth, KisConvolutionWorkerFFT< _IteratorFactory_ >::m_kernelFFT, KisConvolutionWorker< _IteratorFactory_ >::m_painter, KisSelection::selectedRect(), KisPainter::selection, KisConvolutionKernel::width(), and KisConvolutionWorkerFFT< _IteratorFactory_ >::writeResultToDevice().

◆ fftFillKernelMatrix()

template<class _IteratorFactory_ >
void KisConvolutionWorkerFFT< _IteratorFactory_ >::fftFillKernelMatrix ( const KisConvolutionKernelSP kernel,
fftw_complex * m_kernelFFT )
inlineprivate

Definition at line 415 of file kis_convolution_worker_fft.h.

416 {
417 // find central item
418 QPoint offset((kernel->width() - 1) / 2, (kernel->height() - 1) / 2);
419
420 qint32 xShift = m_fftWidth - offset.x();
421 qint32 yShift = m_fftHeight - offset.y();
422
423 quint32 absXpos, absYpos;
424
425 for (quint32 y = 0; y < kernel->height(); y++)
426 {
427 absYpos = y + yShift;
428 if (absYpos >= m_fftHeight)
429 absYpos -= m_fftHeight;
430
431 for (quint32 x = 0; x < kernel->width(); x++)
432 {
433 absXpos = x + xShift;
434 if (absXpos >= m_fftWidth)
435 absXpos -= m_fftWidth;
436
437 ((double*)m_kernelFFT)[(m_fftWidth + m_extraMem) * absYpos + absXpos] = kernel->data()->coeff(y, x);
438 }
439 }
440 }
Eigen::Matrix< qreal, Eigen::Dynamic, Eigen::Dynamic > data

References KisConvolutionKernel::data, KisConvolutionKernel::height(), KisConvolutionWorkerFFT< _IteratorFactory_ >::m_extraMem, KisConvolutionWorkerFFT< _IteratorFactory_ >::m_fftHeight, KisConvolutionWorkerFFT< _IteratorFactory_ >::m_fftWidth, KisConvolutionWorkerFFT< _IteratorFactory_ >::m_kernelFFT, and KisConvolutionKernel::width().

◆ fftLogMatrix()

template<class _IteratorFactory_ >
void KisConvolutionWorkerFFT< _IteratorFactory_ >::fftLogMatrix ( double * channel,
const QString & f )
inlineprivate

Definition at line 485 of file kis_convolution_worker_fft.h.

486 {
488 QString filename(QDir::homePath() + "/log_" + f + ".txt");
489 dbgKrita << "Log File Name: " << filename;
490 QFile file (filename);
491 if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
492 {
493 dbgKrita << "Failed";
495 return;
496 }
497
498 QTextStream in(&file);
500 for (quint32 y = 0; y < m_fftHeight; y++)
501 {
502 for (quint32 x = 0; x < m_fftWidth; x++)
503 {
504 QString num = QString::number(channel[y * m_fftWidth + x]);
505 while (num.length() < 15)
506 num += " ";
507
508 in << num << " ";
509 }
510 in << "\n";
511 }
513 }
#define dbgKrita
Definition kis_debug.h:45
void setUtf8OnStream(QTextStream &stream)

References dbgKrita, KisConvolutionWorkerFFTLock::fftwMutex, KisConvolutionWorkerFFT< _IteratorFactory_ >::m_fftHeight, KisConvolutionWorkerFFT< _IteratorFactory_ >::m_fftWidth, and KisPortingUtils::setUtf8OnStream().

◆ fftMultiply()

template<class _IteratorFactory_ >
void KisConvolutionWorkerFFT< _IteratorFactory_ >::fftMultiply ( fftw_complex * channel,
fftw_complex * kernel )
inlineprivate

Definition at line 442 of file kis_convolution_worker_fft.h.

443 {
444 // perform complex multiplication
445 fftw_complex *channelPtr = channel;
446 fftw_complex *kernelPtr = kernel;
447
448 fftw_complex tmp;
449
450 for (quint32 pixelPos = 0; pixelPos < m_fftLength; ++pixelPos)
451 {
452 tmp[0] = ((*channelPtr)[0] * (*kernelPtr)[0]) - ((*channelPtr)[1] * (*kernelPtr)[1]);
453 tmp[1] = ((*channelPtr)[0] * (*kernelPtr)[1]) + ((*channelPtr)[1] * (*kernelPtr)[0]);
454
455 (*channelPtr)[0] = tmp[0];
456 (*channelPtr)[1] = tmp[1];
457
458 ++channelPtr;
459 ++kernelPtr;
460 }
461 }

References KisConvolutionWorkerFFT< _IteratorFactory_ >::m_fftLength.

◆ fillCacheFromDevice()

template<class _IteratorFactory_ >
void KisConvolutionWorkerFFT< _IteratorFactory_ >::fillCacheFromDevice ( KisPaintDeviceSP src,
const QRect & rect,
const int cacheRowStride,
const FFTInfo & info,
const QRect & dataRect )
inline

Definition at line 214 of file kis_convolution_worker_fft.h.

218 {
219
220 typename _IteratorFactory_::HLineConstIterator hitSrc =
221 _IteratorFactory_::createHLineConstIterator(src,
222 rect.x(), rect.y(), rect.width(),
223 dataRect);
224
225 const int channelCount = info.numChannels();
226 QVector<double*> channelPtr(channelCount);
227 const auto channelPtrBegin = channelPtr.begin();
228 const auto channelPtrEnd = channelPtr.end();
229
230 auto iFFt = m_channelFFT.constBegin();
231 for (auto i = channelPtrBegin; i != channelPtrEnd; ++i, ++iFFt) {
232 *i = (double*)*iFFt;
233 }
234
235 // prepare cache, reused in all loops
236 QVector<double*> cacheRowStart(channelCount);
237 const auto cacheRowStartBegin = cacheRowStart.begin();
238
239 for (int y = 0; y < rect.height(); ++y) {
240 // cache current channelPtr in cacheRowStart
241 memcpy(cacheRowStart.data(), channelPtr.data(), channelCount * sizeof(double*));
242
243 for (int x = 0; x < rect.width(); ++x) {
244 const quint8 *data = hitSrc->oldRawData();
245
246 // no alpha is a rare case, so just multiply by 1.0 in that case
247 double alphaValue = info.alphaRealPos >= 0 ?
248 info.toDoubleFuncPtr[info.alphaCachePos](data, info.alphaRealPos) : 1.0;
249 int k = 0;
250 for (auto i = channelPtrBegin; i != channelPtrEnd; ++i, ++k) {
251 if (k != info.alphaCachePos) {
252 const quint32 channelPos = info.convChannelList[k]->pos();
253 **i = info.toDoubleFuncPtr[k](data, channelPos) * alphaValue;
254 } else {
255 **i = alphaValue;
256 }
257
258 ++(*i);
259 }
260
261 hitSrc->nextPixel();
262 }
263
264 auto iRowStart = cacheRowStartBegin;
265 for (auto i = channelPtrBegin; i != channelPtrEnd; ++i, ++iRowStart) {
266 *i = *iRowStart + cacheRowStride;
267 }
268
269 hitSrc->nextRow();
270 }
271
272 }

References KisConvolutionWorkerFFT< _IteratorFactory_ >::FFTInfo::alphaCachePos, KisConvolutionWorkerFFT< _IteratorFactory_ >::FFTInfo::alphaRealPos, KisConvolutionWorkerFFT< _IteratorFactory_ >::FFTInfo::convChannelList, KisConvolutionWorkerFFT< _IteratorFactory_ >::m_channelFFT, KisConvolutionWorkerFFT< _IteratorFactory_ >::FFTInfo::numChannels(), and KisConvolutionWorkerFFT< _IteratorFactory_ >::FFTInfo::toDoubleFuncPtr.

◆ isInterrupted()

template<class _IteratorFactory_ >
bool KisConvolutionWorkerFFT< _IteratorFactory_ >::isInterrupted ( )
inlineprivate

Definition at line 524 of file kis_convolution_worker_fft.h.

525 {
526 if (this->m_progress && this->m_progress->interrupted()) {
527 cleanUp();
528 return true;
529 }
530
531 return false;
532 }
bool interrupted() const
Definition KoUpdater.cpp:54

References KisConvolutionWorkerFFT< _IteratorFactory_ >::cleanUp(), KoUpdater::interrupted(), and KisConvolutionWorker< _IteratorFactory_ >::m_progress.

◆ limitValue()

template<class _IteratorFactory_ >
void KisConvolutionWorkerFFT< _IteratorFactory_ >::limitValue ( qreal * value,
qreal lowBound,
qreal highBound )
inline

Definition at line 274 of file kis_convolution_worker_fft.h.

274 {
275 if (*value > highBound) {
276 *value = highBound;
277 } else if (!(*value >= lowBound)) { // value < lowBound or value == NaN
278 // IEEE compliant comparisons with NaN are always false
279 *value = lowBound;
280 }
281 }
float value(const T *src, size_t ch)

References value().

◆ optimumDimensions()

template<class _IteratorFactory_ >
void KisConvolutionWorkerFFT< _IteratorFactory_ >::optimumDimensions ( quint32 & w,
quint32 & h )
inlineprivate

Definition at line 463 of file kis_convolution_worker_fft.h.

464 {
465 // FFTW is most efficient when array size is a factor of 2, 3, 5 or 7
466 quint32 optW = w, optH = h;
467
468 while ((optW % 2 != 0) || (optW % 3 != 0) || (optW % 5 != 0) || (optW % 7 != 0))
469 ++optW;
470
471 while ((optH % 2 != 0) || (optH % 3 != 0) || (optH % 5 != 0) || (optH % 7 != 0))
472 ++optH;
473
474 quint32 optAreaW = optW * h;
475 quint32 optAreaH = optH * w;
476
477 if (optAreaW < optAreaH) {
478 w = optW;
479 }
480 else {
481 h = optH;
482 }
483 }

◆ writeAlphaFromCache()

template<class _IteratorFactory_ >
qreal KisConvolutionWorkerFFT< _IteratorFactory_ >::writeAlphaFromCache ( quint8 * dstPtr,
const quint32 channel,
const FFTInfo & info,
double * channelValuePtr,
bool * dstValueIsNull )
inline

Definition at line 283 of file kis_convolution_worker_fft.h.

287 {
288 qreal channelPixelValue;
289
290 channelPixelValue = *channelValuePtr * info.fftScale + info.absoluteOffset[channel];
291 limitValue(&channelPixelValue, info.minClamp[channel], info.maxClamp[channel]);
292 info.fromDoubleCheckNullFuncPtr[channel](dstPtr, info.convChannelList[channel]->pos(), channelPixelValue, dstValueIsNull);
293
294 return channelPixelValue;
295 }
void limitValue(qreal *value, qreal lowBound, qreal highBound)

References KisConvolutionWorkerFFT< _IteratorFactory_ >::FFTInfo::absoluteOffset, KisConvolutionWorkerFFT< _IteratorFactory_ >::FFTInfo::convChannelList, KisConvolutionWorkerFFT< _IteratorFactory_ >::FFTInfo::fftScale, KisConvolutionWorkerFFT< _IteratorFactory_ >::FFTInfo::fromDoubleCheckNullFuncPtr, KisConvolutionWorkerFFT< _IteratorFactory_ >::limitValue(), KisConvolutionWorkerFFT< _IteratorFactory_ >::FFTInfo::maxClamp, and KisConvolutionWorkerFFT< _IteratorFactory_ >::FFTInfo::minClamp.

◆ writeOneChannelFromCache()

template<class _IteratorFactory_ >
template<bool additionalMultiplierActive>
qreal KisConvolutionWorkerFFT< _IteratorFactory_ >::writeOneChannelFromCache ( quint8 * dstPtr,
const quint32 channel,
const FFTInfo & info,
double * channelValuePtr,
const qreal additionalMultiplier = 0.0 )
inline

Definition at line 298 of file kis_convolution_worker_fft.h.

302 {
303 qreal channelPixelValue;
304
305 if (additionalMultiplierActive) {
306 channelPixelValue = *channelValuePtr * info.fftScale * additionalMultiplier + info.absoluteOffset[channel];
307 } else {
308 channelPixelValue = *channelValuePtr * info.fftScale + info.absoluteOffset[channel];
309 }
310
311 limitValue(&channelPixelValue, info.minClamp[channel], info.maxClamp[channel]);
312
313 info.fromDoubleFuncPtr[channel](dstPtr, info.convChannelList[channel]->pos(), channelPixelValue);
314
315 return channelPixelValue;
316 }

References KisConvolutionWorkerFFT< _IteratorFactory_ >::FFTInfo::absoluteOffset, KisConvolutionWorkerFFT< _IteratorFactory_ >::FFTInfo::convChannelList, KisConvolutionWorkerFFT< _IteratorFactory_ >::FFTInfo::fftScale, KisConvolutionWorkerFFT< _IteratorFactory_ >::FFTInfo::fromDoubleFuncPtr, KisConvolutionWorkerFFT< _IteratorFactory_ >::limitValue(), KisConvolutionWorkerFFT< _IteratorFactory_ >::FFTInfo::maxClamp, and KisConvolutionWorkerFFT< _IteratorFactory_ >::FFTInfo::minClamp.

◆ writeResultToDevice()

template<class _IteratorFactory_ >
void KisConvolutionWorkerFFT< _IteratorFactory_ >::writeResultToDevice ( const QRect & rect,
const int cacheRowStride,
const int halfKernelWidth,
const int halfKernelHeight,
const FFTInfo & info,
const QRect & dataRect )
inline

Definition at line 318 of file kis_convolution_worker_fft.h.

323 {
324
325 typename _IteratorFactory_::HLineIterator hitDst =
326 _IteratorFactory_::createHLineIterator(this->m_painter->device(),
327 rect.x(), rect.y(), rect.width(),
328 dataRect);
329
330 int initialOffset = cacheRowStride * halfKernelHeight + halfKernelWidth;
331
332 const int channelCount = info.numChannels();
333 QVector<double*> channelPtr(channelCount);
334 const auto channelPtrBegin = channelPtr.begin();
335 const auto channelPtrEnd = channelPtr.end();
336
337 auto iFFt = m_channelFFT.constBegin();
338 for (auto i = channelPtrBegin; i != channelPtrEnd; ++i, ++iFFt) {
339 *i = (double*)*iFFt + initialOffset;
340 }
341
342 // prepare cache, reused in all loops
343 QVector<double*> cacheRowStart(channelCount);
344 const auto cacheRowStartBegin = cacheRowStart.begin();
345
346 for (int y = 0; y < rect.height(); ++y) {
347 // cache current channelPtr in cacheRowStart
348 memcpy(cacheRowStart.data(), channelPtr.data(), channelCount * sizeof(double*));
349
350 for (int x = 0; x < rect.width(); ++x) {
351 quint8 *dstPtr = hitDst->rawData();
352
353 if (info.alphaCachePos >= 0) {
354 bool alphaIsNullInDstSpace = false;
355
356 qreal alphaValue =
357 writeAlphaFromCache(dstPtr,
358 info.alphaCachePos,
359 info,
360 channelPtr.at(info.alphaCachePos),
361 &alphaIsNullInDstSpace);
362
363 if (!alphaIsNullInDstSpace &&
364 alphaValue > std::numeric_limits<qreal>::epsilon()) {
365
366 qreal alphaValueInv = 1.0 / alphaValue;
367
368 int k = 0;
369 for (auto i = channelPtrBegin; i != channelPtrEnd; ++i, ++k) {
370 if (k != info.alphaCachePos) {
371 writeOneChannelFromCache<true>(dstPtr,
372 k,
373 info,
374 *i,
375 alphaValueInv);
376 }
377 ++(*i);
378 }
379 } else {
380 int k = 0;
381 for (auto i = channelPtrBegin; i != channelPtrEnd; ++i, ++k) {
382 if (k != info.alphaCachePos) {
383 info.fromDoubleFuncPtr[k](dstPtr,
384 info.convChannelList[k]->pos(),
385 0.0);
386 }
387 ++(*i);
388 }
389 }
390 } else {
391 int k = 0;
392 for (auto i = channelPtrBegin; i != channelPtrEnd; ++i, ++k) {
393 writeOneChannelFromCache<false>(dstPtr,
394 k,
395 info,
396 *i);
397 ++(*i);
398 }
399 }
400
401 hitDst->nextPixel();
402 }
403
404 auto iRowStart = cacheRowStartBegin;
405 for (auto i = channelPtrBegin; i != channelPtrEnd; ++i, ++iRowStart) {
406 *i = *iRowStart + cacheRowStride;
407 }
408
409 hitDst->nextRow();
410 }
411
412 }
qreal writeAlphaFromCache(quint8 *dstPtr, const quint32 channel, const FFTInfo &info, double *channelValuePtr, bool *dstValueIsNull)

References KisConvolutionWorkerFFT< _IteratorFactory_ >::FFTInfo::alphaCachePos, KisConvolutionWorkerFFT< _IteratorFactory_ >::FFTInfo::convChannelList, KisPainter::device, KisConvolutionWorkerFFT< _IteratorFactory_ >::FFTInfo::fromDoubleFuncPtr, KisConvolutionWorkerFFT< _IteratorFactory_ >::m_channelFFT, KisConvolutionWorker< _IteratorFactory_ >::m_painter, KisConvolutionWorkerFFT< _IteratorFactory_ >::FFTInfo::numChannels(), and KisConvolutionWorkerFFT< _IteratorFactory_ >::writeAlphaFromCache().

Member Data Documentation

◆ m_channelFFT

template<class _IteratorFactory_ >
QVector<fftw_complex*> KisConvolutionWorkerFFT< _IteratorFactory_ >::m_channelFFT
private

Definition at line 554 of file kis_convolution_worker_fft.h.

◆ m_currentProgress

template<class _IteratorFactory_ >
float KisConvolutionWorkerFFT< _IteratorFactory_ >::m_currentProgress {0.0}
private

Definition at line 551 of file kis_convolution_worker_fft.h.

551{0.0};

◆ m_extraMem

template<class _IteratorFactory_ >
quint32 KisConvolutionWorkerFFT< _IteratorFactory_ >::m_extraMem {0}
private

Definition at line 550 of file kis_convolution_worker_fft.h.

550{0};

◆ m_fftHeight

template<class _IteratorFactory_ >
quint32 KisConvolutionWorkerFFT< _IteratorFactory_ >::m_fftHeight {0}
private

Definition at line 548 of file kis_convolution_worker_fft.h.

548{0};

◆ m_fftLength

template<class _IteratorFactory_ >
quint32 KisConvolutionWorkerFFT< _IteratorFactory_ >::m_fftLength {0}
private

Definition at line 549 of file kis_convolution_worker_fft.h.

549{0};

◆ m_fftWidth

template<class _IteratorFactory_ >
quint32 KisConvolutionWorkerFFT< _IteratorFactory_ >::m_fftWidth {0}
private

Definition at line 547 of file kis_convolution_worker_fft.h.

547{0};

◆ m_kernelFFT

template<class _IteratorFactory_ >
fftw_complex* KisConvolutionWorkerFFT< _IteratorFactory_ >::m_kernelFFT {0}
private

Definition at line 553 of file kis_convolution_worker_fft.h.

553{0};

The documentation for this class was generated from the following file: