Paste P237

GSoC status work on, Krita AvX optimization at 12-Jun-2018
ActivePublic

Authored by vanyossi on Jun 14 2018, 2:29 AM.
diff --git a/libs/image/kis_antialiasing_fade_maker.h b/libs/image/kis_antialiasing_fade_maker.h
index cc9b05d412..6ef1b25032 100644
--- a/libs/image/kis_antialiasing_fade_maker.h
+++ b/libs/image/kis_antialiasing_fade_maker.h
@@ -83,6 +83,26 @@ public:
return false;
}
+ qreal getRadius(){
+ return m_radius;
+ }
+
+ qreal getAntialiasingFadeStart(){
+ return m_antialiasingFadeStart;
+ }
+
+ qreal getFadeStartValue() {
+ return m_fadeStartValue;
+ }
+
+ qreal getAntialiasingFadeCoeff(){
+ return m_antialiasingFadeCoeff;
+ }
+
+ bool getAliasingEnabled(){
+ return m_enableAntialiasing;
+ }
+
private:
qreal m_radius;
quint8 m_fadeStartValue;
diff --git a/libs/image/kis_brush_mask_applicator_factories.cpp b/libs/image/kis_brush_mask_applicator_factories.cpp
index 2c54a61ef8..c8b14e9fd8 100644
--- a/libs/image/kis_brush_mask_applicator_factories.cpp
+++ b/libs/image/kis_brush_mask_applicator_factories.cpp
@@ -20,6 +20,9 @@
#include "kis_circle_mask_generator.h"
#include "kis_circle_mask_generator_p.h"
+#include "kis_gauss_circle_mask_generator_p.h"
+#include "kis_curve_circle_mask_generator_p.h"
+
#include "kis_brush_mask_applicators.h"
#include "kis_brush_mask_applicator_base.h"
@@ -42,6 +45,24 @@ MaskApplicatorFactory<KisCircleMaskGenerator, KisBrushMaskVectorApplicator>::cre
return new KisBrushMaskVectorApplicator<KisCircleMaskGenerator,Vc::CurrentImplementation::current()>(maskGenerator);
}
+template<>
+template<>
+MaskApplicatorFactory<KisGaussCircleMaskGenerator, KisBrushMaskVectorApplicator>::ReturnType
+MaskApplicatorFactory<KisGaussCircleMaskGenerator, KisBrushMaskVectorApplicator>::create<Vc::CurrentImplementation::current()>(ParamType maskGenerator)
+{
+ return new KisBrushMaskVectorApplicator<KisGaussCircleMaskGenerator,Vc::CurrentImplementation::current()>(maskGenerator);
+}
+
+
+template<>
+template<>
+MaskApplicatorFactory<KisCurveCircleMaskGenerator, KisBrushMaskVectorApplicator>::ReturnType
+MaskApplicatorFactory<KisCurveCircleMaskGenerator, KisBrushMaskVectorApplicator>::create<Vc::CurrentImplementation::current()>(ParamType maskGenerator)
+{
+ return new KisBrushMaskVectorApplicator<KisCurveCircleMaskGenerator,Vc::CurrentImplementation::current()>(maskGenerator);
+}
+
+
#if defined HAVE_VC
struct KisCircleMaskGenerator::FastRowProcessor
@@ -134,4 +155,224 @@ FastRowProcessor::process<Vc::CurrentImplementation::current()>(float* buffer, i
}
}
+
+struct KisGaussCircleMaskGenerator::FastRowProcessor
+{
+ FastRowProcessor(KisGaussCircleMaskGenerator *maskGenerator)
+ : d(maskGenerator->d.data()) {}
+
+ template<Vc::Implementation _impl>
+ void process(float* buffer, int width, float y, float cosa, float sina,
+ float centerX, float centerY);
+
+ KisGaussCircleMaskGenerator::Private *d;
+};
+
+template<> void KisGaussCircleMaskGenerator::
+FastRowProcessor::process<Vc::CurrentImplementation::current()>(float* buffer, int width, float y, float cosa, float sina,
+ float centerX, float centerY)
+{
+ const bool antialiasOn = d->fadeMaker.getAliasingEnabled();
+
+ float y_ = y - centerY;
+ float sinay_ = sina * y_;
+ float cosay_ = cosa * y_;
+
+ float* bufferPointer = buffer;
+
+ Vc::float_v currentIndices = Vc::float_v::IndexesFromZero();
+
+ Vc::float_v increment((float)Vc::float_v::size());
+ Vc::float_v vCenterX(centerX);
+ Vc::float_v vCenter(d->center);
+
+ Vc::float_v vCosa(cosa);
+ Vc::float_v vSina(sina);
+ Vc::float_v vCosaY_(cosay_);
+ Vc::float_v vSinaY_(sinay_);
+
+ Vc::float_v vYCoeff(d->ycoef);
+ Vc::float_v vDistfactor(d->distfactor);
+ Vc::float_v vAlphafactor(d->alphafactor);
+
+ Vc::float_v vFadeRadius(d->fadeMaker.getRadius());
+ Vc::float_v vFadeStartValue(d->fadeMaker.getFadeStartValue());
+ Vc::float_v vFadeAFadeStart(d->fadeMaker.getAntialiasingFadeStart());
+ Vc::float_v vFadeAFadeCoeff(d->fadeMaker.getAntialiasingFadeCoeff());
+
+ Vc::float_v vOne(Vc::One);
+ Vc::float_v vZero(Vc::Zero);
+ Vc::float_v vValMax(255.f);
+
+ for (int i=0; i < width; i+= Vc::float_v::size()){
+
+ Vc::float_v x_ = currentIndices - vCenterX;
+
+ Vc::float_v xr = x_ * vCosa - vSinaY_;
+ Vc::float_v yr = x_ * vSina + vCosaY_;
+
+ Vc::float_v dist = sqrt(pow2(xr) + pow2(yr * vYCoeff));
+
+ // BEGIN FadeMaker needFade vectorized
+ // follow fademaker rules for outsideMask
+ Vc::float_m outsideMask = dist > vFadeRadius;
+ dist(outsideMask) = vOne;
+
+ Vc::float_m fadeStartMask(false);
+ // if antialias is off, do not process
+ if(antialiasOn){
+ fadeStartMask = dist > vFadeAFadeStart;
+ dist((outsideMask ^ fadeStartMask) & fadeStartMask) = (vFadeStartValue + (dist - vFadeAFadeStart) * vFadeAFadeCoeff) / vValMax;
+ }
+ Vc::float_m excludeMask(outsideMask | fadeStartMask);
+
+ if (!excludeMask.isFull()) {
+ Vc::float_v valDist = dist * vDistfactor;
+ Vc::float_v fullFade = vAlphafactor * ( d->vErf(valDist + vCenter) - d->vErf(valDist - vCenter));
+
+ Vc::float_m mask;
+ // Mask undefined values, out of range are out of mask
+ mask = Vc::isfinite(fullFade);
+ fullFade.setZero(!mask);
+
+ // Mask in the inner circe of the mask
+ mask = fullFade < vZero;
+ fullFade.setZero(mask);
+
+ // Mask the outter circle
+ mask = fullFade > 254.974f;
+ fullFade(mask) = vValMax;
+
+ // Mask (value - value), presicion errors.
+ Vc::float_v vFade = (vValMax - fullFade) / vValMax;
+
+ // return original dist values before vFade transform
+ vFade(excludeMask) = dist;
+ vFade.store(bufferPointer, Vc::Aligned);
+
+ } else {
+ dist.store(bufferPointer, Vc::Aligned);
+ }
+ currentIndices = currentIndices + increment;
+
+ bufferPointer += Vc::float_v::size();
+ }
+}
+
+struct KisCurveCircleMaskGenerator::FastRowProcessor
+{
+ FastRowProcessor(KisCurveCircleMaskGenerator *maskGenerator)
+ : d(maskGenerator->d.data()) {}
+
+ template<Vc::Implementation _impl>
+ void process(float* buffer, int width, float y, float cosa, float sina,
+ float centerX, float centerY);
+
+ KisCurveCircleMaskGenerator::Private *d;
+};
+
+
+template<> void KisCurveCircleMaskGenerator::
+FastRowProcessor::process<Vc::CurrentImplementation::current()>(float* buffer, int width, float y, float cosa, float sina,
+ float centerX, float centerY)
+{
+ const bool antialiasOn = d->fadeMaker.getAliasingEnabled();
+
+ float y_ = y - centerY;
+ float sinay_ = sina * y_;
+ float cosay_ = cosa * y_;
+
+ float* bufferPointer = buffer;
+
+ qreal* curveDataPointer = d->curveData.data();
+
+ Vc::float_v currentIndices = Vc::float_v::IndexesFromZero();
+
+ Vc::float_v increment((float)Vc::float_v::size());
+ Vc::float_v vCenterX(centerX);
+
+ Vc::float_v vCosa(cosa);
+ Vc::float_v vSina(sina);
+ Vc::float_v vCosaY_(cosay_);
+ Vc::float_v vSinaY_(sinay_);
+
+ Vc::float_v vYCoeff(d->ycoef);
+ Vc::float_v vXCoeff(d->xcoef);
+ Vc::float_v vCurveResolution(d->curveResolution);
+
+ Vc::float_v vCurvedData(Vc::Zero);
+ Vc::float_v vCurvedData1(Vc::Zero);
+
+ Vc::float_v vFadeRadius(d->fadeMaker.getRadius());
+ Vc::float_v vFadeStartValue(d->fadeMaker.getFadeStartValue());
+ Vc::float_v vFadeAFadeStart(d->fadeMaker.getAntialiasingFadeStart());
+ Vc::float_v vFadeAFadeCoeff(d->fadeMaker.getAntialiasingFadeCoeff());
+
+ Vc::float_v vOne(Vc::One);
+ Vc::float_v vZero(Vc::Zero);
+ Vc::float_v vValMax(255.f);
+
+ for (int i=0; i < width; i+= Vc::float_v::size()){
+
+ Vc::float_v x_ = currentIndices - vCenterX;
+
+ Vc::float_v xr = x_ * vCosa - vSinaY_;
+ Vc::float_v yr = x_ * vSina + vCosaY_;
+
+ Vc::float_v dist = pow2(xr * vXCoeff) + pow2(yr * vYCoeff);
+
+ // BEGIN FadeMaker needFade vectorized
+ // follow fademaker rules for outsideMask
+ Vc::float_m outsideMask = dist > vFadeRadius;
+ dist(outsideMask) = vOne;
+
+ Vc::float_m fadeStartMask(false);
+ // if antialias is off, do not process
+ if(antialiasOn){
+ fadeStartMask = dist > vFadeAFadeStart;
+ dist((outsideMask ^ fadeStartMask) & fadeStartMask) = (vFadeStartValue + (dist - vFadeAFadeStart) * vFadeAFadeCoeff) / vValMax;
+ }
+
+ Vc::float_m excludeMask = outsideMask | fadeStartMask;
+
+ if (!excludeMask.isFull()) {
+ Vc::float_v valDist = dist * vCurveResolution;
+ // truncate
+ Vc::SimdArray<quint16,Vc::float_v::size()> vAlphaValue(valDist);
+ Vc::float_v vFloatAlphaValue = vAlphaValue;
+
+ Vc::float_v alphaValueF = valDist - vFloatAlphaValue;
+
+ vCurvedData.gather(curveDataPointer,vAlphaValue);
+ vCurvedData1.gather(curveDataPointer,vAlphaValue + 1);
+// Vc::float_v vCurvedData1(curveDataPointer,vAlphaValue + 1);
+
+ // vAlpha
+ Vc::float_v fullFade = (
+ (1.0f - alphaValueF) * vCurvedData +
+ alphaValueF * vCurvedData1);
+
+ Vc::float_m mask;
+ // Mask in the inner circe of the mask
+ mask = fullFade < vZero;
+ fullFade.setZero(mask);
+
+ // Mask outer circle of mask
+ mask = fullFade >= vOne;
+ Vc::float_v vFade = (1.0f - fullFade);
+ vFade.setZero(mask);
+
+ // return original dist values before vFade transform
+ vFade(excludeMask) = dist;
+ vFade.store(bufferPointer, Vc::Aligned);
+
+ } else {
+ dist.store(bufferPointer, Vc::Aligned);
+ }
+ currentIndices = currentIndices + increment;
+
+ bufferPointer += Vc::float_v::size();
+ }
+}
+
#endif /* defined HAVE_VC */
diff --git a/libs/image/kis_circle_mask_generator.cpp b/libs/image/kis_circle_mask_generator.cpp
index a27db05731..6c64dcf3c1 100644
--- a/libs/image/kis_circle_mask_generator.cpp
+++ b/libs/image/kis_circle_mask_generator.cpp
@@ -139,3 +139,8 @@ void KisCircleMaskGenerator::setSoftness(qreal softness)
d->transformedFadeX = d->xfadecoef * safeSoftnessCoeff;
d->transformedFadeY = d->yfadecoef * safeSoftnessCoeff;
}
+
+void KisCircleMaskGenerator::resetMaskApplicator(bool forceScalar)
+{
+ d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisCircleMaskGenerator, KisBrushMaskVectorApplicator> >(this,forceScalar));
+}
diff --git a/libs/image/kis_circle_mask_generator.h b/libs/image/kis_circle_mask_generator.h
index c6aaa04143..0fdb389d9a 100644
--- a/libs/image/kis_circle_mask_generator.h
+++ b/libs/image/kis_circle_mask_generator.h
@@ -49,6 +49,8 @@ public:
void setSoftness(qreal softness) override;
void setScale(qreal scaleX, qreal scaleY) override;
+ void resetMaskApplicator(bool forceScalar);
+
private:
qreal norme(qreal a, qreal b) const {
diff --git a/libs/image/kis_curve_circle_mask_generator.cpp b/libs/image/kis_curve_circle_mask_generator.cpp
index 4df3be0f07..77a39565a7 100644
--- a/libs/image/kis_curve_circle_mask_generator.cpp
+++ b/libs/image/kis_curve_circle_mask_generator.cpp
@@ -17,9 +17,27 @@
*/
#include <compositeops/KoVcMultiArchBuildSupport.h> //MSVC requires that Vc come first
-
#include <cmath>
+#include <config-vc.h>
+#ifdef HAVE_VC
+#if defined(__clang__)
+#pragma GCC diagnostic ignored "-Wundef"
+#pragma GCC diagnostic ignored "-Wlocal-type-template-args"
+#endif
+#if defined _MSC_VER
+// Lets shut up the "possible loss of data" and "forcing value to bool 'true' or 'false'
+#pragma warning ( push )
+#pragma warning ( disable : 4244 )
+#pragma warning ( disable : 4800 )
+#endif
+#include <Vc/Vc>
+#include <Vc/IO>
+#if defined _MSC_VER
+#pragma warning ( pop )
+#endif
+#endif
+
#include <QDomDocument>
#include <QVector>
#include <QPointF>
@@ -29,38 +47,13 @@
#include "kis_fast_math.h"
#include "kis_base_mask_generator.h"
-#include "kis_curve_circle_mask_generator.h"
-#include "kis_cubic_curve.h"
#include "kis_antialiasing_fade_maker.h"
+#include "kis_brush_mask_applicator_factories.h"
+#include "kis_curve_circle_mask_generator.h"
+#include "kis_curve_circle_mask_generator_p.h"
+#include "kis_cubic_curve.h"
-struct Q_DECL_HIDDEN KisCurveCircleMaskGenerator::Private
-{
- Private(bool enableAntialiasing)
- : fadeMaker(*this, enableAntialiasing)
- {
- }
-
- Private(const Private &rhs)
- : xcoef(rhs.xcoef),
- ycoef(rhs.ycoef),
- curveResolution(rhs.curveResolution),
- curveData(rhs.curveData),
- curvePoints(rhs.curvePoints),
- dirty(true),
- fadeMaker(rhs.fadeMaker,*this)
- {
- }
-
- qreal xcoef, ycoef;
- qreal curveResolution;
- QVector<qreal> curveData;
- QList<QPointF> curvePoints;
- bool dirty;
-
- KisAntialiasingFadeMaker1D<Private> fadeMaker;
- inline quint8 value(qreal dist) const;
-};
KisCurveCircleMaskGenerator::KisCurveCircleMaskGenerator(qreal diameter, qreal ratio, qreal fh, qreal fv, int spikes, const KisCubicCurve &curve, bool antialiasEdges)
: KisMaskGenerator(diameter, ratio, fh, fv, spikes, antialiasEdges, CIRCLE, SoftId), d(new Private(antialiasEdges))
@@ -73,12 +66,15 @@ KisCurveCircleMaskGenerator::KisCurveCircleMaskGenerator(qreal diameter, qreal r
d->dirty = false;
setScale(1.0, 1.0);
+
+ d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisCurveCircleMaskGenerator, KisBrushMaskVectorApplicator> >(this));
}
KisCurveCircleMaskGenerator::KisCurveCircleMaskGenerator(const KisCurveCircleMaskGenerator &rhs)
: KisMaskGenerator(rhs),
d(new Private(*rhs.d))
{
+ d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisCurveCircleMaskGenerator, KisBrushMaskVectorApplicator> >(this));
}
KisCurveCircleMaskGenerator::~KisCurveCircleMaskGenerator()
@@ -108,6 +104,16 @@ bool KisCurveCircleMaskGenerator::shouldSupersample() const
return effectiveSrcWidth() < 10 || effectiveSrcHeight() < 10;
}
+bool KisCurveCircleMaskGenerator::shouldVectorize() const
+{
+ return !shouldSupersample() && spikes() == 2;
+}
+
+KisBrushMaskApplicatorBase* KisCurveCircleMaskGenerator::applicator()
+{
+ return d->applicator.data();
+}
+
inline quint8 KisCurveCircleMaskGenerator::Private::value(qreal dist) const
{
qreal distance = dist * curveResolution;
@@ -118,6 +124,7 @@ inline quint8 KisCurveCircleMaskGenerator::Private::value(qreal dist) const
qreal alpha = (
(1.0 - alphaValueF) * curveData.at(alphaValue) +
alphaValueF * curveData.at(alphaValue+1));
+
return (1.0 - alpha) * 255;
}
@@ -178,3 +185,8 @@ void KisCurveCircleMaskGenerator::transformCurveForSoftness(qreal softness,const
KisCubicCurve curve(newList);
result = curve.floatTransfer( curveResolution );
}
+
+void KisCurveCircleMaskGenerator::resetMaskApplicator(bool forceScalar)
+{
+ d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisCurveCircleMaskGenerator, KisBrushMaskVectorApplicator> >(this,forceScalar));
+}
diff --git a/libs/image/kis_curve_circle_mask_generator.h b/libs/image/kis_curve_circle_mask_generator.h
index a5db1ae129..1b75196209 100644
--- a/libs/image/kis_curve_circle_mask_generator.h
+++ b/libs/image/kis_curve_circle_mask_generator.h
@@ -19,11 +19,12 @@
#ifndef _KIS_CURVE_CIRCLE_MASK_GENERATOR_H_
#define _KIS_CURVE_CIRCLE_MASK_GENERATOR_H_
-#include <QScopedPointer>
-#include "kritaimage_export.h"
-
#include <QList>
#include <QVector>
+#include <QScopedPointer>
+
+#include "kritaimage_export.h"
+#include "kis_mask_generator.h"
class KisCubicCurve;
class QDomElement;
@@ -38,7 +39,8 @@ class QPointF;
*/
class KRITAIMAGE_EXPORT KisCurveCircleMaskGenerator : public KisMaskGenerator
{
-
+public:
+ struct FastRowProcessor;
public:
KisCurveCircleMaskGenerator(qreal radius, qreal ratio, qreal fh, qreal fv, int spikes,const KisCubicCurve& curve, bool antialiasEdges);
@@ -55,6 +57,11 @@ public:
void toXML(QDomDocument& , QDomElement&) const override;
void setSoftness(qreal softness) override;
+ bool shouldVectorize() const override;
+ KisBrushMaskApplicatorBase* applicator() override;
+
+ void resetMaskApplicator(bool forceScalar);
+
static void transformCurveForSoftness(qreal softness,const QList<QPointF> &points, int curveResolution, QVector<qreal> &result);
private:
diff --git a/libs/image/kis_curve_circle_mask_generator_p.h b/libs/image/kis_curve_circle_mask_generator_p.h
new file mode 100644
index 0000000000..2497963b62
--- /dev/null
+++ b/libs/image/kis_curve_circle_mask_generator_p.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2010 Lukáš Tvrdý <lukast.dev@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KIS_CURVE_CIRCLE_MASK_GENERATOR_P_H
+#define KIS_CURVE_CIRCLE_MASK_GENERATOR_P_H
+
+#include "kis_antialiasing_fade_maker.h"
+#include "kis_brush_mask_applicator_base.h"
+
+struct Q_DECL_HIDDEN KisCurveCircleMaskGenerator::Private
+{
+ Private(bool enableAntialiasing)
+ : fadeMaker(*this, enableAntialiasing)
+ {
+ }
+
+ Private(const Private &rhs)
+ : xcoef(rhs.xcoef),
+ ycoef(rhs.ycoef),
+ curveResolution(rhs.curveResolution),
+ curveData(rhs.curveData),
+ curvePoints(rhs.curvePoints),
+ dirty(true),
+ fadeMaker(rhs.fadeMaker,*this)
+ {
+ }
+
+ qreal xcoef, ycoef;
+ qreal curveResolution;
+ QVector<qreal> curveData;
+ QList<QPointF> curvePoints;
+ bool dirty;
+
+ KisAntialiasingFadeMaker1D<Private> fadeMaker;
+ QScopedPointer<KisBrushMaskApplicatorBase> applicator;
+
+ inline quint8 value(qreal dist) const;
+};
+
+#endif // KIS_CURVE_CIRCLE_MASK_GENERATOR_P_H
diff --git a/libs/image/kis_gauss_circle_mask_generator.cpp b/libs/image/kis_gauss_circle_mask_generator.cpp
index 50977c95f6..91e08a7cd7 100644
--- a/libs/image/kis_gauss_circle_mask_generator.cpp
+++ b/libs/image/kis_gauss_circle_mask_generator.cpp
@@ -20,6 +20,25 @@
#include <compositeops/KoVcMultiArchBuildSupport.h> //MSVC requires that Vc come first
#include <cmath>
+#include <config-vc.h>
+#ifdef HAVE_VC
+#if defined(__clang__)
+#pragma GCC diagnostic ignored "-Wundef"
+#pragma GCC diagnostic ignored "-Wlocal-type-template-args"
+#endif
+#if defined _MSC_VER
+// Lets shut up the "possible loss of data" and "forcing value to bool 'true' or 'false'
+#pragma warning ( push )
+#pragma warning ( disable : 4244 )
+#pragma warning ( disable : 4800 )
+#endif
+#include <Vc/Vc>
+#include <Vc/IO>
+#if defined _MSC_VER
+#pragma warning ( pop )
+#endif
+#endif
+
#include <QDomDocument>
#include <QVector>
#include <QPointF>
@@ -29,8 +48,11 @@
#include "kis_fast_math.h"
#include "kis_base_mask_generator.h"
-#include "kis_gauss_circle_mask_generator.h"
#include "kis_antialiasing_fade_maker.h"
+#include "kis_brush_mask_applicator_factories.h"
+#include "kis_brush_mask_applicator_base.h"
+#include "kis_gauss_circle_mask_generator.h"
+#include "kis_gauss_circle_mask_generator_p.h"
#define M_SQRT_2 1.41421356237309504880
@@ -41,47 +63,28 @@
#endif
-struct Q_DECL_HIDDEN KisGaussCircleMaskGenerator::Private
-{
- Private(bool enableAntialiasing)
- : fadeMaker(*this, enableAntialiasing)
- {
- }
-
- Private(const Private &rhs)
- : ycoef(rhs.ycoef),
- fade(rhs.fade),
- center(rhs.center),
- distfactor(rhs.distfactor),
- alphafactor(rhs.alphafactor),
- fadeMaker(rhs.fadeMaker, *this)
- {
- }
-
- qreal ycoef;
- qreal fade;
- qreal center, distfactor, alphafactor;
- KisAntialiasingFadeMaker1D<Private> fadeMaker;
-
- inline quint8 value(qreal dist) const;
-};
-
KisGaussCircleMaskGenerator::KisGaussCircleMaskGenerator(qreal diameter, qreal ratio, qreal fh, qreal fv, int spikes, bool antialiasEdges)
: KisMaskGenerator(diameter, ratio, fh, fv, spikes, antialiasEdges, CIRCLE, GaussId),
d(new Private(antialiasEdges))
{
d->ycoef = 1.0 / ratio;
d->fade = 1.0 - (fh + fv) / 2.0;
+
if (d->fade == 0.0) d->fade = 1e-6;
else if (d->fade == 1.0) d->fade = 1.0 - 1e-6; // would become undefined for fade == 0 or 1
+
d->center = (2.5 * (6761.0*d->fade-10000.0))/(M_SQRT_2*6761.0*d->fade);
d->alphafactor = 255.0 / (2.0 * erf(d->center));
+
+ d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisGaussCircleMaskGenerator, KisBrushMaskVectorApplicator> >(this));
+
}
KisGaussCircleMaskGenerator::KisGaussCircleMaskGenerator(const KisGaussCircleMaskGenerator &rhs)
: KisMaskGenerator(rhs),
d(new Private(*rhs.d))
{
+ d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisGaussCircleMaskGenerator, KisBrushMaskVectorApplicator> >(this));
}
KisMaskGenerator* KisGaussCircleMaskGenerator::clone() const
@@ -109,6 +112,21 @@ inline quint8 KisGaussCircleMaskGenerator::Private::value(qreal dist) const
return (quint8) 255 - ret;
}
+bool KisGaussCircleMaskGenerator::shouldSupersample() const
+{
+ return effectiveSrcWidth() < 10 || effectiveSrcHeight() < 10;
+}
+
+bool KisGaussCircleMaskGenerator::shouldVectorize() const
+{
+ return !shouldSupersample() && spikes() == 2;
+}
+
+KisBrushMaskApplicatorBase* KisGaussCircleMaskGenerator::applicator()
+{
+ return d->applicator.data();
+}
+
quint8 KisGaussCircleMaskGenerator::valueAt(qreal x, qreal y) const
{
if (isEmpty()) return 255;
@@ -125,3 +143,8 @@ quint8 KisGaussCircleMaskGenerator::valueAt(qreal x, qreal y) const
return d->value(dist);
}
+
+void KisGaussCircleMaskGenerator::resetMaskApplicator(bool forceScalar)
+{
+ d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisGaussCircleMaskGenerator, KisBrushMaskVectorApplicator> >(this,forceScalar));
+}
diff --git a/libs/image/kis_gauss_circle_mask_generator.h b/libs/image/kis_gauss_circle_mask_generator.h
index ae6158c9ee..1872641f48 100644
--- a/libs/image/kis_gauss_circle_mask_generator.h
+++ b/libs/image/kis_gauss_circle_mask_generator.h
@@ -20,16 +20,18 @@
#ifndef _KIS_GAUSS_MASK_GENERATOR_H_
#define _KIS_GAUSS_MASK_GENERATOR_H_
-#include <QScopedPointer>
#include "kritaimage_export.h"
+#include "kis_mask_generator.h"
+#include <QScopedPointer>
/**
* This mask generator uses a Gaussian-blurred circle
*/
class KRITAIMAGE_EXPORT KisGaussCircleMaskGenerator : public KisMaskGenerator
{
-
+public:
+ struct FastRowProcessor;
public:
KisGaussCircleMaskGenerator(qreal diameter, qreal ratio, qreal fh, qreal fv, int spikes, bool antialiasEdges);
@@ -41,6 +43,13 @@ public:
void setScale(qreal scaleX, qreal scaleY) override;
+ bool shouldSupersample() const override;
+
+ bool shouldVectorize() const override;
+ KisBrushMaskApplicatorBase* applicator() override;
+
+ void resetMaskApplicator(bool forceScalar);
+
private:
qreal norme(qreal a, qreal b) const {
diff --git a/libs/image/kis_gauss_circle_mask_generator_p.h b/libs/image/kis_gauss_circle_mask_generator_p.h
new file mode 100644
index 0000000000..ff139f5039
--- /dev/null
+++ b/libs/image/kis_gauss_circle_mask_generator_p.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2008-2009 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _KIS_GAUSS_MASK_GENERATOR_P_H_
+#define _KIS_GAUSS_MASK_GENERATOR_P_H_
+
+#include "kis_antialiasing_fade_maker.h"
+#include "kis_brush_mask_applicator_base.h"
+
+struct Q_DECL_HIDDEN KisGaussCircleMaskGenerator::Private
+{
+ Private(bool enableAntialiasing)
+ : fadeMaker(*this, enableAntialiasing)
+ {
+ }
+
+ Private(const Private &rhs)
+ : ycoef(rhs.ycoef),
+ fade(rhs.fade),
+ center(rhs.center),
+ distfactor(rhs.distfactor),
+ alphafactor(rhs.alphafactor),
+ fadeMaker(rhs.fadeMaker, *this)
+ {
+ }
+
+ qreal ycoef;
+ qreal fade;
+ qreal center;
+ qreal distfactor;
+ qreal alphafactor;
+ KisAntialiasingFadeMaker1D<Private> fadeMaker;
+
+ QScopedPointer<KisBrushMaskApplicatorBase> applicator;
+
+ inline quint8 value(qreal dist) const;
+
+ #if defined HAVE_VC
+ // vectorized erf function, precision 1e-5
+ Vc::float_v vErf(Vc::float_v x) {
+ Vc::float_v xa = abs(x);
+ Vc::float_m precisionLimit(xa >= 9.3f); // wrong result for any number beyond this
+ xa(precisionLimit) = 0;
+ Vc::float_v sign(Vc::One);
+ Vc::float_m invertMask = x < 0.f;
+ sign(invertMask) = -1.f;
+
+ // CONSTANTS
+ float a1 = 0.254829592;
+ float a2 = -0.284496736;
+ float a3 = 1.421413741;
+ float a4 = -1.453152027;
+ float a5 = 1.061405429;
+ float p = 0.3275911;
+
+ Vc::float_v t = 1.0f / (1.0f + p * xa);
+ Vc::float_v y = 1.0f - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * exp(-xa * xa);
+ y(precisionLimit) = 1.0f;
+ return sign * y;
+ }
+ #endif /* defined HAVE_VC */
+};
+
+#endif /* _KIS_GAUSS_MASK_GENERATOR_P_H_ */
diff --git a/libs/image/tests/CMakeLists.txt b/libs/image/tests/CMakeLists.txt
index 90a5e6289e..979f93f1dd 100644
--- a/libs/image/tests/CMakeLists.txt
+++ b/libs/image/tests/CMakeLists.txt
@@ -124,6 +124,8 @@ ecm_add_tests(
kis_marker_painter_test.cpp
kis_lazy_brush_test.cpp
kis_colorize_mask_test.cpp
+ kis_mask_similarity_test.cpp
+ KisMaskGeneratorBenchmark.cpp
NAME_PREFIX "krita-image-"
LINK_LIBRARIES kritaimage Qt5::Test)
diff --git a/libs/image/tests/KisMaskGeneratorBenchmark.cpp b/libs/image/tests/KisMaskGeneratorBenchmark.cpp
new file mode 100644
index 0000000000..6488fdb237
--- /dev/null
+++ b/libs/image/tests/KisMaskGeneratorBenchmark.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2018 Iván Santa María <ghevan@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <QTest>
+#include <QPointF>
+#include <KoColor.h>
+#include <QElapsedTimer>
+
+#include "KisMaskGeneratorBenchmark.h"
+
+#include "kis_mask_similarity_test.h"
+
+#include "kis_brush_mask_applicator_base.h"
+#include "kis_mask_generator.h"
+#include "kis_cubic_curve.h"
+#include "krita_utils.h"
+
+#include "testutil.h"
+
+class KisMaskGeneratorBenchmarkTester
+{
+public:
+ KisMaskGeneratorBenchmarkTester(KisBrushMaskApplicatorBase *_applicatorBase, QRect _bounds)
+ : applicatorBase(_applicatorBase)
+ , m_bounds(_bounds)
+ {
+ KisFixedPaintDeviceSP m_paintDev = new KisFixedPaintDevice(m_colorSpace);
+ m_paintDev->setRect(m_bounds);
+ m_paintDev->initialize(255);
+
+ MaskProcessingData data(m_paintDev, m_colorSpace,
+ 0.0, 1.0,
+ m_bounds.width() / 2.0, m_bounds.height() / 2.0,0);
+
+ // Start Benchmark
+ applicatorBase->initializeData(&data);
+
+ QElapsedTimer maskGenerationTime;
+ maskGenerationTime.start();
+
+ QBENCHMARK {
+
+ applicatorBase->process(m_bounds);
+ }
+ }
+
+protected:
+ const KoColorSpace *m_colorSpace = KoColorSpaceRegistry::instance()->rgb8();
+ QRect m_bounds;
+
+ KisBrushMaskApplicatorBase *applicatorBase;
+ KisFixedPaintDeviceSP m_paintDev;
+};
+
+void KisMaskGeneratorBenchmark::testDefaultScalarMask()
+{
+ QRect bounds(0,0,1000,1000);
+ {
+ KisCircleMaskGenerator circScalar(1000, 1.0, 0.5, 0.5, 2, true);
+ circScalar.resetMaskApplicator(true); // Force usage of scalar backend
+
+ KisMaskGeneratorBenchmarkTester(circScalar.applicator(), bounds);
+ }
+}
+
+void KisMaskGeneratorBenchmark::testDefaultVectorMask()
+{
+ QRect bounds(0,0,1000,1000);
+ {
+ KisCircleMaskGenerator circVectr(1000, 1.0, 0.5, 0.5, 2, true);
+ KisMaskGeneratorBenchmarkTester(circVectr.applicator(), bounds);
+ }
+}
+
+void KisMaskGeneratorBenchmark::testCircularGaussScalarMask()
+{
+ QRect bounds(0,0,1000,1000);
+ {
+ KisGaussCircleMaskGenerator circScalar(1000, 1.0, 0.5, 0.5, 2, true);
+ circScalar.setDiameter(1000);
+ circScalar.resetMaskApplicator(true); // Force usage of scalar backend
+
+ KisMaskGeneratorBenchmarkTester(circScalar.applicator(), bounds);
+ }
+}
+
+void KisMaskGeneratorBenchmark::testCircularGaussVectorMask()
+{
+ QRect bounds(0,0,1000,1000);
+ {
+ KisGaussCircleMaskGenerator circVectr(1000, 1.0, 0.5, 0.5, 2, true);
+ circVectr.setDiameter(1000);
+ KisMaskGeneratorBenchmarkTester(circVectr.applicator(), bounds);
+ }
+}
+
+void KisMaskGeneratorBenchmark::testCircularSoftScalarMask()
+{
+ QRect bounds(0,0,1000,1000);
+ KisCubicCurve pointsCurve;
+ pointsCurve.fromString(QString("0,1;1,0"));
+ {
+ KisCurveCircleMaskGenerator circScalar(1000, 1.0, 0.5, 0.5, 2, pointsCurve, true);
+ circScalar.setSoftness(0.5);
+ circScalar.resetMaskApplicator(true); // Force usage of scalar backend
+
+ KisMaskGeneratorBenchmarkTester(circScalar.applicator(), bounds);
+ }
+}
+
+void KisMaskGeneratorBenchmark::testCircularSoftVectorMask()
+{
+ QRect bounds(0,0,1000,1000);
+ KisCubicCurve pointsCurve;
+ pointsCurve.fromString(QString("0,1;1,0"));
+ {
+ KisCurveCircleMaskGenerator circVectr(1000, 1.0, 0.5, 0.5, 2, pointsCurve, true);
+ circVectr.setSoftness(0.5);
+ KisMaskGeneratorBenchmarkTester(circVectr.applicator(), bounds);
+ }
+}
+
+QTEST_MAIN(KisMaskGeneratorBenchmark)
diff --git a/libs/image/tests/KisMaskGeneratorBenchmark.h b/libs/image/tests/KisMaskGeneratorBenchmark.h
new file mode 100644
index 0000000000..86318b1605
--- /dev/null
+++ b/libs/image/tests/KisMaskGeneratorBenchmark.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018 Iván Santa María <ghevan@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KISMASKGENERATORBENCHMARK_H
+#define KISMASKGENERATORBENCHMARK_H
+
+#include <QtTest>
+
+class KisMaskGeneratorBenchmark : public QObject
+{
+ Q_OBJECT
+private Q_SLOTS:
+
+ void testDefaultScalarMask();
+ void testDefaultVectorMask();
+
+ void testCircularGaussScalarMask();
+ void testCircularGaussVectorMask();
+
+ void testCircularSoftScalarMask();
+ void testCircularSoftVectorMask();
+};
+
+#endif // KISMASKGENERATORBENCHMARK_H
diff --git a/libs/image/tests/kis_mask_similarity_test.cpp b/libs/image/tests/kis_mask_similarity_test.cpp
new file mode 100644
index 0000000000..ae13ffb33d
--- /dev/null
+++ b/libs/image/tests/kis_mask_similarity_test.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2018 Iván Santa María <ghevan@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "kis_mask_similarity_test.h"
+
+#include <QTest>
+#include <QPointF>
+
+#include <KoColor.h>
+#include <testutil.h>
+
+#include "kis_brush_mask_applicator_base.h"
+#include "kis_mask_generator.h"
+#include "kis_cubic_curve.h"
+#include "krita_utils.h"
+
+enum MaskType {
+ DEFAULT, CIRC_GAUSS, CIRC_SOFT, RECT_GAUSS, RECT_SOFT, STAMP
+};
+
+class KisMaskSimilarityTester
+{
+
+public:
+ KisMaskSimilarityTester(KisBrushMaskApplicatorBase *_legacy, KisBrushMaskApplicatorBase *_vectorized, QRect _bounds, MaskType type, bool renderImage = true)
+ : legacy(_legacy)
+ , vectorized(_vectorized)
+ , m_bounds(_bounds)
+ {
+ KisFixedPaintDeviceSP m_paintDev = new KisFixedPaintDevice(m_colorSpace);
+ m_paintDev->setRect(m_bounds);
+ m_paintDev->initialize(255);
+
+ MaskProcessingData data(m_paintDev, m_colorSpace,
+ 0.0, 1.0,
+ m_bounds.width() / 2.0, m_bounds.height() / 2.0,0);
+
+ // Start legacy scalar processing
+ legacy->initializeData(&data);
+ legacy->process(m_bounds);
+
+ QImage scalarImage(m_paintDev->convertToQImage(m_colorSpace->profile()));
+ scalarImage.invertPixels(); // Make pixel color black
+
+ // Start vector processing
+ m_paintDev->initialize(255);
+ vectorized->initializeData(&data);
+ vectorized->process(m_bounds);
+
+ QImage vectorImage(m_paintDev->convertToQImage(m_colorSpace->profile()));
+ vectorImage.invertPixels(); // Make pixel color black
+
+ if (renderImage) {
+ scalarImage.save(QString(getTypeName(type) + "_scalar_mask.png"),"PNG");
+ vectorImage.save(QString(getTypeName(type) +"_vector_mask.png"),"PNG");
+ }
+
+ // Check for differences, max errors: 0
+ QPoint tmpPt;
+ QVERIFY(TestUtil::compareQImages(tmpPt,scalarImage, vectorImage, 0, 2, 0));
+ }
+
+private:
+ QString getTypeName(MaskType type) {
+ QString strName;
+ switch (type) {
+ case CIRC_GAUSS:
+ strName = "CircGauss";
+ break;
+ case CIRC_SOFT:
+ strName = "CircSoft";
+ break;
+ case RECT_GAUSS:
+ strName = "RectGauss";
+ break;
+ case RECT_SOFT:
+ strName = "RectSoft";
+ break;
+ case STAMP:
+ strName = "Stamp";
+ break;
+ default:
+ strName = "Default";
+ break;
+ }
+ return strName;
+ }
+
+protected:
+ const KoColorSpace *m_colorSpace = KoColorSpaceRegistry::instance()->rgb8();
+
+ KisBrushMaskApplicatorBase *legacy;
+ KisBrushMaskApplicatorBase *vectorized;
+ QRect m_bounds;
+ KisFixedPaintDeviceSP m_paintDev;
+};
+
+
+void KisMaskSimilarityTest::testCircleMask()
+{
+ QRect bounds(0,0,500,500);
+ {
+ KisCircleMaskGenerator circVectr(500, 1.0, 0.5, 0.5, 2, true);
+ KisCircleMaskGenerator circScalar(circVectr);
+
+ circScalar.resetMaskApplicator(true); // Force usage of scalar backend
+ KisMaskSimilarityTester(circScalar.applicator(), circVectr.applicator(), bounds, DEFAULT);
+ }
+}
+
+void KisMaskSimilarityTest::testGaussCircleMask()
+{
+ QRect bounds(0,0,500,500);
+ {
+ KisGaussCircleMaskGenerator circVectr(500, 1.0, .8, .2, 2, true);
+ circVectr.setDiameter(500);
+ KisGaussCircleMaskGenerator circScalar(circVectr);
+
+ circScalar.resetMaskApplicator(true); // Force usage of scalar backend
+ KisMaskSimilarityTester(circScalar.applicator(), circVectr.applicator(), bounds, CIRC_GAUSS);
+ }
+ // Exahustive test
+ for (size_t i = 0; i <= 100; i += 3){
+ for (size_t j = 0; j <= 100; j += 3){
+ for (size_t k = 0; k <= 100; k += 15){
+ {
+ KisGaussCircleMaskGenerator circVectr(500, k/100.f, i/100.f, j/100.f, 2, true);
+ circVectr.setDiameter(500);
+ KisGaussCircleMaskGenerator circScalar(circVectr);
+
+ circScalar.resetMaskApplicator(true); // Force usage of scalar backend
+ KisMaskSimilarityTester(circScalar.applicator(), circVectr.applicator(), bounds,CIRC_GAUSS,false);
+ }
+ } } } // end for
+}
+
+void KisMaskSimilarityTest::testSoftCircleMask()
+{
+ QRect bounds(0,0,500,500);
+ KisCubicCurve pointsCurve;
+ pointsCurve.fromString(QString("0,1;1,0"));
+ {
+ KisCurveCircleMaskGenerator circVectr(500, 1.0, 0.5, 0.5, 2, pointsCurve,true);
+ circVectr.setDiameter(500);
+ // circVectr.setSoftness(1.0);
+ KisCurveCircleMaskGenerator circScalar(circVectr);
+
+ circScalar.resetMaskApplicator(true); // Force usage of scalar backend
+ KisMaskSimilarityTester(circScalar.applicator(), circVectr.applicator(), bounds, CIRC_SOFT);
+ }
+
+ // Exahustive test
+ for (size_t i = 0; i <= 100; i += 3){
+ for (size_t j = 0; j <= 100; j += 3){
+ for (size_t k = 0; k <= 100; k += 15){
+ {
+ KisCurveCircleMaskGenerator circVectr(500, k/100.f, i/100.f, j/100.f, 2,pointsCurve, true);
+ circVectr.setDiameter(500);
+ KisCurveCircleMaskGenerator circScalar(circVectr);
+
+ circScalar.resetMaskApplicator(true); // Force usage of scalar backend
+ KisMaskSimilarityTester(circScalar.applicator(), circVectr.applicator(), bounds,CIRC_SOFT,false);
+ }
+ } } } // end for
+}
+
+QTEST_MAIN(KisMaskSimilarityTest)
diff --git a/libs/image/tests/kis_mask_similarity_test.h b/libs/image/tests/kis_mask_similarity_test.h
new file mode 100644
index 0000000000..231f2de921
--- /dev/null
+++ b/libs/image/tests/kis_mask_similarity_test.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018 Iván Santa María <ghevan@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KIS_MASK_SIMILARITY_TEST
+#define KIS_MASK_SIMILARITY_TEST
+
+#include <QtTest>
+
+class KisMaskSimilarityTest : public QObject
+{
+ Q_OBJECT
+private Q_SLOTS:
+
+ void testCircleMask();
+ void testGaussCircleMask();
+ void testSoftCircleMask();
+};
+
+#endif
diff --git a/libs/pigment/compositeops/KoVcMultiArchBuildSupport.h b/libs/pigment/compositeops/KoVcMultiArchBuildSupport.h
index 2bdd069a74..f81fbea0f6 100644
--- a/libs/pigment/compositeops/KoVcMultiArchBuildSupport.h
+++ b/libs/pigment/compositeops/KoVcMultiArchBuildSupport.h
@@ -109,4 +109,14 @@ createOptimizedClass(typename FactoryType::ParamType param)
}
+template<class FactoryType>
+typename FactoryType::ReturnType
+createOptimizedClass(typename FactoryType::ParamType param, bool forceScalarImplemetation)
+{
+ if(forceScalarImplemetation){
+ return FactoryType::template create<Vc::ScalarImpl>(param);
+ }
+ return createOptimizedClass<FactoryType>(param);
+}
+
#endif /* __KOVCMULTIARCHBUILDSUPPORT_H */
vanyossi created this paste.Jun 14 2018, 2:29 AM
vanyossi created this object in space S1 KDE Community.
vanyossi updated the paste's language from cpp to diff.