diff --git a/libs/image/kis_brush_mask_applicator_factories.cpp b/libs/image/kis_brush_mask_applicator_factories.cpp --- a/libs/image/kis_brush_mask_applicator_factories.cpp +++ b/libs/image/kis_brush_mask_applicator_factories.cpp @@ -24,6 +24,8 @@ #include "kis_gauss_circle_mask_generator_p.h" #include "kis_curve_circle_mask_generator_p.h" #include "kis_gauss_rect_mask_generator_p.h" +#include "kis_curve_rect_mask_generator_p.h" +#include "kis_rect_mask_generator_p.h" #include "kis_brush_mask_applicators.h" #include "kis_brush_mask_applicator_base.h" @@ -63,6 +65,14 @@ return new KisBrushMaskVectorApplicator(maskGenerator); } +template<> +template<> +MaskApplicatorFactory::ReturnType +MaskApplicatorFactory::create(ParamType maskGenerator) +{ + return new KisBrushMaskVectorApplicator(maskGenerator); +} + template<> template<> MaskApplicatorFactory::ReturnType @@ -71,6 +81,14 @@ return new KisBrushMaskVectorApplicator(maskGenerator); } +template<> +template<> +MaskApplicatorFactory::ReturnType +MaskApplicatorFactory::create(ParamType maskGenerator) +{ + return new KisBrushMaskVectorApplicator(maskGenerator); +} + #if defined HAVE_VC @@ -180,7 +198,7 @@ template<> void KisGaussCircleMaskGenerator:: FastRowProcessor::process(float* buffer, int width, float y, float cosa, float sina, float centerX, float centerY) -{ +{ float y_ = y - centerY; float sinay_ = sina * y_; float cosay_ = cosa * y_; @@ -306,7 +324,7 @@ if (!excludeMask.isFull()) { Vc::float_v valDist = dist * vCurveResolution; // truncate - Vc::SimdArray vAlphaValue(valDist); + Vc::float_v::IndexType vAlphaValue(valDist); Vc::float_v vFloatAlphaValue = vAlphaValue; Vc::float_v alphaValueF = valDist - vFloatAlphaValue; @@ -355,6 +373,100 @@ KisGaussRectangleMaskGenerator::Private *d; }; +struct KisRectangleMaskGenerator::FastRowProcessor +{ + FastRowProcessor(KisRectangleMaskGenerator *maskGenerator) + : d(maskGenerator->d.data()) {} + + template + void process(float* buffer, int width, float y, float cosa, float sina, + float centerX, float centerY); + + KisRectangleMaskGenerator::Private *d; +}; + +template<> void KisRectangleMaskGenerator:: +FastRowProcessor::process(float* buffer, int width, float y, float cosa, float sina, + float centerX, float centerY) +{ + const bool useSmoothing = d->copyOfAntialiasEdges; + + 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 vCosa(cosa); + Vc::float_v vSina(sina); + Vc::float_v vCosaY_(cosay_); + Vc::float_v vSinaY_(sinay_); + + Vc::float_v vXCoeff(d->xcoeff); + Vc::float_v vYCoeff(d->ycoeff); + + Vc::float_v vTransformedFadeX(d->transformedFadeX); + Vc::float_v vTransformedFadeY(d->transformedFadeY); + + Vc::float_v vOne(Vc::One); + Vc::float_v vZero(Vc::Zero); + Vc::float_v vTolerance(10000.f); + + for (int i=0; i < width; i+= Vc::float_v::size()){ + + Vc::float_v x_ = currentIndices - vCenterX; + + Vc::float_v xr = Vc::abs(x_ * vCosa - vSinaY_); + Vc::float_v yr = Vc::abs(x_ * vSina + vCosaY_); + + Vc::float_v nxr = xr * vXCoeff; + Vc::float_v nyr = yr * vYCoeff; + + Vc::float_m outsideMask = (nxr > vOne) || (nyr > vOne); + + if (!outsideMask.isFull()) { + if (useSmoothing) { + xr = Vc::abs(xr) + vOne; + yr = Vc::abs(yr) + vOne; + } + + Vc::float_v fxr = xr * vTransformedFadeX; + Vc::float_v fyr = yr * vTransformedFadeY; + + Vc::float_v fxrNorm = nxr * (fxr - vOne) / (fxr - nxr); + Vc::float_v fyrNorm = nyr * (fyr - vOne) / (fyr - nyr); + + Vc::float_v vFade(vZero); + + Vc::float_v::IndexType fxrInt(fxr * vTolerance); + Vc::float_v::IndexType fyrInt(fyr * vTolerance); + + Vc::float_m fadeXMask = (fxr > vOne) && ((fxrInt >= fyrInt) || fyr < vOne); + Vc::float_m fadeYMask = (fyr > vOne) && ((fyrInt > fxrInt) || fxr < vOne); + + vFade(fadeXMask) = fxrNorm; + vFade(!fadeXMask && fadeYMask) = fyrNorm; + + // Mask out the outer circe of the mask + vFade(outsideMask) = vOne; + vFade.store(bufferPointer, Vc::Aligned); + } else { + // Mask out everything outside the circle + vOne.store(bufferPointer, Vc::Aligned); + } + + currentIndices = currentIndices + increment; + + bufferPointer += Vc::float_v::size(); + } +} + + template<> void KisGaussRectangleMaskGenerator:: FastRowProcessor::process(float* buffer, int width, float y, float cosa, float sina, float centerX, float centerY) @@ -432,4 +544,111 @@ } } +struct KisCurveRectangleMaskGenerator::FastRowProcessor +{ + FastRowProcessor(KisCurveRectangleMaskGenerator *maskGenerator) + : d(maskGenerator->d.data()) {} + + template + void process(float* buffer, int width, float y, float cosa, float sina, + float centerX, float centerY); + + KisCurveRectangleMaskGenerator::Private *d; +}; + +template<> void KisCurveRectangleMaskGenerator:: +FastRowProcessor::process(float* buffer, int width, float y, float cosa, float sina, + float centerX, float centerY) +{ + 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->ycoeff); + Vc::float_v vXCoeff(d->xcoeff); + Vc::float_v vCurveResolution(d->curveResolution); + + 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 = abs(x_ * vSina + vCosaY_); + + Vc::float_v vValue; + + // check if we need to apply fader on values + Vc::float_m excludeMask = d->fadeMaker.needFade(xr,yr); + vValue(excludeMask) = vOne; + + if (!excludeMask.isFull()) { + // We need to mask the extra area given for aliniation + // the next operation should never give values above 1 + Vc::float_v preSIndex = abs(xr) * vXCoeff; + Vc::float_v preTIndex = abs(yr) * vYCoeff; + + preSIndex(preSIndex > vOne) = vOne; + preTIndex(preTIndex > vOne) = vOne; + + Vc::float_v::IndexType sIndex( round(preSIndex * vCurveResolution)); + Vc::float_v::IndexType tIndex( round(preTIndex * vCurveResolution)); + + Vc::float_v::IndexType sIndexInverted = vCurveResolution - sIndex; + Vc::float_v::IndexType tIndexInverted = vCurveResolution - tIndex; + + Vc::float_v vCurvedDataSIndex(curveDataPointer, sIndex); + Vc::float_v vCurvedDataTIndex(curveDataPointer, tIndex); + Vc::float_v vCurvedDataSIndexInv(curveDataPointer, sIndexInverted); + Vc::float_v vCurvedDataTIndexInv(curveDataPointer, tIndexInverted); + + Vc::float_v fullFade = vValMax * (vOne - (vCurvedDataSIndex * (vOne - vCurvedDataSIndexInv) * + vCurvedDataTIndex * (vOne - vCurvedDataTIndexInv))); + + // apply antialias fader + d->fadeMaker.apply2DFader(fullFade,excludeMask,xr,yr); + + Vc::float_m 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 = fullFade / vValMax; + + // return original vValue values before vFade transform + vFade(excludeMask) = vValue; + vFade.store(bufferPointer, Vc::Aligned); + + } else { + vValue.store(bufferPointer, Vc::Aligned); + } + currentIndices = currentIndices + increment; + + bufferPointer += Vc::float_v::size(); + } +} + #endif /* defined HAVE_VC */ diff --git a/libs/image/kis_curve_rect_mask_generator.h b/libs/image/kis_curve_rect_mask_generator.h --- a/libs/image/kis_curve_rect_mask_generator.h +++ b/libs/image/kis_curve_rect_mask_generator.h @@ -32,7 +32,8 @@ */ class KRITAIMAGE_EXPORT KisCurveRectangleMaskGenerator : public KisMaskGenerator { - +public: + struct FastRowProcessor; public: KisCurveRectangleMaskGenerator(qreal radius, qreal ratio, qreal fh, qreal fv, int spikes, const KisCubicCurve& curve, bool antialiasEdges); @@ -48,9 +49,13 @@ void setSoftness(qreal softness) override; + bool shouldVectorize() const override; + KisBrushMaskApplicatorBase* applicator() override; + void resetMaskApplicator(bool forceScalar); + private: struct Private; - Private* const d; + const QScopedPointer d; }; #endif diff --git a/libs/image/kis_curve_rect_mask_generator.cpp b/libs/image/kis_curve_rect_mask_generator.cpp --- a/libs/image/kis_curve_rect_mask_generator.cpp +++ b/libs/image/kis_curve_rect_mask_generator.cpp @@ -20,44 +20,38 @@ #include +#include +#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 +#include +#if defined _MSC_VER +#pragma warning ( pop ) +#endif +#endif + #include #include #include #include -#include "kis_curve_rect_mask_generator.h" -#include "kis_cubic_curve.h" #include "kis_antialiasing_fade_maker.h" +#include "kis_brush_mask_applicator_factories.h" +#include "kis_brush_mask_applicator_base.h" +#include "kis_curve_rect_mask_generator.h" +#include "kis_curve_rect_mask_generator_p.h" +#include "kis_cubic_curve.h" -struct Q_DECL_HIDDEN KisCurveRectangleMaskGenerator::Private -{ - Private(bool enableAntialiasing) - : fadeMaker(*this, enableAntialiasing) - { - } - - Private(const Private &rhs) - : xcoeff(rhs.xcoeff), - ycoeff(rhs.ycoeff), - curveResolution(rhs.curveResolution), - curveData(rhs.curveData), - curvePoints(rhs.curvePoints), - dirty(rhs.dirty), - fadeMaker(rhs.fadeMaker, *this) - { - } - - qreal xcoeff, ycoeff; - qreal curveResolution; - QVector curveData; - QList curvePoints; - bool dirty; - - KisAntialiasingFadeMaker2D fadeMaker; - - quint8 value(qreal xr, qreal yr) const; -}; KisCurveRectangleMaskGenerator::KisCurveRectangleMaskGenerator(qreal diameter, qreal ratio, qreal fh, qreal fv, int spikes, const KisCubicCurve &curve, bool antialiasEdges) : KisMaskGenerator(diameter, ratio, fh, fv, spikes, antialiasEdges, RECTANGLE, SoftId), d(new Private(antialiasEdges)) @@ -69,12 +63,15 @@ d->dirty = false; setScale(1.0, 1.0); + + d->applicator.reset(createOptimizedClass >(this)); } KisCurveRectangleMaskGenerator::KisCurveRectangleMaskGenerator(const KisCurveRectangleMaskGenerator &rhs) : KisMaskGenerator(rhs), d(new Private(*rhs.d)) { + d->applicator.reset(createOptimizedClass >(this)); } KisMaskGenerator* KisCurveRectangleMaskGenerator::clone() const @@ -97,7 +94,6 @@ KisCurveRectangleMaskGenerator::~KisCurveRectangleMaskGenerator() { - delete d; } quint8 KisCurveRectangleMaskGenerator::Private::value(qreal xr, qreal yr) const @@ -148,3 +144,18 @@ d->dirty = false; } +bool KisCurveRectangleMaskGenerator::shouldVectorize() const +{ + return !shouldSupersample() && spikes() == 2; +} + +KisBrushMaskApplicatorBase* KisCurveRectangleMaskGenerator::applicator() +{ + return d->applicator.data(); +} + +void KisCurveRectangleMaskGenerator::resetMaskApplicator(bool forceScalar) +{ + d->applicator.reset(createOptimizedClass >(this,forceScalar)); +} + diff --git a/libs/image/kis_curve_rect_mask_generator_p.h b/libs/image/kis_curve_rect_mask_generator_p.h new file mode 100644 --- /dev/null +++ b/libs/image/kis_curve_rect_mask_generator_p.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2010 Lukáš Tvrdý + * + * 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_RECT_MASK_GENERATOR_P_H +#define KIS_CURVE_RECT_MASK_GENERATOR_P_H + +#include + +#include "kis_antialiasing_fade_maker.h" +#include "kis_brush_mask_applicator_base.h" + +struct Q_DECL_HIDDEN KisCurveRectangleMaskGenerator::Private +{ + Private(bool enableAntialiasing) + : fadeMaker(*this, enableAntialiasing) + { + } + + Private(const Private &rhs) + : xcoeff(rhs.xcoeff), + ycoeff(rhs.ycoeff), + curveResolution(rhs.curveResolution), + curveData(rhs.curveData), + curvePoints(rhs.curvePoints), + dirty(rhs.dirty), + fadeMaker(rhs.fadeMaker, *this) + { + } + + qreal xcoeff, ycoeff; + qreal curveResolution; + QVector curveData; + QList curvePoints; + bool dirty; + + KisAntialiasingFadeMaker2D fadeMaker; + QScopedPointer applicator; + + inline quint8 value(qreal xr, qreal yr) const; +}; + +#endif // KIS_CURVE_RECT_MASK_GENERATOR_P_H diff --git a/libs/image/kis_rect_mask_generator.h b/libs/image/kis_rect_mask_generator.h --- a/libs/image/kis_rect_mask_generator.h +++ b/libs/image/kis_rect_mask_generator.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2008-2009 Cyrille Berger + * Copyright (c) 2018 Ivan Santa Maria * * 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 @@ -22,7 +23,6 @@ #include #include "kritaimage_export.h" - #include "kis_mask_generator.h" /** @@ -30,7 +30,8 @@ */ class KRITAIMAGE_EXPORT KisRectangleMaskGenerator : public KisMaskGenerator { - +public: + struct FastRowProcessor; public: KisRectangleMaskGenerator(qreal radius, qreal ratio, qreal fh, qreal fv, int spikes, bool antialiasEdges); @@ -44,6 +45,10 @@ void setScale(qreal scaleX, qreal scaleY) override; void setSoftness(qreal softness) override; + bool shouldVectorize() const override; + KisBrushMaskApplicatorBase* applicator() override; + void resetMaskApplicator(bool forceScalar); + private: struct Private; const QScopedPointer d; diff --git a/libs/image/kis_rect_mask_generator.cpp b/libs/image/kis_rect_mask_generator.cpp --- a/libs/image/kis_rect_mask_generator.cpp +++ b/libs/image/kis_rect_mask_generator.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2004,2007,2008,2009.2010 Cyrille Berger + * Copyright (c) 2018 Ivan Santa Maria * * 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 @@ -19,43 +20,53 @@ #include //MSVC requires that Vc come first #include +#include +#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 +#include +#if defined _MSC_VER +#pragma warning ( pop ) +#endif +#endif + + #include #include "kis_fast_math.h" - #include "kis_rect_mask_generator.h" +#include "kis_rect_mask_generator_p.h" #include "kis_base_mask_generator.h" -#include +#include "kis_brush_mask_applicator_factories.h" +#include "kis_brush_mask_applicator_base.h" -struct Q_DECL_HIDDEN KisRectangleMaskGenerator::Private { - double m_c; - qreal xcoeff; - qreal ycoeff; - qreal xfadecoeff; - qreal yfadecoeff; - qreal transformedFadeX; - qreal transformedFadeY; -}; +#include KisRectangleMaskGenerator::KisRectangleMaskGenerator(qreal radius, qreal ratio, qreal fh, qreal fv, int spikes, bool antialiasEdges) : KisMaskGenerator(radius, ratio, fh, fv, spikes, antialiasEdges, RECTANGLE, DefaultId), d(new Private) { - if (fv == 0 && fh == 0) { - d->m_c = 0; - } else { - d->m_c = (fv / fh); - Q_ASSERT(!qIsNaN(d->m_c)); - - } - setScale(1.0, 1.0); + + // store the variable locally to allow vector implementation read it easily + d->copyOfAntialiasEdges = antialiasEdges; + d->applicator.reset(createOptimizedClass >(this)); } KisRectangleMaskGenerator::KisRectangleMaskGenerator(const KisRectangleMaskGenerator &rhs) : KisMaskGenerator(rhs), d(new Private(*rhs.d)) { + d->applicator.reset(createOptimizedClass >(this)); } KisMaskGenerator* KisRectangleMaskGenerator::clone() const @@ -75,6 +86,7 @@ d->ycoeff = 2.0 / effectiveSrcHeight(); d->xfadecoeff = (horizontalFade() == 0) ? 1 : (2.0 / (horizontalFade() * effectiveSrcWidth())); d->yfadecoeff = (verticalFade() == 0) ? 1 : (2.0 / (verticalFade() * effectiveSrcHeight())); + setSoftness(this->softness()); } @@ -92,6 +104,21 @@ return effectiveSrcWidth() < 10 || effectiveSrcHeight() < 10; } +bool KisRectangleMaskGenerator::shouldVectorize() const +{ + return !shouldSupersample() && spikes() == 2; +} + +KisBrushMaskApplicatorBase* KisRectangleMaskGenerator::applicator() +{ + return d->applicator.data(); +} + +void KisRectangleMaskGenerator::resetMaskApplicator(bool forceScalar) +{ + d->applicator.reset(createOptimizedClass >(this,forceScalar)); +} + quint8 KisRectangleMaskGenerator::valueAt(qreal x, qreal y) const { if (isEmpty()) return 255; @@ -115,11 +142,14 @@ qreal fxr = xr * d->transformedFadeX; qreal fyr = yr * d->transformedFadeY; - if (fxr > 1.0 && (fxr > fyr || fyr < 1.0)) { + int fxrInt = fxr * 1e4; + int fyrInt = fyr * 1e4; + + if (fxr > 1.0 && (fxrInt >= fyrInt || fyr < 1.0)) { return 255 * nxr * (fxr - 1.0) / (fxr - nxr); } - if (fyr > 1.0 && (fyr > fxr || fxr < 1.0)) { + if (fyr > 1.0 && (fyrInt > fxrInt || fxr < 1.0)) { return 255 * nyr * (fyr - 1.0) / (fyr - nyr); } diff --git a/libs/image/kis_rect_mask_generator_p.h b/libs/image/kis_rect_mask_generator_p.h new file mode 100644 --- /dev/null +++ b/libs/image/kis_rect_mask_generator_p.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2008-2009 Cyrille Berger + * Copyright (c) 2018 Ivan Santa Maria + * + * 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_RECT_MASK_GENERATOR_P_H +#define KIS_RECT_MASK_GENERATOR_P_H + +struct Q_DECL_HIDDEN KisRectangleMaskGenerator::Private { + Private() + : xcoeff(0), + ycoeff(0), + xfadecoeff(0), + yfadecoeff(0), + transformedFadeX(0), + transformedFadeY(0), + copyOfAntialiasEdges(false) + { + } + + Private(const Private &rhs) + : xcoeff(rhs.xcoeff), + ycoeff(rhs.ycoeff), + xfadecoeff(rhs.xfadecoeff), + yfadecoeff(rhs.yfadecoeff), + transformedFadeX(rhs.transformedFadeX), + transformedFadeY(rhs.transformedFadeY), + copyOfAntialiasEdges(rhs.copyOfAntialiasEdges) + { + } + qreal xcoeff; + qreal ycoeff; + qreal xfadecoeff; + qreal yfadecoeff; + qreal transformedFadeX; + qreal transformedFadeY; + + bool copyOfAntialiasEdges; + bool noFading; + + QScopedPointer applicator; +}; + + +#endif // KIS_RECT_MASK_GENERATOR_P_H diff --git a/libs/image/tests/KisMaskGeneratorBenchmark.h b/libs/image/tests/KisMaskGeneratorBenchmark.h --- a/libs/image/tests/KisMaskGeneratorBenchmark.h +++ b/libs/image/tests/KisMaskGeneratorBenchmark.h @@ -25,7 +25,6 @@ { Q_OBJECT private Q_SLOTS: - void testDefaultScalarMask(); void testDefaultVectorMask(); @@ -35,8 +34,15 @@ void testCircularSoftScalarMask(); void testCircularSoftVectorMask(); + void testRectangularScalarMask(); + void testRectangularVectorMask(); + void testRectangularGaussScalarMask(); void testRectangularGaussVectorMask(); + + void testRectangularSoftScalarMask(); + void testRectangularSoftVectorMask(); + }; #endif // KISMASKGENERATORBENCHMARK_H diff --git a/libs/image/tests/KisMaskGeneratorBenchmark.cpp b/libs/image/tests/KisMaskGeneratorBenchmark.cpp --- a/libs/image/tests/KisMaskGeneratorBenchmark.cpp +++ b/libs/image/tests/KisMaskGeneratorBenchmark.cpp @@ -135,6 +135,24 @@ } } +void KisMaskGeneratorBenchmark::testRectangularScalarMask(){ + QRect bounds(0,0,1000,1000); + { + KisRectangleMaskGenerator rectScalar(1000, 1.0, 0.5, 0.5, 2, true); + rectScalar.resetMaskApplicator(true); // Force usage of scalar backend + + KisMaskGeneratorBenchmarkTester(rectScalar.applicator(), bounds); + } +} + +void KisMaskGeneratorBenchmark::testRectangularVectorMask(){ + QRect bounds(0,0,1000,1000); + { + KisRectangleMaskGenerator rectScalar(1000, 1.0, 0.5, 0.5, 2, true); + KisMaskGeneratorBenchmarkTester(rectScalar.applicator(), bounds); + } +} + void KisMaskGeneratorBenchmark::testRectangularGaussScalarMask() { QRect bounds(0,0,1000,1000); @@ -156,4 +174,29 @@ } } +void KisMaskGeneratorBenchmark::testRectangularSoftScalarMask() +{ + QRect bounds(0,0,1000,1000); + KisCubicCurve pointsCurve; + pointsCurve.fromString(QString("0,1;1,0")); + { + KisCurveRectangleMaskGenerator circScalar(1000, 1.0, 0.5, 0.5, 2, pointsCurve, true); + + circScalar.resetMaskApplicator(true); // Force usage of scalar backend + + KisMaskGeneratorBenchmarkTester(circScalar.applicator(), bounds); + } +} +void KisMaskGeneratorBenchmark::testRectangularSoftVectorMask() +{ + QRect bounds(0,0,1000,1000); + KisCubicCurve pointsCurve; + pointsCurve.fromString(QString("0,1;1,0")); + { + KisCurveRectangleMaskGenerator circVectr(1000, 1.0, 0.5, 0.5, 2, pointsCurve, true); + + KisMaskGeneratorBenchmarkTester(circVectr.applicator(), bounds); + } +} + QTEST_MAIN(KisMaskGeneratorBenchmark) diff --git a/libs/image/tests/kis_mask_similarity_test.h b/libs/image/tests/kis_mask_similarity_test.h --- a/libs/image/tests/kis_mask_similarity_test.h +++ b/libs/image/tests/kis_mask_similarity_test.h @@ -29,7 +29,10 @@ void testCircleMask(); void testGaussCircleMask(); void testSoftCircleMask(); + + void testRectMask(); void testGaussRectMask(); + void testSoftRectMask(); }; #endif diff --git a/libs/image/tests/kis_mask_similarity_test.cpp b/libs/image/tests/kis_mask_similarity_test.cpp --- a/libs/image/tests/kis_mask_similarity_test.cpp +++ b/libs/image/tests/kis_mask_similarity_test.cpp @@ -41,7 +41,7 @@ enum MaskType { - DEFAULT, CIRC_GAUSS, CIRC_SOFT, RECT_GAUSS, RECT_SOFT, STAMP + DEFAULT, CIRC_GAUSS, CIRC_SOFT, RECT, RECT_GAUSS, RECT_SOFT, STAMP }; class KisMaskSimilarityTester @@ -76,18 +76,24 @@ QImage vectorImage(m_paintDev->convertToQImage(m_colorSpace->profile())); vectorImage.invertPixels(); // Make pixel color black + if (renderImage || QTest::currentTestFailed()) { + + } + // Check for differences, max errors: 0 QPoint tmpPt; - QVERIFY(TestUtil::compareQImages(tmpPt,scalarImage, vectorImage, 0, 2, 0)); - - if (renderImage || QTest::currentTestFailed()) { + if (!TestUtil::compareQImages(tmpPt,scalarImage, vectorImage, 0, 2, 0)) { scalarImage.save(QString(getTypeName(type) + "_scalar_mask.png"),"PNG"); vectorImage.save(QString(getTypeName(type) + "_vector_mask.png"),"PNG"); + + QFAIL(QString("Masks differ! first different pixel: %1,%2 \n").arg(tmpPt.x()).arg(tmpPt.y()).toLatin1()); } + + } - static void exahustiveTest(QRect bounds, MaskType type) { + static bool exahustiveTest(QRect bounds, MaskType type) { // Exahustive test for (size_t i = 0; i <= 100; i += FADE_STEP){ @@ -116,6 +122,16 @@ KisMaskSimilarityTester(bCircScalar.applicator(), bCircVectr.applicator(), bounds,type,false); break; + } + case RECT: + { + KisRectangleMaskGenerator bCircVectr(499.5, k/100.f, i/100.f, j/100.f, 2, true); + KisRectangleMaskGenerator bCircScalar(bCircVectr); + bCircScalar.resetMaskApplicator(true); // Force usage of scalar backend + + KisMaskSimilarityTester(bCircScalar.applicator(), bCircVectr.applicator(), bounds,type,false); + break; + } case RECT_GAUSS: { @@ -126,16 +142,32 @@ KisMaskSimilarityTester(bCircScalar.applicator(), bCircVectr.applicator(), bounds,type,false); break; + } + case RECT_SOFT: + { + KisCubicCurve pointsCurve; + pointsCurve.fromString(QString("0,1;1,0")); + KisCurveRectangleMaskGenerator bCircVectr(499.5, k/100.f, i/100.f, j/100.f, 2, pointsCurve, true); + KisCurveRectangleMaskGenerator bCircScalar(bCircVectr); + bCircScalar.resetMaskApplicator(true); // Force usage of scalar backend + + KisMaskSimilarityTester(bCircScalar.applicator(), bCircVectr.applicator(), bounds,type,false); + break; } default: { - return; break; } } + if (QTest::currentTestFailed()) { + QWARN(QString("Mask features: Ratio=%1, hfade=%2, vfade=%3 \n") + .arg(k/100.f,0,'g',2).arg(i/100.f,0,'g',2).arg(j/100.f,0,'g',2).toLatin1()); + return false; + } + } } } // end for - return; + return true; } private: @@ -148,6 +180,9 @@ case CIRC_SOFT: strName = "CircSoft"; break; + case RECT: + strName = "Rect"; + break; case RECT_GAUSS: strName = "RectGauss"; break; @@ -176,9 +211,9 @@ void KisMaskSimilarityTest::testCircleMask() { - QRect bounds(0,0,500,500); + QRect bounds(0,0,700,700); { - KisCircleMaskGenerator circVectr(499.5, 1.0, 0.5, 0.5, 2, true); + KisCircleMaskGenerator circVectr(499.5, 0.2, 0.5, 0.5, 2, true); KisCircleMaskGenerator circScalar(circVectr); circScalar.resetMaskApplicator(true); // Force usage of scalar backend @@ -188,9 +223,9 @@ void KisMaskSimilarityTest::testGaussCircleMask() { - QRect bounds(0,0,520,520); + QRect bounds(0,0,700,700); { - KisGaussCircleMaskGenerator circVectr(499.5, 1.0, 1, 1, 2, true); + KisGaussCircleMaskGenerator circVectr(499.5, 0.2, 1, 1, 2, true); circVectr.setDiameter(499.5); KisGaussCircleMaskGenerator circScalar(circVectr); @@ -198,16 +233,16 @@ KisMaskSimilarityTester(circScalar.applicator(), circVectr.applicator(), bounds, CIRC_GAUSS); } - KisMaskSimilarityTester::exahustiveTest(bounds,CIRC_GAUSS); +// KisMaskSimilarityTester::exahustiveTest(bounds,CIRC_GAUSS); } void KisMaskSimilarityTest::testSoftCircleMask() { - QRect bounds(0,0,520,520); + QRect bounds(0,0,700,700); KisCubicCurve pointsCurve; pointsCurve.fromString(QString("0,1;1,0")); { - KisCurveCircleMaskGenerator circVectr(499.5, 1.0, 0.5, 0.5, 2, pointsCurve,true); + KisCurveCircleMaskGenerator circVectr(499.5, 0.2, 0.5, 0.5, 2, pointsCurve,true); circVectr.setDiameter(500); // circVectr.setSoftness(1.0); KisCurveCircleMaskGenerator circScalar(circVectr); @@ -216,21 +251,52 @@ KisMaskSimilarityTester(circScalar.applicator(), circVectr.applicator(), bounds, CIRC_SOFT); } - KisMaskSimilarityTester::exahustiveTest(bounds,CIRC_SOFT); +// KisMaskSimilarityTester::exahustiveTest(bounds,CIRC_SOFT); +} + +void KisMaskSimilarityTest::testRectMask() +{ + QRect bounds(0,0,700,700); + { +// KisRectangleMaskGenerator rectVectr(499.5, 0.2, 0.05, 0.05, 2, true); + KisRectangleMaskGenerator rectVectr(499.5, 0.1, 1, 1, 2, false); + KisRectangleMaskGenerator rectScalar(rectVectr); + + rectScalar.resetMaskApplicator(true); // Force usage of scalar backend + KisMaskSimilarityTester(rectScalar.applicator(), rectVectr.applicator(), bounds, RECT); + } + + KisMaskSimilarityTester::exahustiveTest(bounds, RECT); } void KisMaskSimilarityTest::testGaussRectMask() { - QRect bounds(0,0,540,540); + QRect bounds(0,0,700,700); { - KisGaussRectangleMaskGenerator circVectr(499.5, 1.0, 0.5, 0.2, 2, true); + KisGaussRectangleMaskGenerator circVectr(499.5, 0.2, 0.5, 0.2, 2, true); KisGaussRectangleMaskGenerator circScalar(circVectr); circScalar.resetMaskApplicator(true); // Force usage of scalar backend KisMaskSimilarityTester(circScalar.applicator(), circVectr.applicator(), bounds, RECT_GAUSS); } - KisMaskSimilarityTester::exahustiveTest(bounds,RECT_GAUSS); +// KisMaskSimilarityTester::exahustiveTest(bounds,RECT_GAUSS); +} + +void KisMaskSimilarityTest::testSoftRectMask() +{ + QRect bounds(0,0,700,700); + KisCubicCurve pointsCurve; + pointsCurve.fromString(QString("0,1;1,0")); + { + KisCurveRectangleMaskGenerator circVectr(499.5, 0.2, 0.5, 0.2, 2, pointsCurve, true); + KisCurveRectangleMaskGenerator circScalar(circVectr); + circVectr.setDiameter(499.5); + + circScalar.resetMaskApplicator(true); // Force usage of scalar backend + KisMaskSimilarityTester(circScalar.applicator(), circVectr.applicator(), bounds, RECT_SOFT); + } +// KisMaskSimilarityTester::exahustiveTest(bounds,RECT_SOFT); } QTEST_MAIN(KisMaskSimilarityTest) diff --git a/libs/ui/tests/FreehandStrokeBenchmark.h b/libs/ui/tests/FreehandStrokeBenchmark.h --- a/libs/ui/tests/FreehandStrokeBenchmark.h +++ b/libs/ui/tests/FreehandStrokeBenchmark.h @@ -30,7 +30,11 @@ void testDefaultTip(); void testSoftTip(); void testGaussianTip(); + + void testRectangularTip(); void testRectGaussianTip(); + void testRectSoftTip(); + void testStampTip(); void testColorsmudgeDefaultTip(); diff --git a/libs/ui/tests/FreehandStrokeBenchmark.cpp b/libs/ui/tests/FreehandStrokeBenchmark.cpp --- a/libs/ui/tests/FreehandStrokeBenchmark.cpp +++ b/libs/ui/tests/FreehandStrokeBenchmark.cpp @@ -128,11 +128,21 @@ benchmarkBrush("testing_1000px_auto_gaussian.kpp"); } +void FreehandStrokeBenchmark::testRectangularTip() +{ + benchmarkBrush("testing_1000px_auto_rectangular.kpp"); +} + void FreehandStrokeBenchmark::testRectGaussianTip() { benchmarkBrush("testing_1000px_auto_gaussian_rect.kpp"); } +void FreehandStrokeBenchmark::testRectSoftTip() +{ + benchmarkBrush("testing_1000px_auto_soft_rect.kpp"); +} + void FreehandStrokeBenchmark::testStampTip() { benchmarkBrush("testing_1000px_stamp_450_rotated.kpp"); diff --git a/libs/ui/tests/data/testing_1000px_auto_rectangular.kpp b/libs/ui/tests/data/testing_1000px_auto_rectangular.kpp new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@