diff --git a/benchmarks/kis_mask_generator_benchmark.cpp b/benchmarks/kis_mask_generator_benchmark.cpp index dc88f64551..da3709a01e 100644 --- a/benchmarks/kis_mask_generator_benchmark.cpp +++ b/benchmarks/kis_mask_generator_benchmark.cpp @@ -1,104 +1,111 @@ /* * Copyright (c) 2010 Cyrille Berger * * 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 #ifdef HAVE_VC #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_mask_generator_benchmark.h" #include "kis_circle_mask_generator.h" #include "kis_rect_mask_generator.h" void KisMaskGeneratorBenchmark::benchmarkCircle() { KisCircleMaskGenerator gen(1000, 0.5, 0.5, 0.5, 3, true); QBENCHMARK{ for(int i = -600; i < 600; ++i) { for(int j = -600; j < 600; ++j) { gen.valueAt(i, j); } } } } #include #include #include "kis_fixed_paint_device.h" #include "kis_types.h" #include "kis_brush_mask_applicator_base.h" #include "krita_utils.h" -void KisMaskGeneratorBenchmark::benchmarkSIMD() -{ -#ifdef HAVE_VC +void benchmarkSIMD(qreal fade) { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KisFixedPaintDeviceSP dev = new KisFixedPaintDevice(cs); - dev->setRect(QRect(0, 0, 100, 100)); + dev->setRect(QRect(0, 0, 1000, 1000)); dev->initialize(); MaskProcessingData data(dev, cs, 0.0, 1.0, - 50, 50, 0); + 500, 500, 0); - KisCircleMaskGenerator gen(100, 0.5, 0.5, 0.5, 2, false); + KisCircleMaskGenerator gen(1000, 1.0, fade, fade, 2, false); KisBrushMaskApplicatorBase *applicator = gen.applicator(); applicator->initializeData(&data); QVector rects = KritaUtils::splitRectIntoPatches(dev->bounds(), QSize(63, 63)); QBENCHMARK{ Q_FOREACH (const QRect &rc, rects) { applicator->process(rc); } } -#endif +} + +void KisMaskGeneratorBenchmark::benchmarkSIMD_SharpBrush() +{ + benchmarkSIMD(1.0); +} + +void KisMaskGeneratorBenchmark::benchmarkSIMD_FadedBrush() +{ + benchmarkSIMD(0.5); } void KisMaskGeneratorBenchmark::benchmarkSquare() { KisRectangleMaskGenerator gen(1000, 0.5, 0.5, 0.5, 3, true); QBENCHMARK{ for(int i = -600; i < 600; ++i) { for(int j = -600; j < 600; ++j) { gen.valueAt(i, j); } } } } QTEST_MAIN(KisMaskGeneratorBenchmark) diff --git a/benchmarks/kis_mask_generator_benchmark.h b/benchmarks/kis_mask_generator_benchmark.h index a7fa369551..a70bfe5dc3 100644 --- a/benchmarks/kis_mask_generator_benchmark.h +++ b/benchmarks/kis_mask_generator_benchmark.h @@ -1,34 +1,35 @@ /* * Copyright (c) 2010 Cyrille Berger * * 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_GENERATOR_BENCHMARK_H #define KIS_MASK_GENERATOR_BENCHMARK_H #include class KisMaskGeneratorBenchmark : public QObject { Q_OBJECT private Q_SLOTS: void benchmarkCircle(); - void benchmarkSIMD(); + void benchmarkSIMD_SharpBrush(); + void benchmarkSIMD_FadedBrush(); void benchmarkSquare(); - + }; #endif diff --git a/libs/image/kis_brush_mask_applicator_factories.cpp b/libs/image/kis_brush_mask_applicator_factories.cpp index fbfda53848..e9f7f66519 100644 --- a/libs/image/kis_brush_mask_applicator_factories.cpp +++ b/libs/image/kis_brush_mask_applicator_factories.cpp @@ -1,130 +1,137 @@ /* * Copyright (c) 2012 Dmitry Kazakov * * 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_brush_mask_applicator_factories.h" #include "kis_circle_mask_generator.h" #include "kis_circle_mask_generator_p.h" #include "kis_brush_mask_applicators.h" #include "kis_brush_mask_applicator_base.h" #define a(_s) #_s #define b(_s) a(_s) template<> template<> MaskApplicatorFactory::ReturnType MaskApplicatorFactory::create(ParamType maskGenerator) { return new KisBrushMaskScalarApplicator(maskGenerator); } template<> template<> MaskApplicatorFactory::ReturnType MaskApplicatorFactory::create(ParamType maskGenerator) { return new KisBrushMaskVectorApplicator(maskGenerator); } #if defined HAVE_VC struct KisCircleMaskGenerator::FastRowProcessor { FastRowProcessor(KisCircleMaskGenerator *maskGenerator) : d(maskGenerator->d) {} template void process(float* buffer, int width, float y, float cosa, float sina, float centerX, float centerY); KisCircleMaskGenerator::Private *d; }; template<> void KisCircleMaskGenerator:: FastRowProcessor::process(float* buffer, int width, float y, float cosa, float sina, float centerX, float centerY) { const bool useSmoothing = d->copyOfAntialiasEdges; + const bool noFading = d->noFading; 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->xcoef); Vc::float_v vYCoeff(d->ycoef); Vc::float_v vTransformedFadeX(d->transformedFadeX); Vc::float_v vTransformedFadeY(d->transformedFadeY); - Vc::float_v vOne(1.0f); + Vc::float_v vOne(Vc::One); 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 n = pow2(xr * vXCoeff) + pow2(yr * vYCoeff); Vc::float_m outsideMask = n > vOne; if (!outsideMask.isFull()) { - if (useSmoothing) { - xr = Vc::abs(xr) + vOne; - yr = Vc::abs(yr) + vOne; - } + if (noFading) { + Vc::float_v vFade(Vc::Zero); + vFade(outsideMask) = vOne; + vFade.store(bufferPointer, Vc::Aligned); + } else { + if (useSmoothing) { + xr = Vc::abs(xr) + vOne; + yr = Vc::abs(yr) + vOne; + } - Vc::float_v vNormFade = pow2(xr * vTransformedFadeX) + pow2(yr * vTransformedFadeY); + Vc::float_v vNormFade = pow2(xr * vTransformedFadeX) + pow2(yr * vTransformedFadeY); - //255 * n * (normeFade - 1) / (normeFade - n) - Vc::float_v vFade = n * (vNormFade - vOne) / (vNormFade - n); + //255 * n * (normeFade - 1) / (normeFade - n) + Vc::float_v vFade = n * (vNormFade - vOne) / (vNormFade - n); - // Mask in the inner circe of the mask - Vc::float_m mask = vNormFade < vOne; - vFade.setZero(mask); + // Mask in the inner circe of the mask + Vc::float_m mask = vNormFade < vOne; + vFade.setZero(mask); - // Mask out the outer circe of the mask - vFade(outsideMask) = vOne; + // Mask out the outer circe of the mask + vFade(outsideMask) = vOne; - vFade.store(bufferPointer, Vc::Aligned); + 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; } } #endif /* defined HAVE_VC */ diff --git a/libs/image/kis_circle_mask_generator.cpp b/libs/image/kis_circle_mask_generator.cpp index e2454f6930..07f5fdc935 100644 --- a/libs/image/kis_circle_mask_generator.cpp +++ b/libs/image/kis_circle_mask_generator.cpp @@ -1,126 +1,130 @@ /* * Copyright (c) 2004,2007-2009 Cyrille Berger * Copyright (c) 2010 Lukáš Tvrdý * Copyright (c) 2012 Sven Langkamp * * 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 #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_circle_mask_generator.h" #include "kis_circle_mask_generator_p.h" #include "kis_base_mask_generator.h" #include "kis_brush_mask_applicator_factories.h" #include "kis_brush_mask_applicator_base.h" KisCircleMaskGenerator::KisCircleMaskGenerator(qreal diameter, qreal ratio, qreal fh, qreal fv, int spikes, bool antialiasEdges) : KisMaskGenerator(diameter, ratio, fh, fv, spikes, antialiasEdges, CIRCLE, DefaultId), d(new Private) { setScale(1.0, 1.0); // store the variable locally to allow vector implementation read it easily d->copyOfAntialiasEdges = antialiasEdges; d->applicator = createOptimizedClass >(this); } void KisCircleMaskGenerator::setScale(qreal scaleX, qreal scaleY) { KisMaskGenerator::setScale(scaleX, scaleY); d->xcoef = 2.0 / effectiveSrcWidth(); d->ycoef = 2.0 / effectiveSrcHeight(); d->xfadecoef = (horizontalFade() == 0) ? 1 : (2.0 / (horizontalFade() * effectiveSrcWidth())); d->yfadecoef = (verticalFade() == 0) ? 1 : (2.0 / (verticalFade() * effectiveSrcHeight())); d->transformedFadeX = KisMaskGenerator::softness() * d->xfadecoef; d->transformedFadeY = KisMaskGenerator::softness() * d->yfadecoef; + + d->noFading = !d->copyOfAntialiasEdges && + qFuzzyCompare(d->xcoef, d->transformedFadeX) && + qFuzzyCompare(d->ycoef, d->transformedFadeY); } KisCircleMaskGenerator::~KisCircleMaskGenerator() { delete d->applicator; delete d; } bool KisCircleMaskGenerator::shouldSupersample() const { return effectiveSrcWidth() < 10 || effectiveSrcHeight() < 10; } bool KisCircleMaskGenerator::shouldVectorize() const { return !shouldSupersample() && spikes() == 2; } KisBrushMaskApplicatorBase* KisCircleMaskGenerator::applicator() { return d->applicator; } quint8 KisCircleMaskGenerator::valueAt(qreal x, qreal y) const { if (isEmpty()) return 255; qreal xr = (x /*- m_xcenter*/); qreal yr = qAbs(y /*- m_ycenter*/); fixRotation(xr, yr); qreal n = norme(xr * d->xcoef, yr * d->ycoef); if (n > 1.0) return 255; // we add +1.0 to ensure correct antialising on the border if (antialiasEdges()) { xr = qAbs(xr) + 1.0; yr = qAbs(yr) + 1.0; } qreal nf = norme(xr * d->transformedFadeX, yr * d->transformedFadeY); if (nf < 1.0) return 0; return 255 * n * (nf - 1.0) / (nf - n); } void KisCircleMaskGenerator::setSoftness(qreal softness) { KisMaskGenerator::setSoftness(softness); qreal safeSoftnessCoeff = qreal(1.0) / qMax(qreal(0.01), softness); d->transformedFadeX = d->xfadecoef * safeSoftnessCoeff; d->transformedFadeY = d->yfadecoef * safeSoftnessCoeff; } diff --git a/libs/image/kis_circle_mask_generator_p.h b/libs/image/kis_circle_mask_generator_p.h index d738583b2d..7f7c330a92 100644 --- a/libs/image/kis_circle_mask_generator_p.h +++ b/libs/image/kis_circle_mask_generator_p.h @@ -1,31 +1,32 @@ /* * Copyright (c) 2008-2009 Cyrille Berger * * 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_CIRCLE_MASK_GENERATOR_P_H_ #define _KIS_CIRCLE_MASK_GENERATOR_P_H_ struct Q_DECL_HIDDEN KisCircleMaskGenerator::Private { double xcoef, ycoef; double xfadecoef, yfadecoef; double transformedFadeX, transformedFadeY; bool copyOfAntialiasEdges; + bool noFading; KisBrushMaskApplicatorBase *applicator; }; #endif /* _KIS_CIRCLE_MASK_GENERATOR_P_H_ */