Commit 30796fca authored by Dmitry Kazakov's avatar Dmitry Kazakov

Fix application of Gaussian Blur with FFTW (about 30% faster)

The patch fixes a slowdown we introduced when implemented
two-stage gaussian convolution application. This two-stage
approach is good for spacial convolution algorithm, but it
is no good for FFTW one. Because every kernel (even one-
dimensional) should be first split into 2D-wave-plane, which is
extremely slow.

CCBUG:407062
parent 588cc008
......@@ -99,6 +99,16 @@ KisConvolutionWorker<factory>* KisConvolutionPainter::createWorker(const KisConv
}
bool KisConvolutionPainter::supportsFFTW()
{
#ifdef HAVE_FFTW3
return true;
#else
return false;
#endif
}
KisConvolutionPainter::KisConvolutionPainter()
: KisPainter(),
m_enginePreference(NONE)
......
......@@ -47,6 +47,15 @@ public:
KisConvolutionPainter(KisPaintDeviceSP device);
KisConvolutionPainter(KisPaintDeviceSP device, KisSelectionSP selection);
enum TestingEnginePreference {
NONE,
SPATIAL,
FFTW
};
KisConvolutionPainter(KisPaintDeviceSP device, TestingEnginePreference enginePreference);
/**
* Convolve all channels in src using the specified kernel; there is only one kernel for all
* channels possible. By default the border pixels are not convolved, that is, convolving
......@@ -74,17 +83,12 @@ public:
*/
bool needsTransaction(const KisConvolutionKernelSP kernel) const;
static bool supportsFFTW();
protected:
friend class KisConvolutionPainterTest;
enum TestingEnginePreference {
NONE,
SPATIAL,
FFTW
};
KisConvolutionPainter(KisPaintDeviceSP device, TestingEnginePreference enginePreference);
private:
template<class factory>
......
......@@ -100,6 +100,17 @@ KisGaussianKernel::createVerticalKernel(qreal radius)
return KisConvolutionKernel::fromMatrix(matrix, 0, matrix.sum());
}
KisConvolutionKernelSP
KisGaussianKernel::createUniform2DKernel(qreal xRadius, qreal yRadius)
{
Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> h = createHorizontalMatrix(xRadius);
Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> v = createVerticalMatrix(yRadius);
Eigen::Matrix<qreal, Eigen::Dynamic, Eigen::Dynamic> uni = v * h;
return KisConvolutionKernel::fromMatrix(uni, 0, uni.sum());
}
void KisGaussianKernel::applyGaussian(KisPaintDeviceSP device,
const QRect& rect,
qreal xRadius, qreal yRadius,
......@@ -109,7 +120,22 @@ void KisGaussianKernel::applyGaussian(KisPaintDeviceSP device,
{
QPoint srcTopLeft = rect.topLeft();
if (xRadius > 0.0 && yRadius > 0.0) {
if (KisConvolutionPainter::supportsFFTW()) {
KisConvolutionPainter painter(device, KisConvolutionPainter::FFTW);
painter.setChannelFlags(channelFlags);
painter.setProgress(progressUpdater);
KisConvolutionKernelSP kernel2D = KisGaussianKernel::createUniform2DKernel(xRadius, yRadius);
QScopedPointer<KisTransaction> transaction;
if (createTransaction && painter.needsTransaction(kernel2D)) {
transaction.reset(new KisTransaction(device));
}
painter.applyMatrix(kernel2D, device, srcTopLeft, srcTopLeft, rect.size(), BORDER_REPEAT);
} else if (xRadius > 0.0 && yRadius > 0.0) {
KisPaintDeviceSP interm = new KisPaintDevice(device->colorSpace());
KisConvolutionKernelSP kernelHoriz = KisGaussianKernel::createHorizontalKernel(xRadius);
......
......@@ -41,6 +41,9 @@ public:
static KisConvolutionKernelSP
createVerticalKernel(qreal radius);
static KisConvolutionKernelSP
createUniform2DKernel(qreal xRadius, qreal yRadius);
static qreal sigmaFromRadius(qreal radius);
static int kernelSizeFromRadius(qreal radius);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment